From 77b223381ca9f23c930aae6ddcb92dcbb7da8fad Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Wed, 11 Feb 2026 08:20:27 +0100 Subject: [PATCH 1/6] ITS3: define alignable volumes Signed-off-by: Felix Schlepper --- .../ITS/base/include/ITSBase/GeometryTGeo.h | 2 +- .../ITSMFT/ITS/base/src/GeometryTGeo.cxx | 8 +--- .../ITSMFT/ITS/simulation/src/Detector.cxx | 16 ++----- .../DescriptorInnerBarrelITS3.h | 8 ++-- .../src/DescriptorInnerBarrelITS3.cxx | 44 +++++++++++++++++++ 5 files changed, 54 insertions(+), 24 deletions(-) diff --git a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h index e236c898851f5..c8ef445e273d3 100644 --- a/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h +++ b/Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h @@ -314,7 +314,7 @@ class GeometryTGeo : public o2::itsmft::GeometryTGeo static const char* getITS3PixelArrayPattern(int layer) { return Form("%s%d", getITS3PixelArrayPatternRaw(), layer); }; /// sym name of the layer - static const char* composeSymNameITS(bool isITS3 = false); + static const char* composeSymNameITS(); /// sym name of the layer static const char* composeSymNameLayer(int lr, bool isITS3 = false); diff --git a/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx b/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx index 60570b2f204c5..5dc499d05037e 100644 --- a/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx +++ b/Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx @@ -290,14 +290,8 @@ bool GeometryTGeo::getChipId(int index, int& lay, int& hba, int& sta, int& hsta, } //__________________________________________________________________________ -const char* GeometryTGeo::composeSymNameITS(bool isITS3) +const char* GeometryTGeo::composeSymNameITS() { - if (isITS3) { -#ifdef ENABLE_UPGRADES - return o2::detectors::DetID(o2::detectors::DetID::IT3).getName(); -#endif - } - return o2::detectors::DetID(o2::detectors::DetID::ITS).getName(); } diff --git a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx index 8cfe13097d581..f98bf8ef19cf5 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/Detector.cxx @@ -1106,7 +1106,7 @@ void Detector::addAlignableVolumes() const TString detName = GetName(); TString path = Form("/cave_1/barrel_1/%s_2", GeometryTGeo::getITSVolPattern()); - TString sname = GeometryTGeo::composeSymNameITS((detName == "IT3")); + TString sname = GeometryTGeo::composeSymNameITS(); LOG(debug) << sname << " <-> " << path; @@ -1119,13 +1119,13 @@ void Detector::addAlignableVolumes() const if (lr < mNumberInnerLayers) { if (detName == "ITS") { ((DescriptorInnerBarrelITS2*)mDescriptorIB.get())->addAlignableVolumesLayer(lr, mWrapperLayerId[lr], path, lastUID); + } else { + ((DescriptorInnerBarrelITS3*)mDescriptorIB.get())->addAlignableVolumesLayer(lr, mWrapperLayerId[lr], path, lastUID); } } else { addAlignableVolumesLayer(lr, path, lastUID); } } - - return; } void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) const @@ -1148,8 +1148,6 @@ void Detector::addAlignableVolumesLayer(int lr, TString& parent, Int_t& lastUID) for (Int_t hb = start; hb < nhbarrel; hb++) { addAlignableVolumesHalfBarrel(lr, hb, path, lastUID); } - - return; } void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent, Int_t& lastUID) const @@ -1177,8 +1175,6 @@ void Detector::addAlignableVolumesHalfBarrel(Int_t lr, Int_t hb, TString& parent for (int st = 0; st < nstaves; st++) { addAlignableVolumesStave(lr, hb, st, path, lastUID); } - - return; } void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& parent, Int_t& lastUID) const @@ -1205,8 +1201,6 @@ void Detector::addAlignableVolumesStave(Int_t lr, Int_t hb, Int_t st, TString& p for (Int_t sst = start; sst < nhstave; sst++) { addAlignableVolumesHalfStave(lr, hb, st, sst, path, lastUID); } - - return; } void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t hst, TString& parent, Int_t& lastUID) const @@ -1236,8 +1230,6 @@ void Detector::addAlignableVolumesHalfStave(Int_t lr, Int_t hb, Int_t st, Int_t for (Int_t md = start; md < nmodules; md++) { addAlignableVolumesModule(lr, hb, st, hst, md, path, lastUID); } - - return; } void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, TString& parent, Int_t& lastUID) const @@ -1266,8 +1258,6 @@ void Detector::addAlignableVolumesModule(Int_t lr, Int_t hb, Int_t st, Int_t hst for (Int_t ic = 0; ic < nchips; ic++) { addAlignableVolumesChip(lr, hb, st, hst, md, ic, path, lastUID); } - - return; } void Detector::addAlignableVolumesChip(Int_t lr, Int_t hb, Int_t st, Int_t hst, Int_t md, Int_t ch, TString& parent, diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h index 80565df55d154..3e230cee474bd 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h @@ -40,17 +40,19 @@ class DescriptorInnerBarrelITS3 : public o2::its::DescriptorInnerBarrel void createLayer(int idLayer, TGeoVolume* dest); void createServices(TGeoVolume* dest); void configure() {} + void addAlignableVolumesLayer(int idLayer, int wrapperLayerId, TString& parentPath, int& lastUID) const; protected: - int mNumLayers{constants::nLayers}; - // wrapper volume properties static constexpr double mTolerance{1e-3}; static constexpr double mWrapperMinRadiusITS3{constants::radiiInner[0] - mTolerance}; static constexpr double mWrapperMaxRadiusITS3{constants::services::radiusOuter + mTolerance}; - static constexpr double mWrapperZSpanITS3{constants::services::length * 2 + mTolerance}; // z length is divided in half + static constexpr double mWrapperZSpanITS3{(constants::services::length * 2) + mTolerance}; // z length is divided in half private: + void addAlignableVolumesHalfBarrel(int idLayer, int iHB, TString& parentPath, int& lastUID) const; + void addAlignableVolumesChips(int idLayer, int iHalfBarrel, TString& parentPath, int& lastUID) const; + std::array, constants::nLayers> mIBLayers; std::unique_ptr mServices; diff --git a/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx b/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx index 04f244284d5b6..42644fbfe0c38 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx @@ -10,6 +10,8 @@ // or submit itself to any jurisdiction. #include "ITS3Simulation/DescriptorInnerBarrelITS3.h" +#include "ITSBase/GeometryTGeo.h" +#include "Framework/Logger.h" using namespace o2::its3; @@ -26,3 +28,45 @@ void DescriptorInnerBarrelITS3::createServices(TGeoVolume* dest) mServices = std::make_unique(); mServices->createCYSSAssembly(dest); } + +void DescriptorInnerBarrelITS3::addAlignableVolumesLayer(int idLayer, int wrapperLayerId, TString& parentPath, int& lastUID) const +{ + TString wrpV = wrapperLayerId != -1 ? Form("%s%d_1", its::GeometryTGeo::getITSWrapVolPattern(), wrapperLayerId) : ""; + TString path = Form("%s/%s/%s%d_0", parentPath.Data(), wrpV.Data(), its::GeometryTGeo::getITS3LayerPattern(), idLayer); + TString sname = its::GeometryTGeo::composeSymNameLayer(idLayer, true); + + for (int iHalfBarrel{0}; iHalfBarrel < 2; ++iHalfBarrel) { + addAlignableVolumesHalfBarrel(idLayer, iHalfBarrel, path, lastUID); + } +} + +void DescriptorInnerBarrelITS3::addAlignableVolumesHalfBarrel(int idLayer, int iHB, TString& parentPath, int& lastUID) const +{ + // for ITS3 smallest alignable volume is the half-barrel (e.g., the carbon-form composite structure with the sensors) + TString path = Form("%s/%s%d_%d", parentPath.Data(), its::GeometryTGeo::getITS3HalfBarrelPattern(), idLayer, iHB); + TString sname = its::GeometryTGeo::composeSymNameHalfBarrel(idLayer, iHB, true); + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path; + } + addAlignableVolumesChips(idLayer, iHB, path, lastUID); +} + +void DescriptorInnerBarrelITS3::addAlignableVolumesChips(int idLayer, int iHB, TString& parentPath, int& lastUID) const +{ + for (int seg{0}; seg < constants::nSegments[idLayer]; ++seg) { + for (int rsu{0}; rsu < constants::segment::nRSUs; ++rsu) { + for (int tile{0}; tile < constants::rsu::nTiles; ++tile) { + TString path = parentPath; + path += Form("/%s_0/", its::GeometryTGeo::getITS3ChipPattern(idLayer)); + path += Form("%s_%d/", its::GeometryTGeo::getITS3SegmentPattern(idLayer), seg); + path += Form("%s_%d/", its::GeometryTGeo::getITS3RSUPattern(idLayer), rsu); + path += Form("%s_%d/", its::GeometryTGeo::getITS3TilePattern(idLayer), tile); + TString sname = its::GeometryTGeo::composeSymNameChip(idLayer, iHB, 0, seg, rsu, tile, true); + if (!gGeoManager->SetAlignableEntry(sname.Data(), path.Data())) { + LOG(fatal) << "Unable to set alignable entry ! " << sname << " : " << path; + } + ++lastUID; + } + } + } +} From f8e23e0e2b42a382084453f8fe9c41560b60050b Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Wed, 11 Feb 2026 08:21:02 +0100 Subject: [PATCH 2/6] ITS3: load chip response functions from ccdb Signed-off-by: Felix Schlepper --- .../ITS3/macros/test/CheckChipResponseFile.C | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C b/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C index 32d5bad87ce21..5bc053c516079 100644 --- a/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C +++ b/Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C @@ -22,6 +22,7 @@ #include #include +#include "CCDB/BasicCCDBManager.h" #define ENABLE_UPGRADES #include "ITSMFTSimulation/AlpideSimResponse.h" #include "ITS3Simulation/ChipSimResponse.h" @@ -37,16 +38,12 @@ double cm2um(double cm) { return cm * 1e+4; } std::unique_ptr mAlpSimResp0, mAlpSimResp1, mAptSimResp1; -std::unique_ptr loadResponse(const std::string& fileName, const std::string& respName) +std::unique_ptr loadResponse(const std::string& path) { - TFile* f = TFile::Open(fileName.data()); - if (!f) { - std::cerr << fileName << " not found" << std::endl; - return nullptr; - } - auto base = f->Get(respName.c_str()); + auto& cdb = o2::ccdb::BasicCCDBManager::instance(); + o2::itsmft::AlpideSimResponse* base = cdb.get(path); if (!base) { - std::cerr << respName << " not found in " << fileName << std::endl; + std::cerr << path << " not found in " << '\n'; return nullptr; } return std::make_unique(base); @@ -54,24 +51,24 @@ std::unique_ptr loadResponse(const std::string& fileN void LoadRespFunc() { - std::string AptsFile = "$(O2_ROOT)/share/Detectors/Upgrades/ITS3/data/ITS3ChipResponseData/APTSResponseData.root"; - std::string AlpideFile = "$(O2_ROOT)/share/Detectors/ITSMFT/data/AlpideResponseData/AlpideResponseData.root"; + auto& cdb = o2::ccdb::BasicCCDBManager::instance(); + cdb.setURL("https://alice-ccdb.cern.ch/"); std::cout << "=====================\n"; LOGP(info, "ALPIDE Vbb=0V response"); - mAlpSimResp0 = loadResponse(AlpideFile, "response0"); // Vbb=0V + mAlpSimResp0 = loadResponse("ITSMFT/Calib/ALPIDEResponseVbb0"); // Vbb=0V mAlpSimResp0->computeCentreFromData(); mAlpSimResp0->print(); LOGP(info, "Response Centre {}", mAlpSimResp0->getRespCentreDep()); std::cout << "=====================\n"; LOGP(info, "ALPIDE Vbb=-3V response"); - mAlpSimResp1 = loadResponse(AlpideFile, "response1"); // Vbb=-3V + mAlpSimResp1 = loadResponse("ITSMFT/Calib/ALPIDEResponseVbbM3"); // Vbb=-3V mAlpSimResp1->computeCentreFromData(); mAlpSimResp1->print(); LOGP(info, "Response Centre {}", mAlpSimResp1->getRespCentreDep()); std::cout << "=====================\n"; LOGP(info, "APTS response"); - mAptSimResp1 = loadResponse(AptsFile, "response1"); // APTS + mAptSimResp1 = loadResponse("IT3/Calib/APTSResponse"); // APTS mAptSimResp1->computeCentreFromData(); mAptSimResp1->print(); LOGP(info, "Response Centre {}", mAptSimResp1->getRespCentreDep()); From 22759e0919af4b9cadf58a9340e4c6f3c2049a9a Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Tue, 3 Feb 2026 12:39:10 +0100 Subject: [PATCH 3/6] ITS3: improve stepping speed & trk frame Signed-off-by: Felix Schlepper --- .../ITS3/base/include/ITS3Base/SpecsV2.h | 2 +- .../ITS3/reconstruction/src/IOUtils.cxx | 37 ++++++---- .../include/ITS3Simulation/ITS3Layer.h | 5 +- .../ITS3/simulation/src/ITS3Layer.cxx | 68 +++++++++---------- 4 files changed, 59 insertions(+), 53 deletions(-) diff --git a/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h b/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h index a7422c55e72b8..937fa8d2e982c 100644 --- a/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h +++ b/Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h @@ -104,7 +104,7 @@ namespace carbonfoam // TODO: Waiting for the further information from WP5(Corrado) constexpr double HringLength{6.0 * mm}; // from blueprint constexpr double longeronsWidth{2.0 * mm}; // what is the height of the longerons? -constexpr double longeronsLength{segment::length - 2 * HringLength}; // 263mm from blueprint; overrriden to be consitent +constexpr double longeronsLength{segment::length - (2 * HringLength)}; // 263mm from blueprint; overrriden to be consitent constexpr double edgeBetwChipAndFoam{1.0 * mm}; // from blueprint but not used cause forms are already overlapping constexpr double gapBetwHringsLongerons{0.05 * mm}; // from blueprint constexpr std::array nHoles{11, 11, 11}; // how many holes for each layer? diff --git a/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx b/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx index d7ba4d48dbce4..e898631837169 100644 --- a/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx +++ b/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx @@ -10,17 +10,19 @@ // or submit itself to any jurisdiction. #include "ITS3Reconstruction/IOUtils.h" -#include "ITStracking/IOUtils.h" #include "ITStracking/TimeFrame.h" #include "ITStracking/BoundedAllocator.h" #include "DataFormatsITSMFT/CompCluster.h" #include "DataFormatsITSMFT/ROFRecord.h" #include "ITS3Reconstruction/TopologyDictionary.h" #include "ITSBase/GeometryTGeo.h" -#include "ITS3Base/SpecsV2.h" #include "ITStracking/TrackingConfigParam.h" #include "Framework/Logger.h" +#include + +#include + #include namespace o2::its3::ioutils @@ -45,7 +47,7 @@ void convertCompactClusters(gsl::span clusters, } for (auto& c : clusters) { - float sigmaY2, sigmaZ2, sigmaYZ = 0; + float sigmaY2 = NAN, sigmaZ2 = NAN; auto locXYZ = extractClusterData(c, pattIt, dict, sigmaY2, sigmaZ2); const auto detID = c.getSensorID(); auto& cl3d = output.emplace_back(detID, geom->getMatrixT2L(detID) ^ locXYZ); // local --> tracking @@ -54,7 +56,7 @@ void convertCompactClusters(gsl::span clusters, sigmaY2 += conf.sysErrY2[lrID]; sigmaZ2 += conf.sysErrZ2[lrID]; } - cl3d.setErrors(sigmaY2, sigmaZ2, sigmaYZ); + cl3d.setErrors(sigmaY2, sigmaZ2, 0.f); } } @@ -76,26 +78,31 @@ int loadROFrameDataITS3(its::TimeFrame<7>* tf, for (size_t iRof{0}; iRof < rofs.size(); ++iRof) { const auto& rof = rofs[iRof]; for (int clusterId{rof.getFirstEntry()}; clusterId < rof.getFirstEntry() + rof.getNEntries(); ++clusterId) { - auto& c = clusters[clusterId]; - auto sensorID = c.getSensorID(); - auto layer = geom->getLayer(sensorID); + const auto& c = clusters[clusterId]; + const auto sensorID = c.getSensorID(); + const auto layer = geom->getLayer(sensorID); float sigmaY2{0}, sigmaZ2{0}, sigmaYZ{0}; uint8_t clusterSize{0}; - auto locXYZ = extractClusterData(c, pattIt, dict, sigmaY2, sigmaZ2, clusterSize); + const auto locXYZ = extractClusterData(c, pattIt, dict, sigmaY2, sigmaZ2, clusterSize); clusterSizeVec.push_back(clusterSize); // Transformation to the local --> global - auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; + const auto gloXYZ = geom->getMatrixL2G(sensorID) * locXYZ; // Inverse transformation to the local --> tracking - o2::math_utils::Point3D trkXYZ = geom->getMatrixT2L(sensorID) ^ locXYZ; + const o2::math_utils::Point3D trkXYZ = geom->getMatrixT2L(sensorID) ^ locXYZ; // Tracking alpha angle - float alpha = geom->getSensorRefAlpha(sensorID); - - tf->addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), trkXYZ.x(), alpha, - std::array{trkXYZ.y(), trkXYZ.z()}, + // We want that each cluster rotates its tracking frame to the clusters phi + // that way the track linearization around the measurement is less biases to the arc + // this means automatically that the measurement on the arc is at 0 + // const float alpha = geom->getSensorRefAlpha(sensorID); + const float radius = std::hypot(gloXYZ.x(), gloXYZ.y()); + const float alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); + + tf->addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), radius, alpha, + std::array{0, trkXYZ.z()}, std::array{sigmaY2, sigmaYZ, sigmaZ2}); /// Rotate to the global frame @@ -103,7 +110,7 @@ int loadROFrameDataITS3(its::TimeFrame<7>* tf, tf->addClusterExternalIndexToLayer(layer, clusterId); } for (unsigned int iL{0}; iL < tf->getUnsortedClusters().size(); ++iL) { - tf->mROFramesClusters[iL][iRof + 1] = tf->getUnsortedClusters()[iL].size(); + tf->mROFramesClusters[iL][iRof + 1] = (int)tf->getUnsortedClusters()[iL].size(); } } diff --git a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h index fd9195f9ee228..f45a4469ae2b8 100644 --- a/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h +++ b/Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h @@ -26,7 +26,7 @@ namespace o2::its3 { /// This class defines the geometry for the ITS3 IB layers. -class ITS3Layer +class ITS3Layer final { // The hierarchy will be the following: // ITS2 -> ITS3 @@ -76,7 +76,6 @@ class ITS3Layer void buildPartial(TGeoVolume* motherVolume, TGeoMatrix* mat = nullptr, BuildLevel level = BuildLevel::kAll, bool createMaterials = false); private: - bool mBuilt{false}; TGeoMedium* mSilicon{nullptr}; TGeoMedium* mAir{nullptr}; TGeoMedium* mCarbon{nullptr}; @@ -91,7 +90,7 @@ class ITS3Layer void createSegment(); void createChip(); void createCarbonForm(); - TGeoCompositeShape* getHringShape(TGeoTubeSeg* Hring); + TGeoCompositeShape* getHringShape(TGeoTubeSeg* Hring) const; void createLayerImpl(); uint8_t mNLayer{0}; // Layer number diff --git a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx index e0be011096450..c0f8fdc19d03b 100644 --- a/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx +++ b/Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx @@ -67,11 +67,11 @@ void ITS3Layer::createLayer(TGeoVolume* motherVolume) // Create one layer of ITS3 and attach it to the motherVolume. getMaterials(); createLayerImpl(); - mBuilt = true; if (motherVolume == nullptr) { return; } + // Add it to motherVolume auto* trans = new TGeoTranslation(0, 0, -constants::segment::lengthSensitive / 2.); motherVolume->AddNode(mLayer, 0, trans); @@ -122,8 +122,8 @@ void ITS3Layer::createTile() mTile->AddNode(mPixelArray, 0, phiRotPixelArray); // Biasing - double biasPhi1 = constants::pixelarray::width / mR * o2m::Rad2Deg + readoutPhi2; - double biasPhi2 = biasing::width / mR * o2m::Rad2Deg + biasPhi1; + double biasPhi1 = (constants::pixelarray::width / mR * o2m::Rad2Deg) + readoutPhi2; + double biasPhi2 = (biasing::width / mR * o2m::Rad2Deg) + biasPhi1; auto biasing = new TGeoTubeSeg(mRmin, mRmax, biasing::length / 2, biasPhi1, biasPhi2); auto biasingVol = new TGeoVolume(Form("biasing%d", mNLayer), biasing, mSilicon); biasingVol->SetLineColor(biasing::color); @@ -131,9 +131,9 @@ void ITS3Layer::createTile() mTile->AddNode(biasingVol, 0); // Power Switches are on the side right side of the pixel array and biasing. - auto zMovePowerSwitches = new TGeoTranslation(0, 0, +powerswitches::length / 2. + constants::pixelarray::length / 2.); + auto zMovePowerSwitches = new TGeoTranslation(0, 0, (+powerswitches::length / 2.) + (constants::pixelarray::length / 2.)); double powerPhi1 = readoutPhi2; - double powerPhi2 = powerswitches::width / mR * o2m::Rad2Deg + powerPhi1; + double powerPhi2 = (powerswitches::width / mR * o2m::Rad2Deg) + powerPhi1; auto powerSwitches = new TGeoTubeSeg(mRmin, mRmax, powerswitches::length / 2, powerPhi1, powerPhi2); auto powerSwitchesVol = new TGeoVolume(Form("powerswitches%d", mNLayer), powerSwitches, mSilicon); powerSwitchesVol->SetLineColor(powerswitches::color); @@ -166,7 +166,7 @@ void ITS3Layer::createRSU() // Lower Left auto zMoveLL1 = new TGeoTranslation(0, 0, constants::tile::length); auto zMoveLL2 = new TGeoTranslation(0, 0, constants::tile::length * 2.); - auto zMoveLLDB = new TGeoTranslation(0, 0, -databackbone::length / 2. - constants::pixelarray::length / 2.); + auto zMoveLLDB = new TGeoTranslation(0, 0, (-databackbone::length / 2.) - (constants::pixelarray::length / 2.)); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, nullptr); mRSU->AddNode(mTile, nCopyRSU++, zMoveLL1); @@ -175,9 +175,9 @@ void ITS3Layer::createRSU() // Lower Right auto zMoveLR0 = new TGeoTranslation(0, 0, +length / 2.); - auto zMoveLR1 = new TGeoTranslation(0, 0, constants::tile::length + length / 2.); - auto zMoveLR2 = new TGeoTranslation(0, 0, constants::tile::length * 2. + length / 2.); - auto zMoveLRDB = new TGeoTranslation(0, 0, -databackbone::length / 2. + length / 2. - constants::pixelarray::length / 2.); + auto zMoveLR1 = new TGeoTranslation(0, 0, constants::tile::length + (length / 2.)); + auto zMoveLR2 = new TGeoTranslation(0, 0, (constants::tile::length * 2.) + (length / 2.)); + auto zMoveLRDB = new TGeoTranslation(0, 0, (-databackbone::length / 2.) + (length / 2.) - (constants::pixelarray::length / 2.)); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, zMoveLR0); mRSU->AddNode(mTile, nCopyRSU++, zMoveLR1); @@ -192,7 +192,7 @@ void ITS3Layer::createRSU() // Upper Left auto zMoveUL1 = new TGeoCombiTrans(0, 0, constants::tile::length, rot); auto zMoveUL2 = new TGeoCombiTrans(0, 0, constants::tile::length * 2., rot); - auto zMoveULDB = new TGeoCombiTrans(0, 0, -databackbone::length / 2. - constants::pixelarray::length / 2., rot); + auto zMoveULDB = new TGeoCombiTrans(0, 0, (-databackbone::length / 2.) - (constants::pixelarray::length / 2.), rot); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, rot); mRSU->AddNode(mTile, nCopyRSU++, zMoveUL1); @@ -201,9 +201,9 @@ void ITS3Layer::createRSU() // Upper Right auto zMoveUR0 = new TGeoCombiTrans(0, 0, +length / 2., rot); - auto zMoveUR1 = new TGeoCombiTrans(0, 0, constants::tile::length + length / 2., rot); - auto zMoveUR2 = new TGeoCombiTrans(0, 0, constants::tile::length * 2. + length / 2., rot); - auto zMoveURDB = new TGeoCombiTrans(0, 0, -databackbone::length / 2. + length / 2. - constants::pixelarray::length / 2., rot); + auto zMoveUR1 = new TGeoCombiTrans(0, 0, constants::tile::length + (length / 2.), rot); + auto zMoveUR2 = new TGeoCombiTrans(0, 0, (constants::tile::length * 2.) + (length / 2.), rot); + auto zMoveURDB = new TGeoCombiTrans(0, 0, (-databackbone::length / 2.) + (length / 2.) - (constants::pixelarray::length / 2.), rot); // Lets attach the tiles to the QS. mRSU->AddNode(mTile, nCopyRSU++, zMoveUR0); mRSU->AddNode(mTile, nCopyRSU++, zMoveUR1); @@ -225,9 +225,9 @@ void ITS3Layer::createSegment() mSegment = new TGeoVolumeAssembly(its3TGeo::getITS3SegmentPattern(mNLayer)); mSegment->VisibleDaughters(); - for (size_t i{0}; i < nRSUs; ++i) { - auto zMove = new TGeoTranslation(0, 0, +i * constants::rsu::length + constants::rsu::databackbone::length + constants::pixelarray::length / 2.); - mSegment->AddNode(mRSU, i, zMove); + for (unsigned int i{0}; i < nRSUs; ++i) { + auto zMove = new TGeoTranslation(0, 0, (i * constants::rsu::length) + constants::rsu::databackbone::length + (constants::pixelarray::length / 2.)); + mSegment->AddNode(mRSU, (int)i, zMove); } // LEC @@ -242,7 +242,7 @@ void ITS3Layer::createSegment() mSegment->AddNode(lecVol, 0, zMoveLEC); // REC; reuses lecPhi1,2 - auto zMoveREC = new TGeoTranslation(0, 0, nRSUs * constants::rsu::length + rec::length / 2.); + auto zMoveREC = new TGeoTranslation(0, 0, (nRSUs * constants::rsu::length) + (rec::length / 2.)); auto rec = new TGeoTubeSeg(mRmin, mRmax, rec::length / 2., lecPhi1, lecPhi2); auto recVol = new TGeoVolume(Form("rec%d", mNLayer), rec, mSilicon); @@ -266,11 +266,11 @@ void ITS3Layer::createChip() auto phiOffset = constants::segment::width / mR * o2m::Rad2Deg; for (unsigned int i{0}; i < constants::nSegments[mNLayer]; ++i) { auto rot = new TGeoRotation(Form("its3PhiSegmentOffset_%d_%d", mNLayer, i), 0, 0, phiOffset * i); - mChip->AddNode(mSegment, i, rot); + mChip->AddNode(mSegment, (int)i, rot); } // Add metal stack positioned radially outward - auto zMoveMetal = new TGeoTranslation(0, 0, constants::metalstack::length / 2. - constants::segment::lec::length); + auto zMoveMetal = new TGeoTranslation(0, 0, (constants::metalstack::length / 2.) - constants::segment::lec::length); auto metal = new TGeoTubeSeg(mRmax, mRmax + constants::metalstack::thickness, constants::metalstack::length / 2., 0, constants::nSegments[mNLayer] * phiOffset); auto metalVol = new TGeoVolume(Form("metal%d", mNLayer), metal, mCopper); metalVol->SetLineColor(constants::metalstack::color); @@ -296,7 +296,7 @@ void ITS3Layer::createCarbonForm() dRadius = constants::carbonfoam::thicknessOuterFoam; // TODO: lack of carbon foam radius for layer 2, use 0.7 cm as a temporary value } double phiSta = edgeBetwChipAndFoam / (0.5 * constants::radii[mNLayer + 1] + constants::radii[mNLayer]) * o2m::Rad2Deg; - double phiEnd = (constants::nSegments[mNLayer] * constants::segment::width) / constants::radii[mNLayer] * o2m::Rad2Deg - phiSta; + double phiEnd = ((constants::nSegments[mNLayer] * constants::segment::width) / constants::radii[mNLayer] * o2m::Rad2Deg) - phiSta; double phiLongeronsCover = longeronsWidth / (0.5 * constants::radii[mNLayer + 1] + constants::radii[mNLayer]) * o2m::Rad2Deg; // H-rings foam @@ -308,35 +308,37 @@ void ITS3Layer::createCarbonForm() HringCVol->SetLineColor(color); auto HringAVol = new TGeoVolume(Form("hringA%d", mNLayer), HringAWithHoles, mCarbon); HringAVol->SetLineColor(color); - auto zMoveHringC = new TGeoTranslation(0, 0, -constants::segment::lec::length + HringLength / 2.); - auto zMoveHringA = new TGeoTranslation(0, 0, -constants::segment::lec::length + HringLength / 2. + constants::segment::length - HringLength); + auto zMoveHringC = new TGeoTranslation(0, 0, -constants::segment::lec::length + (HringLength / 2.)); + auto zMoveHringA = new TGeoTranslation(0, 0, -constants::segment::lec::length + (HringLength / 2.) + constants::segment::length - HringLength); // Longerons are made by same material + // added separately to make navigation faster [[maybe_unused]] auto longeronR = new TGeoTubeSeg(Form("longeronR%d", mNLayer), mRmax, mRmax + dRadius, longeronsLength / 2., phiSta, phiSta + phiLongeronsCover); [[maybe_unused]] auto longeronL = new TGeoTubeSeg(Form("longeronL%d", mNLayer), mRmax, mRmax + dRadius, longeronsLength / 2., phiEnd - phiLongeronsCover, phiEnd); - TString nameLongerons = Form("longeronR%d + longeronL%d", mNLayer, mNLayer); - auto longerons = new TGeoCompositeShape(nameLongerons); - auto longeronsVol = new TGeoVolume(Form("longerons%d", mNLayer), longerons, mCarbon); - longeronsVol->SetLineColor(color); - auto zMoveLongerons = new TGeoTranslation(0, 0, -constants::segment::lec::length + constants::segment::length / 2.); + auto longeronRVol = new TGeoVolume(Form("longeronR%d", mNLayer), longeronR, mCarbon); + longeronRVol->SetLineColor(color); + auto longeronLVol = new TGeoVolume(Form("longeronL%d", mNLayer), longeronL, mCarbon); + longeronLVol->SetLineColor(color); + auto zMoveLongerons = new TGeoTranslation(0, 0, -constants::segment::lec::length + (constants::segment::length / 2.)); mCarbonForm->AddNode(HringCVol, 0, zMoveHringC); mCarbonForm->AddNode(HringAVol, 0, zMoveHringA); - mCarbonForm->AddNode(longeronsVol, 0, zMoveLongerons); + mCarbonForm->AddNode(longeronRVol, 0, zMoveLongerons); + mCarbonForm->AddNode(longeronLVol, 0, zMoveLongerons); mCarbonForm->AddNode(mChip, 0); } -TGeoCompositeShape* ITS3Layer::getHringShape(TGeoTubeSeg* Hring) +TGeoCompositeShape* ITS3Layer::getHringShape(TGeoTubeSeg* Hring) const { // Function to dig holes in H-rings using namespace constants::carbonfoam; double stepPhiHoles = (Hring->GetPhi2() - Hring->GetPhi1()) / (nHoles[mNLayer]); - double phiHolesSta = Hring->GetPhi1() + stepPhiHoles / 2.; + double phiHolesSta = Hring->GetPhi1() + (stepPhiHoles / 2.); double radiusHring = 0.5 * (Hring->GetRmin() + Hring->GetRmax()); TGeoCompositeShape* HringWithHoles = nullptr; TString nameAllHoles = ""; for (int iHoles = 0; iHoles < nHoles[mNLayer]; iHoles++) { - double phiHole = phiHolesSta + stepPhiHoles * iHoles; + double phiHole = phiHolesSta + (stepPhiHoles * iHoles); TString nameHole = Form("hole_%d_%d", iHoles, mNLayer); [[maybe_unused]] auto hole = new TGeoTube(nameHole, 0, radiusHoles[mNLayer], 3 * Hring->GetDz()); // move hole to the hring radius @@ -376,9 +378,7 @@ void ITS3Layer::createLayerImpl() void ITS3Layer::buildPartial(TGeoVolume* motherVolume, TGeoMatrix* mat, BuildLevel level, bool createMaterials) { - if (!mBuilt) { - getMaterials(createMaterials); - } + getMaterials(createMaterials); switch (level) { case BuildLevel::kPixelArray: createPixelArray(); From 42c3bc9464d9d9a1319974d1a7181d8d9c01d7ee Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 5 Feb 2026 17:45:16 +0100 Subject: [PATCH 4/6] ITS3: alignment Signed-off-by: Felix Schlepper --- .../Upgrades/ITS3/alignment/CMakeLists.txt | 30 +- .../include/ITS3Align/AlignmentHierarchy.h | 258 ++++++ .../include/ITS3Align/AlignmentParams.h | 54 ++ .../include/ITS3Align/AlignmentSensors.h | 41 + .../include/ITS3Align/AlignmentSpec.h | 23 + .../include/ITS3Align/AlignmentTypes.h | 67 ++ .../ITS3/alignment/src/AlignmentHierarchy.cxx | 197 +++++ .../ITS3/alignment/src/AlignmentParams.cxx | 13 + .../ITS3/alignment/src/AlignmentSensors.cxx | 169 ++++ .../ITS3/alignment/src/AlignmentSpec.cxx | 799 ++++++++++++++++++ .../ITS3/alignment/src/AlignmentTypes.cxx | 24 + .../ITS3/alignment/src/ITS3AlignLinkDef.h | 8 + .../ITS3/alignment/src/alignment-workflow.cxx | 64 ++ .../ITS3/reconstruction/src/IOUtils.cxx | 27 +- dependencies/O2Dependencies.cmake | 18 + 15 files changed, 1774 insertions(+), 18 deletions(-) create mode 100644 Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentHierarchy.h create mode 100644 Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentParams.h create mode 100644 Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSensors.h create mode 100644 Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h create mode 100644 Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentTypes.h create mode 100644 Detectors/Upgrades/ITS3/alignment/src/AlignmentHierarchy.cxx create mode 100644 Detectors/Upgrades/ITS3/alignment/src/AlignmentParams.cxx create mode 100644 Detectors/Upgrades/ITS3/alignment/src/AlignmentSensors.cxx create mode 100644 Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx create mode 100644 Detectors/Upgrades/ITS3/alignment/src/AlignmentTypes.cxx create mode 100644 Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx diff --git a/Detectors/Upgrades/ITS3/alignment/CMakeLists.txt b/Detectors/Upgrades/ITS3/alignment/CMakeLists.txt index f89ad821c65e7..5a3f3dd0d2d07 100644 --- a/Detectors/Upgrades/ITS3/alignment/CMakeLists.txt +++ b/Detectors/Upgrades/ITS3/alignment/CMakeLists.txt @@ -9,18 +9,42 @@ # granted to it by virtue of its status as an Intergovernmental Organization # or submit itself to any jurisdiction. +# add_compile_options(-O0 -g -fPIC -fno-omit-frame-pointer) o2_add_library(ITS3Align + TARGETVARNAME targetName SOURCES src/MisalignmentParameters.cxx src/MisalignmentHits.cxx src/MisalignmentManager.cxx src/Deformations.cxx + src/AlignmentHierarchy.cxx + src/AlignmentSensors.cxx + src/AlignmentParams.cxx + src/AlignmentTypes.cxx + src/AlignmentSpec.cxx PUBLIC_LINK_LIBRARIES O2::MathUtils O2::Steer O2::ITSBase - O2::ITSMFTSimulation) + O2::ITSMFTSimulation + O2::Framework + O2::GlobalTrackingWorkflowReaders + O2::GlobalTrackingWorkflowHelpers + O2::DataFormatsGlobalTracking + O2::DetectorsVertexing + GBL::GBL) +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() o2_target_root_dictionary(ITS3Align HEADERS include/ITS3Align/MisalignmentParameters.h include/ITS3Align/MisalignmentHits.h - include/ITS3Align/MisalignmentHits.h - include/ITS3Align/Deformations.h) + include/ITS3Align/Deformations.h + include/ITS3Align/AlignmentParams.h + include/ITS3Align/AlignmentTypes.h) + + +o2_add_executable(alignment-workflow + SOURCES src/alignment-workflow.cxx + COMPONENT_NAME its3 + PUBLIC_LINK_LIBRARIES O2::ITS3Align) diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentHierarchy.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentHierarchy.h new file mode 100644 index 0000000000000..eddbee0acf7f7 --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentHierarchy.h @@ -0,0 +1,258 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS3_ALIGNMENT_HIERARCHY_H +#define O2_ITS3_ALIGNMENT_HIERARCHY_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace o2::its3::align +{ +using Matrix36 = Eigen::Matrix; +using Matrix66 = Eigen::Matrix; + +using RigidBodyDOFMask = uint8_t; +template +constexpr RigidBodyDOFMask DOF_BIT(Args... bits) +{ + return (RigidBodyDOFMask{0} | ... | (RigidBodyDOFMask{1} << bits)); +} +// DOFs are defined in LOC +enum RigidBodyDOF : RigidBodyDOFMask { + TX = 0, // Translation along local X + TY, // Translation along local Y + TZ, // Translation along local Z + RX, // Rotation around local X + RY, // Rotation around local Y + RZ, // Rotation around local Z + NDOF, +}; +constexpr RigidBodyDOFMask RigidBodyDOFTra = DOF_BIT(TX, TY, TZ); +constexpr RigidBodyDOFMask RigidBodyDOFRot = DOF_BIT(RX, RY, RZ); +constexpr RigidBodyDOFMask RigidBodyDOFAll = RigidBodyDOFTra | RigidBodyDOFRot; +constexpr RigidBodyDOFMask RigidBodyDOFNone = 0; +constexpr RigidBodyDOFMask RigidBodyDOFPseudo = std::numeric_limits::max(); // special value representing that the volume itself does not have any dofs but should not curtail the parent's ones +static constexpr const char* RigidBodyDOFNames[RigidBodyDOF::NDOF] = {"TX", "TY", "TZ", "RX", "RY", "RZ"}; +inline bool hasRigidBodyDOF(RigidBodyDOFMask m, RigidBodyDOFMask d) +{ + return (m == RigidBodyDOFPseudo) || (m & DOF_BIT(d)); +} +inline void enableRigidBodyDOF(RigidBodyDOFMask& m, RigidBodyDOFMask d) +{ + m |= DOF_BIT(d); +} +inline void disableRigidBodyDOF(RigidBodyDOFMask& m, RigidBodyDOFMask d) +{ + m &= ~DOF_BIT(d); +} +// return the rigid body derivatives +// trk has be at in the measurment frame +auto getRigidBodyDerivatives(const auto& trk) +{ + // calculate slopes + const double tgl = trk.getTgl(), snp = trk.getSnp(); + const double csp = 1. / sqrt(1. + (tgl * tgl)); + const double u = trk.getY(), v = trk.getZ(); + const double uP = snp * csp, vP = tgl * csp; + Matrix36 der; + der.setZero(); + // columns: Tt, Tu, Tv, Rt, Ru, Rv + // (X) (Y) (Z) (RX) (RY) (RZ) + der << uP, -1., 0., v, v * uP, -u * uP, + vP, 0., -1., -u, v * vP, -u * vP; + return der; +} + +class GlobalLabel +{ + // Millepede label is any positive integer [1....) + public: + using T = uint32_t; + static constexpr int DOF_BITS = 5; // 0...4 + static constexpr int ID_BITS = 23; // 5...27 + static constexpr int SENS_BITS = 1; // 28 + static constexpr int TOTAL_BITS = sizeof(T) * 8; + static constexpr int DET_BITS = TOTAL_BITS - (DOF_BITS + ID_BITS + SENS_BITS) - 1; // one less bit since GBL uses int! + static constexpr T bitMask(int b) noexcept + { + return (T(1) << b) - T(1); + } + static constexpr int DOF_SHIFT = 0; + static constexpr T DOF_MAX = (T(1) << DOF_BITS) - T(1); + static constexpr T DOF_MASK = DOF_MAX << DOF_SHIFT; + static constexpr int ID_SHIFT = DOF_BITS; + static constexpr T ID_MAX = (T(1) << ID_BITS) - T(1); + static constexpr T ID_MASK = ID_MAX << ID_SHIFT; + static constexpr int SENS_SHIFT = ID_BITS + DOF_BITS; + static constexpr T SENS_MAX = (T(1) << SENS_BITS) - T(1); + static constexpr T SENS_MASK = SENS_MAX << SENS_SHIFT; + static constexpr int DET_SHIFT = DOF_BITS + ID_BITS + SENS_BITS; + static constexpr T DET_MAX = (T(1) << DET_BITS) - T(1); + static constexpr T DET_MASK = DET_MAX << DET_SHIFT; + + GlobalLabel(T det, T id, bool sens) : mID(((((id + 1) & ID_MAX) << ID_SHIFT) | ((det & DET_MAX) << DET_SHIFT) | ((sens & SENS_MAX) << SENS_SHIFT))) + { + } + + constexpr T raw(T dof) const noexcept { return (mID & ~DOF_MASK) | ((dof & DOF_MAX) << DOF_SHIFT); } + constexpr int rawGBL(T dof) const noexcept { return static_cast(raw(dof)); } + constexpr T id() const noexcept + { + return ((mID - 1) & ID_MASK) >> ID_SHIFT; + } + constexpr T det() const noexcept + { + return (mID & DET_MASK) >> DET_SHIFT; + } + constexpr bool sens() const noexcept + { + return (mID & SENS_MASK) >> SENS_SHIFT; + } + + std::string asString() const + { + return std::format("Det:{} Id:{} Sens:{}", det(), id(), sens()); + } + + constexpr auto operator<=>(const GlobalLabel&) const noexcept = default; + + private: + T mID{0}; +}; + +// Rigid body constraints for the parents +class HierarchyConstraint +{ + public: + HierarchyConstraint(std::string name, double value) : mName(std::move(name)), mValue(value) {} + void add(uint32_t lab, double coeff) + { + mLabels.push_back(lab); + mCoeff.push_back(coeff); + } + void write(std::ostream& os) const; + auto getSize() const noexcept { return mLabels.size(); } + + private: + std::string mName; // name of the constraint + double mValue{0.0}; // constraint value + std::vector mLabels; // parameter labels + std::vector mCoeff; // their coefficients +}; + +class AlignableVolume +{ + public: + using Ptr = std::unique_ptr; + using SensorMapping = std::map; + + AlignableVolume(const AlignableVolume&) = default; + AlignableVolume(AlignableVolume&&) = delete; + AlignableVolume& operator=(const AlignableVolume&) = default; + AlignableVolume& operator=(AlignableVolume&&) = delete; + AlignableVolume(const char* symName, uint32_t label, uint32_t det, bool sens, RigidBodyDOFMask dof); + AlignableVolume(const char* symName, GlobalLabel label, RigidBodyDOFMask dof); + virtual ~AlignableVolume() = default; + + void finalise(uint8_t level = 0); + + // steering file output + void writeRigidBodyConstraints(std::ostream& os) const; + void writeParameters(std::ostream& os) const; + void writeTree(std::ostream& os, int indent = 0) const; + + // tree-like + auto getLevel() const noexcept { return mLevel; } + bool isRoot() const noexcept { return mParent == nullptr; } + bool isLeaf() const noexcept { return mChildren.empty(); } + template + requires std::derived_from + AlignableVolume* addChild(const char* symName, uint32_t label, uint32_t det, bool sens, RigidBodyDOFMask dof) + { + auto c = std::make_unique(symName, label, det, sens, dof); + return setParent(std::move(c)); + } + template + requires std::derived_from + AlignableVolume* addChild(const char* symName, GlobalLabel lbl, RigidBodyDOFMask dof) + { + auto c = std::make_unique(symName, lbl, dof); + return setParent(std::move(c)); + } + + // bfs traversal + void traverse(const std::function& visitor) + { + visitor(this); + for (auto& c : mChildren) { + c->traverse(visitor); + } + } + + std::string getSymName() const noexcept { return mSymName; } + GlobalLabel getLabel() const noexcept { return mLabel; } + AlignableVolume* getParent() const { return mParent; } + size_t getNChildren() const noexcept { return mChildren.size(); } + void setRigidBodyDOF(RigidBodyDOFMask m) noexcept { mDOF = m; } + RigidBodyDOFMask getRigidBodyDOF() const noexcept { return mDOF; } + + // transformation matrices + virtual void defineMatrixL2G() {} + virtual void defineMatrixT2L() {} + virtual void computeJacobianL2T(const double* pos, Matrix66& jac) const {}; + const TGeoHMatrix& getL2P() const { return mL2P; } + const TGeoHMatrix& getT2L() const { return mT2L; } + const Matrix66& getJL2P() const { return mJL2P; } + const Matrix66& getJP2L() const { return mJP2L; } + + protected: + /// matrices + AlignableVolume* mParent{nullptr}; // parent + TGeoPNEntry* mPNE{nullptr}; // physical entry + TGeoPhysicalNode* mPN{nullptr}; // physical node + TGeoHMatrix mL2G; // (LOC) -> (GLO) + TGeoHMatrix mL2P; // (LOC) -> (PAR) + Matrix66 mJL2P; // jac (LOC) -> (PAR) + Matrix66 mJP2L; // jac (PAR) -> (LOC) + TGeoHMatrix mT2L; // (TRK) -> (LOC) + + private: + double mPreSigma{0.0}; // asigned pre-sigma + std::string mSymName; // unique symbolic name + GlobalLabel mLabel; // internal global idetenifier + uint8_t mLevel{0}; // depth-in tree + RigidBodyDOFMask mDOF{RigidBodyDOFAll}; // allowed dofs + + AlignableVolume* setParent(Ptr c) + { + c->mParent = this; + mChildren.push_back(std::move(c)); + return mChildren.back().get(); + } + std::vector mChildren; // children + + void init(); +}; + +} // namespace o2::its3::align + +#endif diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentParams.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentParams.h new file mode 100644 index 0000000000000..f267a5fe0da7f --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentParams.h @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_ITS3_ALIGNMENTPARAMS_H_ +#define ALICEO2_ITS3_ALIGNMENTPARAMS_H_ + +#include "CommonUtils/ConfigurableParam.h" +#include "CommonUtils/ConfigurableParamHelper.h" +#include "DetectorsBase/Propagator.h" + +namespace o2::its3::align +{ +struct AlignmentParams : public o2::conf::ConfigurableParamHelper { + // Track selection + float minPt = 1.f; // minimum pt required + int minITSCls = 7; // minimum number of ITS clusters + float maxITSChi2Ndf = 1.2; // maximum ITS track chi2 + + // propagation opt + double maxSnp = 0.85; + double maxStep = 2.0; + // o2::base::PropagatorD::MatCorrType matCorrType = o2::base::PropagatorD::MatCorrType::USEMatCorrTGeo; + o2::base::PropagatorD::MatCorrType matCorrType = o2::base::PropagatorD::MatCorrType::USEMatCorrLUT; + + bool useStableRefit = true; // use input tracks as linearization point + float minMS = 1e-6f; // minimum scattering to account for + float maxChi2Ndf = 10; // maximum Chi2/Ndf allowed for GBL fit + + // Ridder options + int ridderMaxExtrap = 10; + double ridderRelIniStep[5] = {0.01, 0.01, 0.02, 0.02, 0.02}; + double ridderMaxIniStep[5] = {0.1, 0.1, 0.05, 0.05, 0.05}; + double ridderShrinkFac = 2.0; + double ridderEps = 1e-16; + double ridderMaxJacDiagTol = 0.1; // max tolerance of diagonal elements away from 1 + + // MillePede output + std::string milleBinFile = "mp2data.bin"; + std::string milleConFile = "mp2con.txt"; + std::string milleParamFile = "mp2param.txt"; + std::string milleTreeFile = "mp2tree.txt"; + + O2ParamDef(AlignmentParams, "ITS3AlignmentParams"); +}; +} // namespace o2::its3::align + +#endif diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSensors.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSensors.h new file mode 100644 index 0000000000000..f2a2cf5ce7331 --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSensors.h @@ -0,0 +1,41 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS3_ALIGNMENT_SENSORS_H +#define O2_ITS3_ALIGNMENT_SENSORS_H + +#include "ITS3Align/AlignmentHierarchy.h" + +namespace o2::its3::align +{ + +AlignableVolume::Ptr buildHierarchyITS(AlignableVolume::SensorMapping& sensorMap); +AlignableVolume::Ptr buildHierarchyIT3(AlignableVolume::SensorMapping& sensorMap); + +class AlignableSensorITS final : public AlignableVolume +{ + using AlignableVolume::AlignableVolume; + void defineMatrixL2G() final; + void defineMatrixT2L() final; + void computeJacobianL2T(const double* pos, Matrix66& jac) const final; +}; + +class AlignableSensorIT3 final : public AlignableVolume +{ + using AlignableVolume::AlignableVolume; + void defineMatrixL2G() final {} + void defineMatrixT2L() final {} + void computeJacobianL2T(const double* pos, Matrix66& jac) const final {} +}; + +} // namespace o2::its3::align + +#endif diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h new file mode 100644 index 0000000000000..84422f774b202 --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentSpec.h @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS3_ALIGNMENT_H +#define O2_ITS3_ALIGNMENT_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/DataProcessorSpec.h" + +namespace o2::its3::align +{ +o2::framework::DataProcessorSpec getAlignmentSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, bool withPV, bool withITS3); +} // namespace o2::its3::align + +#endif diff --git a/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentTypes.h b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentTypes.h new file mode 100644 index 0000000000000..605b50f350a24 --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/include/ITS3Align/AlignmentTypes.h @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS3_ALIGNMENT_TYPES_H +#define O2_ITS3_ALIGNMENT_TYPES_H + +#include +#include "ReconstructionDataFormats/Track.h" +#include "DataFormatsITS/TrackITS.h" + +namespace o2::its3::align +{ + +struct Measurement final { + double dy = 0.f; + double dz = 0.f; + double sig2y = 0.f; + double sig2z = 0.f; + double phi = 0.f; + double z = 0.f; + ClassDefNV(Measurement, 1) +}; + +struct FrameInfoExt final { + int16_t sens = -1; + int8_t lr = -1; // -1 = vtx + o2::math_utils::Point3D trk; + o2::math_utils::Point3D loc; + o2::math_utils::Point3D glo; + float x{-999.f}; + float alpha{-999.f}; + std::array positionTrackingFrame = {999., 999.}; + std::array covarianceTrackingFrame = {999., 999., 999.}; + + std::string asString() const; + + ClassDefNV(FrameInfoExt, 1) +}; + +struct FitInfo final { + float chi2Ndf{-1}; // Chi2/Ndf of track refit + float chi2{-1}; // Chi2 + int ndf; // ndf + ClassDefNV(FitInfo, 1) +}; + +struct Track { + o2::its::TrackITS its; // original ITS track + o2::track::TrackParCovD track; // track at innermost update point, refitted from outwards seed + FitInfo kfFit; // kf fit information + FitInfo gblFit; // gbl fit information + std::vector points; // measurment point + std::vector info; // frame info + ClassDefNV(Track, 1) +}; + +} // namespace o2::its3::align + +#endif diff --git a/Detectors/Upgrades/ITS3/alignment/src/AlignmentHierarchy.cxx b/Detectors/Upgrades/ITS3/alignment/src/AlignmentHierarchy.cxx new file mode 100644 index 0000000000000..0329ab928709e --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/src/AlignmentHierarchy.cxx @@ -0,0 +1,197 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include + +#include +#include + +#include "ITS3Align/AlignmentHierarchy.h" +#include "ITSBase/GeometryTGeo.h" +#include "Framework/Logger.h" +#include "MathUtils/Utils.h" + +using namespace o2::its3::align; + +void HierarchyConstraint::write(std::ostream& os) const +{ + os << "!!! " << mName << '\n'; + os << "Constraint " << mValue << '\n'; + for (size_t i{0}; i < mLabels.size(); ++i) { + os << mLabels[i] << " " << mCoeff[i] << '\n'; + } + os << '\n'; +} + +AlignableVolume::AlignableVolume(const char* symName, uint32_t label, uint32_t det, bool sens, RigidBodyDOFMask dof) : mSymName(symName), mLabel(det, label, sens), mDOF(dof) +{ + init(); +} + +AlignableVolume::AlignableVolume(const char* symName, GlobalLabel label, RigidBodyDOFMask dof) : mSymName(symName), mLabel(label), mDOF(dof) +{ + init(); +} + +void AlignableVolume::init() +{ + // check if this sym volume actually exists + mPNE = gGeoManager->GetAlignableEntry(mSymName.c_str()); + if (mPNE == nullptr) { + LOGP(fatal, "Symbolic volume '{}' has no corresponding alignable entry!", mSymName); + } + mPN = mPNE->GetPhysicalNode(); + if (mPN == nullptr) { + LOGP(debug, "Adding physical node to {}", mSymName); + mPN = gGeoManager->MakePhysicalNode(mPNE->GetTitle()); + if (mPN == nullptr) { + LOGP(fatal, "Failed to make physical node for {}", mSymName); + } + } +} + +void AlignableVolume::finalise(uint8_t level) +{ + if (level == 0 && !isRoot()) { + LOGP(fatal, "Finalise should be called only from the root node!"); + } + mLevel = level; + if (!isLeaf()) { + // depth first + for (const auto& c : mChildren) { + c->finalise(level + 1); + } + // check if any children have any dofs otherwise disable the dof for this parent + for (uint8_t iDOF{0}; iDOF < RigidBodyDOF::NDOF; ++iDOF) { + if (!(mDOF & DOF_BIT(iDOF))) { + continue; + } + int nChildrenDOF{0}; // count of children with any dof active + for (const auto& c : mChildren) { + if (c->getRigidBodyDOF()) { + ++nChildrenDOF; + } + } + if (!nChildrenDOF) { + LOGP(warn, "Auto-disabling DOF {} for {} since no active children", RigidBodyDOFNames[iDOF], mSymName); + disableRigidBodyDOF(mDOF, iDOF); + } + } + } else { + // for sensors we need also to define the transformation from the measurment (TRK) to the local frame (LOC) + // need to it with including possible pre-alignment to allow for iterative convergence + // (TRK) is defined wrt global z-axis + defineMatrixL2G(); + defineMatrixT2L(); + } + if (!isRoot()) { + // prepare the transformation matrices, e.g. from child frame to parent frame + // this is not necessarily just one level transformation + TGeoHMatrix mat = *mPN->GetMatrix(); // global matrix (including possible pre-alignment) from this volume to the global frame + if (isLeaf()) { + mat = mL2G; // for sensor volumes they might have redefined the L2G definition + } + auto inv = mParent->mPN->GetMatrix()->Inverse(); // global (including possible pre-alignment) from this volume to the global frame + mat.MultiplyLeft(inv); // left mult. effectively subtracts the parent transformation which is included in the the childs + mL2P = mat; // now this is directly the child to the parent transformation (LOC) (including possible pre-alignment) + + // prepare jacobian from child to parent frame + Eigen::Map> rotL2P(mL2P.GetRotationMatrix()); + Eigen::Matrix3d rotInv = rotL2P.transpose(); // parent-to-child rotation + const double* t = mL2P.GetTranslation(); // child origin in parent frame + Eigen::Matrix3d skewT; + skewT << 0, -t[2], t[1], t[2], 0, -t[0], -t[1], t[0], 0; + mJL2P.setZero(); + mJL2P.topLeftCorner<3, 3>() = rotInv; + mJL2P.topRightCorner<3, 3>() = -rotInv * skewT; + mJL2P.bottomRightCorner<3, 3>() = rotInv; + mJP2L = mJL2P.inverse(); + } +} + +void AlignableVolume::writeRigidBodyConstraints(std::ostream& os) const +{ + // generate hierarchy constraints: parent = averge of children + // (1/N) * sum_k sum_j (J_hk^{-1})_{i,j} * child_k_j = 0 + + if (isLeaf()) { + return; + } + + for (uint8_t iDOF{0}; iDOF < RigidBodyDOF::NDOF; ++iDOF) { + if (!(mDOF & DOF_BIT(iDOF))) { + continue; + } + double nChildrenDOF{0.}; // count of children with this dof active + for (const auto& c : mChildren) { + if (c->getRigidBodyDOF()) { + ++nChildrenDOF; + } + } + if (nChildrenDOF == 0.) { + LOGP(fatal, "{} has dof {} active but no children with this active dof!", mSymName, RigidBodyDOFNames[iDOF]); + } + const double invN = 1.0 / nChildrenDOF; + HierarchyConstraint con(std::format("DOF {} for {}", RigidBodyDOFNames[iDOF], mSymName), 0.0); + for (const auto& c : mChildren) { + if (!c->getRigidBodyDOF()) { + continue; + } + for (uint8_t jDOF{0}; jDOF < RigidBodyDOF::NDOF; ++jDOF) { + if (!hasRigidBodyDOF(c->getRigidBodyDOF(), jDOF)) { + continue; + } + double coeff = invN * c->getJP2L()(iDOF, jDOF); + con.add(c->getLabel().raw(jDOF), coeff); + } + } + + con.write(os); + } + for (const auto& c : mChildren) { + c->writeRigidBodyConstraints(os); + } +} + +void AlignableVolume::writeParameters(std::ostream& os) const +{ + if (isRoot()) { + os << "Parameter\n"; + } + for (uint8_t iDOF{0}; iDOF < RigidBodyDOF::NDOF; ++iDOF) { + os << std::format("{:<10} {:>+15g} {:>+15g} ! {} {} ", mLabel.raw(iDOF), mPreSigma, (hasRigidBodyDOF(mDOF, iDOF) ? 0.0 : -1.0), (hasRigidBodyDOF(mDOF, iDOF) ? 'V' : 'F'), RigidBodyDOFNames[iDOF]) << mSymName << '\n'; + } + for (const auto& c : mChildren) { + c->writeParameters(os); + } +} + +void AlignableVolume::writeTree(std::ostream& os, int indent) const +{ + os << std::string(static_cast(indent * 2), ' ') << mSymName << (mLabel.sens() ? " (sens)" : " (pasv)"); + if (mDOF == RigidBodyDOFPseudo) { + os << " is a pseudo-volume"; + } else if (mDOF == RigidBodyDOFNone) { + os << " no DOFs " << mLabel.raw(0); + } else { + os << " with DOFs ["; + for (uint8_t iDOF{0}; iDOF < RigidBodyDOF::NDOF; ++iDOF) { + if (hasRigidBodyDOF(mDOF, iDOF)) { + os << " " << RigidBodyDOFNames[iDOF] << " (" << mLabel.raw(iDOF) << ") "; + } + } + os << " ]"; + } + os << '\n'; + for (const auto& c : mChildren) { + c->writeTree(os, indent + 2); + } +} diff --git a/Detectors/Upgrades/ITS3/alignment/src/AlignmentParams.cxx b/Detectors/Upgrades/ITS3/alignment/src/AlignmentParams.cxx new file mode 100644 index 0000000000000..0d89cb4d4cffd --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/src/AlignmentParams.cxx @@ -0,0 +1,13 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITS3Align/AlignmentParams.h" +O2ParamImpl(o2::its3::align::AlignmentParams); diff --git a/Detectors/Upgrades/ITS3/alignment/src/AlignmentSensors.cxx b/Detectors/Upgrades/ITS3/alignment/src/AlignmentSensors.cxx new file mode 100644 index 0000000000000..b9c6f4c32e70d --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/src/AlignmentSensors.cxx @@ -0,0 +1,169 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include + +#include +#include + +#include "ITSMFTBase/SegmentationAlpide.h" +#include "ITS3Align/AlignmentSensors.h" +#include "ITSBase/GeometryTGeo.h" + +namespace o2::its3::align +{ + +AlignableVolume::Ptr buildHierarchyITS(AlignableVolume::SensorMapping& sensorMap) +{ + uint32_t gLbl{0}, det{0}; + auto geom = o2::its::GeometryTGeo::Instance(); + AlignableVolume *volHB{nullptr}, *volSt{nullptr}, *volHSt{nullptr}, *volMod{nullptr}; + std::unordered_map sym2vol; + + auto root = std::make_unique(geom->composeSymNameITS(), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[root->getSymName()] = root.get(); + for (int ilr = 0; ilr < geom->getNumberOfLayers(); ilr++) { + for (int ihb = 0; ihb < geom->getNumberOfHalfBarrels(); ihb++) { + volHB = root->addChild(geom->composeSymNameHalfBarrel(ilr, ihb), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volHB->getSymName()] = volHB; + int nstavesHB = geom->getNumberOfStaves(ilr) / 2; + for (int ist = 0; ist < nstavesHB; ist++) { + volSt = volHB->addChild(geom->composeSymNameStave(ilr, ihb, ist), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volSt->getSymName()] = volSt; + for (int ihst = 0; ihst < geom->getNumberOfHalfStaves(ilr); ihst++) { + volHSt = volSt->addChild(geom->composeSymNameHalfStave(ilr, ihb, ist, ihst), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volHSt->getSymName()] = volHSt; + for (int imd = 0; imd < geom->getNumberOfModules(ilr); imd++) { + volMod = volHSt->addChild(geom->composeSymNameModule(ilr, ihb, ist, ihst, imd), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volMod->getSymName()] = volMod; + } + } + } + } + } + + // NOTE: for ITS sensors the local x and y are swapped + int lay = 0, hba = 0, sta = 0, ssta = 0, modd = 0, chip = 0; + for (int ich = 0; ich < geom->getNumberOfChips(); ich++) { + geom->getChipId(ich, lay, hba, sta, ssta, modd, chip); + GlobalLabel lbl(det, ich, true); + AlignableVolume* parVol = sym2vol[modd < 0 ? geom->composeSymNameStave(lay, hba, sta) : geom->composeSymNameModule(lay, hba, sta, ssta, modd)]; + if (!parVol) { + throw std::runtime_error(fmt::format("did not find parent for chip {}", ich)); + } + int nch = modd < 0 ? geom->getNumberOfChipsPerStave(lay) : geom->getNumberOfChipsPerModule(lay); + int jch = ich % nch; + if (ich == 148 || ich == 147) { + RigidBodyDOFMask m = DOF_BIT(RigidBodyDOF::TZ); + parVol->setRigidBodyDOF(m); + sensorMap[lbl] = parVol->addChild(geom->composeSymNameChip(lay, hba, sta, ssta, modd, jch), lbl, m); + } else { + sensorMap[lbl] = parVol->addChild(geom->composeSymNameChip(lay, hba, sta, ssta, modd, jch), lbl, RigidBodyDOFNone); + } + } + return root; +} + +AlignableVolume::Ptr buildHierarchyIT3(AlignableVolume::SensorMapping& sensorMap) +{ + uint32_t gLbl{0}, det{0}; + auto geom = o2::its::GeometryTGeo::Instance(); + AlignableVolume *volHB{nullptr}, *volSt{nullptr}, *volHSt{nullptr}, *volMod{nullptr}; + std::unordered_map sym2vol; + + auto root = std::make_unique(geom->composeSymNameITS(), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[root->getSymName()] = root.get(); + for (int ilr = 0; ilr < geom->getNumberOfLayers(); ilr++) { + const bool isLayITS3 = (ilr < 3); + for (int ihb = 0; ihb < geom->getNumberOfHalfBarrels(); ihb++) { + volHB = root->addChild(geom->composeSymNameHalfBarrel(ilr, ihb, isLayITS3), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volHB->getSymName()] = volHB; + if (isLayITS3) { // for its3 there are no more alignable volumes after this! + continue; + } + int nstavesHB = geom->getNumberOfStaves(ilr) / 2; + for (int ist = 0; ist < nstavesHB; ist++) { + volSt = volHB->addChild(geom->composeSymNameStave(ilr, ihb, ist), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volSt->getSymName()] = volSt; + for (int ihst = 0; ihst < geom->getNumberOfHalfStaves(ilr); ihst++) { + volHSt = volSt->addChild(geom->composeSymNameHalfStave(ilr, ihb, ist, ihst), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volHSt->getSymName()] = volHSt; + for (int imd = 0; imd < geom->getNumberOfModules(ilr); imd++) { + volMod = volHSt->addChild(geom->composeSymNameModule(ilr, ihb, ist, ihst, imd), gLbl++, det, false, RigidBodyDOFNone); + sym2vol[volMod->getSymName()] = volMod; + } + } + } + } + } + + int lay = 0, hba = 0, sta = 0, ssta = 0, modd = 0, chip = 0; + for (int ich = 0; ich < geom->getNumberOfChips(); ich++) { + geom->getChipId(ich, lay, hba, sta, ssta, modd, chip); + const bool isLayITS3 = (lay < 3); + GlobalLabel lbl(det, ich, true); + if (isLayITS3) { + // ITS3 chips by construction do not have any DOFs still add them to have the measurment to alignable layer relation + AlignableVolume* parVol = sym2vol[geom->composeSymNameHalfBarrel(lay, hba, true)]; + if (!parVol) { + throw std::runtime_error(fmt::format("did not find parent for chip {}", ich)); + } + sensorMap[lbl] = parVol->addChild(geom->composeSymNameChip(lay, hba, sta, ssta, modd, chip, true), lbl, RigidBodyDOFPseudo); + } else { + AlignableVolume* parVol = sym2vol[modd < 0 ? geom->composeSymNameStave(lay, hba, sta) : geom->composeSymNameModule(lay, hba, sta, ssta, modd)]; + if (!parVol) { + throw std::runtime_error(fmt::format("did not find parent for chip {}", ich)); + } + int nch = modd < 0 ? geom->getNumberOfChipsPerStave(lay) : geom->getNumberOfChipsPerModule(lay); + int jch = ich % nch; + sensorMap[lbl] = parVol->addChild(geom->composeSymNameChip(lay, hba, sta, ssta, modd, jch), lbl, RigidBodyDOFNone); + } + } + return root; +} + +void AlignableSensorITS::defineMatrixL2G() +{ + // the chip volume is not the measurment plane, need to correct for the epitaxial layer + const auto* chipL2G = mPN->GetMatrix(); + mL2G = *chipL2G; + double delta = itsmft::SegmentationAlpide::SensorLayerThickness - itsmft::SegmentationAlpide::SensorLayerThicknessEff; + TGeoTranslation tra(0., 0.5 * delta, 0.); + mL2G *= tra; +} + +void AlignableSensorITS::defineMatrixT2L() +{ + double locA[3] = {-100., 0., 0.}, locB[3] = {100., 0., 0.}, gloA[3], gloB[3]; + mL2G.LocalToMaster(locA, gloA); + mL2G.LocalToMaster(locB, gloB); + double dx = gloB[0] - gloA[0], dy = gloB[1] - gloA[1]; + double t = (gloB[0] * dx + gloB[1] * dy) / (dx * dx + dy * dy); + double xp = gloB[0] - (dx * t), yp = gloB[1] - (dy * t); + double alp = std::atan2(yp, xp); + o2::math_utils::bringTo02Pid(alp); + mT2L.RotateZ(alp * TMath::RadToDeg()); // mT2L before is identity and afterwards rotated + const TGeoHMatrix l2gI = mL2G.Inverse(); + mT2L.MultiplyLeft(l2gI); +} + +void AlignableSensorITS::computeJacobianL2T(const double* posLoc, Matrix66& jac) const +{ + jac.setZero(); + Eigen::Map> rotT2L(mT2L.GetRotationMatrix()); + Eigen::Matrix3d skew, rotL2T = rotT2L.transpose(); + skew << 0, -posLoc[2], posLoc[1], posLoc[2], 0, -posLoc[0], -posLoc[1], posLoc[0], 0; + jac.topLeftCorner<3, 3>() = rotL2T; + jac.topRightCorner<3, 3>() = -rotL2T * skew; + jac.bottomRightCorner<3, 3>() = rotL2T; +} + +} // namespace o2::its3::align diff --git a/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx b/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx new file mode 100644 index 0000000000000..b4a03a32e8494 --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/src/AlignmentSpec.cxx @@ -0,0 +1,799 @@ +// Copyright 2019-2026 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include + +#ifdef WITH_OPENMP +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "ITSBase/GeometryTGeo.h" +#include "CommonUtils/EnumFlags.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "Steer/MCKinematicsReader.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "ITS3Reconstruction/TopologyDictionary.h" +#include "DataFormatsITSMFT/TopologyDictionary.h" +#include "ITStracking/MathUtils.h" +#include "ITS3Reconstruction/IOUtils.h" +#include "ITS3Align/AlignmentParams.h" +#include "ITS3Align/AlignmentTypes.h" +#include "ITS3Align/AlignmentHierarchy.h" +#include "ITS3Align/AlignmentSensors.h" + +namespace o2::its3::align +{ +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using DataRequest = o2::globaltracking::DataRequest; +using PVertex = o2::dataformats::PrimaryVertex; +using V2TRef = o2::dataformats::VtxTrackRef; +using VTIndex = o2::dataformats::VtxTrackIndex; +using GTrackID = o2::dataformats::GlobalTrackID; +using TrackD = o2::track::TrackParCovD; + +class AlignmentSpec final : public Task +{ + public: + ~AlignmentSpec() final = default; + AlignmentSpec(const AlignmentSpec&) = delete; + AlignmentSpec(AlignmentSpec&&) = delete; + AlignmentSpec& operator=(const AlignmentSpec&) = delete; + AlignmentSpec& operator=(AlignmentSpec&&) = delete; + AlignmentSpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC, bool withPV) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC), mWithPV(withPV) + { + } + + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; + void process(); + + private: + void updateTimeDependentParams(ProcessingContext& pc); + void buildHierarchy(); + + // calculate the transport jacobian for points FROM and TO numerically via ridder's method + // this assumes the track is already at point FROM and will be extrapolated to TO's x (xTo) + // method does not modify the original track + bool getTransportJacobian(const TrackD& track, double xTo, double alphaTo, gbl::Matrix5d& jac, gbl::Matrix5d& err); + + // refit ITS track with inward/outward fit (opt. impose pv as additional constraint) + // after this we have the refitted track at the innermost update point + bool prepareITSTrack(int iTrk, const o2::its::TrackITS& itsTrack, Track& resTrack); + + // prepare ITS measuremnt points + void prepareMeasurments(std::span clusters, std::span pattIt); + + // build track to vertex association + void buildT2V(); + + // create a track in double precision from single precision + TrackD convertTrack(const track::TrackParCov& trk) const noexcept; + + // Steering debug + enum class OutputOpt : uint8_t { + VerboseGBL = 0, + MilleData, + MilleSteer, + Debug, + }; + utils::EnumFlags mOutOpt; + std::unique_ptr mDBGOut; + std::vector mPVs; + std::vector mT2PV; + const o2::itsmft::TopologyDictionary* mITSDict{nullptr}; + const o2::its3::TopologyDictionary* mIT3Dict{nullptr}; + o2::globaltracking::RecoContainer* mRecoData = nullptr; + std::unique_ptr mcReader; + std::vector mITSTrackingInfo; + std::shared_ptr mDataRequest; + std::shared_ptr mGGCCDBRequest; + std::unique_ptr mHierarchy; // tree-hiearchy + AlignableVolume::SensorMapping mChip2Hiearchy; // global label mapping to leaves in the tree + bool mUseMC{false}; + bool mWithPV{false}; + GTrackID::mask_t mTracksSrc; + int mNThreads{1}; +}; + +void AlignmentSpec::init(InitContext& ic) +{ + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mNThreads = ic.options().get("nthreads"); + mOutOpt.set(ic.options().get("output")); + if (mOutOpt) { + LOG(info) << mOutOpt.pstring(); + mDBGOut = std::make_unique("its3_debug_alg.root", "recreate"); + } + if (mUseMC) { + mcReader = std::make_unique("collisioncontext.root"); + } +} + +void AlignmentSpec::run(ProcessingContext& pc) +{ + o2::globaltracking::RecoContainer recoData; + mRecoData = &recoData; + mRecoData->collectData(pc, *mDataRequest); + updateTimeDependentParams(pc); + process(); + mRecoData = nullptr; +} + +void AlignmentSpec::process() +{ + if (!mITSDict && !mIT3Dict) { + LOGP(fatal, "ITS data is not loaded"); + } + const auto& param = AlignmentParams::Instance(); + auto prop = o2::base::PropagatorD::Instance(); + const auto bz = prop->getNominalBz(); + const auto itsTracks = mRecoData->getITSTracks(); + const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); + const auto clusITS = mRecoData->getITSClusters(); + const auto patterns = mRecoData->getITSClustersPatterns(); + std::span mcLbls; + if (mUseMC) { + mcLbls = mRecoData->getITSTracksMCLabels(); + } + prepareMeasurments(clusITS, patterns); + + if (mWithPV) { + buildT2V(); + } + + LOGP(info, "Starting fits with {} threads", mNThreads); + + // Data + std::vector> gblTrajSlots(mNThreads); + std::vector> resTrackSlots(mNThreads); + + auto timeStart = std::chrono::high_resolution_clock::now(); + int cFailedRefit{0}, cFailedProp{0}, cSelected{0}, cGBLFit{0}, cGBLFitFail{0}, cGBLChi2Rej{0}, cGBLConstruct{0}; + double chi2Sum{0}, lostWeightSum{0}; + int ndfSum{0}; +#ifdef WITH_OPENMP +#pragma omp parallel num_threads(mNThreads) \ + reduction(+ : cFailedRefit) \ + reduction(+ : cFailedProp) \ + reduction(+ : cSelected) \ + reduction(+ : cGBLFit) \ + reduction(+ : cGBLFitFail) \ + reduction(+ : cGBLChi2Rej) \ + reduction(+ : cGBLConstruct) \ + reduction(+ : chi2Sum) \ + reduction(+ : lostWeightSum) \ + reduction(+ : ndfSum) +#endif + { +#ifdef WITH_OPENMP + const int tid = omp_get_thread_num(); +#else + const int tid = 0; +#endif + auto& gblTrajSlot = gblTrajSlots[tid]; + auto& resTrackSlot = resTrackSlots[tid]; + +#ifdef WITH_OPENMP +#pragma omp for schedule(dynamic) +#endif + for (size_t iTrk = 0; iTrk < (int)itsTracks.size(); ++iTrk) { + const auto& trk = itsTracks[iTrk]; + if (trk.getNClusters() < param.minITSCls || + (trk.getChi2() / ((float)trk.getNClusters() * 2 - 5)) >= param.maxITSChi2Ndf || + trk.getPt() < param.minPt || + (mUseMC && (!mcLbls[iTrk].isValid() || !mcLbls[iTrk].isCorrect()))) { + continue; + } + ++cSelected; + Track& resTrack = resTrackSlot.emplace_back(); + if (!prepareITSTrack((int)iTrk, trk, resTrack)) { + ++cFailedRefit; + resTrackSlot.pop_back(); + continue; + } + + o2::track::TrackParD* refLin = nullptr; + if (param.useStableRefit) { + refLin = &resTrack.track; + } + + // outward stepping from track IU + auto wTrk = resTrack.track; + const bool hasPV = resTrack.info[0].lr == -1; + std::vector points; + bool first = true, failed = false; + const int np = (int)resTrack.points.size(); + track::TrackLTIntegral lt; + lt.setTimeNotNeeded(); + constexpr int perm[5] = {4, 2, 3, 0, 1}; // ALICE->GBL: Q/Pt,Snp,Tgl,Y,Z + + // calcualte seed precision from IU covariance + // auto covALICE = resTrack.track.getCov(); + // gbl::Matrix5d seedCov, seedPrec; + // for (int i = 0; i < 5; i++) { + // for (int j = 0; j < 5; j++) { + // // getCov returns lower triangle in packed form + // int iA = perm[i], jA = perm[j]; + // if (iA < jA) { + // std::swap(iA, jA); + // } + // seedCov(i, j) = covALICE[(iA * (iA + 1) / 2) + jA]; + // } + // } + // seedPrec = seedCov.inverse(); + + for (int ip{0}; ip < np; ++ip) { + const auto& frame = resTrack.info[ip]; + gbl::Matrix5d err = gbl::Matrix5d::Identity(), jacALICE = gbl::Matrix5d::Identity(), jacGBL; + float msErr = 0.f; + if (!first) { + // numerically calculates the transport jacobian from prev. point to this point + // then we actually do the step to the point and accumulate the material + if (!getTransportJacobian(wTrk, frame.x, frame.alpha, jacALICE, err) || + !prop->propagateToAlphaX(wTrk, refLin, frame.alpha, frame.x, false, param.maxSnp, param.maxStep, 1, param.matCorrType, <)) { + ++cFailedProp; + failed = true; + break; + } + msErr = its::math_utils::MSangle(trk.getPID().getMass(), trk.getP(), lt.getX2X0()); + } else { + first = false; + } + + // after computing jac, reorder to GBL convention + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + jacGBL(i, j) = jacALICE(perm[i], perm[j]); + } + } + + // wTrk is now in the measurment frame + gbl::GblPoint point(jacGBL); + // measurement + Eigen::Vector2d res, prec; + res << frame.positionTrackingFrame[0] - wTrk.getY(), frame.positionTrackingFrame[1] - wTrk.getZ(); + prec << 1. / resTrack.points[ip].sig2y, 1. / resTrack.points[ip].sig2z; + // the projection matrix is in the tracking frame the idendity so no need to diagonalize it + point.addMeasurement(res, prec); + if (msErr > param.minMS && ip < np - 1) { + Eigen::Vector2d scat(0., 0.), scatPrec = Eigen::Vector2d::Constant(1. / (msErr * msErr)); + point.addScatterer(scat, scatPrec); + lt.clearFast(); // only clear if accounted + } + + if (frame.lr >= 0) { + GlobalLabel lbl(0, frame.sens, true); + if (mChip2Hiearchy.find(lbl) == mChip2Hiearchy.end()) { + LOGP(fatal, "Cannot find global label: {}", lbl.asString()); + } + + // derivatives for all sensitive volumes and their parents + // this is the derivative in TRK but we want to align in LOC + // so dr/da_(LOC) = dr/da_(TRK) * da_(TRK)/da_(LOC) + const auto* sensorVol = mChip2Hiearchy.at(lbl); + Matrix36 der = getRigidBodyDerivatives(wTrk); + int nCol = sensorVol->getLevel() * RigidBodyDOF::NDOF; + std::vector gLabels; + gLabels.reserve(nCol); + Eigen::MatrixXd gDer(3, nCol); + + // 1) sensor: TRK -> LOC via precomputed T2L and J_L2T + const double posTrk[3] = {frame.x, 0., 0.}; + double posLoc[3]; + sensorVol->getT2L().LocalToMaster(posTrk, posLoc); + Matrix66 jacL2T; + sensorVol->computeJacobianL2T(posLoc, jacL2T); + der *= jacL2T; + for (uint8_t iDOF{0}; iDOF < RigidBodyDOF::NDOF; ++iDOF) { + gLabels.push_back(sensorVol->getLabel().rawGBL(iDOF)); + } + Eigen::Index curCol{0}; + gDer.middleCols(curCol++ * RigidBodyDOF::NDOF, RigidBodyDOF::NDOF) = der; + + // 2) chain through parents: child's J_L2P + for (const auto* child = sensorVol; child->getParent() && !child->getParent()->isRoot(); child = child->getParent()) { + der *= child->getJL2P(); + const auto* parent = child->getParent(); + for (uint8_t iDOF{0}; iDOF < RigidBodyDOF::NDOF; ++iDOF) { + gLabels.push_back(parent->getLabel().rawGBL(iDOF)); + } + gDer.middleCols(curCol++ * RigidBodyDOF::NDOF, RigidBodyDOF::NDOF) = der; + } + point.addGlobals(gLabels, gDer); + } + + if (mOutOpt[OutputOpt::VerboseGBL]) { + static Eigen::IOFormat fmt(4, 0, ", ", "\n", "[", "]"); + LOGP(info, "WORKING-POINT {}", ip); + LOGP(info, "Track: {}", wTrk.asString()); + LOGP(info, "FrameInfo: {}", frame.asString()); + std::cout << "jacALICE:\n" + << jacALICE.format(fmt) << '\n'; + std::cout << "jacGBL:\n" + << jacGBL.format(fmt) << '\n'; + LOGP(info, "Point {}: GBL res=({}, {}), KF stored res=({}, {})", + ip, res[0], res[1], resTrack.points[ip].dy, resTrack.points[ip].dz); + LOGP(info, "residual: dy={} dz={}", res[0], res[1]); + LOGP(info, "precision: precY={} precZ={}", prec[0], prec[1]); + point.printPoint(5); + } + points.push_back(point); + } + if (!failed) { + // TODO: check why external seed worsens fit? + // gbl::GblTrajectory traj(points, 1, seedPrec, std::abs(bz) > 0.001); + gbl::GblTrajectory traj(points, std::abs(bz) > 0.001); + if (traj.isValid()) { + double chi2 = NAN, lostWeight = NAN; + int ndf = 0; + if (auto ierr = traj.fit(chi2, ndf, lostWeight); !ierr) { + if (mOutOpt[OutputOpt::VerboseGBL]) { + LOGP(info, "GBL FIT chi2 {} ndf {}", chi2, ndf); + traj.printTrajectory(5); + } + if (chi2 / ndf > param.maxChi2Ndf) { + LOGP(error, "GBL fit exceeded red chi2 {}", chi2 / ndf); + ++cGBLChi2Rej; + if (std::abs(resTrack.kfFit.chi2Ndf - 1) < 0.02) { + LOGP(error, "\tGBL is far away from KF fit!!!!"); + continue; + } + } else { + ++cGBLFit; + chi2Sum += chi2; + lostWeightSum += lostWeight; + ndfSum += ndf; + if (mOutOpt[OutputOpt::MilleData]) { + gblTrajSlot.push_back(traj); + } + FitInfo fit{.ndf = ndf, .chi2 = (float)chi2, .chi2Ndf = (float)chi2 / (float)ndf}; + resTrack.gblFit = fit; + } + } else { + ++cGBLFitFail; + } + } else { + ++cGBLConstruct; + } + } + } + } + auto timeEnd = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(timeEnd - timeStart); + LOGP(info, "Fitted {} tracks out of {} (selected {}) in {} sec", cGBLFit, itsTracks.size(), cSelected, duration.count() / 1e3); + LOGP(info, "\tRefit failed for {} tracks; Failed prop for {} tracks", cFailedRefit, cFailedProp); + LOGP(info, "\tGBL SUMMARY:"); + LOGP(info, "\t\tGBL construction failed {}", cGBLConstruct); + LOGP(info, "\t\tGBL fit failed {}", cGBLFitFail); + LOGP(info, "\t\tGBL chi2Ndf rejected {}", cGBLChi2Rej); + if (!ndfSum) { + LOGP(info, "\t\tGBL Chi2/Ndf = NDF IS 0"); + } else { + LOGP(info, "\t\tGBL Chi2/Ndf = {}", chi2Sum / ndfSum); + } + LOGP(info, "\t\tGBL LostWeight = {}", lostWeightSum); + LOGP(info, "Streaming results to output"); + if (mOutOpt[OutputOpt::MilleData]) { + gbl::MilleBinary mille(param.milleBinFile, true); + for (auto& slot : gblTrajSlots) { + for (auto& traj : slot) { + traj.milleOut(mille); + } + } + } + if (mOutOpt[OutputOpt::Debug]) { + for (auto& slot : resTrackSlots) { + for (auto& res : slot) { + (*mDBGOut) << "res" + << "trk=" << res + << "\n"; + } + } + } +} + +void AlignmentSpec::updateTimeDependentParams(ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + if (static bool initOnce{false}; !initOnce) { + initOnce = true; + auto geom = o2::its::GeometryTGeo::Instance(); + o2::its::GeometryTGeo::Instance()->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G, o2::math_utils::TransformType::T2G)); + AlignmentParams::Instance().printKeyValues(true, true); + + buildHierarchy(); + } +} + +void AlignmentSpec::buildHierarchy() +{ + if (mIT3Dict) { + mHierarchy = buildHierarchyIT3(mChip2Hiearchy); + } else { + mHierarchy = buildHierarchyITS(mChip2Hiearchy); + } + + const auto& param = AlignmentParams::Instance(); + mHierarchy->finalise(); + if (mOutOpt[OutputOpt::MilleSteer]) { + std::ofstream tree(param.milleTreeFile); + mHierarchy->writeTree(tree); + std::ofstream cons(param.milleConFile); + mHierarchy->writeRigidBodyConstraints(cons); + std::ofstream par(param.milleParamFile); + mHierarchy->writeParameters(par); + } +} + +bool AlignmentSpec::getTransportJacobian(const TrackD& track, double xTo, double alphaTo, gbl::Matrix5d& jac, gbl::Matrix5d& err) +{ + auto prop = o2::base::PropagatorD::Instance(); + const auto bz = prop->getNominalBz(); + const auto& param = AlignmentParams::Instance(); + const auto minStep = std::sqrt(std::numeric_limits::epsilon()); + const gbl::Vector5d x0(track.getParams()); + auto trackC = track; + o2::track::TrackParD* refLin{nullptr}; + if (param.useStableRefit) { + refLin = &trackC; + } + + auto propagate = [&](gbl::Vector5d& p) -> bool { + TrackD tmp(track); + for (int i{0}; i < track::kNParams; ++i) { + tmp.setParam(p[i], i); + } + if (!prop->propagateToAlphaX(tmp, refLin, alphaTo, xTo, false, param.maxSnp, param.maxStep, 1, param.matCorrType)) { + return false; + } + p = gbl::Vector5d(tmp.getParams()); + return true; + }; + + for (int iPar{0}; iPar < track::kNParams; ++iPar) { + // step size + double h = std::min(param.ridderMaxIniStep[iPar], std::max(minStep, std::abs(track.getParam(iPar)) * param.ridderRelIniStep[iPar]) * std::pow(param.ridderShrinkFac, param.ridderMaxExtrap / 2)); + ; + // romberg tableu + Eigen::MatrixXd cur(track::kNParams, param.ridderMaxExtrap); + Eigen::MatrixXd pre(track::kNParams, param.ridderMaxExtrap); + double normErr = std::numeric_limits::max(); + gbl::Vector5d bestDeriv = gbl::Vector5d::Constant(std::numeric_limits::max()); + for (int iExt{0}; iExt < param.ridderMaxExtrap; ++iExt) { + gbl::Vector5d xPlus = x0, xMinus = x0; + xPlus(iPar) += h; + xMinus(iPar) -= h; + if (!propagate(xPlus) || !propagate(xMinus)) { + return false; + } + cur.col(0) = (xPlus - xMinus) / (2.0 * h); + if (!iExt) { + bestDeriv = cur.col(0); + } + // shrink step in next iteration + h /= param.ridderShrinkFac; + // richardson extrapolation + double fac = param.ridderShrinkFac * param.ridderShrinkFac; + for (int k{1}; k <= iExt; ++k) { + cur.col(k) = (fac * cur.col(k - 1) - pre.col(k - 1)) / (fac - 1.0); + fac *= param.ridderShrinkFac * param.ridderShrinkFac; + double e = std::max((cur.col(k) - cur.col(k - 1)).norm(), (cur.col(k) - pre.col(k - 1)).norm()); + if (e <= normErr) { + normErr = e; + bestDeriv = cur.col(k); + if (normErr < param.ridderEps) { + break; + } + } + } + if (normErr < param.ridderEps) { + break; + } + // check stability + if (iExt > 0) { + double tableauErr = (cur.col(iExt) - pre.col(iExt - 1)).norm(); + if (tableauErr >= 2.0 * normErr) { + break; + } + } + std::swap(cur, pre); + } + if (bestDeriv.isApproxToConstant(std::numeric_limits::max())) { + return false; + } + jac.col(iPar) = bestDeriv; + err.col(iPar) = gbl::Vector5d::Constant(normErr); + } + + if (jac.isIdentity(1e-8)) { + LOGP(error, "Near jacobian idendity for taking track from {} to {}", track.getX(), xTo); + return false; + } + // only check for elements where there is no change expected q/pt, tgl + if (std::abs(1. - jac(4, 4)) > param.ridderMaxJacDiagTol || std::abs(1. - jac(3, 3)) > param.ridderMaxJacDiagTol) { + LOGP(error, "Diagonal element not expected to change in propagation jacobian is to far away from 1"); + LOG(info) << jac; + return false; + } + + return true; +} + +bool AlignmentSpec::prepareITSTrack(int iTrk, const o2::its::TrackITS& itsTrack, align::Track& resTrack) +{ + const auto& param = AlignmentParams::Instance(); + const auto itsClRefs = mRecoData->getITSTracksClusterRefs(); + auto trFit = convertTrack(itsTrack.getParamOut()); // take outer track fit as start of refit + auto prop = o2::base::PropagatorD::Instance(); + auto geom = o2::its::GeometryTGeo::Instance(); + const auto bz = prop->getNominalBz(); + std::array frameArr{}; + o2::track::TrackParD trkOut = trFit, *refLin = nullptr; + if (param.useStableRefit) { + refLin = &trkOut; + } + + auto accountCluster = [&](int i, TrackD& tr, float& chi2, Measurement& meas, o2::track::TrackParD* refLin) { + if (frameArr[i]) { // update with cluster + if (!prop->propagateToAlphaX(tr, refLin, frameArr[i]->alpha, frameArr[i]->x, false, param.maxSnp, param.maxStep, 1, param.matCorrType)) { + return 2; + } + meas.dy = frameArr[i]->positionTrackingFrame[0] - tr.getY(); + meas.dz = frameArr[i]->positionTrackingFrame[1] - tr.getZ(); + meas.sig2y = frameArr[i]->covarianceTrackingFrame[0]; + meas.sig2z = frameArr[i]->covarianceTrackingFrame[2]; + meas.z = tr.getZ(); + meas.phi = tr.getPhi(); + o2::math_utils::bringTo02Pid(meas.phi); + chi2 += (float)tr.getPredictedChi2Quiet(frameArr[i]->positionTrackingFrame, frameArr[i]->covarianceTrackingFrame); + if (!tr.update(frameArr[i]->positionTrackingFrame, frameArr[i]->covarianceTrackingFrame)) { + return 2; + } + if (refLin) { // displace the reference to the last updated cluster + refLin->setY(frameArr[i]->positionTrackingFrame[0]); + refLin->setZ(frameArr[i]->positionTrackingFrame[1]); + } + return 0; + } + return 1; + }; + + // add PV as constraint + FrameInfoExt* pvInfo{nullptr}; + if (mWithPV) { + const int iPV = mT2PV[iTrk]; + if (iPV < 0) { + return false; + } + const auto& pv = mPVs[iPV]; + auto tmp = convertTrack(itsTrack.getParamIn()); + if (!prop->propagateToDCA(pv, tmp, bz)) { + return false; + } + pvInfo = new FrameInfoExt; + pvInfo->alpha = (float)tmp.getAlpha(); + float ca{0}, sa{0}; + o2::math_utils::bringTo02Pi(pvInfo->alpha); + o2::math_utils::sincos(pvInfo->alpha, sa, ca); + pvInfo->x = tmp.getX(); + pvInfo->positionTrackingFrame[0] = -pv.getX() * sa + pv.getY() * ca; + pvInfo->positionTrackingFrame[1] = pv.getZ(); + pvInfo->covarianceTrackingFrame[0] = 0.5 * (pv.getSigmaX2() + pv.getSigmaY2()); + pvInfo->covarianceTrackingFrame[2] = pv.getSigmaY2(); + pvInfo->sens = -1; + pvInfo->lr = -1; + } + frameArr[0] = pvInfo; + + // collect all track clusters to array, placing them to layer+1 slot + int nCl = itsTrack.getNClusters(); + for (int i = 0; i < nCl; i++) { // clusters are ordered from the outermost to the innermost + const auto& curInfo = mITSTrackingInfo[itsClRefs[itsTrack.getClusterEntry(i)]]; + frameArr[1 + curInfo.lr] = &curInfo; + } + + // start refit + resTrack.points.clear(); + resTrack.info.clear(); + trFit.resetCovariance(); + trFit.setCov(trFit.getQ2Pt() * trFit.getQ2Pt() * trFit.getCov()[14], 14); + float chi2{0}; + for (int i{7}; i >= 0; --i) { + Measurement point; + int res = accountCluster(i, trFit, chi2, point, refLin); + if (res == 2) { + return false; + } else if (res == 0) { + resTrack.points.push_back(point); + resTrack.info.push_back(*frameArr[i]); + resTrack.track = trFit; // put track to whatever the IU is + } + } + // reverse inserted points so they are in the same order as the track + std::reverse(resTrack.info.begin(), resTrack.info.end()); + std::reverse(resTrack.points.begin(), resTrack.points.end()); + resTrack.kfFit.chi2 = chi2; + resTrack.kfFit.ndf = (int)resTrack.info.size() * 2 - 5; + resTrack.kfFit.chi2Ndf = chi2 / (float)resTrack.kfFit.ndf; + + delete pvInfo; + + return true; +} + +void AlignmentSpec::prepareMeasurments(std::span clusters, std::span patterns) +{ + LOGP(info, "Preparing {} measurments", clusters.size()); + auto geom = its::GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); + mITSTrackingInfo.clear(); + mITSTrackingInfo.reserve(clusters.size()); + auto pattIt = patterns.begin(); + for (const auto& cls : clusters) { + const auto sens = cls.getSensorID(); + const auto lay = geom->getLayer(sens); + float sigmaY2{0}, sigmaZ2{0}; + math_utils::Point3D locXYZ; + if (mIT3Dict) { + locXYZ = o2::its3::ioutils::extractClusterData(cls, pattIt, mIT3Dict, sigmaY2, sigmaZ2); + } else { + locXYZ = o2::its::ioutils::extractClusterData(cls, pattIt, mITSDict, sigmaY2, sigmaZ2); + } + // Transformation to the local --> global + const auto gloXYZ = geom->getMatrixL2G(sens) * locXYZ; + // Inverse transformation to the local --> tracking + const o2::math_utils::Point3D trkXYZ = geom->getMatrixT2L(sens) ^ locXYZ; + // Tracking alpha angle + // We want that each cluster rotates its tracking frame to the clusters phi + // that way the track linearization around the measurement is less biases to the arc + // this means automatically that the measurement on the arc is at 0 for the curved layers + float alpha = geom->getSensorRefAlpha(sens); + float x = trkXYZ.x(), y = trkXYZ.y(); + if (mIT3Dict && lay < 3) { + y = 0.f; + // alpha&x always have to be defined wrt to the global Z axis! + x = std::hypot(gloXYZ.x(), gloXYZ.y()); + alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); + } + mITSTrackingInfo.emplace_back(sens, lay, trkXYZ, locXYZ, gloXYZ, x, alpha, + std::array{y, trkXYZ.z()}, + std::array{sigmaY2, 0., sigmaZ2}); + } +} + +void AlignmentSpec::buildT2V() +{ + const auto& itsTracks = mRecoData->getITSTracks(); + mT2PV.clear(); + mT2PV.resize(itsTracks.size(), -1); + if (mUseMC) { + mPVs.reserve(mcReader->getNEvents(0)); + for (int iEve{0}; iEve < mcReader->getNEvents(0); ++iEve) { + const auto& eve = mcReader->getMCEventHeader(0, iEve); + dataformats::VertexBase vtx; + constexpr float err{30e-7f}; + vtx.setX((float)eve.GetX() + (float)gRandom->Gaus(0.f, err)); + vtx.setY((float)eve.GetY() + (float)gRandom->Gaus(0.f, err)); + vtx.setZ((float)eve.GetZ() + (float)gRandom->Gaus(0.f, err)); + vtx.setCov(err, 0.f, 0.f, err, 0.f, err); + mPVs.push_back(vtx); + } + const auto& mcLbls = mRecoData->getITSTracksMCLabels(); + for (size_t iTrk{0}; iTrk < mcLbls.size(); ++iTrk) { + const auto& lbl = mcLbls[iTrk]; + if (!lbl.isValid() || !lbl.isCorrect()) { + continue; + } + const auto& mcTrk = mcReader->getTrack(lbl); + if (mcTrk->isPrimary()) { + mT2PV[iTrk] = lbl.getEventID(); + } + } + } else { + LOGP(fatal, "Data PV to track TODO"); + } +} + +TrackD AlignmentSpec::convertTrack(const track::TrackParCov& trk) const noexcept +{ + TrackD dst; + dst.setX(trk.getX()); + dst.setAlpha(trk.getAlpha()); + for (int iPar{0}; iPar < track::kNParams; ++iPar) { + dst.setParam(trk.getParam(iPar), iPar); + } + dst.setAbsCharge(trk.getAbsCharge()); + dst.setPID(trk.getPID()); + dst.setUserField(trk.getUserField()); + for (int iCov{0}; iCov < track::kCovMatSize; ++iCov) { + dst.setCov(trk.getCov()[iCov], iCov); + } + return dst; +} + +void AlignmentSpec::endOfStream(EndOfStreamContext& /*ec*/) +{ + mDBGOut->Close(); + mDBGOut.reset(); +} + +void AlignmentSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { + LOG(info) << "its cluster dictionary updated"; + mITSDict = (const o2::itsmft::TopologyDictionary*)obj; + return; + } + if (matcher == ConcreteDataMatcher("IT3", "CLUSDICT", 0)) { + LOG(info) << "it3 cluster dictionary updated"; + mIT3Dict = (const o2::its3::TopologyDictionary*)obj; + return; + } +} + +DataProcessorSpec getAlignmentSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, bool withPV, bool withITS) +{ + auto dataRequest = std::make_shared(); + dataRequest->requestTracks(srcTracks, useMC); + if (!withITS) { + dataRequest->requestIT3Clusters(useMC); + } else { + dataRequest->requestClusters(srcClusters, useMC); + } + if (withPV && !useMC) { + dataRequest->requestPrimaryVertices(useMC); + } + auto ggRequest = std::make_shared(false, // orbitResetTime + true, // GRPECS=true + true, // GRPLHCIF + true, // GRPMagField + true, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, // inputs + true, // askOnce + true); // propagatorD + Options opts{ + {"nthreads", VariantType::Int, 1, {"number of threads"}}, + {"output", VariantType::String, "", {"output flags"}}, + }; + + return DataProcessorSpec{ + .name = "its3-alignment", + .inputs = dataRequest->inputs, + .outputs = {}, + .algorithm = AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC, withPV)}, + .options = opts}; +} +} // namespace o2::its3::align diff --git a/Detectors/Upgrades/ITS3/alignment/src/AlignmentTypes.cxx b/Detectors/Upgrades/ITS3/alignment/src/AlignmentTypes.cxx new file mode 100644 index 0000000000000..2231a715cdd12 --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/src/AlignmentTypes.cxx @@ -0,0 +1,24 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include + +#include "ITS3Align/AlignmentTypes.h" +ClassImp(o2::its3::align::Point); +ClassImp(o2::its3::align::FrameInfoExt); +ClassImp(o2::its3::align::FitInfo); +ClassImp(o2::its3::align::Track); + +std::string o2::its3::align::FrameInfoExt::asString() const +{ + return std::format("Sensor={} Layer={} TrkX={} Alpha={}\n\tTRK: y={} z={}\n\tMEAS: y={} z={}", sens, lr, x, alpha, trk.y(), trk.z(), positionTrackingFrame[0], positionTrackingFrame[1]); +} diff --git a/Detectors/Upgrades/ITS3/alignment/src/ITS3AlignLinkDef.h b/Detectors/Upgrades/ITS3/alignment/src/ITS3AlignLinkDef.h index ef526284f3a58..527eeebeb82d5 100644 --- a/Detectors/Upgrades/ITS3/alignment/src/ITS3AlignLinkDef.h +++ b/Detectors/Upgrades/ITS3/alignment/src/ITS3AlignLinkDef.h @@ -17,4 +17,12 @@ #pragma link C++ class o2::its3::align::MisalignmentParameters + ; +#pragma link C++ struct o2::its3::align::AlignmentParams + ; +#pragma link C++ class o2::conf::ConfigurableParamHelper < o2::its3::align::AlignmentParams> + ; + +#pragma link C++ struct o2::its3::align::Measurement + ; +#pragma link C++ struct o2::its3::align::FrameInfoExt + ; +#pragma link C++ struct o2::its3::align::FitInfo + ; +#pragma link C++ struct o2::its3::align::Track + ; + #endif diff --git a/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx b/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx new file mode 100644 index 0000000000000..29c0f380f319b --- /dev/null +++ b/Detectors/Upgrades/ITS3/alignment/src/alignment-workflow.cxx @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CallbacksPolicy.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "ITS3Align/AlignmentSpec.h" + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} +void customize(std::vector& workflowOptions) +{ + std::vector options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"enable MC propagation"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, + {"cluster-sources", VariantType::String, "ITS", {"comma-separated list of cluster sources to use"}}, + {"with-its", VariantType::Bool, false, {"ITS alignment mode"}}, + {"without-pv", VariantType::Bool, false, {"Do not use in track refit the PV as an additional constraint"}}, + {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfg) +{ + o2::conf::ConfigurableParam::updateFromString(cfg.options().get("configKeyValues")); + + const GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + const GID::mask_t allowedSourcesClus = GID::getSourcesMask("ITS"); + const GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(cfg.options().get("track-sources")); + const GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(cfg.options().get("cluster-sources")); + const auto useMC = !cfg.options().get("disable-mc"); + const auto withPV = !cfg.options().get("without-pv"); + const auto withITS = cfg.options().get("with-its"); + + WorkflowSpec specs; + o2::globaltracking::InputHelper::addInputSpecs(cfg, specs, srcCls, srcTrc, srcTrc, useMC); + if (withPV && !useMC) { + o2::globaltracking::InputHelper::addInputSpecsPVertex(cfg, specs, useMC); + } + + specs.emplace_back(o2::its3::align::getAlignmentSpec(srcTrc, srcCls, useMC, withPV, withITS)); + + o2::raw::HBFUtilsInitializer hbfIni(cfg, specs); + return std::move(specs); +} diff --git a/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx b/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx index e898631837169..ff306d83cee44 100644 --- a/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx +++ b/Detectors/Upgrades/ITS3/reconstruction/src/IOUtils.cxx @@ -17,13 +17,6 @@ #include "ITS3Reconstruction/TopologyDictionary.h" #include "ITSBase/GeometryTGeo.h" #include "ITStracking/TrackingConfigParam.h" -#include "Framework/Logger.h" - -#include - -#include - -#include namespace o2::its3::ioutils { @@ -52,7 +45,7 @@ void convertCompactClusters(gsl::span clusters, const auto detID = c.getSensorID(); auto& cl3d = output.emplace_back(detID, geom->getMatrixT2L(detID) ^ locXYZ); // local --> tracking if (applyMisalignment) { - auto lrID = geom->getLayer(detID); + const auto lrID = geom->getLayer(detID); sigmaY2 += conf.sysErrY2[lrID]; sigmaZ2 += conf.sysErrZ2[lrID]; } @@ -96,13 +89,17 @@ int loadROFrameDataITS3(its::TimeFrame<7>* tf, // Tracking alpha angle // We want that each cluster rotates its tracking frame to the clusters phi // that way the track linearization around the measurement is less biases to the arc - // this means automatically that the measurement on the arc is at 0 - // const float alpha = geom->getSensorRefAlpha(sensorID); - const float radius = std::hypot(gloXYZ.x(), gloXYZ.y()); - const float alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); - - tf->addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), radius, alpha, - std::array{0, trkXYZ.z()}, + // this means automatically that the measurement on the arc is at 0 for the curved layers + float alpha = geom->getSensorRefAlpha(sensorID); + float x = trkXYZ.x(), y = trkXYZ.y(); + if (layer < 3) { + y = 0.f; + x = std::hypot(gloXYZ.x(), gloXYZ.y()); + alpha = std::atan2(gloXYZ.y(), gloXYZ.x()); + } + + tf->addTrackingFrameInfoToLayer(layer, gloXYZ.x(), gloXYZ.y(), gloXYZ.z(), x, alpha, + std::array{y, trkXYZ.z()}, std::array{sigmaY2, sigmaYZ, sigmaZ2}); /// Rotate to the global frame diff --git a/dependencies/O2Dependencies.cmake b/dependencies/O2Dependencies.cmake index 26f381a4ef79f..c38044f6db935 100644 --- a/dependencies/O2Dependencies.cmake +++ b/dependencies/O2Dependencies.cmake @@ -113,6 +113,24 @@ set_package_properties(fmt PROPERTIES TYPE REQUIRED) find_package(nlohmann_json) set_package_properties(nlohmann_json PROPERTIES TYPE REQUIRED) +# Our Eigen3 install only provides the header files +# 'mock' the cmake target +add_library(Eigen3::Eigen INTERFACE IMPORTED) +set_target_properties(Eigen3::Eigen PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${EIGEN3_ROOT}/include/eigen3" +) + +find_package(GBL) +set_package_properties(GBL PROPERTIES TYPE REQUIRED) +if(GBL_FOUND AND NOT TARGET GBL::GBL) + add_library(GBL::GBL INTERFACE IMPORTED) + target_include_directories(GBL::GBL INTERFACE ${GBL_INCLUDE_DIR}) + target_link_libraries(GBL::GBL INTERFACE + ${GBL_LIBRARIES} + Eigen3::Eigen + ) +endif() + find_package(Boost 1.70 COMPONENTS container thread From 6f2520d66108412d1701b5b4ef81161b511b6f47 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Thu, 19 Feb 2026 15:27:26 +0100 Subject: [PATCH 5/6] Study: add v0 mc Signed-off-by: Felix Schlepper --- .../study/CMakeLists.txt | 6 + .../include/GlobalTrackingStudy/SVMCStudy.h | 26 + .../study/include/GlobalTrackingStudy/V0Ext.h | 26 +- .../study/src/GlobalTrackingStudyLinkDef.h | 2 + .../study/src/SVMCStudy.cxx | 564 ++++++++++++++++++ .../study/src/sv-mc-study-workflow.cxx | 69 +++ 6 files changed, 692 insertions(+), 1 deletion(-) create mode 100644 Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVMCStudy.h create mode 100644 Detectors/GlobalTrackingWorkflow/study/src/SVMCStudy.cxx create mode 100644 Detectors/GlobalTrackingWorkflow/study/src/sv-mc-study-workflow.cxx diff --git a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt index df42af503db46..b2be54a4dc167 100644 --- a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt @@ -16,6 +16,7 @@ o2_add_library(GlobalTrackingStudy SOURCES src/TPCTrackStudy.cxx src/TrackingStudy.cxx src/SVStudy.cxx + src/SVMCStudy.cxx src/TrackMCStudy.cxx src/TPCDataFilter.cxx src/ITSOffsStudy.cxx @@ -50,6 +51,11 @@ o2_add_executable(study-workflow SOURCES src/sv-study-workflow.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTrackingStudy) +o2_add_executable(study-workflow + COMPONENT_NAME sv-mc + SOURCES src/sv-mc-study-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingStudy) + o2_add_executable(study-workflow COMPONENT_NAME tpc-track SOURCES src/tpc-track-study-workflow.cxx diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVMCStudy.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVMCStudy.h new file mode 100644 index 0000000000000..b7efd27d75012 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVMCStudy.h @@ -0,0 +1,26 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SV_GAMMA_STUDY_H +#define O2_SV_GAMMA_STUDY_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/DataProcessorSpec.h" +#include "TPCCalibration/CorrectionMapsLoader.h" + +namespace o2::svstudy +{ + +o2::framework::DataProcessorSpec getSVMCStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcCls, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); + +} // namespace o2::svstudy + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h index b1a9f6923f04d..48f5d39bc2f25 100644 --- a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h @@ -15,7 +15,7 @@ #define ALICEO2_V0EXT_H #include "ReconstructionDataFormats/V0.h" -#include "SimulationDataFormat/MCCompLabel.h" +#include "SimulationDataFormat/MCTrack.h" namespace o2::dataformats { @@ -44,6 +44,30 @@ struct V0Ext { ClassDefNV(V0Ext, 2); }; +enum PoolInfo : uint8_t { + Unset = (1 << 0), + Considered = (1 << 1), // considered (should be all not unassigned?) + Accepted = (1 << 2), // accepted into pool + Unassigned = (1 << 3), // tracks that were not assigned to a collision +}; +struct ProngMCInfoExt { + detectors::DetID::mask_t recoMask; // detector mask + o2::track::TrackPar trk; // most global reco'd track + MCTrack mcTrk; + uint8_t poolStatus = PoolInfo::Unset; + ClassDefNV(ProngMCInfoExt, 1); +}; + +struct V0MCExt { + V0 v0; // reconstructed v0 + MCTrack mcTrk; + std::array prInfo{}; + const ProngMCInfoExt& getPrInfo(int i) const { return prInfo[i]; } + bool hasBothProngs() const noexcept { return prInfo[0].recoMask.any() && prInfo[1].recoMask.any(); } + + ClassDefNV(V0MCExt, 1); +}; + } // namespace o2::dataformats #endif diff --git a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h index 416820fc9aebb..d63e20a41643a 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h +++ b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h @@ -16,7 +16,9 @@ #pragma link off all functions; #pragma link C++ class o2::dataformats::ProngInfoExt + ; +#pragma link C++ class o2::dataformats::ProngMCInfoExt + ; #pragma link C++ class o2::dataformats::V0Ext + ; +#pragma link C++ class o2::dataformats::V0MCExt + ; #pragma link C++ class o2::dataformats::TrackInfoExt + ; #pragma link C++ class std::vector < o2::dataformats::TrackInfoExt> + ; #pragma link C++ class std::vector < o2::dataformats::ProngInfoExt> + ; diff --git a/Detectors/GlobalTrackingWorkflow/study/src/SVMCStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/SVMCStudy.cxx new file mode 100644 index 0000000000000..4a994aed7a53a --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/SVMCStudy.cxx @@ -0,0 +1,564 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include + +#include + +#include "GlobalTrackingStudy/SVMCStudy.h" +#include "CommonConstants/GeomConstants.h" +#include "GlobalTrackingStudy/V0Ext.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/Task.h" +#include "DetectorsVertexing/SVertexerParams.h" +#include "DetectorsVertexing/SVertexer.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "Steer/MCKinematicsReader.h" +#include "SimulationDataFormat/MCUtils.h" +#include "TPCCalibration/VDriftHelper.h" +#include "TPCCalibration/CorrectionMapsLoader.h" +#include "DataFormatsITSMFT/TrkClusRef.h" + +namespace o2::svstudy +{ + +using DetID = o2::detectors::DetID; +using DataRequest = o2::globaltracking::DataRequest; + +using PVertex = o2::dataformats::PrimaryVertex; +using V2TRef = o2::dataformats::VtxTrackRef; +using VTIndex = o2::dataformats::VtxTrackIndex; +using GTrackID = o2::dataformats::VtxTrackIndex; +using TBracket = o2::math_utils::Bracketf_t; +using V0ID = o2::dataformats::V0Index; +using TrackCand = o2::vertexing::SVertexer::TrackCand; + +class SVMCStudySpec final : public o2::framework::Task +{ + public: + SVMCStudySpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, GTrackID::mask_t src) : mDataRequest(dr), mGGCCDBRequest(gr), mSrc(src) + { + mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); + mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); + mTPCCorrMapsLoader.setCheckCTPIDCConsistency(sclOpts.checkCTPIDCconsistency); + } + void init(o2::framework::InitContext& ic) final; + void run(o2::framework::ProcessingContext& pc) final; + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + void finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) final; + + private: + void updateTimeDependentParams(o2::framework::ProcessingContext& pc); + void buildV0MC(); + void buildT2V0(); + void buildT2V(); + bool acceptTrack(const GTrackID gid, const o2::track::TrackParCov& trc) const; + bool processTPCTrack(const o2::tpc::TrackTPC& trTPC, GTrackID gid, int vtxid, dataformats::ProngMCInfoExt& prInfo); + float correctTPCTrack(TrackCand& trc, const o2::tpc::TrackTPC& tTPC, float tmus, float tmusErr) const; + + std::array, 2> mTracksPool{}; // pools of positive and negative seeds sorted in min VtxID + std::array, 2> mVtxFirstTrack{}; // 1st pos. and neg. track of the pools for each vertex + const vertexing::SVertexerParams* mSVParams{nullptr}; + + std::shared_ptr mDataRequest; + std::shared_ptr mGGCCDBRequest; + float mMUS2TPCBin{1.f / (8 * o2::constants::lhc::LHCBunchSpacingMUS)}; + float mTPCBin2Z{0}; + float mTPCVDrift{0}; + float mTPCVDriftCorrFact{1.}; ///< TPC nominal correction factort (wrt ref) + float mTPCVDriftRef{0}; + std::span mTPCTracksArray; ///< input TPC tracks span + const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct{nullptr}; ///< struct holding the TPC cluster indices + std::span mTPCTrackClusIdx; ///< input TPC track cluster indices span + std::span mPVertices; + o2::tpc::VDriftHelper mTPCVDriftHelper; + o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader; + o2::globaltracking::RecoContainer mRecoData; + float mBz{-999}; + const o2::dataformats::MeanVertexObject* mMeanVertex{nullptr}; + std::unordered_map mV0MC; + std::unordered_map mDau2V0; + GTrackID::mask_t mSrc; + TStopwatch mTimer; + + const std::map mPDGNames{{22, "gamma"}, {310, "k0s"}}; + const std::set mPDGV0Acc{22, 310}; +}; + +void SVMCStudySpec::init(o2::framework::InitContext& ic) +{ + mTimer.Stop(); + mTimer.Reset(); + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + if (mSrc[GTrackID::TPC]) { + mTPCCorrMapsLoader.init(ic); + } +} + +void SVMCStudySpec::run(o2::framework::ProcessingContext& pc) +{ + mTimer.Start(false); + mRecoData.collectData(pc, *mDataRequest); + updateTimeDependentParams(pc); + mPVertices = mRecoData.getPrimaryVertices(); + buildV0MC(); + buildT2V0(); + buildT2V(); + + // THIS IS ONLY TO CHECK WHERE SIGNAL IS DISCARDED! + // Build MC particle pool where a MCV0 has a bit_mask indicating if reconstrcuted, in acceptance, reconstructable, .... + // the mc paticle should have its daugther track + // bitmask with origin if reconstructed + // handle ITS tracks with clustersharing + // the rest of the tracks we're allowed to discard + // Build T2V assoc + // ... + utils::TreeStreamRedirector tree("sv_debug.root"); + for (const auto& [_, v0] : mV0MC) { + tree << mPDGNames.at(v0.mcTrk.GetPdgCode()) + << "v0=" << v0 + << "\n"; + } + tree.Close(); + + mTimer.Stop(); +} + +void SVMCStudySpec::endOfStream(o2::framework::EndOfStreamContext& /*ec*/) +{ + LOGP(info, "SVMCStudy total timing: Cpu: {:.3f} Real: {:.3f} s", mTimer.CpuTime(), mTimer.RealTime()); +}; + +void SVMCStudySpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { + return; + } + if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { + return; + } + if (matcher == o2::framework::ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { + LOG(info) << "Imposing new MeanVertex: " << ((const o2::dataformats::MeanVertexObject*)obj)->asString(); + mMeanVertex = (const o2::dataformats::MeanVertexObject*)obj; + return; + } + if (matcher == o2::framework::ConcreteDataMatcher("GLO", "SVPARAM", 0)) { + LOG(info) << "SVertexer Params updated from ccdb"; + return; + } +}; + +void SVMCStudySpec::updateTimeDependentParams(o2::framework::ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + if (mSrc[GTrackID::TPC]) { + mTPCVDriftHelper.extractCCDBInputs(pc); + mTPCCorrMapsLoader.extractCCDBInputs(pc); + } + if (static bool initOnceDone{false}; !initOnceDone) { // these params need to be queried only once + pc.inputs().get("SVParam"); + o2::vertexing::SVertexerParams::Instance().printKeyValues(true, true); + mSVParams = &vertexing::SVertexerParams::Instance(); + } + if (mSrc[GTrackID::TPC]) { + bool updateMaps = false; + if (mTPCCorrMapsLoader.isUpdated()) { + mTPCCorrMapsLoader.acknowledgeUpdate(); + updateMaps = true; + } + if (mTPCVDriftHelper.isUpdated()) { + LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", + mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, + mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, + mTPCVDriftHelper.getSourceName()); + + const auto& v = mTPCVDriftHelper.getVDriftObject(); + mTPCVDrift = v.refVDrift * v.corrFact; + mTPCVDriftCorrFact = v.corrFact; + mTPCVDriftRef = v.refVDrift; + mTPCBin2Z = mTPCVDrift / mMUS2TPCBin; + + mTPCVDriftHelper.acknowledgeUpdate(); + updateMaps = true; + } + if (updateMaps) { + mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); + } + } + pc.inputs().get("meanvtx"); + mBz = o2::base::Propagator::Instance()->getNominalBz(); +} + +void SVMCStudySpec::buildV0MC() +{ + LOGP(info, "Building mc particle association"); + std::map mCounts; + steer::MCKinematicsReader reader("collisioncontext.root"); + for (int iSrc{0}; iSrc < reader.getNSources(); ++iSrc) { + for (int iEve{0}; iEve < reader.getNEvents(iSrc); ++iEve) { + const auto& mcTrks = reader.getTracks(iSrc, iEve); + const int nTrks = (int)mcTrks.size(); + for (int iTrk{0}; iTrk < nTrks; ++iTrk) { + const auto trk = reader.getTrack(iSrc, iEve, iTrk); + if (mPDGV0Acc.contains(trk->GetPdgCode())) { + if ((trk->getLastDaughterTrackId() - trk->getFirstDaughterTrackId()) != 1) { + continue; + } + MCTrack const *dau0{nullptr}, *dau1{nullptr}; + if (!(dau0 = mcutils::MCTrackNavigator::getDaughter0(*trk, mcTrks)) || + !(dau1 = mcutils::MCTrackNavigator::getDaughter1(*trk, mcTrks))) { + continue; + } + dataformats::V0MCExt v0; + v0.mcTrk = *trk; + v0.prInfo[0].mcTrk = *dau0; + v0.prInfo[1].mcTrk = *dau1; + o2::MCCompLabel lblM{iTrk, iEve, iSrc}, lblDau0{trk->getFirstDaughterTrackId(), iEve, iSrc}, lblDau1{trk->getLastDaughterTrackId(), iEve, iSrc}; + mV0MC[lblM] = v0; + mDau2V0[lblDau0] = lblM; + mDau2V0[lblDau1] = lblM; + ++mCounts[trk->GetPdgCode()]; + } + } + } + } + LOGP(info, "Found {} MC V0 total candidates", mV0MC.size()); + for (const auto [pdg, c] : mCounts) { + LOGP(info, "\t{} has {}", mPDGNames.at(pdg), c); + } +} + +void SVMCStudySpec::buildT2V0() +{ + LOGP(info, "Building track to v0 association"); + // find the most global true representation of the reconstructed prong + std::map mCounts; + int totalTracks{0}; + auto creator = [&](auto& trk, GTrackID gid, float /*time0*/, float /*terr*/) { + if constexpr (isBarrelTrack()) { + const auto lbl = mRecoData.getTrackMCLabel(gid); + if (mDau2V0.find(lbl) != mDau2V0.end()) { + auto& v0 = mV0MC[mDau2V0[lbl]]; + int posneg = trk.getSign() < 0 ? 1 : 0; + v0.prInfo[posneg].recoMask = gid.getSourceDetectorsMask(); + v0.prInfo[posneg].trk = trk; + ++mCounts[v0.mcTrk.GetPdgCode()]; + ++totalTracks; + return true; + } + } + return false; + }; + mRecoData.createTracksVariadic(creator); + LOGP(info, "Selected {} reconstructed tracks", totalTracks); + for (const auto [pdg, c] : mCounts) { + LOGP(info, "\t{} has {}", mPDGNames.at(pdg), c); + } +} + +void SVMCStudySpec::buildT2V() +{ + LOGP(info, "Building T2V"); + auto trackIndex = mRecoData.getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks + auto vtxRefs = mRecoData.getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs + bool isTPCloaded = mRecoData.isTrackSourceLoaded(GTrackID::TPC); + bool isITSloaded = mRecoData.isTrackSourceLoaded(GTrackID::ITS); + bool isITSTPCloaded = mRecoData.isTrackSourceLoaded(GTrackID::ITSTPC); + if (isTPCloaded && !mSVParams->mExcludeTPCtracks) { + mTPCTracksArray = mRecoData.getTPCTracks(); + mTPCTrackClusIdx = mRecoData.getTPCTracksClusterRefs(); + mTPCClusterIdxStruct = &mRecoData.inputsTPCclusters->clusterIndex; + } + std::unordered_map> tmap; + std::unordered_map rejmap; + size_t nv = vtxRefs.size() - 1; // The last entry is for unassigned tracks, ignore them + for (int i = 0; i < 2; i++) { + mTracksPool[i].clear(); + mVtxFirstTrack[i].clear(); + mVtxFirstTrack[i].resize(nv, -1); + } + for (int iv = 0; iv < nv; iv++) { + const auto& vtref = vtxRefs[iv]; + int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries(); + for (; it < itLim; it++) { + auto tvid = trackIndex[it]; + if (!mRecoData.isTrackSourceLoaded(tvid.getSource())) { + continue; + } + + // NOTE: since there is per-se no 'stealing' of prong tracks skip all that are not interesting + const auto& trc = mRecoData.getTrackParam(tvid); + int posneg = trc.getSign() < 0 ? 1 : 0; + o2::MCCompLabel lbl = mRecoData.getTrackMCLabel(tvid); + if (mDau2V0.find(lbl) == mDau2V0.end()) { + continue; + } + auto& prInfo = mV0MC[mDau2V0[lbl]].prInfo[posneg]; + prInfo.poolStatus |= dataformats::PoolInfo::Considered; + + if (tvid.getSource() == GTrackID::TPC) { + if (mSVParams->mExcludeTPCtracks) { + continue; + } + if (processTPCTrack(mTPCTracksArray[tvid], tvid, iv, prInfo)) { + continue; + } + } + + if (tvid.isAmbiguous()) { // was this track already processed? + auto tref = tmap.find(tvid); + if (tref != tmap.end()) { + mTracksPool[tref->second.second][tref->second.first].vBracket.setMax(iv); // this track was already processed with other vertex, account the latter + continue; + } + // was it already rejected? + if (rejmap.find(tvid) != rejmap.end()) { + continue; + } + } + + bool hasTPC = false; + bool compatibleWithProton = false; + auto tpcGID = mRecoData.getTPCContributorGID(tvid); + if (tpcGID.isIndexSet() && isTPCloaded) { + hasTPC = true; + } + + // get Nclusters in the ITS if available + int nITSclu = -1; + bool shortOBITSOnlyTrack = false; + auto itsGID = mRecoData.getITSContributorGID(tvid); + if (itsGID.getSource() == GTrackID::ITS) { + if (isITSloaded) { + auto& itsTrack = mRecoData.getITSTrack(itsGID); + nITSclu = itsTrack.getNumberOfClusters(); + if (itsTrack.hasHitOnLayer(6) && itsTrack.hasHitOnLayer(5) && itsTrack.hasHitOnLayer(4) && itsTrack.hasHitOnLayer(3)) { + shortOBITSOnlyTrack = true; + } + } + } else if (itsGID.getSource() == GTrackID::ITSAB) { + if (isITSTPCloaded) { + auto& itsABTracklet = mRecoData.getITSABRef(itsGID); + nITSclu = itsABTracklet.getNClusters(); + } + } + if (!acceptTrack(tvid, trc)) { + if (tvid.isAmbiguous()) { + rejmap[tvid] = true; + } + continue; + } + if ((isTPCloaded && !hasTPC) && (isITSloaded && (nITSclu < mSVParams->mITSSAminNclu && (!shortOBITSOnlyTrack || mSVParams->mRejectITSonlyOBtrack)))) { + continue; // reject short ITS-only + } + + float r = std::hypot(trc.getX(), trc.getY()); + mTracksPool[posneg].emplace_back(TrackCand{trc, tvid, {iv, iv}, r, hasTPC, (int8_t)nITSclu, compatibleWithProton}); + prInfo.poolStatus |= dataformats::PoolInfo::Accepted; + if (tvid.getSource() == GTrackID::TPC) { // constrained TPC track? + correctTPCTrack(mTracksPool[posneg].back(), mTPCTracksArray[tvid], -1, -1); + } + if (tvid.isAmbiguous()) { // track attached to >1 vertex, remember that it was already processed + tmap[tvid] = {mTracksPool[posneg].size() - 1, posneg}; + } + } + } + + // register 1st track of each charge for each vertex + for (int pn = 0; pn < 2; pn++) { + auto& vtxFirstT = mVtxFirstTrack[pn]; + const auto& tracksPool = mTracksPool[pn]; + for (unsigned i = 0; i < tracksPool.size(); i++) { + const auto& t = tracksPool[i]; + for (int j{t.vBracket.getMin()}; j <= t.vBracket.getMax(); ++j) { + if (vtxFirstT[j] == -1) { + vtxFirstT[j] = i; + } + } + } + } + + { + // check the unassigned tracks + std::map mCounts; + const auto& vtref = vtxRefs[nv]; + int it = vtref.getFirstEntry(), itLim = it + vtref.getEntries(); + for (; it < itLim; it++) { + auto tvid = trackIndex[it]; + if (!mRecoData.isTrackSourceLoaded(tvid.getSource())) { + continue; + } + const auto& trc = mRecoData.getTrackParam(tvid); + int posneg = trc.getSign() < 0 ? 1 : 0; + o2::MCCompLabel lbl = mRecoData.getTrackMCLabel(tvid); + if (mDau2V0.find(lbl) == mDau2V0.end()) { + continue; + } + auto& prInfo = mV0MC[mDau2V0[lbl]].prInfo[posneg]; + prInfo.poolStatus |= dataformats::PoolInfo::Unassigned; + ++mCounts[mV0MC[mDau2V0[lbl]].mcTrk.GetPdgCode()]; + } + LOGP(info, "Unassigned to any collision:"); + for (const auto [pdg, c] : mCounts) { + LOGP(info, "\t{} has {}", mPDGNames.at(pdg), c); + } + } + + LOG(info) << "Collected " << mTracksPool[vertexing::SVertexer::POS].size() << " positive and " << mTracksPool[vertexing::SVertexer::NEG].size() << " negative seeds"; +} + +bool SVMCStudySpec::acceptTrack(const GTrackID gid, const o2::track::TrackParCov& trc) const +{ + if (gid.isPVContributor() && mSVParams->maxPVContributors < 1) { + return false; + } + + // DCA to mean vertex + if (mSVParams->minDCAToPV > 0.f) { + o2::track::TrackPar trp(trc); + std::array dca{}; + auto* prop = o2::base::Propagator::Instance(); + if (mSVParams->usePropagator) { + if (trp.getX() > mSVParams->minRFor3DField && !prop->PropagateToXBxByBz(trp, mSVParams->minRFor3DField, mSVParams->maxSnp, mSVParams->maxStep, o2::base::Propagator::MatCorrType(mSVParams->matCorr))) { + return true; // we don't need actually to propagate to the beam-line + } + if (!prop->propagateToDCA(mMeanVertex->getXYZ(), trp, prop->getNominalBz(), mSVParams->maxStep, o2::base::Propagator::MatCorrType(mSVParams->matCorr), &dca)) { + return true; + } + } else { + if (!trp.propagateParamToDCA(mMeanVertex->getXYZ(), prop->getNominalBz(), &dca)) { + return true; + } + } + if (std::abs(dca[0]) < mSVParams->minDCAToPV) { + return false; + } + } + return true; +} + +bool SVMCStudySpec::processTPCTrack(const o2::tpc::TrackTPC& trTPC, GTrackID gid, int vtxid, dataformats::ProngMCInfoExt& prInfo) +{ + int posneg = trTPC.getSign() < 0 ? 1 : 0; + + if (mSVParams->mTPCTrackMaxX > 0. && trTPC.getX() > mSVParams->mTPCTrackMaxX) { + return true; + } + // if TPC trackis unconstrained, try to create in the tracks pool a clone constrained to vtxid vertex time. + if (trTPC.hasBothSidesClusters()) { // this is effectively constrained track + return false; // let it be processed as such + } + const auto& vtx = mPVertices[vtxid]; + auto twe = vtx.getTimeStamp(); + + bool compatibleWithProton = false; + auto& trLoc = mTracksPool[posneg].emplace_back(TrackCand{trTPC, gid, {vtxid, vtxid}, 0., true, -1, compatibleWithProton}); + auto err = correctTPCTrack(trLoc, trTPC, twe.getTimeStamp(), twe.getTimeStampError()); + if (err < 0) { + mTracksPool[posneg].pop_back(); // discard + return true; + } + + if (mSVParams->mTPCTrackPhotonTune) { + // require minimum of tpc clusters + bool dCls = trTPC.getNClusters() < mSVParams->mTPCTrackMinNClusters; + // check track z cuts + bool dDPV = std::abs((trLoc.getX() * trLoc.getTgl()) - trLoc.getZ() + vtx.getZ()) > mSVParams->mTPCTrack2Beam; + // check track transveres cuts + float sna{0}, csa{0}; + o2::math_utils::CircleXYf_t trkCircle; + trLoc.getCircleParams(mBz, trkCircle, sna, csa); + float cR = std::hypot(trkCircle.xC, trkCircle.yC); + float drd2 = std::sqrt((cR * cR) - (trkCircle.rC * trkCircle.rC)); + bool dRD2 = drd2 > mSVParams->mTPCTrackXY2Radius; + + if (dCls || dDPV || dRD2) { + mTracksPool[posneg].pop_back(); + return true; + } + } + + prInfo.poolStatus |= dataformats::PoolInfo::Accepted; + return true; +} + +float SVMCStudySpec::correctTPCTrack(TrackCand& trc, const o2::tpc::TrackTPC& tTPC, float tmus, float tmusErr) const +{ + // Correct the track copy trc of the TPC track for the assumed interaction time + // return extra uncertainty in Z due to the interaction time uncertainty + float tTB = NAN, tTBErr = NAN; + if (tmusErr < 0) { // use track data + tTB = tTPC.getTime0(); + tTBErr = 0.5f * (tTPC.getDeltaTBwd() + tTPC.getDeltaTFwd()); + } else { + tTB = tmus * mMUS2TPCBin; + tTBErr = tmusErr * mMUS2TPCBin; + } + float dDrift = (tTB - tTPC.getTime0()) * mTPCBin2Z; + float driftErr = tTBErr * mTPCBin2Z; + if (driftErr < 0.) { // early return will be discarded anyway + return driftErr; + } + trc.setZ(tTPC.getZ() + (tTPC.hasASideClustersOnly() ? dDrift : -dDrift)); + trc.setCov(trc.getSigmaZ2() + (driftErr * driftErr), o2::track::kSigZ2); + uint8_t sector = 0, row = 0; + auto cl = &tTPC.getCluster(mTPCTrackClusIdx, tTPC.getNClusters() - 1, *mTPCClusterIdxStruct, sector, row); + float x = 0, y = 0, z = 0; + mTPCCorrMapsLoader.Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, tTB); + x = std::max(x, o2::constants::geom::XTPCInnerRef); + trc.minR = std::hypot(x, y); + return driftErr; +} + +o2::framework::DataProcessorSpec getSVMCStudySpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcCls, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +{ + o2::framework::Options opts; + std::vector outputs; + auto dataRequest = std::make_shared(); + + dataRequest->requestTracks(srcTracks, true); + dataRequest->requestClusters(srcCls, true); + dataRequest->requestPrimaryVertices(true); + dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); + dataRequest->inputs.emplace_back("SVParam", "GLO", "SVPARAM", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("GLO/Config/SVertexerParam")); + auto ggRequest = std::make_shared(true, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + true, // GRPMagField + true, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, + true); + if (srcTracks[GTrackID::TPC]) { + o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); + o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + } + return o2::framework::DataProcessorSpec{ + .name = "sv-mc-study", + .inputs = dataRequest->inputs, + .outputs = outputs, + .algorithm = o2::framework::AlgorithmSpec{o2::framework::adaptFromTask(dataRequest, ggRequest, sclOpts, srcTracks)}, + .options = opts}; +} + +} // namespace o2::svstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/src/sv-mc-study-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/sv-mc-study-workflow.cxx new file mode 100644 index 0000000000000..9657ec3d71e36 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/sv-mc-study-workflow.cxx @@ -0,0 +1,69 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// Simplified version of the SVertexer code with dumpable mc output +// to study inefficiencies and cut tuning. + +#include "GlobalTrackingStudy/SVMCStudy.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CallbacksPolicy.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "TPCWorkflow/TPCScalerSpec.h" +#include "TPCCalibration/CorrectionMapsLoader.h" + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; + +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, + {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-mc", VariantType::Bool, false, {"disable mc ?"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + GID::mask_t allowedClsTrc = GID::getSourcesMask("ITS,TPC"); + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); + GID::mask_t srcCls = allowedClsTrc & srcTrc; + if (sclOpt.requestCTPLumi) { + srcTrc = srcTrc | GID::getSourcesMask("CTP"); + } + + WorkflowSpec specs; + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, true); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, true); // P-vertex is always needed + if (sclOpt.needTPCScalersWorkflow() && !configcontext.options().get("disable-root-input")) { + specs.emplace_back(o2::tpc::getTPCScalerSpec(sclOpt.lumiType == 2, sclOpt.enableMShapeCorrection)); + } + specs.emplace_back(o2::svstudy::getSVMCStudySpec(srcTrc, srcCls, sclOpt)); + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return std::move(specs); +} From 5e56621962235343da7a781bc002b18306b1c31f Mon Sep 17 00:00:00 2001 From: GitHub Action Bot Date: Thu, 19 Feb 2026 14:28:17 +0000 Subject: [PATCH 6/6] Updated README --- CHANGELOG.md | 153 +- doc/data/2026-02-o2_prs.json | 4218 +++++++++++++++++++++++++++++ doc/data/2026-02-o2_releases.json | 92 + 3 files changed, 4376 insertions(+), 87 deletions(-) create mode 100644 doc/data/2026-02-o2_prs.json create mode 100644 doc/data/2026-02-o2_releases.json diff --git a/CHANGELOG.md b/CHANGELOG.md index afeaeb595c31a..b3dd95d0cf53a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,103 +1,82 @@ -# Changes since 2022-04-14 +# Changes since 2026-02-05 +## Changes in Algorithm + +- [#15025](https://github.com/AliceO2Group/AliceO2/pull/15025) 2026-02-09: Algorithm: Delete unused files by [@vkucera](https://github.com/vkucera) ## Changes in Analysis -- [#8588](https://github.com/AliceO2Group/AliceO2/pull/8588) 2022-04-21: DPL Analysis: workaround for setting self-index binding before invoking process() by [@aalkin](https://github.com/aalkin) -- [#8609](https://github.com/AliceO2Group/AliceO2/pull/8609) 2022-04-22: Move to fdd version 001 by [@mbroz84](https://github.com/mbroz84) -- [#8637](https://github.com/AliceO2Group/AliceO2/pull/8637) 2022-04-24: remove temporary code by [@jgrosseo](https://github.com/jgrosseo) -- [#8574](https://github.com/AliceO2Group/AliceO2/pull/8574) 2022-04-28: Add energy as a dynamic column by [@njacazio](https://github.com/njacazio) +- [#15014](https://github.com/AliceO2Group/AliceO2/pull/15014) 2026-02-07: Store TPC track A/C side info in the AO2D TrackExtra.fFlags unused bits by [@shahor02](https://github.com/shahor02) +- [#15008](https://github.com/AliceO2Group/AliceO2/pull/15008) 2026-02-17: DPL Analysis: cleanup AnalysisTask.h and ASoA.h by [@aalkin](https://github.com/aalkin) ## Changes in Common -- [#8575](https://github.com/AliceO2Group/AliceO2/pull/8575) 2022-04-14: Missing const declarations on bitset comparisons. by [@pnwkw](https://github.com/pnwkw) -- [#8590](https://github.com/AliceO2Group/AliceO2/pull/8590) 2022-04-17: Move alignment objects to DET/Calib/Align by [@shahor02](https://github.com/shahor02) -- [#8623](https://github.com/AliceO2Group/AliceO2/pull/8623) 2022-04-21: DPL: add dpl_instance tag to distinguish between different NUMA domains by [@ktf](https://github.com/ktf) -- [#8618](https://github.com/AliceO2Group/AliceO2/pull/8618) 2022-04-21: Store original tfCounter in the CTFHeader by [@shahor02](https://github.com/shahor02) -- [#8573](https://github.com/AliceO2Group/AliceO2/pull/8573) 2022-04-25: :MCH: introduce digit time errors in raw decoder by [@aferrero2707](https://github.com/aferrero2707) -- [#8643](https://github.com/AliceO2Group/AliceO2/pull/8643) 2022-04-25: Optionally impose DH.tfCounter from local counter by [@shahor02](https://github.com/shahor02) -- [#8639](https://github.com/AliceO2Group/AliceO2/pull/8639) 2022-04-26: Use tfCounter in time-slot calib, provide real time. by [@shahor02](https://github.com/shahor02) -- [#8667](https://github.com/AliceO2Group/AliceO2/pull/8667) 2022-04-27: Add/use createDirectoriesIfAbsent method, robust against concurrent calls by [@shahor02](https://github.com/shahor02) -- [#8659](https://github.com/AliceO2Group/AliceO2/pull/8659) 2022-04-27: Printing log when we find a default CCDB entry by [@chiarazampolli](https://github.com/chiarazampolli) +- [#15048](https://github.com/AliceO2Group/AliceO2/pull/15048) 2026-02-13: DPL: Enforce that dpl pipeline length is at least as long as number of TFs in flight by [@davidrohr](https://github.com/davidrohr) +- [#15077](https://github.com/AliceO2Group/AliceO2/pull/15077) 2026-02-18: o2-sim: Possibility to switch between TGeo and Geant4 navigation by [@sawenzel](https://github.com/sawenzel) ## Changes in DataFormats -- [#8578](https://github.com/AliceO2Group/AliceO2/pull/8578) 2022-04-14: Add theta calculation to Fwd track by [@pnwkw](https://github.com/pnwkw) -- [#8596](https://github.com/AliceO2Group/AliceO2/pull/8596) 2022-04-17: Work on TPC ZS Encoding by [@davidrohr](https://github.com/davidrohr) -- [#8605](https://github.com/AliceO2Group/AliceO2/pull/8605) 2022-04-18: Implement improved link-based ZS by [@davidrohr](https://github.com/davidrohr) -- [#8612](https://github.com/AliceO2Group/AliceO2/pull/8612) 2022-04-19: Fixes for MID decoding and data access by [@shahor02](https://github.com/shahor02) -- [#8618](https://github.com/AliceO2Group/AliceO2/pull/8618) 2022-04-21: Store original tfCounter in the CTFHeader by [@shahor02](https://github.com/shahor02) -- [#8622](https://github.com/AliceO2Group/AliceO2/pull/8622) 2022-04-21: [FIT] Quick fix - increment FT0 and FDD Digit version by [@mslupeck](https://github.com/mslupeck) -- [#8595](https://github.com/AliceO2Group/AliceO2/pull/8595) 2022-04-21: ctp config to ccdb by [@lietava](https://github.com/lietava) -- [#8643](https://github.com/AliceO2Group/AliceO2/pull/8643) 2022-04-25: Optionally impose DH.tfCounter from local counter by [@shahor02](https://github.com/shahor02) -- [#8642](https://github.com/AliceO2Group/AliceO2/pull/8642) 2022-04-25: Provide MCH clusters via global-track-cluster-reader and RecoContainer by [@shahor02](https://github.com/shahor02) -- [#8651](https://github.com/AliceO2Group/AliceO2/pull/8651) 2022-04-27: [QC-751] Remove obsolete QC flags by [@knopers8](https://github.com/knopers8) +- [#15029](https://github.com/AliceO2Group/AliceO2/pull/15029) 2026-02-09: DataFormats: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15030](https://github.com/AliceO2Group/AliceO2/pull/15030) 2026-02-10: SimulationDataFormat: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#14986](https://github.com/AliceO2Group/AliceO2/pull/14986) 2026-02-11: EventsPerBC calibration task for FT0 (O2-6563) by [@wpierozak](https://github.com/wpierozak) +- [#15057](https://github.com/AliceO2Group/AliceO2/pull/15057) 2026-02-11: TPC: time gain calibration optimizations by [@matthias-kleiner](https://github.com/matthias-kleiner) +- [#15027](https://github.com/AliceO2Group/AliceO2/pull/15027) 2026-02-12: MUON: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15082](https://github.com/AliceO2Group/AliceO2/pull/15082) 2026-02-19: Ctpdev: getting list of unmasked inputs by [@lietava](https://github.com/lietava) +- [#15026](https://github.com/AliceO2Group/AliceO2/pull/15026) 2026-02-19: EMCAL: Delete unused files by [@vkucera](https://github.com/vkucera) ## Changes in Detectors -- [#8584](https://github.com/AliceO2Group/AliceO2/pull/8584) 2022-04-14: ITS: remove unused variables to fix warnings by [@mconcas](https://github.com/mconcas) -- [#8579](https://github.com/AliceO2Group/AliceO2/pull/8579) 2022-04-14: Reporting and protection for interleaved chip data error by [@shahor02](https://github.com/shahor02) -- [#8577](https://github.com/AliceO2Group/AliceO2/pull/8577) 2022-04-14: TPC: reduce use of static keyword by [@sawenzel](https://github.com/sawenzel) -- [#8593](https://github.com/AliceO2Group/AliceO2/pull/8593) 2022-04-15: DPL: Catch exception from stol when parsing invalid run number by [@davidrohr](https://github.com/davidrohr) -- [#8594](https://github.com/AliceO2Group/AliceO2/pull/8594) 2022-04-15: Fix for not throwing exception in cpv::RawReaderMemory when processin… by [@sevdokim](https://github.com/sevdokim) -- [#8586](https://github.com/AliceO2Group/AliceO2/pull/8586) 2022-04-15: Multiple fixes in Alpide decoding/error handling by [@shahor02](https://github.com/shahor02) -- [#8599](https://github.com/AliceO2Group/AliceO2/pull/8599) 2022-04-16: Use flag HBFUtils.obligatorySOR to start raw data from TF with SOX + fixes by [@shahor02](https://github.com/shahor02) -- [#8601](https://github.com/AliceO2Group/AliceO2/pull/8601) 2022-04-17: Apply TF ordering policy to all writers by [@shahor02](https://github.com/shahor02) -- [#8596](https://github.com/AliceO2Group/AliceO2/pull/8596) 2022-04-17: Work on TPC ZS Encoding by [@davidrohr](https://github.com/davidrohr) -- [#8604](https://github.com/AliceO2Group/AliceO2/pull/8604) 2022-04-18: Fix misleading variable names by [@davidrohr](https://github.com/davidrohr) -- [#8605](https://github.com/AliceO2Group/AliceO2/pull/8605) 2022-04-18: Implement improved link-based ZS by [@davidrohr](https://github.com/davidrohr) -- [#8587](https://github.com/AliceO2Group/AliceO2/pull/8587) 2022-04-19: Add multiple output function in calibration workflow of MFT by [@syano0822](https://github.com/syano0822) -- [#8612](https://github.com/AliceO2Group/AliceO2/pull/8612) 2022-04-19: Fixes for MID decoding and data access by [@shahor02](https://github.com/shahor02) -- [#8614](https://github.com/AliceO2Group/AliceO2/pull/8614) 2022-04-19: Reduce default max memory to 12GB by [@mpuccio](https://github.com/mpuccio) -- [#8585](https://github.com/AliceO2Group/AliceO2/pull/8585) 2022-04-21: Fix metadata and remove log - TOFDCSconfig by [@chiarazampolli](https://github.com/chiarazampolli) -- [#8616](https://github.com/AliceO2Group/AliceO2/pull/8616) 2022-04-21: Protection against non-existing feeId in the MID RDH by [@dstocco](https://github.com/dstocco) -- [#8618](https://github.com/AliceO2Group/AliceO2/pull/8618) 2022-04-21: Store original tfCounter in the CTFHeader by [@shahor02](https://github.com/shahor02) -- [#8621](https://github.com/AliceO2Group/AliceO2/pull/8621) 2022-04-21: Update HmpidCoder2.cxx by [@fapfap69](https://github.com/fapfap69) -- [#8615](https://github.com/AliceO2Group/AliceO2/pull/8615) 2022-04-21: [EMCAL-630] Move log level of EMCAL decoding errors to "alarm" by [@mfasDa](https://github.com/mfasDa) -- [#8622](https://github.com/AliceO2Group/AliceO2/pull/8622) 2022-04-21: [FIT] Quick fix - increment FT0 and FDD Digit version by [@mslupeck](https://github.com/mslupeck) -- [#8595](https://github.com/AliceO2Group/AliceO2/pull/8595) 2022-04-21: ctp config to ccdb by [@lietava](https://github.com/lietava) -- [#8617](https://github.com/AliceO2Group/AliceO2/pull/8617) 2022-04-22: Add option to change tracker algorithm only keeping the best track by [@dstocco](https://github.com/dstocco) -- [#8627](https://github.com/AliceO2Group/AliceO2/pull/8627) 2022-04-22: CPV: mute raw decoder error reporting for 10 minutes if it reports mo… by [@sevdokim](https://github.com/sevdokim) -- [#8628](https://github.com/AliceO2Group/AliceO2/pull/8628) 2022-04-22: Improve verbosity in DCS DP processing (MFT, GRP) by [@chiarazampolli](https://github.com/chiarazampolli) -- [#8610](https://github.com/AliceO2Group/AliceO2/pull/8610) 2022-04-22: MFT: Update the noise scan to protect from double EOS. by [@tomas-herman](https://github.com/tomas-herman) -- [#8631](https://github.com/AliceO2Group/AliceO2/pull/8631) 2022-04-22: TRD: Reduce default verbosity of DCS processor by [@martenole](https://github.com/martenole) -- [#8633](https://github.com/AliceO2Group/AliceO2/pull/8633) 2022-04-23: Fix the Run Number into CCDB items by [@fapfap69](https://github.com/fapfap69) -- [#8635](https://github.com/AliceO2Group/AliceO2/pull/8635) 2022-04-23: [MCH] add protection against too many track candidates by [@pillot](https://github.com/pillot) -- [#8632](https://github.com/AliceO2Group/AliceO2/pull/8632) 2022-04-23: use default FDD table version by [@jgrosseo](https://github.com/jgrosseo) -- [#8573](https://github.com/AliceO2Group/AliceO2/pull/8573) 2022-04-25: :MCH: introduce digit time errors in raw decoder by [@aferrero2707](https://github.com/aferrero2707) -- [#8647](https://github.com/AliceO2Group/AliceO2/pull/8647) 2022-04-25: AODconverter does not need global MID and MCH clusters by [@shahor02](https://github.com/shahor02) -- [#8640](https://github.com/AliceO2Group/AliceO2/pull/8640) 2022-04-25: CCDBPopulator optionally fatals on failed upload (def=on) by [@shahor02](https://github.com/shahor02) -- [#8643](https://github.com/AliceO2Group/AliceO2/pull/8643) 2022-04-25: Optionally impose DH.tfCounter from local counter by [@shahor02](https://github.com/shahor02) -- [#8642](https://github.com/AliceO2Group/AliceO2/pull/8642) 2022-04-25: Provide MCH clusters via global-track-cluster-reader and RecoContainer by [@shahor02](https://github.com/shahor02) -- [#8645](https://github.com/AliceO2Group/AliceO2/pull/8645) 2022-04-25: Suppress FT0 channels ordering check in CTF encoder by [@shahor02](https://github.com/shahor02) -- [#8653](https://github.com/AliceO2Group/AliceO2/pull/8653) 2022-04-26: Optional syst.error on tracks Y,Z covariance + extra debug output by [@shahor02](https://github.com/shahor02) -- [#8639](https://github.com/AliceO2Group/AliceO2/pull/8639) 2022-04-26: Use tfCounter in time-slot calib, provide real time. by [@shahor02](https://github.com/shahor02) -- [#8667](https://github.com/AliceO2Group/AliceO2/pull/8667) 2022-04-27: Add/use createDirectoriesIfAbsent method, robust against concurrent calls by [@shahor02](https://github.com/shahor02) -- [#8662](https://github.com/AliceO2Group/AliceO2/pull/8662) 2022-04-27: CPV: improve raw errors handling in RawReaderMemory to avoid infinite loop… by [@sevdokim](https://github.com/sevdokim) -- [#8670](https://github.com/AliceO2Group/AliceO2/pull/8670) 2022-04-27: Fix: attach corect input in its/mft entropy decoder by [@shahor02](https://github.com/shahor02) -- [#8658](https://github.com/AliceO2Group/AliceO2/pull/8658) 2022-04-27: MCH: speedup finding of used cluster combinations by [@pillot](https://github.com/pillot) -- [#8664](https://github.com/AliceO2Group/AliceO2/pull/8664) 2022-04-27: MRRTF-154: MCH raw data decoder now catches exceptions by [@aphecetche](https://github.com/aphecetche) -- [#8650](https://github.com/AliceO2Group/AliceO2/pull/8650) 2022-04-27: [OCTRL-564] Filling RCT information when uploading GRP at end of run by [@chiarazampolli](https://github.com/chiarazampolli) -## Changes in EventVisualisation +- [#15023](https://github.com/AliceO2Group/AliceO2/pull/15023) 2026-02-06: ITS: GPU: partial revert of memory clearing by [@f3sch](https://github.com/f3sch) +- [#15021](https://github.com/AliceO2Group/AliceO2/pull/15021) 2026-02-06: Promote --ctf-dict from process to workflow level option by [@shahor02](https://github.com/shahor02) +- [#15010](https://github.com/AliceO2Group/AliceO2/pull/15010) 2026-02-07: Add ability to retain TrackQA for all global tracks by [@ddobrigk](https://github.com/ddobrigk) +- [#15014](https://github.com/AliceO2Group/AliceO2/pull/15014) 2026-02-07: Store TPC track A/C side info in the AO2D TrackExtra.fFlags unused bits by [@shahor02](https://github.com/shahor02) +- [#15043](https://github.com/AliceO2Group/AliceO2/pull/15043) 2026-02-10: [A3 TRK] Sensor orientation fix + first try to close in-stave gaps by [@scannito](https://github.com/scannito) +- [#15047](https://github.com/AliceO2Group/AliceO2/pull/15047) 2026-02-10: Fix codechecker violation by [@davidrohr](https://github.com/davidrohr) +- [#15032](https://github.com/AliceO2Group/AliceO2/pull/15032) 2026-02-10: GlobalTrackingWorkflow: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15036](https://github.com/AliceO2Group/AliceO2/pull/15036) 2026-02-10: TRD: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15062](https://github.com/AliceO2Group/AliceO2/pull/15062) 2026-02-11: DCS: Fix undefined behavior and invalid pointer access by [@davidrohr](https://github.com/davidrohr) +- [#14986](https://github.com/AliceO2Group/AliceO2/pull/14986) 2026-02-11: EventsPerBC calibration task for FT0 (O2-6563) by [@wpierozak](https://github.com/wpierozak) +- [#15034](https://github.com/AliceO2Group/AliceO2/pull/15034) 2026-02-11: MFT: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15057](https://github.com/AliceO2Group/AliceO2/pull/15057) 2026-02-11: TPC: time gain calibration optimizations by [@matthias-kleiner](https://github.com/matthias-kleiner) +- [#15037](https://github.com/AliceO2Group/AliceO2/pull/15037) 2026-02-11: Vertexing: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15051](https://github.com/AliceO2Group/AliceO2/pull/15051) 2026-02-12: ITS3: load chip response functions from ccdb by [@f3sch](https://github.com/f3sch) +- [#15052](https://github.com/AliceO2Group/AliceO2/pull/15052) 2026-02-12: ITS3: split longerons, improving stepping speed by [@f3sch](https://github.com/f3sch) +- [#15004](https://github.com/AliceO2Group/AliceO2/pull/15004) 2026-02-12: ITSMFT: scaffolding for staggered clusterization by [@f3sch](https://github.com/f3sch) +- [#15027](https://github.com/AliceO2Group/AliceO2/pull/15027) 2026-02-12: MUON: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15067](https://github.com/AliceO2Group/AliceO2/pull/15067) 2026-02-13: [A3 TRK] Fix kCylinder option + services crossing by [@scannito](https://github.com/scannito) +- [#15064](https://github.com/AliceO2Group/AliceO2/pull/15064) 2026-02-13: Support to plug-and-play external (CAD) geometry by [@sawenzel](https://github.com/sawenzel) +- [#15045](https://github.com/AliceO2Group/AliceO2/pull/15045) 2026-02-14: Add option to compress out non-dEdx info in TrackQA table by [@ddobrigk](https://github.com/ddobrigk) +- [#14985](https://github.com/AliceO2Group/AliceO2/pull/14985) 2026-02-16: Afit 124 by [@wpierozak](https://github.com/wpierozak) +- [#15066](https://github.com/AliceO2Group/AliceO2/pull/15066) 2026-02-16: First version of the hit based CA tracker for ALICE3 IT/OT by [@mpuccio](https://github.com/mpuccio) +- [#15075](https://github.com/AliceO2Group/AliceO2/pull/15075) 2026-02-17: [ALICE3] Adapt CA for 2T simulations by [@mpuccio](https://github.com/mpuccio) +- [#15072](https://github.com/AliceO2Group/AliceO2/pull/15072) 2026-02-17: [ALICE3] Fix geometry overlaps in tracker (ML/OT) by [@marcovanleeuwen](https://github.com/marcovanleeuwen) +- [#15073](https://github.com/AliceO2Group/AliceO2/pull/15073) 2026-02-17: A3: Add geometries for IOTOF by [@njacazio](https://github.com/njacazio) +- [#15055](https://github.com/AliceO2Group/AliceO2/pull/15055) 2026-02-17: ALICE 3 feat: Configurable VD design, set def to IRIS 4, remove IRIS disks by [@plariono](https://github.com/plariono) +- [#15070](https://github.com/AliceO2Group/AliceO2/pull/15070) 2026-02-17: ALICE3-TRK: adapt ordering key for digits to the large number of columns in the VD by [@atriolo](https://github.com/atriolo) +- [#15074](https://github.com/AliceO2Group/AliceO2/pull/15074) 2026-02-18: ALICE3-TRK: fix detector ID assignment to hits by [@atriolo](https://github.com/atriolo) +- [#15077](https://github.com/AliceO2Group/AliceO2/pull/15077) 2026-02-18: o2-sim: Possibility to switch between TGeo and Geant4 navigation by [@sawenzel](https://github.com/sawenzel) +- [#15078](https://github.com/AliceO2Group/AliceO2/pull/15078) 2026-02-19: [ALICE3] Change to upper-case 'S' in "FT3sensor_*" strings by [@altsybee](https://github.com/altsybee) +- [#15079](https://github.com/AliceO2Group/AliceO2/pull/15079) 2026-02-19: [ITS] Protect ultra low pt selections at the tracklet level by [@mpuccio](https://github.com/mpuccio) +- [#15082](https://github.com/AliceO2Group/AliceO2/pull/15082) 2026-02-19: Ctpdev: getting list of unmasked inputs by [@lietava](https://github.com/lietava) +- [#15026](https://github.com/AliceO2Group/AliceO2/pull/15026) 2026-02-19: EMCAL: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15035](https://github.com/AliceO2Group/AliceO2/pull/15035) 2026-02-19: TPC: Delete unused files by [@vkucera](https://github.com/vkucera) +## Changes in Examples -- [#8625](https://github.com/AliceO2Group/AliceO2/pull/8625) 2022-04-21: Option to not write json files in the ED workflow that are empty by [@pnwkw](https://github.com/pnwkw) -- [#8580](https://github.com/AliceO2Group/AliceO2/pull/8580) 2022-04-23: Implemented reading MFT tracks from AOD files by [@pnwkw](https://github.com/pnwkw) -- [#8654](https://github.com/AliceO2Group/AliceO2/pull/8654) 2022-04-26: Event Display: compile on macOS by [@ktf](https://github.com/ktf) -- [#8667](https://github.com/AliceO2Group/AliceO2/pull/8667) 2022-04-27: Add/use createDirectoriesIfAbsent method, robust against concurrent calls by [@shahor02](https://github.com/shahor02) +- [#15056](https://github.com/AliceO2Group/AliceO2/pull/15056) 2026-02-13: Update examples on AO2D creation from MCTracks by [@jackal1-66](https://github.com/jackal1-66) ## Changes in Framework -- [#8620](https://github.com/AliceO2Group/AliceO2/pull/8620) 2022-04-20: DPL: work with ROOT master by [@ktf](https://github.com/ktf) -- [#8588](https://github.com/AliceO2Group/AliceO2/pull/8588) 2022-04-21: DPL Analysis: workaround for setting self-index binding before invoking process() by [@aalkin](https://github.com/aalkin) -- [#8630](https://github.com/AliceO2Group/AliceO2/pull/8630) 2022-04-21: DPL: add documentation to o2::framework::workflow::combine by [@ktf](https://github.com/ktf) -- [#8623](https://github.com/AliceO2Group/AliceO2/pull/8623) 2022-04-21: DPL: add dpl_instance tag to distinguish between different NUMA domains by [@ktf](https://github.com/ktf) -- [#8626](https://github.com/AliceO2Group/AliceO2/pull/8626) 2022-04-22: Fix Partition, add separate sliceByCached for joins, filtered and nested filtered by [@saganatt](https://github.com/saganatt) -- [#8609](https://github.com/AliceO2Group/AliceO2/pull/8609) 2022-04-22: Move to fdd version 001 by [@mbroz84](https://github.com/mbroz84) -- [#8606](https://github.com/AliceO2Group/AliceO2/pull/8606) 2022-04-22: readout-proxy: correctly populate TimingInfo by [@ktf](https://github.com/ktf) -- [#8637](https://github.com/AliceO2Group/AliceO2/pull/8637) 2022-04-24: remove temporary code by [@jgrosseo](https://github.com/jgrosseo) -- [#8644](https://github.com/AliceO2Group/AliceO2/pull/8644) 2022-04-25: DPL: Use startTime instead of tfCounter in whenAllOrdered policy by [@davidrohr](https://github.com/davidrohr) -- [#8649](https://github.com/AliceO2Group/AliceO2/pull/8649) 2022-04-25: DPL: do not send the oldest possible timeframe to out of band channels by [@ktf](https://github.com/ktf) -- [#8659](https://github.com/AliceO2Group/AliceO2/pull/8659) 2022-04-27: Printing log when we find a default CCDB entry by [@chiarazampolli](https://github.com/chiarazampolli) -- [#8574](https://github.com/AliceO2Group/AliceO2/pull/8574) 2022-04-28: Add energy as a dynamic column by [@njacazio](https://github.com/njacazio) +- [#15016](https://github.com/AliceO2Group/AliceO2/pull/15016) 2026-02-05: DPL: Improve message when we do not have enough resources to process. by [@ktf](https://github.com/ktf) +- [#15014](https://github.com/AliceO2Group/AliceO2/pull/15014) 2026-02-07: Store TPC track A/C side info in the AO2D TrackExtra.fFlags unused bits by [@shahor02](https://github.com/shahor02) +- [#15038](https://github.com/AliceO2Group/AliceO2/pull/15038) 2026-02-09: Framework: Delete unused files by [@vkucera](https://github.com/vkucera) +- [#15053](https://github.com/AliceO2Group/AliceO2/pull/15053) 2026-02-11: DPL Analysis: fix topology adjust corner case by [@aalkin](https://github.com/aalkin) +- [#15046](https://github.com/AliceO2Group/AliceO2/pull/15046) 2026-02-11: DPL: oldest possible timeframe triggered CompletionPolicy by [@ktf](https://github.com/ktf) +- [#15061](https://github.com/AliceO2Group/AliceO2/pull/15061) 2026-02-12: DPL: introduce range based views to navigate data model by [@ktf](https://github.com/ktf) +- [#15048](https://github.com/AliceO2Group/AliceO2/pull/15048) 2026-02-13: DPL: Enforce that dpl pipeline length is at least as long as number of TFs in flight by [@davidrohr](https://github.com/davidrohr) +- [#15059](https://github.com/AliceO2Group/AliceO2/pull/15059) 2026-02-15: DPL Examples: use the new completion policy for parallel processing by [@ktf](https://github.com/ktf) +- [#15008](https://github.com/AliceO2Group/AliceO2/pull/15008) 2026-02-17: DPL Analysis: cleanup AnalysisTask.h and ASoA.h by [@aalkin](https://github.com/aalkin) +## Changes in Generators + +- [#15068](https://github.com/AliceO2Group/AliceO2/pull/15068) 2026-02-13: Fix Header info forwarding by [@jackal1-66](https://github.com/jackal1-66) ## Changes in Steer -- [#8599](https://github.com/AliceO2Group/AliceO2/pull/8599) 2022-04-16: Use flag HBFUtils.obligatorySOR to start raw data from TF with SOX + fixes by [@shahor02](https://github.com/shahor02) +- [#15064](https://github.com/AliceO2Group/AliceO2/pull/15064) 2026-02-13: Support to plug-and-play external (CAD) geometry by [@sawenzel](https://github.com/sawenzel) +- [#15077](https://github.com/AliceO2Group/AliceO2/pull/15077) 2026-02-18: o2-sim: Possibility to switch between TGeo and Geant4 navigation by [@sawenzel](https://github.com/sawenzel) ## Changes in Utilities -- [#8589](https://github.com/AliceO2Group/AliceO2/pull/8589) 2022-04-14: Fix EPN stderr monitor by [@davidrohr](https://github.com/davidrohr) -- [#8660](https://github.com/AliceO2Group/AliceO2/pull/8660) 2022-04-28: [QC-769] Desambiguify DS and Merger names by [@Barthelemy](https://github.com/Barthelemy) +- [#15039](https://github.com/AliceO2Group/AliceO2/pull/15039) 2026-02-09: Utilities: Delete unused files by [@vkucera](https://github.com/vkucera) diff --git a/doc/data/2026-02-o2_prs.json b/doc/data/2026-02-o2_prs.json new file mode 100644 index 0000000000000..066ba0835f8bf --- /dev/null +++ b/doc/data/2026-02-o2_prs.json @@ -0,0 +1,4218 @@ +{ + "repository": { + "pullRequests": { + "edges": [ + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-22T18:49:21Z", + "title": "DPL: do not do the new early forwarding for some of the data", + "number": 14984, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-16T13:14:29Z", + "title": "Afit 124", + "number": 14985, + "author": { + "login": "wpierozak" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/Reconstructor.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/reconstruction/src/Reconstructor.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RecoWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/ReconstructorSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/ReconstructorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/fdd-reco-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CollisionTimeRecoTask.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/reconstruction/src/CollisionTimeRecoTask.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/RecoWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/ReconstructionSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/ReconstructionSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/ft0-reco-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/BaseRecoTask.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/reconstruction/src/BaseRecoTask.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/include/FV0Workflow/RecoWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/include/FV0Workflow/ReconstructionSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/src/ReconstructionSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T13:41:39Z", + "title": "EventsPerBC calibration task for FT0 (O2-6563)", + "number": 14986, + "author": { + "login": "wpierozak" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/FIT/FT0/CMakeLists.txt" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FT0/include/DataFormatsFT0/EventsPerBc.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/FIT/FT0/src/DataFormatsFT0LinkDef.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/README.md" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/include/FT0Calibration/EventsPerBcCalibrator.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/src/EventsPerBcCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/src/FT0CalibrationLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcProcessor-Workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/calibration/workflow/FT0EventsPerBcSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/macros/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/macros/FT0readEventsPerBc.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-22T14:59:04Z", + "title": "Revert \"DPL Analysis: Use dangling edges context in more places\"", + "number": 14987, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/AnalysisSupport/src/AODWriterHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/CCDBSupport/src/AnalysisCCDBHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AnalysisSupportHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-27T13:50:19Z", + "title": "DPL Analysis: Use dangling edges context in more places", + "number": 14988, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/AnalysisSupport/src/AODWriterHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/CCDBSupport/src/AnalysisCCDBHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/CCDBSupport/src/AnalysisCCDBHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AnalysisSupportHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ArrowSupport.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/WorkflowHelpers.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "TRD: updates in vdrift and ExB calibration + possibility to use slope in chi2 matching", + "number": 14989, + "author": { + "login": "glegras" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/CalGain.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/CalVdriftExB.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TRD/include/DataFormatsTRD/Constants.h" + } + }, + { + "node": { + "path": "Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/TrackletTransformer.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/TrackletTransformer.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/README.md" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/include/TRDCalibration/CalibrationParams.h" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/include/TRDCalibration/CalibratorVdExB.h" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/macros/manualCalibFit.C" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/src/CalibratorVdExB.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/src/TrackBasedCalib.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/VdAndExBCalibSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDTrackletTransformerSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUSettingsList.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-26T21:02:27Z", + "title": "DPL: move snapshot code to use concepts", + "number": 14990, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataAllocator.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/SerializationMethods.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-26T07:56:50Z", + "title": "Implement AO2D file checks for full_system_test", + "number": 14991, + "author": { + "login": "jackal1-66" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-24T15:57:57Z", + "title": "PVertexer::refitVertexFull for refitting with different geom.", + "number": 14992, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/CheckResidConfig.h" + } + }, + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/study/src/CheckResid.cxx" + } + }, + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/PVertexer.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/PVertexer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-25T09:38:47Z", + "title": "Ctpdev: task for populating BK with ctp config/scalers", + "number": 14993, + "author": { + "login": "lietava" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/CTP/workflowScalers/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/CTP/workflowScalers/include/CTPWorkflowScalers/ctpCCDBManager.h" + } + }, + { + "node": { + "path": "Detectors/CTP/workflowScalers/src/ctp-bk-write.cxx" + } + }, + { + "node": { + "path": "Detectors/CTP/workflowScalers/src/ctpCCDBManager.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "Add Lc resonances to physics constants", + "number": 14994, + "author": { + "login": "apalasciano" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/Constants/include/CommonConstants/PhysicsConstants.h" + } + }, + { + "node": { + "path": "Common/Constants/include/CommonConstants/make_pdg_header.py" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "DPL: do not anticipate oldestPossibleTimeframe", + "number": 14995, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-29T12:44:05Z", + "title": "DPL Analysis: cleanup AnalysisTask.h and ASoA.h", + "number": 14996, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ASoA.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisManagers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/StructToTuple.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-27T22:01:19Z", + "title": "ITSMFT: fix number of rofs per TF", + "number": 14997, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Steer/DigitizerWorkflow/src/ITSMFTDigitizerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-28T08:12:21Z", + "title": "GPU CMake: Improve architecture auto-detection", + "number": 14998, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "dependencies/FindO2GPU.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-29T08:03:40Z", + "title": "ITS: GPU: reduce memory allocations", + "number": 14999, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/strtag.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-28T19:51:31Z", + "title": "DPL: disable early forwarding for output proxies", + "number": 15000, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ExternalFairMQDeviceProxy.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-29T08:01:00Z", + "title": "GPU: Parallelize TPC pad filter over pad rows instead of cachelines.", + "number": 15001, + "author": { + "login": "fweig" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUTPCGeometry.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/GPUDefParametersDefaults.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TPCClusterFinder/GPUTPCCFCheckPadBaseline.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-02T21:00:28Z", + "title": "Leave single implementation of TRD RecoParam", + "number": 15002, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Align/include/Align/AlignableDetectorTRD.h" + } + }, + { + "node": { + "path": "Detectors/Align/src/AlignableDetectorTRD.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackInterpolation.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TRD/base/include/TRDBase/RecoParam.h" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/RecoParam.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/base/src/TRDBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/include/TRDCalibration/TrackBasedCalib.h" + } + }, + { + "node": { + "path": "Detectors/TRD/calibration/src/TrackBasedCalib.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/qc/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TRD/qc/include/TRDQC/Tracking.h" + } + }, + { + "node": { + "path": "Detectors/TRD/qc/src/Tracking.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/TRDGlobalTrackingSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/GPUConstantMem.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUDataTypesIO.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUTRDRecoParam.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUTRDRecoParam.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/GPUTrackingLinkDef_O2.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTracking.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingGetters.inc" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Global/GPUChainTrackingIO.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/GPUTRDTracker.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/TRDTracking/macros/run_trd_tracker.C" + } + }, + { + "node": { + "path": "GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h" + } + }, + { + "node": { + "path": "GPU/Workflow/src/GPUWorkflowSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-30T10:03:46Z", + "title": "DPL: fix device signpost segfaults for o2-dpl-raw-proxy", + "number": 15003, + "author": { + "login": "ehellbar" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-12T10:08:38Z", + "title": "ITSMFT: scaffolding for staggered clusterization", + "number": 15004, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/src/StrangenessTrackingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ClustererSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/ClusterWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/ClusterWriterWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/workflow/include/MFTWorkflow/ClusterWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/workflow/src/ClusterWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/workflow/src/ClustererSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/workflow/src/mft-cluster-writer-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/Clusterer.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/ClustererParam.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/src/Clusterer.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClusterWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/ClustererSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/ClusterReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/ClusterWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/ClustererSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ITS3/workflow/src/RecoWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-30T11:05:55Z", + "title": "Revert \"DPL Analysis: cleanup AnalysisTask.h and ASoA.h\"", + "number": 15005, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ASoA.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisManagers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/StructToTuple.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-01-31T17:59:49Z", + "title": "DPL: improve type_to_task_name function", + "number": 15006, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/src/AnalysisTask.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_TypeToTaskName.cxx" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/TypeIdHelpers.h" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "DPL Analysis: fix process functions skipped due to malformed check", + "number": 15007, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-17T13:47:48Z", + "title": "DPL Analysis: cleanup AnalysisTask.h and ASoA.h", + "number": 15008, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/ASoA.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisManagers.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisTask.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/Configurable.h" + } + }, + { + "node": { + "path": "Framework/Core/test/test_Concepts.cxx" + } + }, + { + "node": { + "path": "Framework/Foundation/include/Framework/StructToTuple.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-02T12:16:21Z", + "title": "Revert abbreviations until we get green light from the affected people", + "number": 15009, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/AnalysisTask.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-07T12:01:30Z", + "title": "Add ability to retain TrackQA for all global tracks", + "number": 15010, + "author": { + "login": "ddobrigk" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-03T09:48:58Z", + "title": "Disable tests for reverted exceptions", + "number": 15011, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/test/test_TypeToTaskName.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-03T13:01:02Z", + "title": "Brown paperbag issue with reverted feature.", + "number": 15012, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/test/test_TypeToTaskName.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-04T16:56:23Z", + "title": "Fix and improve TPC Loopers implementation", + "number": 15013, + "author": { + "login": "jackal1-66" + }, + "files": { + "edges": [ + { + "node": { + "path": "Generators/include/Generators/Generator.h" + } + }, + { + "node": { + "path": "Generators/include/Generators/TPCLoopers.h" + } + }, + { + "node": { + "path": "Generators/src/Generator.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-07T12:02:07Z", + "title": "Store TPC track A/C side info in the AO2D TrackExtra.fFlags unused bits", + "number": 15014, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/AnalysisDataModel.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DataTypes.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-05T10:47:28Z", + "title": "GPU: Delete unused files", + "number": 15015, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Base/hip/test/testGPUsortHIP.hip" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SectorTracker/GPUTPCDefinitions.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/makefile_opencl_compiler.cxx" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/opencl_compiler_structs.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/utils/opencl_obtain_program.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-05T08:20:34Z", + "title": "DPL: Improve message when we do not have enough resources to process.", + "number": 15016, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-05T14:34:24Z", + "title": "Add back tuned parameters for old architectures TAHITI TESLA FERMI PASCAL KEPLER", + "number": 15017, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/.clang-format" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/.clang-format-ignore" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/GPUParameters.json" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-05T19:28:46Z", + "title": "Don't use 'No CUDA devices found' as CUDA architecture", + "number": 15018, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "dependencies/FindO2GPU.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-05T11:07:23Z", + "title": "Add the .clang-format-ignore", + "number": 15019, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": ".clang-format-ignore" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "First commit of processing common mode values in O2", + "number": 15020, + "author": { + "login": "tubagundem" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/CMV.h" + } + }, + { + "node": { + "path": "Detectors/TPC/base/include/TPCBase/RDHUtils.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/CMVToVectorSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/CMVToVectorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-cmv-to-vector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-06T08:26:36Z", + "title": "Promote --ctf-dict from process to workflow level option", + "number": 15021, + "author": { + "login": "shahor02" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/CTFCoderBase.h" + } + }, + { + "node": { + "path": "Detectors/CPV/reconstruction/include/CPVReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/include/CPVWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/include/CPVWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/CPV/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/CTF/workflow/include/CTFWorkflow/CTFReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/CTF/workflow/src/CTFReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/CTF/workflow/src/ctf-reader-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/CTP/reconstruction/include/CTPReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/CTP/workflow/include/CTPWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/CTP/workflow/include/CTPWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/CTP/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/CTP/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/CTP/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/workflow/include/EMCALWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/EMCAL/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/reconstruction/include/FT0Reconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/reconstruction/include/FV0Reconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/include/FV0Workflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FV0/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/include/HMPIDReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/common/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/CTF/include/MCHCTF/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/CTF/include/MCHCTF/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/CTF/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/CTF/include/MIDCTF/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/include/MIDWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/reconstruction/include/PHOSReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/workflow/include/PHOSWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/PHOS/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/PHOS/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/reconstruction/include/TOFReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/include/TOFWorkflowUtils/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/include/TPCWorkflow/RecoWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/tpc-reco-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/reconstruction/include/TRDReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/include/TRDWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/TRD/workflow/src/entropy-encoder-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/reconstruction/include/ZDCReconstruction/CTFCoder.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyDecoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/include/ZDCWorkflow/EntropyEncoderSpec.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/EntropyDecoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/workflow/src/entropy-encoder-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-05T19:32:10Z", + "title": "GPU: Add converter scripts for CSV parameter file to JSON and vice versa", + "number": 15022, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/json_to_csv.python" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-06T08:50:01Z", + "title": "ITS: GPU: partial revert of memory clearing", + "number": 15023, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-07T08:35:07Z", + "title": "GPU CMake: Avoid repetitive JSON parsing", + "number": 15024, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/GPUParameters.json.example" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/csv_to_json.sh" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/cmake/config.cmake" + } + }, + { + "node": { + "path": "GPU/GPUTracking/cmake/gpu_param_header_generator.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-09T08:46:25Z", + "title": "Algorithm: Delete unused files", + "number": 15025, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Algorithm/include/Algorithm/BitstreamReader.h" + } + }, + { + "node": { + "path": "Algorithm/test/test_BitstreamReader.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-19T10:53:33Z", + "title": "EMCAL: Delete unused files", + "number": 15026, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/EMCALChannelData.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/EMCAL/src/EMCALChannelData.cxx" + } + }, + { + "node": { + "path": "Detectors/EMCAL/reconstruction/run/rawReaderTRUDigits.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-12T09:34:04Z", + "title": "MUON: Delete unused files", + "number": 15027, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/MUON/MCH/src/DsChannelGroup.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Mapping/SegContour/src/SegmentationSVGWriter.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUBare.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferCRUUserLogic.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTBare.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MCH/Raw/Encoder/Payload/RefBufferGBTUserLogic.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Filtering/test/bench_Filter.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/include/MIDWorkflow/DecodedDataDumpSpec.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/include/MIDWorkflow/RawAggregatorSpec.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/DecodedDataDumpSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/decoded-data-dump-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "ZDC: Delete unused files", + "number": 15028, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/ZDC/include/DataFormatsZDC/FEEConfig.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/calib/testWorkflow/DataGeneratorSpec.h" + } + }, + { + "node": { + "path": "Detectors/ZDC/calib/testWorkflow/data-generator-workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/ZDC/calib/testWorkflow/zdc-calib-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-09T09:10:32Z", + "title": "DataFormats: Delete unused files", + "number": 15029, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Headers/include/Headers/SubframeMetadata.h" + } + }, + { + "node": { + "path": "DataFormats/Legacy/HLT/include/AliceHLT/TPCRawCluster.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T07:52:12Z", + "title": "SimulationDataFormat: Delete unused files", + "number": 15030, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/simulation/include/SimulationDataFormat/ProcessingEventInfo.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "FIT: Delete unused files", + "number": 15031, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/FIT/FDD/reconstruction/include/FDDReconstruction/ReadRaw.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/simulation/include/FDDSimulation/Digits2Raw.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataProcessSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawDataReaderSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/include/FDDWorkflow/RawWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawDataProcessSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawDataReaderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FDD/workflow/src/RawWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataProcessDPLSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0DataReaderDPLSpec.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/FT0Workflow.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/include/FT0Workflow/RawReaderFT0.h" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/FT0DataProcessDPLSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/FT0DataReaderDPLSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/FT0Workflow.cxx" + } + }, + { + "node": { + "path": "Detectors/FIT/FT0/workflow/src/RawReaderFT0.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T09:58:53Z", + "title": "GlobalTrackingWorkflow: Delete unused files", + "number": 15032, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/GlobalTrackingWorkflow/tofworkflow/src/RecoWorkflowSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "HMPID: Delete unused files", + "number": 15033, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawFile.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/include/HMPIDReconstruction/HmpidDecodeRawMem.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidDecodeRawFile.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidDecodeRawMem.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/reconstruction/src/HmpidDecoder.cxx" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/ClusterizerSpec.h_notused.h" + } + }, + { + "node": { + "path": "Detectors/HMPID/workflow/include/HMPIDWorkflow/DigitReaderSpec.h_notused.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T17:05:45Z", + "title": "MFT: Delete unused files", + "number": 15034, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/MFT/calibration/include/MFTCalibration/NoiseSlotCalibrator.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/calibration/src/MchAlignment.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/MFT/calibration/src/NoiseSlotCalibrator.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-19T11:53:16Z", + "title": "TPC: Delete unused files", + "number": 15035, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TPC/reconstruction/include/TPCReconstruction/ClusterContainer.h" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/time-series-merge-integrator.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/workflow/src/time-series-reader.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T09:58:19Z", + "title": "TRD: Delete unused files", + "number": 15036, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TRD/base/src/CalSingleChamberStatus.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T14:11:32Z", + "title": "Vertexing: Delete unused files", + "number": 15037, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Vertexing/include/DetectorsVertexing/FwdDCAFitterN.h" + } + }, + { + "node": { + "path": "Detectors/Vertexing/src/FwdDCAFitterN.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-09T22:46:22Z", + "title": "Framework: Delete unused files", + "number": 15038, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataProcessingStateManager.h" + } + }, + { + "node": { + "path": "Framework/Foundation/src/Traits.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/dummy.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2_sim_its_ALP3.h" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2_sim_tpc.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2_sim_tpc.h" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/test_o2ITSCluserizer.cxx" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/test_o2TPCSimulation.cxx" + } + }, + { + "node": { + "path": "Framework/Utils/test/DPLBroadcasterMerger.cxx" + } + }, + { + "node": { + "path": "Framework/Utils/test/DPLBroadcasterMerger.h" + } + }, + { + "node": { + "path": "Framework/Utils/test/DPLOutputTest.h" + } + }, + { + "node": { + "path": "Framework/Utils/test/test_DPLBroadcasterMerger.cxx" + } + }, + { + "node": { + "path": "Framework/Utils/test/test_DPLOutputTest.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-09T08:25:15Z", + "title": "Utilities: Delete unused files", + "number": 15039, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Utilities/DataCompression/include/DataCompression/CodingModelDispatcher.h" + } + }, + { + "node": { + "path": "Utilities/DataCompression/include/DataCompression/runtime_container.h" + } + }, + { + "node": { + "path": "Utilities/DataCompression/tpccluster_parameter_model.h" + } + }, + { + "node": { + "path": "Utilities/rANS/include/rANS/internal/containers/HistogramInterface.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T09:50:56Z", + "title": "Update omp detection for macOS", + "number": 15040, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "dependencies/FindOpenMPMacOS.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-07T23:03:15Z", + "title": "GPU: Generate GPU parameter files only if GPU build is actually enabled", + "number": 15041, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/GPUParameters.csv" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/json_to_csv.python" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/tools/dumpGPUDefParam.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-09T08:14:55Z", + "title": "GPU CMake: Improve architecture detection, split parameter header between device and non-device options", + "number": 15042, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/Base/cuda/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Base/hip/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/cmake/gpu_param_header_generator.cmake" + } + }, + { + "node": { + "path": "dependencies/FindO2GPU.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T00:50:34Z", + "title": "[A3 TRK] Sensor orientation fix + first try to close in-stave gaps", + "number": 15043, + "author": { + "login": "scannito" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T12:27:46Z", + "title": "GPU Parameters: Add script to generate parameter file from parameter list csv/json and architecture", + "number": 15044, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Definitions/Parameters/gpu_param_header_generator.cmake" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/Benchmark/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/Standalone/tools/dumpGPUParamByArch.sh" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/CMakeLists.txt" + } + }, + { + "node": { + "path": "GPU/GPUTracking/display/filterMacros/setinclude.sh.in" + } + }, + { + "node": { + "path": "dependencies/FindO2GPU.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-14T08:47:18Z", + "title": "Add option to compress out non-dEdx info in TrackQA table", + "number": 15045, + "author": { + "login": "ddobrigk" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h" + } + }, + { + "node": { + "path": "Detectors/AOD/src/AODProducerWorkflowSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T09:02:56Z", + "title": "DPL: oldest possible timeframe triggered CompletionPolicy", + "number": 15046, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/CompletionPolicyHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/CompletionPolicyHelpers.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-10T13:21:56Z", + "title": "Fix codechecker violation", + "number": 15047, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/EMCAL/base/src/ClusterFactory.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-13T08:03:18Z", + "title": "DPL: Enforce that dpl pipeline length is at least as long as number of TFs in flight", + "number": 15048, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataRelayer.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DefaultsHelpers.h" + } + }, + { + "node": { + "path": "Framework/Core/src/ArrowSupport.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/CommonServices.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataProcessingDevice.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DataRelayer.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/DefaultsHelpers.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/benchmark_DataRelayer.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_DataRelayer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "MID: remove input wildcards in MID workflows", + "number": 15049, + "author": { + "login": "ehellbar" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/MUON/MID/Workflow/include/MIDWorkflow/ColumnDataSpecsUtils.h" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/CalibDataProcessorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/ClusterizerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/ColumnDataSpecsUtils.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/DecodedDataAggregatorSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/EntropyEncoderSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/FilteringBCSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/FilteringSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/MaskMakerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/TimingSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/MUON/MID/Workflow/src/ZeroSuppressionSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "ITS3: define alignable volumes", + "number": 15050, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/base/include/ITSBase/GeometryTGeo.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/base/src/GeometryTGeo.cxx" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/DescriptorInnerBarrelITS3.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ITS3/simulation/src/DescriptorInnerBarrelITS3.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-12T08:01:29Z", + "title": "ITS3: load chip response functions from ccdb", + "number": 15051, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ITS3/macros/test/CheckChipResponseFile.C" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-12T08:01:55Z", + "title": "ITS3: split longerons, improving stepping speed", + "number": 15052, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ITS3/base/include/ITS3Base/SpecsV2.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ITS3/simulation/include/ITS3Simulation/ITS3Layer.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ITS3/simulation/src/ITS3Layer.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T10:18:18Z", + "title": "DPL Analysis: fix topology adjust corner case", + "number": 15053, + "author": { + "login": "aalkin" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/src/ArrowSupport.cxx" + } + }, + { + "node": { + "path": "run/o2sim_kine_publisher.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T18:00:46Z", + "title": "ITS: GPU: use mean vertex constraint for gpu processing", + "number": 15054, + "author": { + "login": "f3sch" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full-system-test/dpl-workflow.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-17T18:15:57Z", + "title": "ALICE 3 feat: Configurable VD design, set def to IRIS 4, remove IRIS disks", + "number": 15055, + "author": { + "login": "plariono" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/base/include/TRKBase/TRKBaseParam.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/VDGeometryBuilder.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-13T09:47:41Z", + "title": "Update examples on AO2D creation from MCTracks", + "number": 15056, + "author": { + "login": "jackal1-66" + }, + "files": { + "edges": [ + { + "node": { + "path": "run/SimExamples/HepMC_STARlight/run_HepMCToAOD.sh" + } + }, + { + "node": { + "path": "run/SimExamples/McTracksToAOD/run_O2Kine.sh" + } + }, + { + "node": { + "path": "run/SimExamples/McTracksToAOD/run_Pythia8.sh" + } + }, + { + "node": { + "path": "run/SimExamples/McTracksToAOD/run_trigger.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T18:48:07Z", + "title": "TPC: time gain calibration optimizations", + "number": 15057, + "author": { + "login": "matthias-kleiner" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/include/TPCCalibration/CalibdEdx.h" + } + }, + { + "node": { + "path": "Detectors/TPC/calibration/src/CalibdEdx.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-16T13:10:23Z", + "title": "Add Kine publisher test", + "number": 15058, + "author": { + "login": "jackal1-66" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-15T13:29:48Z", + "title": "DPL Examples: use the new completion policy for parallel processing", + "number": 15059, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/CompletionPolicyHelpers.h" + } + }, + { + "node": { + "path": "Framework/TestWorkflows/src/o2ParallelWorkflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "DPL: move to std::span in some tests", + "number": 15060, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/test/test_DataAllocator.cxx" + } + }, + { + "node": { + "path": "Framework/Core/test/test_FairMQ.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-12T12:32:13Z", + "title": "DPL: introduce range based views to navigate data model", + "number": 15061, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/DataModelViews.h" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T23:17:13Z", + "title": "DCS: Fix undefined behavior and invalid pointer access", + "number": 15062, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/DCS/src/DataPointCreator.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-11T23:15:05Z", + "title": "GPU Vulkan Display: fix DEPFILE path", + "number": 15063, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/cmake/vulkan_display.cmake" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-13T21:00:49Z", + "title": "Support to plug-and-play external (CAD) geometry", + "number": 15064, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Base/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/O2Tessellated.h" + } + }, + { + "node": { + "path": "Detectors/Base/include/DetectorsBase/TGeoGeometryUtils.h" + } + }, + { + "node": { + "path": "Detectors/Base/src/DetectorsBaseLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Base/src/O2Tessellated.cxx" + } + }, + { + "node": { + "path": "Detectors/Base/src/TGeoGeometryUtils.cxx" + } + }, + { + "node": { + "path": "Detectors/Base/src/bvh2_extra_kernels.h" + } + }, + { + "node": { + "path": "Detectors/Base/src/bvh2_third_party.h" + } + }, + { + "node": { + "path": "Detectors/Passive/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Passive/include/DetectorsPassive/ExternalModule.h" + } + }, + { + "node": { + "path": "Detectors/Passive/src/ExternalModule.cxx" + } + }, + { + "node": { + "path": "Steer/include/Steer/O2MCApplicationBase.h" + } + }, + { + "node": { + "path": "Steer/src/O2MCApplication.cxx" + } + }, + { + "node": { + "path": "macro/build_geometry.C" + } + }, + { + "node": { + "path": "scripts/geometry/O2_CADtoTGeo.py" + } + }, + { + "node": { + "path": "scripts/geometry/README.md" + } + }, + { + "node": { + "path": "scripts/geometry/simulating_CAD_modules.md" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-12T13:40:38Z", + "title": "FST: Make previousOrbit configurable", + "number": 15065, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "prodtests/full_system_test.sh" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-16T15:03:27Z", + "title": "First version of the hit based CA tracker for ALICE3 IT/OT", + "number": 15066, + "author": { + "login": "mpuccio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h" + } + }, + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/include/ITStracking/Tracker.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/macros/test/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/macros/test/CheckTracksCA.C" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/reconstruction/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TRKReconstructionLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/CMakeLists.txt" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/README.md" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/RecoWorkflow.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackWriterSpec.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/include/TRKWorkflow/TrackerSpec.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/src/RecoWorkflow.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackWriterSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/src/trk-reco-workflow.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-13T16:44:24Z", + "title": "[A3 TRK] Fix kCylinder option + services crossing", + "number": 15067, + "author": { + "login": "scannito" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKLayer.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-13T21:14:44Z", + "title": "Fix Header info forwarding", + "number": 15068, + "author": { + "login": "jackal1-66" + }, + "files": { + "edges": [ + { + "node": { + "path": "Generators/src/GeneratorHybrid.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-16T10:20:12Z", + "title": "GPU TPC: Assume more sector track hits for low field data", + "number": 15069, + "author": { + "login": "davidrohr" + }, + "files": { + "edges": [ + { + "node": { + "path": "GPU/GPUTracking/DataTypes/GPUMemorySizeScalers.h" + } + }, + { + "node": { + "path": "GPU/GPUTracking/SectorTracker/GPUTPCTracker.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-17T18:16:53Z", + "title": "ALICE3-TRK: adapt ordering key for digits to the large number of columns in the VD", + "number": 15070, + "author": { + "login": "atriolo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/ChipDigitsContainer.h" + } + } + ] + } + } + }, + { + "node": { + "state": "CLOSED", + "mergedAt": null, + "title": "[ALICE3] Fix geometry overlaps in tracker (ML/OT)", + "number": 15071, + "author": { + "login": "marcovanleeuwen" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-17T18:12:33Z", + "title": "[ALICE3] Fix geometry overlaps in tracker (ML/OT)", + "number": 15072, + "author": { + "login": "marcovanleeuwen" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-17T20:54:35Z", + "title": "A3: Add geometries for IOTOF", + "number": 15073, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-18T14:11:44Z", + "title": "ALICE3-TRK: fix detector ID assignment to hits", + "number": 15074, + "author": { + "login": "atriolo" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-17T21:08:44Z", + "title": "[ALICE3] Adapt CA for 2T simulations", + "number": 15075, + "author": { + "login": "mpuccio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/reconstruction/include/TRKReconstruction/TimeFrame.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/reconstruction/src/TimeFrame.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/workflow/src/TrackerSpec.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "CCDB: report stats about CCDB fetches / misses to DPL", + "number": 15076, + "author": { + "login": "ktf" + }, + "files": { + "edges": [ + { + "node": { + "path": "CCDB/include/CCDB/BasicCCDBManager.h" + } + }, + { + "node": { + "path": "CCDB/src/BasicCCDBManager.cxx" + } + }, + { + "node": { + "path": "Framework/Core/CMakeLists.txt" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/DataProcessingStats.h" + } + }, + { + "node": { + "path": "Framework/Core/include/Framework/ServiceRegistryRef.h" + } + }, + { + "node": { + "path": "Framework/Core/src/CommonServices.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/ServiceRegistryRef.cxx" + } + }, + { + "node": { + "path": "Framework/Core/src/runDataProcessing.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-18T08:46:28Z", + "title": "o2-sim: Possibility to switch between TGeo and Geant4 navigation", + "number": 15077, + "author": { + "login": "sawenzel" + }, + "files": { + "edges": [ + { + "node": { + "path": "Common/SimConfig/include/SimConfig/G4Params.h" + } + }, + { + "node": { + "path": "Common/SimConfig/src/SimConfigLinkDef.h" + } + }, + { + "node": { + "path": "Detectors/gconfig/g4Config.C" + } + }, + { + "node": { + "path": "Steer/src/O2MCApplication.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-19T06:54:50Z", + "title": "[ALICE3] Change to upper-case 'S' in \"FT3sensor_*\" strings ", + "number": 15078, + "author": { + "login": "altsybee" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/FT3/simulation/src/FT3Module.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-19T09:18:54Z", + "title": "[ITS] Protect ultra low pt selections at the tracklet level", + "number": 15079, + "author": { + "login": "mpuccio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/ITSMFT/ITS/tracking/src/TimeFrame.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "path for LHCphase ccdb configurable", + "number": 15080, + "author": { + "login": "noferini" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/TOF/calibration/include/TOFCalibration/LHCClockCalibrator.h" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/src/LHCClockCalibrator.cxx" + } + }, + { + "node": { + "path": "Detectors/TOF/calibration/testWorkflow/LHCClockCalibratorSpec.h" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "[ALICE3] Add proto segmentation of TF3", + "number": 15081, + "author": { + "login": "njacazio" + }, + "files": { + "edges": [ + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/base/include/IOTOFBase/IOTOFBaseParam.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Detector.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/simulation/include/IOTOFSimulation/Layer.h" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Layer.cxx" + } + }, + { + "node": { + "path": "Detectors/Upgrades/ALICE3/TRK/base/src/GeometryTGeo.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "MERGED", + "mergedAt": "2026-02-19T09:17:05Z", + "title": "Ctpdev: getting list of unmasked inputs", + "number": 15082, + "author": { + "login": "lietava" + }, + "files": { + "edges": [ + { + "node": { + "path": "DataFormats/Detectors/CTP/include/DataFormatsCTP/Configuration.h" + } + }, + { + "node": { + "path": "DataFormats/Detectors/CTP/src/Configuration.cxx" + } + } + ] + } + } + }, + { + "node": { + "state": "OPEN", + "mergedAt": null, + "title": "BinningPolicy: Fix bug in getAllBinsCount", + "number": 15083, + "author": { + "login": "vkucera" + }, + "files": { + "edges": [ + { + "node": { + "path": "Framework/Core/include/Framework/BinningPolicy.h" + } + } + ] + } + } + } + ] + } + } +} diff --git a/doc/data/2026-02-o2_releases.json b/doc/data/2026-02-o2_releases.json new file mode 100644 index 0000000000000..d5b844b42ca35 --- /dev/null +++ b/doc/data/2026-02-o2_releases.json @@ -0,0 +1,92 @@ +{ + "repository": { + "releases": { + "edges": [ + { + "node": { + "tagName": "v21.15", + "publishedAt": "2021-04-13T12:15:45Z" + } + }, + { + "node": { + "tagName": "v21.14", + "publishedAt": "2021-04-11T15:52:11Z" + } + }, + { + "node": { + "tagName": "v21.13", + "publishedAt": "2021-03-30T20:28:48Z" + } + }, + { + "node": { + "tagName": "v21.11", + "publishedAt": "2021-03-17T07:01:20Z" + } + }, + { + "node": { + "tagName": "v21.10", + "publishedAt": "2021-03-12T08:23:39Z" + } + }, + { + "node": { + "tagName": "v21.09", + "publishedAt": "2021-03-03T06:17:35Z" + } + }, + { + "node": { + "tagName": "v21.07", + "publishedAt": "2021-02-16T17:29:26Z" + } + }, + { + "node": { + "tagName": "v21.05", + "publishedAt": "2021-02-10T21:53:36Z" + } + }, + { + "node": { + "tagName": "v21.03", + "publishedAt": "2021-01-21T13:14:28Z" + } + }, + { + "node": { + "tagName": "v21.01", + "publishedAt": "2021-01-05T16:47:05Z" + } + }, + { + "node": { + "tagName": "v20.49", + "publishedAt": "2020-12-11T16:12:56Z" + } + }, + { + "node": { + "tagName": "v1.3.0", + "publishedAt": "2020-09-22T07:21:04Z" + } + }, + { + "node": { + "tagName": "v1.2.0", + "publishedAt": "2020-02-25T09:10:00Z" + } + }, + { + "node": { + "tagName": "O2-1.0.0", + "publishedAt": "2018-11-21T13:41:46Z" + } + } + ] + } + } +}