diff --git a/algo/ca/TrackingChain.cxx b/algo/ca/TrackingChain.cxx index cffede81ec2f89f36b88f324108032358e57ce59..73b3d47f008991eedb614585c2ba53d5f50f168a 100644 --- a/algo/ca/TrackingChain.cxx +++ b/algo/ca/TrackingChain.cxx @@ -26,8 +26,6 @@ #include <fmt/format.h> #include <xpu/host.h> -using namespace cbm::algo; - using cbm::algo::TrackingChain; using cbm::algo::ca::EDetectorID; using cbm::algo::ca::Framework; @@ -41,7 +39,7 @@ using cbm::algo::ca::constants::clrs::GNb; // grin bald text // --------------------------------------------------------------------------------------------------------------------- // -TrackingChain::TrackingChain(std::shared_ptr<HistogramSender> histoSender) : fQa(Qa(histoSender)) {} +TrackingChain::TrackingChain(std::shared_ptr<cbm::algo::HistogramSender> histoSender) : fQa(Qa(histoSender)) {} // --------------------------------------------------------------------------------------------------------------------- // diff --git a/algo/ca/core/data/CaGrid.cxx b/algo/ca/core/data/CaGrid.cxx index f1e615cfb9af0cb7d0ee3b667331ddab5f904863..f41d2853f3a90c9fda0c6b687f725bd7d0bbfa10 100644 --- a/algo/ca/core/data/CaGrid.cxx +++ b/algo/ca/core/data/CaGrid.cxx @@ -14,113 +14,112 @@ #include <cstring> -using namespace cbm::algo::ca; -using namespace cbm::algo; - - -void Grid::BuildBins(fscal xMin, fscal xMax, fscal yMin, fscal yMax, fscal binWidthX, fscal binWidthY) +namespace cbm::algo::ca { - fMinX = std::min(xMin, xMax); - fMinY = std::min(yMin, yMax); + void Grid::BuildBins(fscal xMin, fscal xMax, fscal yMin, fscal yMax, fscal binWidthX, fscal binWidthY) + { + fMinX = std::min(xMin, xMax); + fMinY = std::min(yMin, yMax); - xMax = std::max(xMin, xMax); - yMax = std::max(yMin, yMax); + xMax = std::max(xMin, xMax); + yMax = std::max(yMin, yMax); - fBinWidthX = binWidthX; - fBinWidthY = binWidthY; + fBinWidthX = binWidthX; + fBinWidthY = binWidthY; - // some sanity checks - if (fBinWidthX < 0.001) { - fBinWidthX = 0.001; - } - if (fBinWidthY < 0.001) { - fBinWidthY = 0.001; - } + // some sanity checks + if (fBinWidthX < 0.001) { + fBinWidthX = 0.001; + } + if (fBinWidthY < 0.001) { + fBinWidthY = 0.001; + } - fBinWidthXinv = 1. / fBinWidthX; - fBinWidthYinv = 1. / fBinWidthY; + fBinWidthXinv = 1. / fBinWidthX; + fBinWidthYinv = 1. / fBinWidthY; - fNx = static_cast<int>(std::ceil((xMax - fMinX) / fBinWidthX)); - fNy = static_cast<int>(std::ceil((yMax - fMinY) / fBinWidthY)); + fNx = static_cast<int>(std::ceil((xMax - fMinX) / fBinWidthX)); + fNy = static_cast<int>(std::ceil((yMax - fMinY) / fBinWidthY)); - // some sanity checks - if (fNx < 1) fNx = 1; - if (fNy < 1) fNy = 1; + // some sanity checks + if (fNx < 1) fNx = 1; + if (fNy < 1) fNy = 1; - fN = fNx * fNy; + fN = fNx * fNy; - fEntries.clear(); - fFirstBinEntryIndex.reset(fN + 1, 0); - fNofBinEntries.reset(fN + 1, 0); -} + fEntries.clear(); + fFirstBinEntryIndex.reset(fN + 1, 0); + fNofBinEntries.reset(fN + 1, 0); + } -void Grid::StoreHits(const Vector<ca::Hit>& hits, ca::HitIndex_t hitStartIndex, ca::HitIndex_t nHits, - const Vector<unsigned char>& hitKeyFlags) -{ - fFirstBinEntryIndex.reset(fN + 1, 0); - fNofBinEntries.reset(fN + 1, 0); - - int nEntries = 0; - for (ca::HitIndex_t ih = 0; ih < nHits; ih++) { - const ca::Hit& hit = hits[hitStartIndex + ih]; - if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) { - fNofBinEntries[GetBin(hit.X(), hit.Y())]++; - nEntries++; + void Grid::StoreHits(const Vector<ca::Hit>& hits, ca::HitIndex_t hitStartIndex, ca::HitIndex_t nHits, + const Vector<unsigned char>& hitKeyFlags) + { + fFirstBinEntryIndex.reset(fN + 1, 0); + fNofBinEntries.reset(fN + 1, 0); + + int nEntries = 0; + for (ca::HitIndex_t ih = 0; ih < nHits; ih++) { + const ca::Hit& hit = hits[hitStartIndex + ih]; + if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) { + fNofBinEntries[GetBin(hit.X(), hit.Y())]++; + nEntries++; + } } - } - fEntries.reset(nEntries); + fEntries.reset(nEntries); - for (int bin = 0; bin < fN; bin++) { - fFirstBinEntryIndex[bin + 1] = fFirstBinEntryIndex[bin] + fNofBinEntries[bin]; - fNofBinEntries[bin] = 0; - } - fNofBinEntries[fN] = 0; - - fMaxRangeX = 0.; - fMaxRangeY = 0.; - fMaxRangeT = 0.; - - for (ca::HitIndex_t ih = 0; ih < nHits; ih++) { - const ca::Hit& hit = hits[hitStartIndex + ih]; - if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) { - int bin = GetBin(hit.X(), hit.Y()); - fEntries[fFirstBinEntryIndex[bin] + fNofBinEntries[bin]].Set(hit, hitStartIndex + ih); - fNofBinEntries[bin]++; - fMaxRangeX = std::max(fMaxRangeX, hit.RangeX()); - fMaxRangeY = std::max(fMaxRangeY, hit.RangeY()); - fMaxRangeT = std::max(fMaxRangeT, hit.RangeT()); + for (int bin = 0; bin < fN; bin++) { + fFirstBinEntryIndex[bin + 1] = fFirstBinEntryIndex[bin] + fNofBinEntries[bin]; + fNofBinEntries[bin] = 0; } - } -} + fNofBinEntries[fN] = 0; -void Grid::RemoveUsedHits(const Vector<ca::Hit>& hits, const Vector<unsigned char>& hitKeyFlags) -{ - int nEntries = 0; - fMaxRangeX = 0.; - fMaxRangeY = 0.; - fMaxRangeT = 0.; - - for (int bin = 0; bin < fN; bin++) { - ca::HitIndex_t firstEntryOld = fFirstBinEntryIndex[bin]; - fFirstBinEntryIndex[bin] = nEntries; - fNofBinEntries[bin] = 0; - for (ca::HitIndex_t i = firstEntryOld; i < fFirstBinEntryIndex[bin + 1]; i++) { - auto entry = fEntries[i]; - const ca::Hit& hit = hits[entry.GetObjectId()]; + fMaxRangeX = 0.; + fMaxRangeY = 0.; + fMaxRangeT = 0.; + for (ca::HitIndex_t ih = 0; ih < nHits; ih++) { + const ca::Hit& hit = hits[hitStartIndex + ih]; if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) { - fEntries[nEntries] = entry; - nEntries++; + int bin = GetBin(hit.X(), hit.Y()); + fEntries[fFirstBinEntryIndex[bin] + fNofBinEntries[bin]].Set(hit, hitStartIndex + ih); fNofBinEntries[bin]++; - fMaxRangeX = std::max(fMaxRangeX, entry.RangeX()); - fMaxRangeY = std::max(fMaxRangeY, entry.RangeY()); - fMaxRangeT = std::max(fMaxRangeT, entry.RangeT()); + fMaxRangeX = std::max(fMaxRangeX, hit.RangeX()); + fMaxRangeY = std::max(fMaxRangeY, hit.RangeY()); + fMaxRangeT = std::max(fMaxRangeT, hit.RangeT()); + } + } + } + + void Grid::RemoveUsedHits(const Vector<ca::Hit>& hits, const Vector<unsigned char>& hitKeyFlags) + { + int nEntries = 0; + fMaxRangeX = 0.; + fMaxRangeY = 0.; + fMaxRangeT = 0.; + + for (int bin = 0; bin < fN; bin++) { + ca::HitIndex_t firstEntryOld = fFirstBinEntryIndex[bin]; + fFirstBinEntryIndex[bin] = nEntries; + fNofBinEntries[bin] = 0; + for (ca::HitIndex_t i = firstEntryOld; i < fFirstBinEntryIndex[bin + 1]; i++) { + auto entry = fEntries[i]; + const ca::Hit& hit = hits[entry.GetObjectId()]; + + if (!(hitKeyFlags[hit.FrontKey()] || hitKeyFlags[hit.BackKey()])) { + fEntries[nEntries] = entry; + nEntries++; + fNofBinEntries[bin]++; + fMaxRangeX = std::max(fMaxRangeX, entry.RangeX()); + fMaxRangeY = std::max(fMaxRangeY, entry.RangeY()); + fMaxRangeT = std::max(fMaxRangeT, entry.RangeT()); + } } } + fFirstBinEntryIndex[fN] = nEntries; + fNofBinEntries[fN] = 0; + fEntries.shrink(nEntries); } - fFirstBinEntryIndex[fN] = nEntries; - fNofBinEntries[fN] = 0; - fEntries.shrink(nEntries); -} +} // namespace cbm::algo::ca \ No newline at end of file diff --git a/algo/ca/core/pars/CaConfigReader.cxx b/algo/ca/core/pars/CaConfigReader.cxx index 88dd41f4ef04796704b96659bdc2ddf5f516f5cd..5df9fc277ea0d55275171c03e252f0b97c74fd01 100644 --- a/algo/ca/core/pars/CaConfigReader.cxx +++ b/algo/ca/core/pars/CaConfigReader.cxx @@ -22,10 +22,10 @@ #include <yaml-cpp/yaml.h> -using namespace std::string_literals; using cbm::algo::ca::ConfigReader; using cbm::algo::ca::EDetectorID; using cbm::algo::ca::InitManager; +using cbm::algo::ca::Iteration; // --------------------------------------------------------------------------------------------------------------------- // diff --git a/algo/ca/core/pars/CaConfigReader.h b/algo/ca/core/pars/CaConfigReader.h index d2d4b2cbe3aff562f51c986f98893aa03ce55afd..9178f975c14a8d0aec99adf0dd92b94f1048f040 100644 --- a/algo/ca/core/pars/CaConfigReader.h +++ b/algo/ca/core/pars/CaConfigReader.h @@ -18,8 +18,6 @@ #include <yaml-cpp/yaml.h> -using namespace cbm::algo::ca; - namespace YAML { class Node; diff --git a/algo/ca/core/pars/CaInitManager.cxx b/algo/ca/core/pars/CaInitManager.cxx index 02530363ecbd5dff79a54d9ba886182f6cd857bb..4d3996da3efaef0f25b365b7e3273f9ad7b8615b 100644 --- a/algo/ca/core/pars/CaInitManager.cxx +++ b/algo/ca/core/pars/CaInitManager.cxx @@ -20,544 +20,543 @@ #include <fstream> #include <sstream> -using namespace constants; +namespace cbm::algo::ca +{ + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::AddStation(const StationInitializer& inStation) { fvStationInfo.push_back(inStation); } + + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::CheckInit() + { + this->CheckCAIterationsInit(); + this->CheckStationsInfoInit(); + fbConfigIsRead = false; + fbGeometryConfigLock = false; + } + + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ClearSetupInfo() + { + // Clear stations set and a thickness map + fvStationInfo.clear(); + fInitController.SetFlag(EInitKey::kStationsInfo, false); + + // Set number of stations do default values + this->ClearStationLayout(); + + // Clear field info + fParameters.fVertexFieldRegion = kf::FieldRegion<fvec>(); + fParameters.fVertexFieldValue = kf::FieldValue<fvec>(); + fInitController.SetFlag(EInitKey::kPrimaryVertexField, false); + + // Clear target position + fParameters.fTargetPos.fill(Undef<float>); + fTargetZ = 0.; + fInitController.SetFlag(EInitKey::kTargetPos, false); + + // Clear field function + fFieldFunction = FieldFunction_t([](const double(&)[3], double(&)[3]) {}); + fInitController.SetFlag(EInitKey::kFieldFunction, false); + + // Clear other flags + fParameters.fRandomSeed = 1; + fParameters.fGhostSuppression = 0; + fInitController.SetFlag(EInitKey::kRandomSeed, false); + fInitController.SetFlag(EInitKey::kGhostSuppression, false); + + fParameters.fMisalignmentX.fill(0.); + fParameters.fMisalignmentY.fill(0.); + fParameters.fMisalignmentT.fill(0.); + + fParameters.fDevIsIgnoreHitSearchAreas = false; + fParameters.fDevIsUseOfOriginalField = false; + fParameters.fDevIsMatchDoubletsViaMc = false; + fParameters.fDevIsMatchTripletsViaMc = false; + fParameters.fDevIsExtendTracksViaMc = false; + fParameters.fDevIsSuppressOverlapHitsViaMc = false; + fParameters.fDevIsParSearchWUsed = false; + } + + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ClearCAIterations() + { + fParameters.fCAIterations.clear(); + fCAIterationsNumberCrosscheck = -1; + fInitController.SetFlag(EInitKey::kCAIterations, false); + fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck, false); + } + + // -------------------------------------------------------------------------------------------------------------------- + // NOTE: this function should be called once in the SendParameters + bool InitManager::FormParametersContainer() + { + // Read configuration files + this->ReadInputConfigs(); + if (!fbConfigIsRead) { // Check config reading status + return false; + } -using cbm::algo::ca::InitManager; -using cbm::algo::ca::Station; -using cbm::algo::ca::StationInitializer; + if (!fParameters.fDevIsParSearchWUsed) { + fInitController.SetFlag(EInitKey::kSearchWindows, true); + } -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::AddStation(const StationInitializer& inStation) { fvStationInfo.push_back(inStation); } + // Apply magnetic field to the station info objects + std::for_each(fvStationInfo.begin(), fvStationInfo.end(), [&](auto& st) { st.SetFieldFunction(fFieldFunction); }); -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::CheckInit() -{ - this->CheckCAIterationsInit(); - this->CheckStationsInfoInit(); - fbConfigIsRead = false; - fbGeometryConfigLock = false; -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ClearSetupInfo() -{ - // Clear stations set and a thickness map - fvStationInfo.clear(); - fInitController.SetFlag(EInitKey::kStationsInfo, false); - - // Set number of stations do default values - this->ClearStationLayout(); - - // Clear field info - fParameters.fVertexFieldRegion = kf::FieldRegion<fvec>(); - fParameters.fVertexFieldValue = kf::FieldValue<fvec>(); - fInitController.SetFlag(EInitKey::kPrimaryVertexField, false); - - // Clear target position - fParameters.fTargetPos.fill(Undef<float>); - fTargetZ = 0.; - fInitController.SetFlag(EInitKey::kTargetPos, false); - - // Clear field function - fFieldFunction = FieldFunction_t([](const double(&)[3], double(&)[3]) {}); - fInitController.SetFlag(EInitKey::kFieldFunction, false); - - // Clear other flags - fParameters.fRandomSeed = 1; - fParameters.fGhostSuppression = 0; - fInitController.SetFlag(EInitKey::kRandomSeed, false); - fInitController.SetFlag(EInitKey::kGhostSuppression, false); - - fParameters.fMisalignmentX.fill(0.); - fParameters.fMisalignmentY.fill(0.); - fParameters.fMisalignmentT.fill(0.); - - fParameters.fDevIsIgnoreHitSearchAreas = false; - fParameters.fDevIsUseOfOriginalField = false; - fParameters.fDevIsMatchDoubletsViaMc = false; - fParameters.fDevIsMatchTripletsViaMc = false; - fParameters.fDevIsExtendTracksViaMc = false; - fParameters.fDevIsSuppressOverlapHitsViaMc = false; - fParameters.fDevIsParSearchWUsed = false; -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ClearCAIterations() -{ - fParameters.fCAIterations.clear(); - fCAIterationsNumberCrosscheck = -1; - fInitController.SetFlag(EInitKey::kCAIterations, false); - fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck, false); -} - -// ---------------------------------------------------------------------------------------------------------------------- -// NOTE: this function should be called once in the SendParameters -bool InitManager::FormParametersContainer() -{ - // Read configuration files - this->ReadInputConfigs(); - if (!fbConfigIsRead) { // Check config reading status - return false; - } + // Check initialization + this->CheckInit(); - if (!fParameters.fDevIsParSearchWUsed) { - fInitController.SetFlag(EInitKey::kSearchWindows, true); - } + if (!fInitController.IsFinalized()) { + LOG(error) << "ca::InitManager: Attempt to form parameters container before all necessary fields were initialized" + << fInitController.ToString(); + return false; + } - // Apply magnetic field to the station info objects - std::for_each(fvStationInfo.begin(), fvStationInfo.end(), [&](auto& st) { st.SetFieldFunction(fFieldFunction); }); + { // Form array of stations + auto destIt = fParameters.fStations.begin(); + for (const auto& station : fvStationInfo) { + if (!station.GetTrackingStatus()) { + continue; + } + *destIt = station.GetStation(); + ++destIt; + } + } - // Check initialization - this->CheckInit(); + // Check the consistency of the parameters object. If object inconsistent, it throws std::logic_error + try { + fParameters.CheckConsistency(); + } + catch (const std::logic_error& err) { + LOG(error) << "ca::InitManager: parameters container consistency check failed. Reason: " << err.what(); + return false; + } - if (!fInitController.IsFinalized()) { - LOG(error) << "ca::InitManager: Attempt to form parameters container before all necessary fields were initialized" - << fInitController.ToString(); - return false; + return true; } - { // Form array of stations - auto destIt = fParameters.fStations.begin(); - for (const auto& station : fvStationInfo) { - if (!station.GetTrackingStatus()) { - continue; - } - *destIt = station.GetStation(); - ++destIt; + // -------------------------------------------------------------------------------------------------------------------- + // + int InitManager::GetNstationsActive() const + { + if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { + std::stringstream msg; + msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized"; + throw std::runtime_error(msg.str()); } + return fParameters.GetNstationsActive(); } - // Check the consistency of the parameters object. If object inconsistent, it throws std::logic_error - try { - fParameters.CheckConsistency(); - } - catch (const std::logic_error& err) { - LOG(error) << "ca::InitManager: parameters container consistency check failed. Reason: " << err.what(); - return false; + // -------------------------------------------------------------------------------------------------------------------- + // + int InitManager::GetNstationsActive(EDetectorID detectorID) const + { + if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { + std::stringstream msg; + msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized"; + throw std::runtime_error(msg.str()); + } + return fParameters.GetNstationsActive(detectorID); } - return true; -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -int InitManager::GetNstationsActive() const -{ - if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { - std::stringstream msg; - msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized"; - throw std::runtime_error(msg.str()); + // -------------------------------------------------------------------------------------------------------------------- + // + int InitManager::GetNstationsGeometry() const + { + if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { + std::stringstream msg; + msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized"; + throw std::runtime_error(msg.str()); + } + return fParameters.GetNstationsGeometry(); } - return fParameters.GetNstationsActive(); -} -// ---------------------------------------------------------------------------------------------------------------------- -// -int InitManager::GetNstationsActive(EDetectorID detectorID) const -{ - if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { - std::stringstream msg; - msg << "ca::InitManager: number of active stations cannot be accessed until the station layout is initialized"; - throw std::runtime_error(msg.str()); + // -------------------------------------------------------------------------------------------------------------------- + // + int InitManager::GetNstationsGeometry(EDetectorID detectorID) const + { + if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { + std::stringstream msg; + msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized"; + throw std::runtime_error(msg.str()); + } + return fParameters.GetNstationsGeometry(detectorID); } - return fParameters.GetNstationsActive(detectorID); -} -// ---------------------------------------------------------------------------------------------------------------------- -// -int InitManager::GetNstationsGeometry() const -{ - if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { - std::stringstream msg; - msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized"; - throw std::runtime_error(msg.str()); + // -------------------------------------------------------------------------------------------------------------------- + // + std::vector<StationInitializer>& InitManager::GetStationInfo() + { + if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { + std::stringstream msg; + msg << "ca::InitManager: station info container cannot be accessed until the station layout is initialized"; + throw std::runtime_error(msg.str()); + } + return fvStationInfo; } - return fParameters.GetNstationsGeometry(); -} -// ---------------------------------------------------------------------------------------------------------------------- -// -int InitManager::GetNstationsGeometry(EDetectorID detectorID) const -{ - if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { - std::stringstream msg; - msg << "ca::InitManager: number of geometry stations cannot be accessed until the station layout is initialized"; - throw std::runtime_error(msg.str()); - } - return fParameters.GetNstationsGeometry(detectorID); -} -// ---------------------------------------------------------------------------------------------------------------------- -// -std::vector<StationInitializer>& InitManager::GetStationInfo() -{ - if (!fInitController.GetFlag(EInitKey::kStationLayoutInitialized)) { - std::stringstream msg; - msg << "ca::InitManager: station info container cannot be accessed until the station layout is initialized"; - throw std::runtime_error(msg.str()); - } - return fvStationInfo; -} + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::InitStationLayout() + { + LOG(info) << "ca::InitManager::InitStationLayout(): ...."; + this->ClearStationLayout(); + std::sort(fvStationInfo.begin(), fvStationInfo.end()); + for (const auto& aStation : fvStationInfo) { + ++fParameters.fvFirstGeoId[static_cast<int>(aStation.GetDetectorID()) + 1]; + } + for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()) - 1; ++iDet) { + fParameters.fvFirstGeoId[iDet + 1] += fParameters.fvFirstGeoId[iDet]; + } -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::InitStationLayout() -{ - LOG(info) << "ca::InitManager::InitStationLayout(): ...."; - this->ClearStationLayout(); - std::sort(fvStationInfo.begin(), fvStationInfo.end()); + fParameters.fNstationsActiveTotal = 0; + for (int iStGeo = 0; iStGeo < static_cast<int>(fvStationInfo.size()); ++iStGeo) { + const auto& aStation = fvStationInfo[iStGeo]; + int iDet = static_cast<int>(aStation.GetDetectorID()); + int iStLocal = aStation.GetStationID(); + // Fill local -> geo map + fParameters.fvGeoToLocalIdMap[iStGeo] = std::make_pair(aStation.GetDetectorID(), iStLocal); + // Fill geo -> local map + fParameters.fvLocalToGeoIdMap[fParameters.fvFirstGeoId[iDet] + iStLocal] = iStGeo; + // Fill geo <-> active map + int iStActive = aStation.GetTrackingStatus() ? fParameters.fNstationsActiveTotal++ : -1; + fParameters.fvGeoToActiveMap[iStGeo] = iStActive; + if (iStActive > -1) { + fParameters.fvActiveToGeoMap[iStActive] = iStGeo; + } + } + fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true); - for (const auto& aStation : fvStationInfo) { - ++fParameters.fvFirstGeoId[static_cast<int>(aStation.GetDetectorID()) + 1]; - } - for (int iDet = 1; iDet < static_cast<int>(fParameters.fvFirstGeoId.size()) - 1; ++iDet) { - fParameters.fvFirstGeoId[iDet + 1] += fParameters.fvFirstGeoId[iDet]; + for (auto& aStation : fvStationInfo) { + aStation.SetGeoLayerID(fParameters.GetStationIndexGeometry(aStation.GetStationID(), aStation.GetDetectorID())); + } } - fParameters.fNstationsActiveTotal = 0; - for (int iStGeo = 0; iStGeo < static_cast<int>(fvStationInfo.size()); ++iStGeo) { - const auto& aStation = fvStationInfo[iStGeo]; - int iDet = static_cast<int>(aStation.GetDetectorID()); - int iStLocal = aStation.GetStationID(); - // Fill local -> geo map - fParameters.fvGeoToLocalIdMap[iStGeo] = std::make_pair(aStation.GetDetectorID(), iStLocal); - // Fill geo -> local map - fParameters.fvLocalToGeoIdMap[fParameters.fvFirstGeoId[iDet] + iStLocal] = iStGeo; - // Fill geo <-> active map - int iStActive = aStation.GetTrackingStatus() ? fParameters.fNstationsActiveTotal++ : -1; - fParameters.fvGeoToActiveMap[iStGeo] = iStActive; - if (iStActive > -1) { - fParameters.fvActiveToGeoMap[iStActive] = iStGeo; + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::InitTargetField(double zStep) + { + if (fInitController.GetFlag(EInitKey::kPrimaryVertexField)) { + LOG(warn) << "ca::InitManager::InitTargetField: attempt to reinitialize the field value and field region " + << "near target. Ignore"; + return; } - } - fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true); - for (auto& aStation : fvStationInfo) { - aStation.SetGeoLayerID(fParameters.GetStationIndexGeometry(aStation.GetStationID(), aStation.GetDetectorID())); + // Check for field function + if (!fInitController.GetFlag(EInitKey::kFieldFunction)) { + std::stringstream msg; + msg << "Attempt to initialize the field value and field region near target before initializing field function"; + throw std::runtime_error(msg.str()); + } + // Check for target defined + if (!fInitController.GetFlag(EInitKey::kTargetPos)) { + std::stringstream msg; + msg << "Attempt to initialize the field value and field region near target before the target position" + << "initialization"; + throw std::runtime_error(msg.str()); + } + constexpr int nDimensions{3}; + constexpr int nPointsNodal{3}; + + std::array<double, nPointsNodal> inputNodalZ{fTargetZ, fTargetZ + zStep, fTargetZ + 2. * zStep}; + std::array<kf::FieldValue<fvec>, nPointsNodal> B{}; + std::array<fvec, nPointsNodal> z{}; + // loop over nodal points + for (int idx = 0; idx < nPointsNodal; ++idx) { + double point[nDimensions]{0., 0., inputNodalZ[idx]}; + double field[nDimensions]{}; + fFieldFunction(point, field); + z[idx] = inputNodalZ[idx]; + B[idx].Set(field[0], field[1], field[2]); + } // loop over nodal points: end + fParameters.fVertexFieldRegion.Set(B[0], z[0], B[1], z[1], B[2], z[2]); + fParameters.fVertexFieldValue = B[0]; + + fInitController.SetFlag(EInitKey::kPrimaryVertexField); + } + + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::PushBackCAIteration(const Iteration& iteration) + { + // TODO: probably some checks must be inserted here (S.Zharko) + if (!fInitController.GetFlag(EInitKey::kCAIterationsNumberCrosscheck)) { + std::stringstream msg; + msg << "Attempt to push back a CA track finder iteration before the number of iterations was defined"; + throw std::runtime_error(msg.str()); + } + fParameters.fCAIterations.push_back(iteration); + } + + // ------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ReadInputConfigs() + { + if (!fbConfigIsRead) { + LOG(info) << "ca::InitManager: reading parameter configuration ..."; + try { + auto configReader = ConfigReader(this, 4); + configReader.SetMainConfigPath(fsConfigInputMain); + configReader.SetUserConfigPath(fsConfigInputUser); + configReader.SetGeometryLock(fbGeometryConfigLock); + configReader.Read(); + fbConfigIsRead = true; + LOG(info) << "ca::InitManager: reading parameter configuration ... \033[1;32mdone\033[0m"; + } + catch (const std::runtime_error& err) { + LOG(error) << "ca::InitManager: reading parameter configuration ... \033[1;31mfail\033[0m. Reason: " + << err.what(); + } + } } -} -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::InitTargetField(double zStep) -{ - if (fInitController.GetFlag(EInitKey::kPrimaryVertexField)) { - LOG(warn) << "ca::InitManager::InitTargetField: attempt to reinitialize the field value and field region " - << "near target. Ignore"; - return; + // ------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ReadGeometrySetup(const std::string& fileName) + { + // Open input binary file + this->SetGeometrySetup(cbm::algo::kf::SetupBuilder::Load<fvec>(fileName)); } - // Check for field function - if (!fInitController.GetFlag(EInitKey::kFieldFunction)) { - std::stringstream msg; - msg << "Attempt to initialize the field value and field region near target before initializing field function"; - throw std::runtime_error(msg.str()); - } - // Check for target defined - if (!fInitController.GetFlag(EInitKey::kTargetPos)) { - std::stringstream msg; - msg << "Attempt to initialize the field value and field region near target before the target position" - << "initialization"; - throw std::runtime_error(msg.str()); - } - constexpr int nDimensions{3}; - constexpr int nPointsNodal{3}; - - std::array<double, nPointsNodal> inputNodalZ{fTargetZ, fTargetZ + zStep, fTargetZ + 2. * zStep}; - std::array<kf::FieldValue<fvec>, nPointsNodal> B{}; - std::array<fvec, nPointsNodal> z{}; - // loop over nodal points - for (int idx = 0; idx < nPointsNodal; ++idx) { - double point[nDimensions]{0., 0., inputNodalZ[idx]}; - double field[nDimensions]{}; - fFieldFunction(point, field); - z[idx] = inputNodalZ[idx]; - B[idx].Set(field[0], field[1], field[2]); - } // loop over nodal points: end - fParameters.fVertexFieldRegion.Set(B[0], z[0], B[1], z[1], B[2], z[2]); - fParameters.fVertexFieldValue = B[0]; - - fInitController.SetFlag(EInitKey::kPrimaryVertexField); -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::PushBackCAIteration(const Iteration& iteration) -{ - // TODO: probably some checks must be inserted here (S.Zharko) - if (!fInitController.GetFlag(EInitKey::kCAIterationsNumberCrosscheck)) { - std::stringstream msg; - msg << "Attempt to push back a CA track finder iteration before the number of iterations was defined"; - throw std::runtime_error(msg.str()); - } - fParameters.fCAIterations.push_back(iteration); -} + // ------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ReadParametersObject(const std::string& fileName) + { + using namespace constants; + // clrs::CL - end colored log + // clrs::GNb - bold green log + // clrs::RDb - bold red log -// --------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ReadInputConfigs() -{ - if (!fbConfigIsRead) { - LOG(info) << "ca::InitManager: reading parameter configuration ..."; - try { - auto configReader = ConfigReader(this, 4); - configReader.SetMainConfigPath(fsConfigInputMain); - configReader.SetUserConfigPath(fsConfigInputUser); - configReader.SetGeometryLock(fbGeometryConfigLock); - configReader.Read(); - fbConfigIsRead = true; - LOG(info) << "ca::InitManager: reading parameter configuration ... \033[1;32mdone\033[0m"; - } - catch (const std::runtime_error& err) { - LOG(error) << "ca::InitManager: reading parameter configuration ... \033[1;31mfail\033[0m. Reason: " - << err.what(); + // Open input binary file + std::ifstream ifs(fileName, std::ios::binary); + if (!ifs) { + std::stringstream msg; + msg << "ca::InitManager: parameters data file \"" << clrs::GNb << fileName << clrs::CL << "\" was not found"; + throw std::runtime_error(msg.str()); } - } -} -// --------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ReadGeometrySetup(const std::string& fileName) -{ - // Open input binary file - this->SetGeometrySetup(cbm::algo::kf::SetupBuilder::Load<fvec>(fileName)); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ReadParametersObject(const std::string& fileName) -{ - // clrs::CL - end colored log - // clrs::GNb - bold green log - // clrs::RDb - bold red log - - // Open input binary file - std::ifstream ifs(fileName, std::ios::binary); - if (!ifs) { - std::stringstream msg; - msg << "ca::InitManager: parameters data file \"" << clrs::GNb << fileName << clrs::CL << "\" was not found"; - throw std::runtime_error(msg.str()); - } + // Get L1InputData object + try { + boost::archive::binary_iarchive ia(ifs); + ia >> fParameters; + fbGeometryConfigLock = true; + } + catch (const std::exception&) { + std::stringstream msg; + msg << "ca::InitManager: parameters file \"" << clrs::GNb << fileName << clrs::CL + << "\" has incorrect data format or was corrupted"; + throw std::runtime_error(msg.str()); + } - // Get L1InputData object - try { - boost::archive::binary_iarchive ia(ifs); - ia >> fParameters; - fbGeometryConfigLock = true; - } - catch (const std::exception&) { - std::stringstream msg; - msg << "ca::InitManager: parameters file \"" << clrs::GNb << fileName << clrs::CL - << "\" has incorrect data format or was corrupted"; - throw std::runtime_error(msg.str()); + fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true); + fInitController.SetFlag(EInitKey::kPrimaryVertexField, true); + fInitController.SetFlag(EInitKey::kSearchWindows, true); } - fInitController.SetFlag(EInitKey::kStationLayoutInitialized, true); - fInitController.SetFlag(EInitKey::kPrimaryVertexField, true); - fInitController.SetFlag(EInitKey::kSearchWindows, true); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ReadSearchWindows(const std::string& fileName) -{ - // Open input binary file - std::ifstream ifs(fileName); - if (!ifs) { - std::stringstream msg; - msg << "ca::InitManager: search window file \"" << fileName << "\" was not found"; - throw std::runtime_error(msg.str()); - } + // ------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ReadSearchWindows(const std::string& fileName) + { + // Open input binary file + std::ifstream ifs(fileName); + if (!ifs) { + std::stringstream msg; + msg << "ca::InitManager: search window file \"" << fileName << "\" was not found"; + throw std::runtime_error(msg.str()); + } - try { - boost::archive::text_iarchive ia(ifs); - int nPars = -1; - int nWindows = -1; - ia >> nPars; - assert(nPars == 1); // Currently only the constant windows are available - ia >> nWindows; - std::stringstream errMsg; - for (int iW = 0; iW < nWindows; ++iW) { - SearchWindow swBuffer; - ia >> swBuffer; - int iStationID = swBuffer.GetStationID(); - int iTrackGrID = swBuffer.GetTrackGroupID(); - if (iStationID < 0 || iStationID > constants::size::MaxNstations) { - errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and " - << constants::size::MaxNstations << ")\n"; + try { + boost::archive::text_iarchive ia(ifs); + int nPars = -1; + int nWindows = -1; + ia >> nPars; + assert(nPars == 1); // Currently only the constant windows are available + ia >> nWindows; + std::stringstream errMsg; + for (int iW = 0; iW < nWindows; ++iW) { + SearchWindow swBuffer; + ia >> swBuffer; + int iStationID = swBuffer.GetStationID(); + int iTrackGrID = swBuffer.GetTrackGroupID(); + if (iStationID < 0 || iStationID > constants::size::MaxNstations) { + errMsg << "\t- wrong station id for entry " << iW << ": " << iStationID << " (should be between 0 and " + << constants::size::MaxNstations << ")\n"; + } + if (iTrackGrID < 0 || iTrackGrID > constants::size::MaxNtrackGroups) { + errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and " + << constants::size::MaxNtrackGroups << ")\n"; + } + fParameters.fSearchWindows[iTrackGrID * constants::size::MaxNstations + iStationID] = swBuffer; } - if (iTrackGrID < 0 || iTrackGrID > constants::size::MaxNtrackGroups) { - errMsg << "\t- wrong track group id for entry " << iW << ": " << iTrackGrID << " (should be between 0 and " - << constants::size::MaxNtrackGroups << ")\n"; + if (errMsg.str().size()) { + std::stringstream msg; + msg << "ca::InitManager: some errors occurred while reading search windows: " << errMsg.str(); + throw std::runtime_error(msg.str()); } - fParameters.fSearchWindows[iTrackGrID * constants::size::MaxNstations + iStationID] = swBuffer; } - if (errMsg.str().size()) { + catch (const std::exception& err) { std::stringstream msg; - msg << "ca::InitManager: some errors occurred while reading search windows: " << errMsg.str(); + msg << "search windows file \"" << fileName << "\" has incorrect data format or was corrupted. "; + msg << "Exception catched: " << err.what(); throw std::runtime_error(msg.str()); } - } - catch (const std::exception& err) { - std::stringstream msg; - msg << "search windows file \"" << fileName << "\" has incorrect data format or was corrupted. "; - msg << "Exception catched: " << err.what(); - throw std::runtime_error(msg.str()); - } - - fInitController.SetFlag(EInitKey::kSearchWindows, true); -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::SetCAIterationsNumberCrosscheck(int nIterations) -{ - fCAIterationsNumberCrosscheck = nIterations; - auto& iterationsContainer = fParameters.fCAIterations; - // NOTE: should be called to prevent multiple copies of objects between the memory reallocations - iterationsContainer.reserve(nIterations); - fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck); -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::SetFieldFunction(const FieldFunction_t& fieldFunction) -{ - if (!fInitController.GetFlag(EInitKey::kFieldFunction)) { - fFieldFunction = fieldFunction; - fInitController.SetFlag(EInitKey::kFieldFunction); - } - else { - LOG(warn) << "ca::InitManager::SetFieldFunction: attempt to reinitialize the field function. Ignored"; + fInitController.SetFlag(EInitKey::kSearchWindows, true); } -} -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::SetGhostSuppression(int ghostSuppression) -{ - if (fInitController.GetFlag(EInitKey::kGhostSuppression)) { - LOG(warn) << "ca::InitManager::SetGhostSuppression: attempt of reinitializating the ghost suppresion flag. Ignore"; - return; - } - fParameters.fGhostSuppression = ghostSuppression; - fInitController.SetFlag(EInitKey::kGhostSuppression); -} + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::SetCAIterationsNumberCrosscheck(int nIterations) + { + fCAIterationsNumberCrosscheck = nIterations; + auto& iterationsContainer = fParameters.fCAIterations; -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::SetRandomSeed(unsigned int seed) -{ - if (fInitController.GetFlag(EInitKey::kRandomSeed)) { - LOG(warn) << "ca::InitManager::SetRandomSeed: attempt of reinitializating the random seed. Ignore"; - return; + // NOTE: should be called to prevent multiple copies of objects between the memory reallocations + iterationsContainer.reserve(nIterations); + fInitController.SetFlag(EInitKey::kCAIterationsNumberCrosscheck); } - fParameters.fRandomSeed = seed; - fInitController.SetFlag(EInitKey::kRandomSeed); -} -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::SetTargetPosition(double x, double y, double z) -{ - if (fInitController.GetFlag(EInitKey::kTargetPos)) { - LOG(warn) << "ca::InitManager::SetTargetPosition: attempt to reinitialize the target position. Ignore"; - return; + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::SetFieldFunction(const FieldFunction_t& fieldFunction) + { + if (!fInitController.GetFlag(EInitKey::kFieldFunction)) { + fFieldFunction = fieldFunction; + fInitController.SetFlag(EInitKey::kFieldFunction); + } + else { + LOG(warn) << "ca::InitManager::SetFieldFunction: attempt to reinitialize the field function. Ignored"; + } } - /// Fill fvec target fields - fParameters.fTargetPos[0] = x; - fParameters.fTargetPos[1] = y; - fParameters.fTargetPos[2] = z; - /// Set additional field for z component in double precision - fTargetZ = z; - fInitController.SetFlag(EInitKey::kTargetPos); -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -Parameters<fvec>&& InitManager::TakeParameters() { return std::move(fParameters); } - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::WriteParametersObject(const std::string& fileName) const -{ - using clrs::CL; - using clrs::GNb; - // Open output binary file - std::ofstream ofs(fileName, std::ios::binary); - if (!ofs) { - std::stringstream msg; - msg << "ca::InitManager: failed opening file \"" << GNb << fileName << CL << "\" to write parameters object"; - throw std::runtime_error(msg.str()); + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::SetGhostSuppression(int ghostSuppression) + { + if (fInitController.GetFlag(EInitKey::kGhostSuppression)) { + LOG(warn) + << "ca::InitManager::SetGhostSuppression: attempt of reinitializating the ghost suppresion flag. Ignore"; + return; + } + fParameters.fGhostSuppression = ghostSuppression; + fInitController.SetFlag(EInitKey::kGhostSuppression); } - LOG(info) << "ca::InitManager: writing CA parameters object to file \"" << GNb << fileName << '\"' << CL; - - // Serialize L1Parameters object and write - boost::archive::binary_oarchive oa(ofs); - oa << fParameters; -} - -// ---------------------------------------------------------------------------------------------------------------------- -// -void InitManager::CheckCAIterationsInit() -{ - bool ifInitPassed = true; - if (!fInitController.GetFlag(EInitKey::kCAIterations)) { - int nIterationsActual = fParameters.fCAIterations.size(); - int nIterationsExpected = fCAIterationsNumberCrosscheck; - if (nIterationsActual != nIterationsExpected) { - LOG(warn) << "ca::InitManager::CheckCAIterations: incorrect number of iterations registered: " - << nIterationsActual << " of " << nIterationsExpected << " expected"; - ifInitPassed = false; + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::SetRandomSeed(unsigned int seed) + { + if (fInitController.GetFlag(EInitKey::kRandomSeed)) { + LOG(warn) << "ca::InitManager::SetRandomSeed: attempt of reinitializating the random seed. Ignore"; + return; } + fParameters.fRandomSeed = seed; + fInitController.SetFlag(EInitKey::kRandomSeed); } - fInitController.SetFlag(EInitKey::kCAIterations, ifInitPassed); -} -// ---------------------------------------------------------------------------------------------------------------------- -// TODO: REWRITE! and add const qualifier (S.Zharko) -void InitManager::CheckStationsInfoInit() -{ - bool ifInitPassed = true; - if (!fInitController.GetFlag(EInitKey::kStationsInfo)) { - // (1) Check the stations themselves - bool bStationsFinalized = std::all_of(fvStationInfo.begin(), fvStationInfo.end(), - [](const auto& st) { return st.GetInitController().IsFinalized(); }); - if (!bStationsFinalized) { - std::stringstream msg; - msg << "ca::InitManager: At least one of the StationInitializer objects is not finalized"; + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::SetTargetPosition(double x, double y, double z) + { + if (fInitController.GetFlag(EInitKey::kTargetPos)) { + LOG(warn) << "ca::InitManager::SetTargetPosition: attempt to reinitialize the target position. Ignore"; + return; } - // (2) Check for maximum allowed number of stations - if (fParameters.GetNstationsGeometry() > constants::size::MaxNstations) { + /// Fill fvec target fields + fParameters.fTargetPos[0] = x; + fParameters.fTargetPos[1] = y; + fParameters.fTargetPos[2] = z; + /// Set additional field for z component in double precision + fTargetZ = z; + fInitController.SetFlag(EInitKey::kTargetPos); + } + + // -------------------------------------------------------------------------------------------------------------------- + // + Parameters<fvec>&& InitManager::TakeParameters() { return std::move(fParameters); } + + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::WriteParametersObject(const std::string& fileName) const + { + using constants::clrs::CL; + using constants::clrs::GNb; + // Open output binary file + std::ofstream ofs(fileName, std::ios::binary); + if (!ofs) { std::stringstream msg; - msg << "Actual total number of registered stations in geometry (" << fParameters.GetNstationsGeometry() - << ") is larger then possible (" << constants::size::MaxNstations - << "). Please, select another set of active tracking detectors or recompile the code with enlarged" - << " constants::size::MaxNstations value"; + msg << "ca::InitManager: failed opening file \"" << GNb << fileName << CL << "\" to write parameters object"; throw std::runtime_error(msg.str()); } - } - fInitController.SetFlag(EInitKey::kStationsInfo, ifInitPassed); -} -// --------------------------------------------------------------------------------------------------------------------- -// -void InitManager::ClearStationLayout() -{ - fParameters.fvFirstGeoId.fill(0); - fParameters.fvLocalToGeoIdMap.fill(0); - fParameters.fvGeoToLocalIdMap.fill(std::make_pair(static_cast<EDetectorID>(0), -1)); - fParameters.fvGeoToActiveMap.fill(-1); // Note: by default all the stations are inactive - fParameters.fvActiveToGeoMap.fill(0); - fParameters.fNstationsActiveTotal = -1; - fInitController.SetFlag(EInitKey::kStationLayoutInitialized, false); -} + LOG(info) << "ca::InitManager: writing CA parameters object to file \"" << GNb << fileName << '\"' << CL; + + // Serialize L1Parameters object and write + boost::archive::binary_oarchive oa(ofs); + oa << fParameters; + } + + // -------------------------------------------------------------------------------------------------------------------- + // + void InitManager::CheckCAIterationsInit() + { + bool ifInitPassed = true; + if (!fInitController.GetFlag(EInitKey::kCAIterations)) { + int nIterationsActual = fParameters.fCAIterations.size(); + int nIterationsExpected = fCAIterationsNumberCrosscheck; + if (nIterationsActual != nIterationsExpected) { + LOG(warn) << "ca::InitManager::CheckCAIterations: incorrect number of iterations registered: " + << nIterationsActual << " of " << nIterationsExpected << " expected"; + ifInitPassed = false; + } + } + fInitController.SetFlag(EInitKey::kCAIterations, ifInitPassed); + } + + // -------------------------------------------------------------------------------------------------------------------- + // TODO: REWRITE! and add const qualifier (S.Zharko) + void InitManager::CheckStationsInfoInit() + { + bool ifInitPassed = true; + if (!fInitController.GetFlag(EInitKey::kStationsInfo)) { + // (1) Check the stations themselves + bool bStationsFinalized = std::all_of(fvStationInfo.begin(), fvStationInfo.end(), + [](const auto& st) { return st.GetInitController().IsFinalized(); }); + if (!bStationsFinalized) { + std::stringstream msg; + msg << "ca::InitManager: At least one of the StationInitializer objects is not finalized"; + } + + // (2) Check for maximum allowed number of stations + if (fParameters.GetNstationsGeometry() > constants::size::MaxNstations) { + std::stringstream msg; + msg << "Actual total number of registered stations in geometry (" << fParameters.GetNstationsGeometry() + << ") is larger then possible (" << constants::size::MaxNstations + << "). Please, select another set of active tracking detectors or recompile the code with enlarged" + << " constants::size::MaxNstations value"; + throw std::runtime_error(msg.str()); + } + } + fInitController.SetFlag(EInitKey::kStationsInfo, ifInitPassed); + } + + // ------------------------------------------------------------------------------------------------------------------- + // + void InitManager::ClearStationLayout() + { + fParameters.fvFirstGeoId.fill(0); + fParameters.fvLocalToGeoIdMap.fill(0); + fParameters.fvGeoToLocalIdMap.fill(std::make_pair(static_cast<EDetectorID>(0), -1)); + fParameters.fvGeoToActiveMap.fill(-1); // Note: by default all the stations are inactive + fParameters.fvActiveToGeoMap.fill(0); + fParameters.fNstationsActiveTotal = -1; + fInitController.SetFlag(EInitKey::kStationLayoutInitialized, false); + } +} // namespace cbm::algo::ca \ No newline at end of file diff --git a/algo/ca/core/pars/CaParameters.cxx b/algo/ca/core/pars/CaParameters.cxx index c89279a12c1c24c77b9b03cc28d931f4ad47b931..286b3c42e98c6e505993b5a876580b74656e4f30 100644 --- a/algo/ca/core/pars/CaParameters.cxx +++ b/algo/ca/core/pars/CaParameters.cxx @@ -311,7 +311,7 @@ std::string Parameters<DataT>::ToString(int verbosity, int indentLevel) const msg << indent << indentCh << "Random seed: " << fRandomSeed << '\n'; msg << indent << indentCh << "Max number of doublets per singlet: " << fMaxDoubletsPerSinglet << '\n'; msg << indent << indentCh << "Max number of triplets per doublet: " << fMaxTripletPerDoublets << '\n'; - msg << indent << indentCh << "Ghost suppresion: " << fGhostSuppression << '\n'; + msg << indent << indentCh << "Ghost suppression: " << fGhostSuppression << '\n'; msg << indent << clrs::CLb << "CA TRACK FINDER ITERATIONS:\n" << clrs::CL; msg << Iteration::ToTableFromVector(fCAIterations); msg << indent << clrs::CLb << "GEOMETRY:\n" << clrs::CL; diff --git a/algo/ca/core/pars/CaStation.cxx b/algo/ca/core/pars/CaStation.cxx index ce84b8ce17f16886e0d81234bc5cab3b084e53e2..a83c1f974f1fe3559db7a50673007c0a34304af1 100644 --- a/algo/ca/core/pars/CaStation.cxx +++ b/algo/ca/core/pars/CaStation.cxx @@ -9,104 +9,103 @@ #include <iomanip> #include <sstream> -using namespace cbm::algo::ca; - -//------------------------------------------------------------------------------------------------------------------------------------ -// -template<typename DataT> -void Station<DataT>::CheckConsistency() const +namespace cbm::algo::ca { - /// Integer fields initialization checks + // -------------------------------------------------------------------------------------------------------------------- + // + template<typename DataT> + void Station<DataT>::CheckConsistency() const + { + /// Integer fields initialization checks - if (type < 0) { - std::stringstream msg; - msg << "CaStation: station type was not initialized (type = " << type << ", type > 0)"; - throw std::logic_error(msg.str()); - } + if (type < 0) { + std::stringstream msg; + msg << "CaStation: station type was not initialized (type = " << type << ", type > 0)"; + throw std::logic_error(msg.str()); + } - if (timeInfo != 0 && timeInfo != 1) { - std::stringstream msg; - msg << "CaStation: illegal time information flag (timeInfo = " << timeInfo << ", " - << "0 [time information is not used] or 1 [time information is used] expected)"; - throw std::logic_error(msg.str()); - } + if (timeInfo != 0 && timeInfo != 1) { + std::stringstream msg; + msg << "CaStation: illegal time information flag (timeInfo = " << timeInfo << ", " + << "0 [time information is not used] or 1 [time information is used] expected)"; + throw std::logic_error(msg.str()); + } - if (fieldStatus != 0 && fieldStatus != 1) { - std::stringstream msg; - msg << "CaStation: illegal field status flag (fieldStatus = " << fieldStatus << ", " - << "0 [station is outside the field] or 1 [station is inside the field] expected"; - throw std::logic_error(msg.str()); - } + if (fieldStatus != 0 && fieldStatus != 1) { + std::stringstream msg; + msg << "CaStation: illegal field status flag (fieldStatus = " << fieldStatus << ", " + << "0 [station is outside the field] or 1 [station is inside the field] expected"; + throw std::logic_error(msg.str()); + } - /// SIMD vector checks: all the words in a SIMD vector must be equal - // TODO: SZh 06.06.2024: Do we still need these checks? - kfutils::CheckSimdVectorEquality<DataT>(fZ, "CaStation::fZ"); - kfutils::CheckSimdVectorEquality<DataT>(Xmax, "CaStation::Xmax"); - kfutils::CheckSimdVectorEquality<DataT>(Ymax, "CaStation::Ymax"); + /// SIMD vector checks: all the words in a SIMD vector must be equal + // TODO: SZh 06.06.2024: Do we still need these checks? + kfutils::CheckSimdVectorEquality<DataT>(fZ, "CaStation::fZ"); + kfutils::CheckSimdVectorEquality<DataT>(Xmax, "CaStation::Xmax"); + kfutils::CheckSimdVectorEquality<DataT>(Ymax, "CaStation::Ymax"); - /// Inner and outer radia checks: - /// (i) both Xmax and Ymax must be > 0 + /// Inner and outer radia checks: + /// (i) both Xmax and Ymax must be > 0 - if (this->GetXmax<float>() < 0. || this->GetYmax<float>() < 0.) { - std::stringstream msg; - msg << "CaStation: " << this->ToString() << " has incorrect sizes: " - << "Xmax = " << this->GetXmax<float>() << " [cm], Ymax = " << this->GetYmax<float>() - << " [cm] (0 < Xmax && 0 < Ymax expected)"; - throw std::logic_error(msg.str()); - } - - /// Check consistency of other members + if (this->GetXmax<float>() < 0. || this->GetYmax<float>() < 0.) { + std::stringstream msg; + msg << "CaStation: " << this->ToString() << " has incorrect sizes: " + << "Xmax = " << this->GetXmax<float>() << " [cm], Ymax = " << this->GetYmax<float>() + << " [cm] (0 < Xmax && 0 < Ymax expected)"; + throw std::logic_error(msg.str()); + } - //materialInfo.CheckConsistency(); - // TODO: Temporarily switched off, because Much has RL = 0, which is actually incorrect, but really is not used. - // One should provide average radiation length values for each Much layer (S.Zharko) - fieldSlice.CheckConsistency(); -} + /// Check consistency of other members -//------------------------------------------------------------------------------------------------------------------------------------ -// -template<typename DataT> -std::string Station<DataT>::ToString(int verbosityLevel, int indentLevel, bool isHeader) const -{ - std::stringstream msg{}; - constexpr char indentChar = '\t'; - constexpr char columnSize = 15; - std::string indent(indentLevel, indentChar); - if (verbosityLevel == 0) { - msg << "station type = " << type << ", z = " << this->GetZ<float>() << " cm"; + //materialInfo.CheckConsistency(); + // TODO: Temporarily switched off, because Much has RL = 0, which is actually incorrect, but really is not used. + // One should provide average radiation length values for each Much layer (S.Zharko) + fieldSlice.CheckConsistency(); } - else { - if (isHeader) { - verbosityLevel = 0; - msg << indent; - msg << std::setw(columnSize) << std::setfill(' ') << "type" << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << "time status" << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << "field status" << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << "geo layer ID" << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << "z [cm]" << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << "Xmax [cm]" << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << "Ymax [cm]"; + + // -------------------------------------------------------------------------------------------------------------------- + // + template<typename DataT> + std::string Station<DataT>::ToString(int verbosityLevel, int indentLevel, bool isHeader) const + { + std::stringstream msg{}; + constexpr char indentChar = '\t'; + constexpr char columnSize = 15; + std::string indent(indentLevel, indentChar); + if (verbosityLevel == 0) { + msg << "station type = " << type << ", z = " << this->GetZ<float>() << " cm"; } else { - msg << indent; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetType() << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetTimeStatus() << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetFieldStatus() << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetGeoLayerID() << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetZ<float>() << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetXmax<float>() << ' '; - msg << std::setw(columnSize) << std::setfill(' ') << this->GetYmax<float>(); - } - if (verbosityLevel > 3) { - msg << indent << "Field approcimation coefficients:\n"; - msg << fieldSlice.ToString(indentLevel + 1) << '\n'; + if (isHeader) { + verbosityLevel = 0; + msg << indent; + msg << std::setw(columnSize) << std::setfill(' ') << "type" << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << "time status" << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << "field status" << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << "geo layer ID" << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << "z [cm]" << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << "Xmax [cm]" << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << "Ymax [cm]"; + } + else { + msg << indent; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetType() << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetTimeStatus() << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetFieldStatus() << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetGeoLayerID() << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetZ<float>() << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetXmax<float>() << ' '; + msg << std::setw(columnSize) << std::setfill(' ') << this->GetYmax<float>(); + } + if (verbosityLevel > 3) { + msg << indent << "\nField slices:\n"; + msg << fieldSlice.ToString(indentLevel + 1, verbosityLevel) << '\n'; + } } + return msg.str(); } - return msg.str(); -} -namespace cbm::algo::ca -{ + template class Station<fvec>; template class Station<float>; template class Station<double>; diff --git a/algo/ca/core/tracking/CaCloneMerger.cxx b/algo/ca/core/tracking/CaCloneMerger.cxx index cfc7404ef6dc3080918db70b000fc3a192acc00a..a36c206cdeae18f2c3fc6d1aacc1233af1485d6e 100644 --- a/algo/ca/core/tracking/CaCloneMerger.cxx +++ b/algo/ca/core/tracking/CaCloneMerger.cxx @@ -17,364 +17,366 @@ #include <iostream> -using namespace cbm::algo::ca; -using namespace cbm::algo; - -// --------------------------------------------------------------------------------------------------------------------- -// -CloneMerger::CloneMerger(const ca::Parameters<fvec>& pars, const fscal mass) : fParameters(pars), fDefaultMass(mass) {} - -// --------------------------------------------------------------------------------------------------------------------- -// -CloneMerger::~CloneMerger() {} - -// --------------------------------------------------------------------------------------------------------------------- -// -void CloneMerger::Exec(const ca::InputData& input, WindowData& wData) +namespace cbm::algo::ca { - Vector<Track>& extTracks = wData.RecoTracks(); - Vector<ca::HitIndex_t>& extRecoHits = wData.RecoHitIndices(); - - Vector<unsigned short>& firstStation = fTrackFirstStation; - Vector<unsigned short>& lastStation = fTrackLastStation; - Vector<ca::HitIndex_t>& firstHit = fTrackFirstHit; - Vector<ca::HitIndex_t>& lastHit = fTrackLastHit; - Vector<unsigned short>& neighbour = fTrackNeighbour; - Vector<fscal>& trackChi2 = fTrackChi2; - Vector<char>& isStored = fTrackIsStored; - Vector<char>& isDownstreamNeighbour = fTrackIsDownstreamNeighbour; - - int nTracks = extTracks.size(); - - assert(nTracks < std::numeric_limits<unsigned short>::max()); - - constexpr unsigned short kNoNeighbour = std::numeric_limits<unsigned short>::max(); - - fTracksNew.clear(); - fTracksNew.reserve(nTracks); - fRecoHitsNew.clear(); - fRecoHitsNew.reserve(extRecoHits.size()); - - firstStation.reset(nTracks); - lastStation.reset(nTracks); - firstHit.reset(nTracks); - lastHit.reset(nTracks); - isStored.reset(nTracks); - trackChi2.reset(nTracks); - neighbour.reset(nTracks); - isDownstreamNeighbour.reset(nTracks); - - ca::HitIndex_t start_hit = 0; - - for (int iTr = 0; iTr < nTracks; iTr++) { - firstHit[iTr] = start_hit; - firstStation[iTr] = input.GetHit(extRecoHits[start_hit]).Station(); - start_hit += extTracks[iTr].fNofHits - 1; - lastHit[iTr] = start_hit; - lastStation[iTr] = input.GetHit(extRecoHits[start_hit]).Station(); - start_hit++; - - isStored[iTr] = false; - neighbour[iTr] = kNoNeighbour; - trackChi2[iTr] = 100000.; - isDownstreamNeighbour[iTr] = false; + // ------------------------------------------------------------------------------------------------------------------- + // + CloneMerger::CloneMerger(const ca::Parameters<fvec>& pars, const fscal mass) : fParameters(pars), fDefaultMass(mass) + { } - kf::TrackKalmanFilter<fvec> fitB; - fitB.SetParticleMass(fDefaultMass); - fitB.SetMask(fmask::One()); - fitB.SetQp0(fvec(0.)); - - kf::TrackKalmanFilter<fvec> fitF; - fitF.SetParticleMass(fDefaultMass); - fitF.SetMask(fmask::One()); - fitF.SetQp0(fvec(0.)); - - TrackParamV& Tb = fitB.Tr(); - TrackParamV& Tf = fitF.Tr(); - kf::FieldValue<fvec> fBm, fBb, fBf _fvecalignment; - kf::FieldRegion<fvec> fld _fvecalignment; - - // Max length for merging - unsigned char maxLengthForMerge = static_cast<unsigned char>(fParameters.GetNstationsActive() - 3); - - for (int iTr = 0; iTr < nTracks; iTr++) { - if (extTracks[iTr].fNofHits > maxLengthForMerge) continue; - for (int jTr = 0; jTr < nTracks; jTr++) { - if (extTracks[jTr].fNofHits > maxLengthForMerge) continue; - if (iTr == jTr) continue; - if (firstStation[iTr] <= lastStation[jTr]) continue; - - unsigned short stab = firstStation[iTr]; - - Tb.Set(extTracks[iTr].fParFirst); - - fitB.SetQp0(fitB.Tr().GetQp()); - - unsigned short staf = lastStation[jTr]; + // ------------------------------------------------------------------------------------------------------------------- + // + CloneMerger::~CloneMerger() {} + + // ------------------------------------------------------------------------------------------------------------------- + // + void CloneMerger::Exec(const ca::InputData& input, WindowData& wData) + { + Vector<Track>& extTracks = wData.RecoTracks(); + Vector<ca::HitIndex_t>& extRecoHits = wData.RecoHitIndices(); + + Vector<unsigned short>& firstStation = fTrackFirstStation; + Vector<unsigned short>& lastStation = fTrackLastStation; + Vector<ca::HitIndex_t>& firstHit = fTrackFirstHit; + Vector<ca::HitIndex_t>& lastHit = fTrackLastHit; + Vector<unsigned short>& neighbour = fTrackNeighbour; + Vector<fscal>& trackChi2 = fTrackChi2; + Vector<char>& isStored = fTrackIsStored; + Vector<char>& isDownstreamNeighbour = fTrackIsDownstreamNeighbour; + + int nTracks = extTracks.size(); + + assert(nTracks < std::numeric_limits<unsigned short>::max()); + + constexpr unsigned short kNoNeighbour = std::numeric_limits<unsigned short>::max(); + + fTracksNew.clear(); + fTracksNew.reserve(nTracks); + fRecoHitsNew.clear(); + fRecoHitsNew.reserve(extRecoHits.size()); + + firstStation.reset(nTracks); + lastStation.reset(nTracks); + firstHit.reset(nTracks); + lastHit.reset(nTracks); + isStored.reset(nTracks); + trackChi2.reset(nTracks); + neighbour.reset(nTracks); + isDownstreamNeighbour.reset(nTracks); + + ca::HitIndex_t start_hit = 0; + + for (int iTr = 0; iTr < nTracks; iTr++) { + firstHit[iTr] = start_hit; + firstStation[iTr] = input.GetHit(extRecoHits[start_hit]).Station(); + start_hit += extTracks[iTr].fNofHits - 1; + lastHit[iTr] = start_hit; + lastStation[iTr] = input.GetHit(extRecoHits[start_hit]).Station(); + start_hit++; + + isStored[iTr] = false; + neighbour[iTr] = kNoNeighbour; + trackChi2[iTr] = 100000.; + isDownstreamNeighbour[iTr] = false; + } - Tf.Set(extTracks[jTr].fParLast); - fitF.SetQp0(fitF.Tr().GetQp()); + kf::TrackKalmanFilter<fvec> fitB; + fitB.SetParticleMass(fDefaultMass); + fitB.SetMask(fmask::One()); + fitB.SetQp0(fvec(0.)); - if (Tf.NdfTime()[0] >= 0. && Tb.NdfTime()[0] >= 0.) { - if (fabs(Tf.GetTime()[0] - Tb.GetTime()[0]) > 3 * sqrt(Tf.C55()[0] + Tb.C55()[0])) continue; - } + kf::TrackKalmanFilter<fvec> fitF; + fitF.SetParticleMass(fDefaultMass); + fitF.SetMask(fmask::One()); + fitF.SetQp0(fvec(0.)); - unsigned short stam; + TrackParamV& Tb = fitB.Tr(); + TrackParamV& Tf = fitF.Tr(); + kf::FieldValue<fvec> fBm, fBb, fBf _fvecalignment; + kf::FieldRegion<fvec> fld _fvecalignment; - fBf = fParameters.GetStation(staf).fieldSlice.GetFieldValue(Tf.X(), Tf.Y()); - fBb = fParameters.GetStation(stab).fieldSlice.GetFieldValue(Tb.X(), Tb.Y()); + // Max length for merging + unsigned char maxLengthForMerge = static_cast<unsigned char>(fParameters.GetNstationsActive() - 3); - unsigned short dist = firstStation[iTr] - lastStation[jTr]; + for (int iTr = 0; iTr < nTracks; iTr++) { + if (extTracks[iTr].fNofHits > maxLengthForMerge) continue; + for (int jTr = 0; jTr < nTracks; jTr++) { + if (extTracks[jTr].fNofHits > maxLengthForMerge) continue; + if (iTr == jTr) continue; + if (firstStation[iTr] <= lastStation[jTr]) continue; - if (dist > 1) - stam = staf + 1; - else - stam = staf - 1; + unsigned short stab = firstStation[iTr]; - fvec zm = fParameters.GetStation(stam).fZ; - fvec xm = fvec(0.5) * (Tf.GetX() + Tf.Tx() * (zm - Tf.Z()) + Tb.GetX() + Tb.Tx() * (zm - Tb.Z())); - fvec ym = fvec(0.5) * (Tf.Y() + Tf.Ty() * (zm - Tf.Z()) + Tb.Y() + Tb.Ty() * (zm - Tb.Z())); - fBm = fParameters.GetStation(stam).fieldSlice.GetFieldValue(xm, ym); - fld.Set(fBb, Tb.Z(), fBm, zm, fBf, Tf.Z()); + Tb.Set(extTracks[iTr].fParFirst); - fvec zMiddle = fvec(0.5) * (Tb.Z() + Tf.Z()); + fitB.SetQp0(fitB.Tr().GetQp()); - fitF.Extrapolate(zMiddle, fld); - fitB.Extrapolate(zMiddle, fld); + unsigned short staf = lastStation[jTr]; - fvec Chi2Tracks(0.); - FilterTracks(&(Tf.X()), &(Tf.C00()), &(Tb.X()), &(Tb.C00()), nullptr, nullptr, &Chi2Tracks); - if (Chi2Tracks[0] > 50) continue; + Tf.Set(extTracks[jTr].fParLast); + fitF.SetQp0(fitF.Tr().GetQp()); - if (Chi2Tracks[0] < trackChi2[iTr] || Chi2Tracks[0] < trackChi2[jTr]) { - if (neighbour[iTr] < kNoNeighbour) { - neighbour[neighbour[iTr]] = kNoNeighbour; - trackChi2[neighbour[iTr]] = 100000.; - isDownstreamNeighbour[neighbour[iTr]] = false; + if (Tf.NdfTime()[0] >= 0. && Tb.NdfTime()[0] >= 0.) { + if (fabs(Tf.GetTime()[0] - Tb.GetTime()[0]) > 3 * sqrt(Tf.C55()[0] + Tb.C55()[0])) continue; } - if (neighbour[jTr] < kNoNeighbour) { - neighbour[neighbour[jTr]] = kNoNeighbour; - trackChi2[neighbour[jTr]] = 100000.; - isDownstreamNeighbour[neighbour[jTr]] = false; + + unsigned short stam; + + fBf = fParameters.GetStation(staf).fieldSlice.GetFieldValue(Tf.X(), Tf.Y()); + fBb = fParameters.GetStation(stab).fieldSlice.GetFieldValue(Tb.X(), Tb.Y()); + + unsigned short dist = firstStation[iTr] - lastStation[jTr]; + + if (dist > 1) + stam = staf + 1; + else + stam = staf - 1; + + fvec zm = fParameters.GetStation(stam).fZ; + fvec xm = fvec(0.5) * (Tf.GetX() + Tf.Tx() * (zm - Tf.Z()) + Tb.GetX() + Tb.Tx() * (zm - Tb.Z())); + fvec ym = fvec(0.5) * (Tf.Y() + Tf.Ty() * (zm - Tf.Z()) + Tb.Y() + Tb.Ty() * (zm - Tb.Z())); + fBm = fParameters.GetStation(stam).fieldSlice.GetFieldValue(xm, ym); + fld.Set(fBb, Tb.Z(), fBm, zm, fBf, Tf.Z()); + + fvec zMiddle = fvec(0.5) * (Tb.Z() + Tf.Z()); + + fitF.Extrapolate(zMiddle, fld); + fitB.Extrapolate(zMiddle, fld); + + fvec Chi2Tracks(0.); + FilterTracks(&(Tf.X()), &(Tf.C00()), &(Tb.X()), &(Tb.C00()), nullptr, nullptr, &Chi2Tracks); + if (Chi2Tracks[0] > 50) continue; + + if (Chi2Tracks[0] < trackChi2[iTr] || Chi2Tracks[0] < trackChi2[jTr]) { + if (neighbour[iTr] < kNoNeighbour) { + neighbour[neighbour[iTr]] = kNoNeighbour; + trackChi2[neighbour[iTr]] = 100000.; + isDownstreamNeighbour[neighbour[iTr]] = false; + } + if (neighbour[jTr] < kNoNeighbour) { + neighbour[neighbour[jTr]] = kNoNeighbour; + trackChi2[neighbour[jTr]] = 100000.; + isDownstreamNeighbour[neighbour[jTr]] = false; + } + neighbour[iTr] = jTr; + neighbour[jTr] = iTr; + trackChi2[iTr] = Chi2Tracks[0]; + trackChi2[jTr] = Chi2Tracks[0]; + isDownstreamNeighbour[iTr] = true; + isDownstreamNeighbour[jTr] = false; } - neighbour[iTr] = jTr; - neighbour[jTr] = iTr; - trackChi2[iTr] = Chi2Tracks[0]; - trackChi2[jTr] = Chi2Tracks[0]; - isDownstreamNeighbour[iTr] = true; - isDownstreamNeighbour[jTr] = false; } } - } - for (int iTr = 0; iTr < nTracks; iTr++) { - if (isStored[iTr]) continue; + for (int iTr = 0; iTr < nTracks; iTr++) { + if (isStored[iTr]) continue; - fTracksNew.push_back(extTracks[iTr]); - if (!isDownstreamNeighbour[iTr]) { - for (ca::HitIndex_t HI = firstHit[iTr]; HI <= lastHit[iTr]; HI++) { - fRecoHitsNew.push_back(extRecoHits[HI]); + fTracksNew.push_back(extTracks[iTr]); + if (!isDownstreamNeighbour[iTr]) { + for (ca::HitIndex_t HI = firstHit[iTr]; HI <= lastHit[iTr]; HI++) { + fRecoHitsNew.push_back(extRecoHits[HI]); + } } - } - if (neighbour[iTr] < kNoNeighbour) { - isStored[neighbour[iTr]] = true; - fTracksNew.back().fNofHits += extTracks[neighbour[iTr]].fNofHits; - for (ca::HitIndex_t HI = firstHit[neighbour[iTr]]; HI <= lastHit[neighbour[iTr]]; HI++) - fRecoHitsNew.push_back(extRecoHits[HI]); - } + if (neighbour[iTr] < kNoNeighbour) { + isStored[neighbour[iTr]] = true; + fTracksNew.back().fNofHits += extTracks[neighbour[iTr]].fNofHits; + for (ca::HitIndex_t HI = firstHit[neighbour[iTr]]; HI <= lastHit[neighbour[iTr]]; HI++) + fRecoHitsNew.push_back(extRecoHits[HI]); + } - if (isDownstreamNeighbour[iTr]) { - for (ca::HitIndex_t HI = firstHit[iTr]; HI <= lastHit[iTr]; HI++) { - fRecoHitsNew.push_back(extRecoHits[HI]); + if (isDownstreamNeighbour[iTr]) { + for (ca::HitIndex_t HI = firstHit[iTr]; HI <= lastHit[iTr]; HI++) { + fRecoHitsNew.push_back(extRecoHits[HI]); + } } } - } - // Save the merging results into external vectors - extTracks = std::move(fTracksNew); - extRecoHits = std::move(fRecoHitsNew); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void CloneMerger::FilterTracks(fvec const r[5], fvec const C[15], fvec const m[5], fvec const V[15], fvec R[5], - fvec W[15], fvec* chi2) -{ - fvec S[15]; - for (int i = 0; i < 15; i++) { - if (W) W[i] = C[i]; - S[i] = C[i] + V[i]; + // Save the merging results into external vectors + extTracks = std::move(fTracksNew); + extRecoHits = std::move(fRecoHitsNew); } - InvertCholesky(S); + // ------------------------------------------------------------------------------------------------------------------- + // + void CloneMerger::FilterTracks(fvec const r[5], fvec const C[15], fvec const m[5], fvec const V[15], fvec R[5], + fvec W[15], fvec* chi2) + { + fvec S[15]; + for (int i = 0; i < 15; i++) { + if (W) W[i] = C[i]; + S[i] = C[i] + V[i]; + } - fvec dzeta[5]; + InvertCholesky(S); - for (int i = 0; i < 5; i++) - dzeta[i] = m[i] - r[i]; + fvec dzeta[5]; - if (W && R) { for (int i = 0; i < 5; i++) - R[i] = r[i]; - - fvec K[5][5]; - MultiplySS(C, S, K); - - fvec KC[15]; - MultiplyMS(K, C, KC); - for (int i = 0; i < 15; i++) - W[i] -= KC[i]; + dzeta[i] = m[i] - r[i]; + + if (W && R) { + for (int i = 0; i < 5; i++) + R[i] = r[i]; + + fvec K[5][5]; + MultiplySS(C, S, K); + + fvec KC[15]; + MultiplyMS(K, C, KC); + for (int i = 0; i < 15; i++) + W[i] -= KC[i]; + + fvec kd; + for (int i = 0; i < 5; i++) { + kd = 0.f; + for (int j = 0; j < 5; j++) + kd += K[i][j] * dzeta[j]; + R[i] += kd; + } + } + if (chi2) { + fvec S_dzeta[5]; + MultiplySR(S, dzeta, S_dzeta); + *chi2 = dzeta[0] * S_dzeta[0] + dzeta[1] * S_dzeta[1] + dzeta[2] * S_dzeta[2] + dzeta[3] * S_dzeta[3] + + dzeta[4] * S_dzeta[4]; + } + } - fvec kd; + // ------------------------------------------------------------------------------------------------------------------- + // + void CloneMerger::InvertCholesky(fvec a[15]) + { + fvec d[5], uud, u[5][5]; for (int i = 0; i < 5; i++) { - kd = 0.f; + d[i] = 0.f; for (int j = 0; j < 5; j++) - kd += K[i][j] * dzeta[j]; - R[i] += kd; + u[i][j] = 0.f; } - } - if (chi2) { - fvec S_dzeta[5]; - MultiplySR(S, dzeta, S_dzeta); - *chi2 = dzeta[0] * S_dzeta[0] + dzeta[1] * S_dzeta[1] + dzeta[2] * S_dzeta[2] + dzeta[3] * S_dzeta[3] - + dzeta[4] * S_dzeta[4]; - } -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void CloneMerger::InvertCholesky(fvec a[15]) -{ - fvec d[5], uud, u[5][5]; - for (int i = 0; i < 5; i++) { - d[i] = 0.f; - for (int j = 0; j < 5; j++) - u[i][j] = 0.f; - } - - for (int i = 0; i < 5; i++) { - uud = 0.f; - for (int j = 0; j < i; j++) - uud += u[j][i] * u[j][i] * d[j]; - uud = a[i * (i + 3) / 2] - uud; - - fvec smallval(1.e-12); - uud = iif(uud >= smallval, uud, smallval); - - d[i] = uud / kf::utils::fabs(uud); - u[i][i] = sqrt(kf::utils::fabs(uud)); - for (int j = i + 1; j < 5; j++) { + for (int i = 0; i < 5; i++) { uud = 0.f; - for (int k = 0; k < i; k++) - uud += u[k][i] * u[k][j] * d[k]; - uud = a[j * (j + 1) / 2 + i] /*a[i][j]*/ - uud; - u[i][j] = d[i] / u[i][i] * uud; + for (int j = 0; j < i; j++) + uud += u[j][i] * u[j][i] * d[j]; + uud = a[i * (i + 3) / 2] - uud; + + fvec smallval(1.e-12); + uud = iif(uud >= smallval, uud, smallval); + + d[i] = uud / kf::utils::fabs(uud); + u[i][i] = sqrt(kf::utils::fabs(uud)); + + for (int j = i + 1; j < 5; j++) { + uud = 0.f; + for (int k = 0; k < i; k++) + uud += u[k][i] * u[k][j] * d[k]; + uud = a[j * (j + 1) / 2 + i] /*a[i][j]*/ - uud; + u[i][j] = d[i] / u[i][i] * uud; + } } - } - fvec u1[5]; + fvec u1[5]; - for (int i = 0; i < 5; i++) { - u1[i] = u[i][i]; - u[i][i] = 1.f / u[i][i]; + for (int i = 0; i < 5; i++) { + u1[i] = u[i][i]; + u[i][i] = 1.f / u[i][i]; + } + for (int i = 0; i < 4; i++) { + u[i][i + 1] = -u[i][i + 1] * u[i][i] * u[i + 1][i + 1]; + } + for (int i = 0; i < 3; i++) { + u[i][i + 2] = u[i][i + 1] * u1[i + 1] * u[i + 1][i + 2] - u[i][i + 2] * u[i][i] * u[i + 2][i + 2]; + } + for (int i = 0; i < 2; i++) { + u[i][i + 3] = u[i][i + 2] * u1[i + 2] * u[i + 2][i + 3] - u[i][i + 3] * u[i][i] * u[i + 3][i + 3]; + u[i][i + 3] -= u[i][i + 1] * u1[i + 1] * (u[i + 1][i + 2] * u1[i + 2] * u[i + 2][i + 3] - u[i + 1][i + 3]); + } + u[0][4] = u[0][2] * u1[2] * u[2][4] - u[0][4] * u[0][0] * u[4][4]; + u[0][4] += u[0][1] * u1[1] * (u[1][4] - u[1][3] * u1[3] * u[3][4] - u[1][2] * u1[2] * u[2][4]); + u[0][4] += u[3][4] * u1[3] * (u[0][3] - u1[2] * u[2][3] * (u[0][2] - u[0][1] * u1[1] * u[1][2])); + + for (int i = 0; i < 5; i++) + a[i + 10] = u[i][4] * d[4] * u[4][4]; + for (int i = 0; i < 4; i++) + a[i + 6] = u[i][3] * u[3][3] * d[3] + u[i][4] * u[3][4] * d[4]; + for (int i = 0; i < 3; i++) + a[i + 3] = u[i][2] * u[2][2] * d[2] + u[i][3] * u[2][3] * d[3] + u[i][4] * u[2][4] * d[4]; + for (int i = 0; i < 2; i++) + a[i + 1] = + u[i][1] * u[1][1] * d[1] + u[i][2] * u[1][2] * d[2] + u[i][3] * u[1][3] * d[3] + u[i][4] * u[1][4] * d[4]; + a[0] = u[0][0] * u[0][0] * d[0] + u[0][1] * u[0][1] * d[1] + u[0][2] * u[0][2] * d[2] + u[0][3] * u[0][3] * d[3] + + u[0][4] * u[0][4] * d[4]; } - for (int i = 0; i < 4; i++) { - u[i][i + 1] = -u[i][i + 1] * u[i][i] * u[i + 1][i + 1]; + + // ------------------------------------------------------------------------------------------------------------------- + // + void CloneMerger::MultiplyMS(fvec const C[5][5], fvec const V[15], fvec K[15]) + { + K[0] = C[0][0] * V[0] + C[0][1] * V[1] + C[0][2] * V[3] + C[0][3] * V[6] + C[0][4] * V[10]; + + K[1] = C[1][0] * V[0] + C[1][1] * V[1] + C[1][2] * V[3] + C[1][3] * V[6] + C[1][4] * V[10]; + K[2] = C[1][0] * V[1] + C[1][1] * V[2] + C[1][2] * V[4] + C[1][3] * V[7] + C[1][4] * V[11]; + + K[3] = C[2][0] * V[0] + C[2][1] * V[1] + C[2][2] * V[3] + C[2][3] * V[6] + C[2][4] * V[10]; + K[4] = C[2][0] * V[1] + C[2][1] * V[2] + C[2][2] * V[4] + C[2][3] * V[7] + C[2][4] * V[11]; + K[5] = C[2][0] * V[3] + C[2][1] * V[4] + C[2][2] * V[5] + C[2][3] * V[8] + C[2][4] * V[12]; + + K[6] = C[3][0] * V[0] + C[3][1] * V[1] + C[3][2] * V[3] + C[3][3] * V[6] + C[3][4] * V[10]; + K[7] = C[3][0] * V[1] + C[3][1] * V[2] + C[3][2] * V[4] + C[3][3] * V[7] + C[3][4] * V[11]; + K[8] = C[3][0] * V[3] + C[3][1] * V[4] + C[3][2] * V[5] + C[3][3] * V[8] + C[3][4] * V[12]; + K[9] = C[3][0] * V[6] + C[3][1] * V[7] + C[3][2] * V[8] + C[3][3] * V[9] + C[3][4] * V[13]; + + K[10] = C[4][0] * V[0] + C[4][1] * V[1] + C[4][2] * V[3] + C[4][3] * V[6] + C[4][4] * V[10]; + K[11] = C[4][0] * V[1] + C[4][1] * V[2] + C[4][2] * V[4] + C[4][3] * V[7] + C[4][4] * V[11]; + K[12] = C[4][0] * V[3] + C[4][1] * V[4] + C[4][2] * V[5] + C[4][3] * V[8] + C[4][4] * V[12]; + K[13] = C[4][0] * V[6] + C[4][1] * V[7] + C[4][2] * V[8] + C[4][3] * V[9] + C[4][4] * V[13]; + K[14] = C[4][0] * V[10] + C[4][1] * V[11] + C[4][2] * V[12] + C[4][3] * V[13] + C[4][4] * V[14]; } - for (int i = 0; i < 3; i++) { - u[i][i + 2] = u[i][i + 1] * u1[i + 1] * u[i + 1][i + 2] - u[i][i + 2] * u[i][i] * u[i + 2][i + 2]; + + // ------------------------------------------------------------------------------------------------------------------- + // + void CloneMerger::MultiplySR(fvec const C[15], fvec const r_in[5], fvec r_out[5]) + { + r_out[0] = r_in[0] * C[0] + r_in[1] * C[1] + r_in[2] * C[3] + r_in[3] * C[6] + r_in[4] * C[10]; + r_out[1] = r_in[0] * C[1] + r_in[1] * C[2] + r_in[2] * C[4] + r_in[3] * C[7] + r_in[4] * C[11]; + r_out[2] = r_in[0] * C[3] + r_in[1] * C[4] + r_in[2] * C[5] + r_in[3] * C[8] + r_in[4] * C[12]; + r_out[3] = r_in[0] * C[6] + r_in[1] * C[7] + r_in[2] * C[8] + r_in[3] * C[9] + r_in[4] * C[13]; + r_out[4] = r_in[0] * C[10] + r_in[1] * C[11] + r_in[2] * C[12] + r_in[3] * C[13] + r_in[4] * C[14]; } - for (int i = 0; i < 2; i++) { - u[i][i + 3] = u[i][i + 2] * u1[i + 2] * u[i + 2][i + 3] - u[i][i + 3] * u[i][i] * u[i + 3][i + 3]; - u[i][i + 3] -= u[i][i + 1] * u1[i + 1] * (u[i + 1][i + 2] * u1[i + 2] * u[i + 2][i + 3] - u[i + 1][i + 3]); + + // ------------------------------------------------------------------------------------------------------------------- + // + void CloneMerger::MultiplySS(fvec const C[15], fvec const V[15], fvec K[5][5]) + { + K[0][0] = C[0] * V[0] + C[1] * V[1] + C[3] * V[3] + C[6] * V[6] + C[10] * V[10]; + K[0][1] = C[0] * V[1] + C[1] * V[2] + C[3] * V[4] + C[6] * V[7] + C[10] * V[11]; + K[0][2] = C[0] * V[3] + C[1] * V[4] + C[3] * V[5] + C[6] * V[8] + C[10] * V[12]; + K[0][3] = C[0] * V[6] + C[1] * V[7] + C[3] * V[8] + C[6] * V[9] + C[10] * V[13]; + K[0][4] = C[0] * V[10] + C[1] * V[11] + C[3] * V[12] + C[6] * V[13] + C[10] * V[14]; + + K[1][0] = C[1] * V[0] + C[2] * V[1] + C[4] * V[3] + C[7] * V[6] + C[11] * V[10]; + K[1][1] = C[1] * V[1] + C[2] * V[2] + C[4] * V[4] + C[7] * V[7] + C[11] * V[11]; + K[1][2] = C[1] * V[3] + C[2] * V[4] + C[4] * V[5] + C[7] * V[8] + C[11] * V[12]; + K[1][3] = C[1] * V[6] + C[2] * V[7] + C[4] * V[8] + C[7] * V[9] + C[11] * V[13]; + K[1][4] = C[1] * V[10] + C[2] * V[11] + C[4] * V[12] + C[7] * V[13] + C[11] * V[14]; + + K[2][0] = C[3] * V[0] + C[4] * V[1] + C[5] * V[3] + C[8] * V[6] + C[12] * V[10]; + K[2][1] = C[3] * V[1] + C[4] * V[2] + C[5] * V[4] + C[8] * V[7] + C[12] * V[11]; + K[2][2] = C[3] * V[3] + C[4] * V[4] + C[5] * V[5] + C[8] * V[8] + C[12] * V[12]; + K[2][3] = C[3] * V[6] + C[4] * V[7] + C[5] * V[8] + C[8] * V[9] + C[12] * V[13]; + K[2][4] = C[3] * V[10] + C[4] * V[11] + C[5] * V[12] + C[8] * V[13] + C[12] * V[14]; + + K[3][0] = C[6] * V[0] + C[7] * V[1] + C[8] * V[3] + C[9] * V[6] + C[13] * V[10]; + K[3][1] = C[6] * V[1] + C[7] * V[2] + C[8] * V[4] + C[9] * V[7] + C[13] * V[11]; + K[3][2] = C[6] * V[3] + C[7] * V[4] + C[8] * V[5] + C[9] * V[8] + C[13] * V[12]; + K[3][3] = C[6] * V[6] + C[7] * V[7] + C[8] * V[8] + C[9] * V[9] + C[13] * V[13]; + K[3][4] = C[6] * V[10] + C[7] * V[11] + C[8] * V[12] + C[9] * V[13] + C[13] * V[14]; + + K[4][0] = C[10] * V[0] + C[11] * V[1] + C[12] * V[3] + C[13] * V[6] + C[14] * V[10]; + K[4][1] = C[10] * V[1] + C[11] * V[2] + C[12] * V[4] + C[13] * V[7] + C[14] * V[11]; + K[4][2] = C[10] * V[3] + C[11] * V[4] + C[12] * V[5] + C[13] * V[8] + C[14] * V[12]; + K[4][3] = C[10] * V[6] + C[11] * V[7] + C[12] * V[8] + C[13] * V[9] + C[14] * V[13]; + K[4][4] = C[10] * V[10] + C[11] * V[11] + C[12] * V[12] + C[13] * V[13] + C[14] * V[14]; } - u[0][4] = u[0][2] * u1[2] * u[2][4] - u[0][4] * u[0][0] * u[4][4]; - u[0][4] += u[0][1] * u1[1] * (u[1][4] - u[1][3] * u1[3] * u[3][4] - u[1][2] * u1[2] * u[2][4]); - u[0][4] += u[3][4] * u1[3] * (u[0][3] - u1[2] * u[2][3] * (u[0][2] - u[0][1] * u1[1] * u[1][2])); - - for (int i = 0; i < 5; i++) - a[i + 10] = u[i][4] * d[4] * u[4][4]; - for (int i = 0; i < 4; i++) - a[i + 6] = u[i][3] * u[3][3] * d[3] + u[i][4] * u[3][4] * d[4]; - for (int i = 0; i < 3; i++) - a[i + 3] = u[i][2] * u[2][2] * d[2] + u[i][3] * u[2][3] * d[3] + u[i][4] * u[2][4] * d[4]; - for (int i = 0; i < 2; i++) - a[i + 1] = - u[i][1] * u[1][1] * d[1] + u[i][2] * u[1][2] * d[2] + u[i][3] * u[1][3] * d[3] + u[i][4] * u[1][4] * d[4]; - a[0] = u[0][0] * u[0][0] * d[0] + u[0][1] * u[0][1] * d[1] + u[0][2] * u[0][2] * d[2] + u[0][3] * u[0][3] * d[3] - + u[0][4] * u[0][4] * d[4]; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void CloneMerger::MultiplyMS(fvec const C[5][5], fvec const V[15], fvec K[15]) -{ - K[0] = C[0][0] * V[0] + C[0][1] * V[1] + C[0][2] * V[3] + C[0][3] * V[6] + C[0][4] * V[10]; - - K[1] = C[1][0] * V[0] + C[1][1] * V[1] + C[1][2] * V[3] + C[1][3] * V[6] + C[1][4] * V[10]; - K[2] = C[1][0] * V[1] + C[1][1] * V[2] + C[1][2] * V[4] + C[1][3] * V[7] + C[1][4] * V[11]; - - K[3] = C[2][0] * V[0] + C[2][1] * V[1] + C[2][2] * V[3] + C[2][3] * V[6] + C[2][4] * V[10]; - K[4] = C[2][0] * V[1] + C[2][1] * V[2] + C[2][2] * V[4] + C[2][3] * V[7] + C[2][4] * V[11]; - K[5] = C[2][0] * V[3] + C[2][1] * V[4] + C[2][2] * V[5] + C[2][3] * V[8] + C[2][4] * V[12]; - - K[6] = C[3][0] * V[0] + C[3][1] * V[1] + C[3][2] * V[3] + C[3][3] * V[6] + C[3][4] * V[10]; - K[7] = C[3][0] * V[1] + C[3][1] * V[2] + C[3][2] * V[4] + C[3][3] * V[7] + C[3][4] * V[11]; - K[8] = C[3][0] * V[3] + C[3][1] * V[4] + C[3][2] * V[5] + C[3][3] * V[8] + C[3][4] * V[12]; - K[9] = C[3][0] * V[6] + C[3][1] * V[7] + C[3][2] * V[8] + C[3][3] * V[9] + C[3][4] * V[13]; - - K[10] = C[4][0] * V[0] + C[4][1] * V[1] + C[4][2] * V[3] + C[4][3] * V[6] + C[4][4] * V[10]; - K[11] = C[4][0] * V[1] + C[4][1] * V[2] + C[4][2] * V[4] + C[4][3] * V[7] + C[4][4] * V[11]; - K[12] = C[4][0] * V[3] + C[4][1] * V[4] + C[4][2] * V[5] + C[4][3] * V[8] + C[4][4] * V[12]; - K[13] = C[4][0] * V[6] + C[4][1] * V[7] + C[4][2] * V[8] + C[4][3] * V[9] + C[4][4] * V[13]; - K[14] = C[4][0] * V[10] + C[4][1] * V[11] + C[4][2] * V[12] + C[4][3] * V[13] + C[4][4] * V[14]; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void CloneMerger::MultiplySR(fvec const C[15], fvec const r_in[5], fvec r_out[5]) -{ - r_out[0] = r_in[0] * C[0] + r_in[1] * C[1] + r_in[2] * C[3] + r_in[3] * C[6] + r_in[4] * C[10]; - r_out[1] = r_in[0] * C[1] + r_in[1] * C[2] + r_in[2] * C[4] + r_in[3] * C[7] + r_in[4] * C[11]; - r_out[2] = r_in[0] * C[3] + r_in[1] * C[4] + r_in[2] * C[5] + r_in[3] * C[8] + r_in[4] * C[12]; - r_out[3] = r_in[0] * C[6] + r_in[1] * C[7] + r_in[2] * C[8] + r_in[3] * C[9] + r_in[4] * C[13]; - r_out[4] = r_in[0] * C[10] + r_in[1] * C[11] + r_in[2] * C[12] + r_in[3] * C[13] + r_in[4] * C[14]; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void CloneMerger::MultiplySS(fvec const C[15], fvec const V[15], fvec K[5][5]) -{ - K[0][0] = C[0] * V[0] + C[1] * V[1] + C[3] * V[3] + C[6] * V[6] + C[10] * V[10]; - K[0][1] = C[0] * V[1] + C[1] * V[2] + C[3] * V[4] + C[6] * V[7] + C[10] * V[11]; - K[0][2] = C[0] * V[3] + C[1] * V[4] + C[3] * V[5] + C[6] * V[8] + C[10] * V[12]; - K[0][3] = C[0] * V[6] + C[1] * V[7] + C[3] * V[8] + C[6] * V[9] + C[10] * V[13]; - K[0][4] = C[0] * V[10] + C[1] * V[11] + C[3] * V[12] + C[6] * V[13] + C[10] * V[14]; - - K[1][0] = C[1] * V[0] + C[2] * V[1] + C[4] * V[3] + C[7] * V[6] + C[11] * V[10]; - K[1][1] = C[1] * V[1] + C[2] * V[2] + C[4] * V[4] + C[7] * V[7] + C[11] * V[11]; - K[1][2] = C[1] * V[3] + C[2] * V[4] + C[4] * V[5] + C[7] * V[8] + C[11] * V[12]; - K[1][3] = C[1] * V[6] + C[2] * V[7] + C[4] * V[8] + C[7] * V[9] + C[11] * V[13]; - K[1][4] = C[1] * V[10] + C[2] * V[11] + C[4] * V[12] + C[7] * V[13] + C[11] * V[14]; - - K[2][0] = C[3] * V[0] + C[4] * V[1] + C[5] * V[3] + C[8] * V[6] + C[12] * V[10]; - K[2][1] = C[3] * V[1] + C[4] * V[2] + C[5] * V[4] + C[8] * V[7] + C[12] * V[11]; - K[2][2] = C[3] * V[3] + C[4] * V[4] + C[5] * V[5] + C[8] * V[8] + C[12] * V[12]; - K[2][3] = C[3] * V[6] + C[4] * V[7] + C[5] * V[8] + C[8] * V[9] + C[12] * V[13]; - K[2][4] = C[3] * V[10] + C[4] * V[11] + C[5] * V[12] + C[8] * V[13] + C[12] * V[14]; - - K[3][0] = C[6] * V[0] + C[7] * V[1] + C[8] * V[3] + C[9] * V[6] + C[13] * V[10]; - K[3][1] = C[6] * V[1] + C[7] * V[2] + C[8] * V[4] + C[9] * V[7] + C[13] * V[11]; - K[3][2] = C[6] * V[3] + C[7] * V[4] + C[8] * V[5] + C[9] * V[8] + C[13] * V[12]; - K[3][3] = C[6] * V[6] + C[7] * V[7] + C[8] * V[8] + C[9] * V[9] + C[13] * V[13]; - K[3][4] = C[6] * V[10] + C[7] * V[11] + C[8] * V[12] + C[9] * V[13] + C[13] * V[14]; - - K[4][0] = C[10] * V[0] + C[11] * V[1] + C[12] * V[3] + C[13] * V[6] + C[14] * V[10]; - K[4][1] = C[10] * V[1] + C[11] * V[2] + C[12] * V[4] + C[13] * V[7] + C[14] * V[11]; - K[4][2] = C[10] * V[3] + C[11] * V[4] + C[12] * V[5] + C[13] * V[8] + C[14] * V[12]; - K[4][3] = C[10] * V[6] + C[11] * V[7] + C[12] * V[8] + C[13] * V[9] + C[14] * V[13]; - K[4][4] = C[10] * V[10] + C[11] * V[11] + C[12] * V[12] + C[13] * V[13] + C[14] * V[14]; -} +} // namespace cbm::algo::ca \ No newline at end of file diff --git a/algo/ca/core/tracking/CaFramework.cxx b/algo/ca/core/tracking/CaFramework.cxx index 422f282f51704d1985bf7002af116d82322dc115..7d06bc85d4ee58074d5d46d12ec80beb5d7bf81a 100644 --- a/algo/ca/core/tracking/CaFramework.cxx +++ b/algo/ca/core/tracking/CaFramework.cxx @@ -14,80 +14,71 @@ #include <sstream> #include <thread> -using namespace cbm::algo::ca; - -namespace -{ - using namespace cbm::algo; // to keep ca:: prefixes in the code -} - -using cbm::algo::ca::ECounter; // monitor counter key type -using cbm::algo::ca::EDetectorID; -using cbm::algo::ca::ETimer; // monitor timer key type -using cbm::algo::ca::Track; -using constants::phys::ProtonMassD; -using constants::phys::SpeedOfLightInv; -using constants::phys::SpeedOfLightInvD; -//using cbm::ca::tools::Debugger; - -// --------------------------------------------------------------------------------------------------------------------- -// -void Framework::Init(const TrackingMode mode) +namespace cbm::algo::ca { - fpTrackFinder = - std::make_unique<ca::TrackFinder>(fParameters, fDefaultMass, mode, fMonitorData, fNofThreads, fCaRecoTime); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void Framework::Finish() -{ - //Debugger::Instance().Write(); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -void Framework::ReceiveInputData(InputData&& inputData) -{ - // ----- Get input data ---------------------------------------------------------------------------------------------- - fInputData = std::move(inputData); -} - - -// --------------------------------------------------------------------------------------------------------------------- -// -void Framework::ReceiveParameters(Parameters<fvec>&& parameters) -{ - fParameters = std::move(parameters); - fNstationsBeforePipe = fParameters.GetNstationsActive(static_cast<EDetectorID>(0)); - - kf::GlobalField::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField()); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -int Framework::GetMcTrackIdForCaHit(int /*iHit*/) -{ - return -1; - /* - int hitId = iHit; - int iMcPoint = CbmL1::Instance()->GetHitBestMcRefs()[hitId]; - if (iMcPoint < 0) return -1; - return CbmL1::Instance()->GetMcPoints()[iMcPoint].ID; - */ -} - -int Framework::GetMcTrackIdForWindowHit(int /*iHit*/) -{ - return -1; - /* - int hitId = fWindowHits[iHit].Id(); - int iMcPoint = CbmL1::Instance()->GetHitBestMcRefs()[hitId]; - if (iMcPoint < 0) return -1; - return CbmL1::Instance()->GetMcPoints()[iMcPoint].ID; - */ -} - + using constants::phys::ProtonMassD; + using constants::phys::SpeedOfLightInv; + using constants::phys::SpeedOfLightInvD; + //using cbm::ca::tools::Debugger; + + // ------------------------------------------------------------------------------------------------------------------- + // + void Framework::Init(const TrackingMode mode) + { + fpTrackFinder = + std::make_unique<ca::TrackFinder>(fParameters, fDefaultMass, mode, fMonitorData, fNofThreads, fCaRecoTime); + } + + // ------------------------------------------------------------------------------------------------------------------- + // + void Framework::Finish() + { + //Debugger::Instance().Write(); + } + + // ------------------------------------------------------------------------------------------------------------------- + // + void Framework::ReceiveInputData(InputData&& inputData) + { + // ----- Get input data -------------------------------------------------------------------------------------------- + fInputData = std::move(inputData); + } + + + // ------------------------------------------------------------------------------------------------------------------- + // + void Framework::ReceiveParameters(Parameters<fvec>&& parameters) + { + fParameters = std::move(parameters); + fNstationsBeforePipe = fParameters.GetNstationsActive(static_cast<EDetectorID>(0)); + + kf::GlobalField::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField()); + } + + // ------------------------------------------------------------------------------------------------------------------- + // + int Framework::GetMcTrackIdForCaHit(int /*iHit*/) + { + return -1; + /* + int hitId = iHit; + int iMcPoint = CbmL1::Instance()->GetHitBestMcRefs()[hitId]; + if (iMcPoint < 0) return -1; + return CbmL1::Instance()->GetMcPoints()[iMcPoint].ID; + */ + } + + int Framework::GetMcTrackIdForWindowHit(int /*iHit*/) + { + return -1; + /* + int hitId = fWindowHits[iHit].Id(); + int iMcPoint = CbmL1::Instance()->GetHitBestMcRefs()[hitId]; + if (iMcPoint < 0) return -1; + return CbmL1::Instance()->GetMcPoints()[iMcPoint].ID; + */ + } +} // namespace cbm::algo::ca /* const CbmL1MCTrack* Framework::GetMcTrackForWindowHit(int iHit) const { diff --git a/algo/ca/core/tracking/CaTrackExtender.cxx b/algo/ca/core/tracking/CaTrackExtender.cxx index 30e19df12ba888da2cfa91b95088a17d40960d20..e05c6d3296027a02a0e4422e98a2822db236c270 100644 --- a/algo/ca/core/tracking/CaTrackExtender.cxx +++ b/algo/ca/core/tracking/CaTrackExtender.cxx @@ -18,316 +18,315 @@ #include <iostream> -using cbm::algo::ca::Vector; // TMP!! -using namespace cbm::algo::ca; +namespace cbm::algo::ca +{ + // ------------------------------------------------------------------------------------------------------------------- + // + TrackExtender::TrackExtender(const ca::Parameters<fvec>& pars, const fscal mass) + : fParameters(pars) + , fSetup(fParameters.GetActiveSetup()) + , fDefaultMass(mass) + { + } -// --------------------------------------------------------------------------------------------------------------------- -// -TrackExtender::TrackExtender(const ca::Parameters<fvec>& pars, const fscal mass) - : fParameters(pars) - , fSetup(fParameters.GetActiveSetup()) - , fDefaultMass(mass) -{ -} + // ------------------------------------------------------------------------------------------------------------------- + // + TrackExtender::~TrackExtender() {} + // ------------------------------------------------------------------------------------------------------------------- + // -// --------------------------------------------------------------------------------------------------------------------- -// -TrackExtender::~TrackExtender() {} + void TrackExtender::FitBranchFast(const ca::Branch& t, TrackParamV& Tout, const kf::FitDirection direction, + const fvec qp0, const bool initParams) + { + CBMCA_DEBUG_ASSERT(t.NHits >= 3); -// --------------------------------------------------------------------------------------------------------------------- -// + kf::TrackKalmanFilter<fvec> fit; + fit.SetParticleMass(fDefaultMass); + fit.SetMask(fmask::One()); + fit.SetTrack(Tout); + TrackParamV& T = fit.Tr(); -void TrackExtender::FitBranchFast(const ca::Branch& t, TrackParamV& Tout, const kf::FitDirection direction, - const fvec qp0, const bool initParams) -{ - CBMCA_DEBUG_ASSERT(t.NHits >= 3); - - kf::TrackKalmanFilter<fvec> fit; - fit.SetParticleMass(fDefaultMass); - fit.SetMask(fmask::One()); - fit.SetTrack(Tout); - TrackParamV& T = fit.Tr(); - - // get hits of current track - const Vector<ca::HitIndex_t>& hits = t.Hits(); // array of indeses of hits of current track - const int nHits = t.NofHits(); - - const signed short int step = (direction == kf::FitDirection::kUpstream ? -1 : 1); // increment for station index - const int iFirstHit = (direction == kf::FitDirection::kUpstream) ? nHits - 1 : 0; - const int iLastHit = (direction == kf::FitDirection::kUpstream) ? 0 : nHits - 1; - - const ca::Hit& hit0 = frWData->Hit(hits[iFirstHit]); - const ca::Hit& hit1 = frWData->Hit(hits[iFirstHit + step]); - const ca::Hit& hit2 = frWData->Hit(hits[iFirstHit + 2 * step]); - - int ista0 = hit0.Station(); - int ista1 = hit1.Station(); - int ista2 = hit2.Station(); - - const ca::Station<fvec>& sta0 = fParameters.GetStation(ista0); - const ca::Station<fvec>& sta1 = fParameters.GetStation(ista1); - const ca::Station<fvec>& sta2 = fParameters.GetStation(ista2); - - fvec x0 = hit0.X(); - fvec y0 = hit0.Y(); - fvec z0 = hit0.Z(); - - fvec x1 = hit1.X(); - fvec y1 = hit1.Y(); - fvec z1 = hit1.Z(); - - fvec x2 = hit2.X(); - fvec y2 = hit2.Y(); - - T.X() = x0; - T.Y() = y0; - if (initParams) { - fvec dzi = fvec(1.) / (z1 - z0); - T.Tx() = (x1 - x0) * dzi; - T.Ty() = (y1 - y0) * dzi; - T.Qp() = qp0; - } - fit.SetQp0(qp0); + // get hits of current track + const Vector<ca::HitIndex_t>& hits = t.Hits(); // array of indeses of hits of current track + const int nHits = t.NofHits(); - T.Z() = z0; - T.Time() = hit0.T(); - T.Vi() = 0.; + const signed short int step = (direction == kf::FitDirection::kUpstream ? -1 : 1); // increment for station index + const int iFirstHit = (direction == kf::FitDirection::kUpstream) ? nHits - 1 : 0; + const int iLastHit = (direction == kf::FitDirection::kUpstream) ? 0 : nHits - 1; - T.ResetErrors(1., 1., .1, .1, 1., (sta0.timeInfo ? hit0.dT2() : 1.e6), 1.e6); - T.Ndf() = fvec(2.); - T.NdfTime() = sta0.timeInfo ? fvec(-1.) : fvec(-2.); + const ca::Hit& hit0 = frWData->Hit(hits[iFirstHit]); + const ca::Hit& hit1 = frWData->Hit(hits[iFirstHit + step]); + const ca::Hit& hit2 = frWData->Hit(hits[iFirstHit + 2 * step]); - T.C00() = hit0.dX2(); - T.C10() = hit0.dXY(); - T.C11() = hit0.dY2(); + int ista0 = hit0.Station(); + int ista1 = hit1.Station(); + int ista2 = hit2.Station(); - kf::FieldRegion<fvec> fld _fvecalignment; - fvec fldZ0 = sta1.fZ; // suppose field is smoth - fvec fldZ1 = sta2.fZ; - fvec fldZ2 = sta0.fZ; + const ca::Station<fvec>& sta0 = fParameters.GetStation(ista0); + const ca::Station<fvec>& sta1 = fParameters.GetStation(ista1); + const ca::Station<fvec>& sta2 = fParameters.GetStation(ista2); + fvec x0 = hit0.X(); + fvec y0 = hit0.Y(); + fvec z0 = hit0.Z(); - kf::FieldValue fldB0 = sta1.fieldSlice.GetFieldValue(x1, y1); - kf::FieldValue fldB1 = sta2.fieldSlice.GetFieldValue(x2, y2); - kf::FieldValue fldB2 = sta0.fieldSlice.GetFieldValue(x0, y0); + fvec x1 = hit1.X(); + fvec y1 = hit1.Y(); + fvec z1 = hit1.Z(); - fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); + fvec x2 = hit2.X(); + fvec y2 = hit2.Y(); - for (int i = iFirstHit + step; step * i <= step * iLastHit; i += step) { - const ca::Hit& hit = frWData->Hit(hits[i]); - int ista = hit.Station(); - const ca::Station<fvec>& sta = fParameters.GetStation(ista); + T.X() = x0; + T.Y() = y0; + if (initParams) { + fvec dzi = fvec(1.) / (z1 - z0); + T.Tx() = (x1 - x0) * dzi; + T.Ty() = (y1 - y0) * dzi; + T.Qp() = qp0; + } + fit.SetQp0(qp0); - fit.Extrapolate(hit.Z(), fld); - ca::utils::FilterHit(fit, hit, fmask(sta.timeInfo)); - auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(T.X(), T.Y()); - fit.MultipleScattering(radThick); - fit.EnergyLossCorrection(radThick, direction); + T.Z() = z0; + T.Time() = hit0.T(); + T.Vi() = 0.; - fldB0 = fldB1; - fldB1 = fldB2; - fldZ0 = fldZ1; - fldZ1 = fldZ2; - fldB2 = sta.fieldSlice.GetFieldValue(hit.X(), hit.Y()); - fldZ2 = sta.fZ; - fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); - } // i + T.ResetErrors(1., 1., .1, .1, 1., (sta0.timeInfo ? hit0.dT2() : 1.e6), 1.e6); + T.Ndf() = fvec(2.); + T.NdfTime() = sta0.timeInfo ? fvec(-1.) : fvec(-2.); - Tout = T; -} // void ca::Framework::BranchFitterFast + T.C00() = hit0.dX2(); + T.C10() = hit0.dXY(); + T.C11() = hit0.dY2(); -/// like BranchFitterFast but more precise -void TrackExtender::FitBranch(const ca::Branch& t, TrackParamV& T, const kf::FitDirection direction, const fvec qp0, - const bool initParams) -{ - FitBranchFast(t, T, direction, qp0, initParams); - for (int i = 0; i < 1; i++) { - FitBranchFast(t, T, !direction, T.Qp(), false); - FitBranchFast(t, T, direction, T.Qp(), false); - } -} // void ca::Framework::BranchFitter + kf::FieldRegion<fvec> fld _fvecalignment; + fvec fldZ0 = sta1.fZ; // suppose field is smoth + fvec fldZ1 = sta2.fZ; + fvec fldZ2 = sta0.fZ; -void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const kf::FitDirection direction, const fvec qp0) -{ - Vector<ca::HitIndex_t> newHits{"ca::TrackExtender::newHits"}; - newHits.reserve(fParameters.GetNstationsActive()); + kf::FieldValue fldB0 = sta1.fieldSlice.GetFieldValue(x1, y1); + kf::FieldValue fldB1 = sta2.fieldSlice.GetFieldValue(x2, y2); + kf::FieldValue fldB2 = sta0.fieldSlice.GetFieldValue(x0, y0); - kf::TrackKalmanFilter<fvec> fit; - fit.SetParticleMass(fDefaultMass); - fit.SetMask(fmask::One()); - fit.SetTrack(Tout); - fit.SetQp0(qp0); + fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); - const signed short int step = (direction == kf::FitDirection::kUpstream) ? -1 : 1; // increment for station index - const int iFirstHit = (direction == kf::FitDirection::kUpstream) ? 2 : t.NofHits() - 3; - // int ista = fInputData->GetHit(t.Hits[iFirstHit]).iSt + 2 * step; // current station. set to the end of track + for (int i = iFirstHit + step; step * i <= step * iLastHit; i += step) { + const ca::Hit& hit = frWData->Hit(hits[i]); + int ista = hit.Station(); + const ca::Station<fvec>& sta = fParameters.GetStation(ista); + + fit.Extrapolate(hit.Z(), fld); + ca::utils::FilterHit(fit, hit, fmask(sta.timeInfo)); + auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(T.X(), T.Y()); + fit.MultipleScattering(radThick); + fit.EnergyLossCorrection(radThick, direction); + + fldB0 = fldB1; + fldB1 = fldB2; + fldZ0 = fldZ1; + fldZ1 = fldZ2; + fldB2 = sta.fieldSlice.GetFieldValue(hit.X(), hit.Y()); + fldZ2 = sta.fZ; + fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); + } // i + + Tout = T; + } // void ca::Framework::BranchFitterFast + + /// like BranchFitterFast but more precise + void TrackExtender::FitBranch(const ca::Branch& t, TrackParamV& T, const kf::FitDirection direction, const fvec qp0, + const bool initParams) + { + FitBranchFast(t, T, direction, qp0, initParams); + for (int i = 0; i < 1; i++) { + FitBranchFast(t, T, !direction, T.Qp(), false); + FitBranchFast(t, T, direction, T.Qp(), false); + } + } // void ca::Framework::BranchFitter - const ca::Hit& hit0 = frWData->Hit(t.Hits()[iFirstHit]); // optimize - const ca::Hit& hit1 = frWData->Hit(t.Hits()[iFirstHit + step]); - const ca::Hit& hit2 = frWData->Hit(t.Hits()[iFirstHit + 2 * step]); - const int ista0 = hit0.Station(); - const int ista1 = hit1.Station(); - const int ista2 = hit2.Station(); + void TrackExtender::FindMoreHits(ca::Branch& t, TrackParamV& Tout, const kf::FitDirection direction, const fvec qp0) + { + Vector<ca::HitIndex_t> newHits{"ca::TrackExtender::newHits"}; + newHits.reserve(fParameters.GetNstationsActive()); - const ca::Station<fvec>& sta0 = fParameters.GetStation(ista0); - const ca::Station<fvec>& sta1 = fParameters.GetStation(ista1); - const ca::Station<fvec>& sta2 = fParameters.GetStation(ista2); + kf::TrackKalmanFilter<fvec> fit; + fit.SetParticleMass(fDefaultMass); + fit.SetMask(fmask::One()); + fit.SetTrack(Tout); + fit.SetQp0(qp0); - fvec x0 = hit0.X(); - fvec y0 = hit0.Y(); + const signed short int step = (direction == kf::FitDirection::kUpstream) ? -1 : 1; // increment for station index + const int iFirstHit = (direction == kf::FitDirection::kUpstream) ? 2 : t.NofHits() - 3; + // int ista = fInputData->GetHit(t.Hits[iFirstHit]).iSt + 2 * step; // current station. set to the end of track - fvec x1 = hit1.X(); - fvec y1 = hit1.Y(); + const ca::Hit& hit0 = frWData->Hit(t.Hits()[iFirstHit]); // optimize + const ca::Hit& hit1 = frWData->Hit(t.Hits()[iFirstHit + step]); + const ca::Hit& hit2 = frWData->Hit(t.Hits()[iFirstHit + 2 * step]); - fvec x2 = hit2.X(); - fvec y2 = hit2.Y(); + const int ista0 = hit0.Station(); + const int ista1 = hit1.Station(); + const int ista2 = hit2.Station(); - kf::FieldRegion<fvec> fld _fvecalignment; - fvec fldZ0 = sta1.fZ; - fvec fldZ1 = sta2.fZ; - fvec fldZ2 = sta0.fZ; + const ca::Station<fvec>& sta0 = fParameters.GetStation(ista0); + const ca::Station<fvec>& sta1 = fParameters.GetStation(ista1); + const ca::Station<fvec>& sta2 = fParameters.GetStation(ista2); - kf::FieldValue fldB0 = sta1.fieldSlice.GetFieldValue(x1, y1); - kf::FieldValue fldB1 = sta2.fieldSlice.GetFieldValue(x2, y2); - kf::FieldValue fldB2 = sta0.fieldSlice.GetFieldValue(x0, y0); + fvec x0 = hit0.X(); + fvec y0 = hit0.Y(); - fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); + fvec x1 = hit1.X(); + fvec y1 = hit1.Y(); - int ista = ista2 + 2 * step; // skip one station. if there would be hit it has to be found on previous stap + fvec x2 = hit2.X(); + fvec y2 = hit2.Y(); - if (ista2 == frWData->CurrentIteration()->GetFirstStationIndex()) ista = ista2 + step; + kf::FieldRegion<fvec> fld _fvecalignment; + fvec fldZ0 = sta1.fZ; + fvec fldZ1 = sta2.fZ; + fvec fldZ2 = sta0.fZ; - const fscal pickGather = frWData->CurrentIteration()->GetPickGather(); - const fvec pickGather2 = pickGather * pickGather; - const fvec maxDZ = frWData->CurrentIteration()->GetMaxDZ(); - for (; (ista < fParameters.GetNstationsActive()) && (ista >= 0); ista += step) { // CHECKME why ista2? + kf::FieldValue fldB0 = sta1.fieldSlice.GetFieldValue(x1, y1); + kf::FieldValue fldB1 = sta2.fieldSlice.GetFieldValue(x2, y2); + kf::FieldValue fldB2 = sta0.fieldSlice.GetFieldValue(x0, y0); - const ca::Station<fvec>& sta = fParameters.GetStation(ista); + fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); - fit.Extrapolate(sta.fZ, fld); + int ista = ista2 + 2 * step; // skip one station. if there would be hit it has to be found on previous stap - fscal r2_best = 1e8; // best distance to hit - int iHit_best = -1; // index of the best hit + if (ista2 == frWData->CurrentIteration()->GetFirstStationIndex()) ista = ista2 + step; - TrackParamV& tr = fit.Tr(); + const fscal pickGather = frWData->CurrentIteration()->GetPickGather(); + const fvec pickGather2 = pickGather * pickGather; + const fvec maxDZ = frWData->CurrentIteration()->GetMaxDZ(); + for (; (ista < fParameters.GetNstationsActive()) && (ista >= 0); ista += step) { // CHECKME why ista2? - const auto& grid = frWData->Grid(ista); - ca::GridArea area(grid, tr.X()[0], tr.Y()[0], - (sqrt(pickGather * tr.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(tr.Tx()))[0], - (sqrt(pickGather * tr.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(tr.Ty()))[0]); + const ca::Station<fvec>& sta = fParameters.GetStation(ista); - if (fParameters.DevIsIgnoreHitSearchAreas()) { - area.DoLoopOverEntireGrid(); - } + fit.Extrapolate(sta.fZ, fld); - ca::HitIndex_t ih = 0; + fscal r2_best = 1e8; // best distance to hit + int iHit_best = -1; // index of the best hit - while (area.GetNextObjectId(ih)) { // loop over the hits in the area + TrackParamV& tr = fit.Tr(); - if (frWData->IsHitSuppressed(ih)) { - continue; - } - const ca::Hit& hit = frWData->Hit(ih); + const auto& grid = frWData->Grid(ista); + ca::GridArea area(grid, tr.X()[0], tr.Y()[0], + (sqrt(pickGather * tr.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(tr.Tx()))[0], + (sqrt(pickGather * tr.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(tr.Ty()))[0]); - if (sta.timeInfo && tr.NdfTime()[0] > -2.) { - fscal dt = hit.T() - tr.Time()[0]; - if (fabs(dt) > sqrt(25. * tr.C55()[0]) + hit.RangeT()) continue; + if (fParameters.DevIsIgnoreHitSearchAreas()) { + area.DoLoopOverEntireGrid(); } - //if (GetFUsed((*fStripFlag)[hit.f] | (*fStripFlag)[hit.b])) continue; // if used + ca::HitIndex_t ih = 0; - if (frWData->IsHitKeyUsed(hit.FrontKey()) || frWData->IsHitKeyUsed(hit.BackKey())) { - continue; - } + while (area.GetNextObjectId(ih)) { // loop over the hits in the area - auto [y, C11] = fit.ExtrapolateLineYdY2(hit.Z()); + if (frWData->IsHitSuppressed(ih)) { + continue; + } + const ca::Hit& hit = frWData->Hit(ih); - // fscal dym_est = ( fPickGather * sqrt(fabs(C11[0]+sta.XYInfo.C11[0])) ); - // fscal y_minus_new = y[0] - dym_est; - // if (yh < y_minus_new) continue; // CHECKME take into account overlaping? + if (sta.timeInfo && tr.NdfTime()[0] > -2.) { + fscal dt = hit.T() - tr.Time()[0]; + if (fabs(dt) > sqrt(25. * tr.C55()[0]) + hit.RangeT()) continue; + } - auto [x, C00] = fit.ExtrapolateLineXdX2(hit.Z()); + //if (GetFUsed((*fStripFlag)[hit.f] | (*fStripFlag)[hit.b])) continue; // if used - fscal d_x = hit.X() - x[0]; - fscal d_y = hit.Y() - y[0]; - fscal d2 = d_x * d_x + d_y * d_y; - if (d2 > r2_best) continue; - fscal dxm_est = sqrt(pickGather2 * C00)[0] + grid.GetMaxRangeX(); - if (fabs(d_x) > dxm_est) continue; + if (frWData->IsHitKeyUsed(hit.FrontKey()) || frWData->IsHitKeyUsed(hit.BackKey())) { + continue; + } - fscal dym_est = sqrt(pickGather2 * C11)[0] + grid.GetMaxRangeY(); - if (fabs(d_y) > dym_est) continue; + auto [y, C11] = fit.ExtrapolateLineYdY2(hit.Z()); - r2_best = d2; - iHit_best = ih; - } + // fscal dym_est = ( fPickGather * sqrt(fabs(C11[0]+sta.XYInfo.C11[0])) ); + // fscal y_minus_new = y[0] - dym_est; + // if (yh < y_minus_new) continue; // CHECKME take into account overlaping? - if (iHit_best < 0) break; + auto [x, C00] = fit.ExtrapolateLineXdX2(hit.Z()); + fscal d_x = hit.X() - x[0]; + fscal d_y = hit.Y() - y[0]; + fscal d2 = d_x * d_x + d_y * d_y; + if (d2 > r2_best) continue; + fscal dxm_est = sqrt(pickGather2 * C00)[0] + grid.GetMaxRangeX(); + if (fabs(d_x) > dxm_est) continue; - const ca::Hit& hit = frWData->Hit(iHit_best); - newHits.push_back(iHit_best); + fscal dym_est = sqrt(pickGather2 * C11)[0] + grid.GetMaxRangeY(); + if (fabs(d_y) > dym_est) continue; - fit.Extrapolate(hit.Z(), fld); - ca::utils::FilterHit(fit, hit, fmask(sta.timeInfo)); - auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(tr.X(), tr.Y()); - fit.MultipleScattering(radThick); - fit.EnergyLossCorrection(radThick, direction); + r2_best = d2; + iHit_best = ih; + } - fldB0 = fldB1; - fldB1 = fldB2; - fldZ0 = fldZ1; - fldZ1 = fldZ2; - fldB2 = sta.fieldSlice.GetFieldValue(hit.X(), hit.Y()); - fldZ2 = sta.fZ; - fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); - } + if (iHit_best < 0) break; - // save hits - const unsigned int NOldHits = t.NofHits(); - const unsigned int NNewHits = newHits.size(); - t.RefHits().enlarge(NNewHits + NOldHits); - if (direction == kf::FitDirection::kUpstream) { - for (int i = NOldHits - 1; i >= 0; i--) { - t.RefHits()[NNewHits + i] = t.RefHits()[i]; + const ca::Hit& hit = frWData->Hit(iHit_best); + newHits.push_back(iHit_best); + + fit.Extrapolate(hit.Z(), fld); + ca::utils::FilterHit(fit, hit, fmask(sta.timeInfo)); + auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(tr.X(), tr.Y()); + fit.MultipleScattering(radThick); + fit.EnergyLossCorrection(radThick, direction); + + fldB0 = fldB1; + fldB1 = fldB2; + fldZ0 = fldZ1; + fldZ1 = fldZ2; + fldB2 = sta.fieldSlice.GetFieldValue(hit.X(), hit.Y()); + fldZ2 = sta.fZ; + fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); } - for (unsigned int i = 0, ii = NNewHits - 1; i < NNewHits; i++, ii--) { - t.RefHits()[i] = newHits[ii]; + + // save hits + const unsigned int NOldHits = t.NofHits(); + const unsigned int NNewHits = newHits.size(); + t.RefHits().enlarge(NNewHits + NOldHits); + + if (direction == kf::FitDirection::kUpstream) { + for (int i = NOldHits - 1; i >= 0; i--) { + t.RefHits()[NNewHits + i] = t.RefHits()[i]; + } + for (unsigned int i = 0, ii = NNewHits - 1; i < NNewHits; i++, ii--) { + t.RefHits()[i] = newHits[ii]; + } } - } - else { // downstream - for (unsigned int i = 0; i < newHits.size(); i++) { - t.RefHits()[NOldHits + i] = newHits[i]; + else { // downstream + for (unsigned int i = 0; i < newHits.size(); i++) { + t.RefHits()[NOldHits + i] = newHits[i]; + } } - } - Tout = fit.Tr(); + Tout = fit.Tr(); -} // void ca::Framework::FindMoreHits + } // void ca::Framework::FindMoreHits -/// Try to extrapolate and find additional hits on other stations -fscal TrackExtender::ExtendBranch(ca::Branch& t, WindowData& wData) -{ - frWData = &wData; - // const unsigned int minNHits = 3; + /// Try to extrapolate and find additional hits on other stations + fscal TrackExtender::ExtendBranch(ca::Branch& t, WindowData& wData) + { + frWData = &wData; + // const unsigned int minNHits = 3; - TrackParamV T; + TrackParamV T; - // downstream + // downstream - FitBranch(t, T, kf::FitDirection::kDownstream, 0.0); - FindMoreHits(t, T, kf::FitDirection::kDownstream, T.Qp()); + FitBranch(t, T, kf::FitDirection::kDownstream, 0.0); + FindMoreHits(t, T, kf::FitDirection::kDownstream, T.Qp()); - // upstream + // upstream - FitBranchFast(t, T, kf::FitDirection::kUpstream, T.Qp(), false); - FindMoreHits(t, T, kf::FitDirection::kUpstream, T.Qp()); + FitBranchFast(t, T, kf::FitDirection::kUpstream, T.Qp(), false); + FindMoreHits(t, T, kf::FitDirection::kUpstream, T.Qp()); - return T.GetChiSq()[0]; -} + return T.GetChiSq()[0]; + } +} // namespace cbm::algo::ca diff --git a/algo/ca/core/tracking/CaTrackFinder.cxx b/algo/ca/core/tracking/CaTrackFinder.cxx index 4706cd67d3995d56781f9bc1df544b94b5b8c2be..41bb434f8386080fa99ece366931aeaba2814795 100644 --- a/algo/ca/core/tracking/CaTrackFinder.cxx +++ b/algo/ca/core/tracking/CaTrackFinder.cxx @@ -30,538 +30,535 @@ #include <thread> -using namespace cbm::algo::ca; - -using cbm::algo::ca::ECounter; // monitor counter key type -using cbm::algo::ca::ETimer; // monitor timer key type -using cbm::algo::ca::Track; -using constants::phys::ProtonMassD; -using constants::phys::SpeedOfLightInv; -using constants::phys::SpeedOfLightInvD; - - -// --------------------------------------------------------------------------------------------------------------------- -// - -TrackFinder::TrackFinder(const ca::Parameters<fvec>& pars, const fscal mass, const ca::TrackingMode& mode, - TrackingMonitorData& monitorData, int nThreads, double& recoTime) - : fParameters(pars) - , fDefaultMass(mass) - , fTrackingMode(mode) - , fMonitorData(monitorData) - , fvMonitorDataThread(nThreads) - , fvWData(nThreads) - , fNofThreads(nThreads) - , fCaRecoTime(recoTime) - , fvRecoTracks(nThreads) - , fvRecoHitIndices(nThreads) - , fWindowLength((ca::TrackingMode::kMcbm == mode) ? 500 : 10000) +namespace cbm::algo::ca { - assert(fNofThreads > 0); + using constants::phys::ProtonMassD; + using constants::phys::SpeedOfLightInv; + using constants::phys::SpeedOfLightInvD; - for (int iThread = 0; iThread < fNofThreads; ++iThread) { - fvRecoTracks[iThread].SetName(std::string("TrackFinder::fvRecoTracks_") + std::to_string(iThread)); - fvRecoHitIndices[iThread].SetName(std::string("TrackFinder::fvRecoHitIndices_") + std::to_string(iThread)); - } -} - -// --------------------------------------------------------------------------------------------------------------------- -//CBM Level 1 4D Reconstruction -//Finds tracks using the Cellular Automaton algorithm -// -TrackFinder::Output_t TrackFinder::FindTracks(const InputData& input, TimesliceHeader& tsHeader) -{ - Output_t output; - Vector<Track>& recoTracks = output.first; //reconstructed tracks - Vector<ca::HitIndex_t>& recoHits = output.second; //packed hits of reconstructed tracks + // ------------------------------------------------------------------------------------------------------------------- + // + TrackFinder::TrackFinder(const ca::Parameters<fvec>& pars, const fscal mass, const ca::TrackingMode& mode, + TrackingMonitorData& monitorData, int nThreads, double& recoTime) + : fParameters(pars) + , fDefaultMass(mass) + , fTrackingMode(mode) + , fMonitorData(monitorData) + , fvMonitorDataThread(nThreads) + , fvWData(nThreads) + , fNofThreads(nThreads) + , fCaRecoTime(recoTime) + , fvRecoTracks(nThreads) + , fvRecoHitIndices(nThreads) + , fWindowLength((ca::TrackingMode::kMcbm == mode) ? 500 : 10000) + { + assert(fNofThreads > 0); - if (input.GetNhits() < 1) { - LOG(warn) << "No hits were passed to the ca::TrackFinder. Stopping the routine"; - return output; + for (int iThread = 0; iThread < fNofThreads; ++iThread) { + fvRecoTracks[iThread].SetName(std::string("TrackFinder::fvRecoTracks_") + std::to_string(iThread)); + fvRecoHitIndices[iThread].SetName(std::string("TrackFinder::fvRecoHitIndices_") + std::to_string(iThread)); + } } + // ------------------------------------------------------------------------------------------------------------------- + //CBM Level 1 4D Reconstruction + //Finds tracks using the Cellular Automaton algorithm // - // The main CaTrackFinder routine - // It splits the input data into sub-timeslices - // and runs the track finder over the sub-slices - // - fMonitorData.StartTimer(ETimer::Tracking); - fMonitorData.StartTimer(ETimer::PrepareTimeslice); - fMonitorData.IncrementCounter(ECounter::TrackingCall); - fMonitorData.IncrementCounter(ECounter::RecoHit, input.GetNhits()); - - auto timerStart = std::chrono::high_resolution_clock::now(); - - auto& wDataThread0 = fvWData[0]; // NOTE: Thread 0 must be always defined - - // ----- Reset data arrays ------------------------------------------------------------------------------------------- - - wDataThread0.HitKeyFlags().reset(input.GetNhitKeys(), 0); - - fHitTimeInfo.reset(input.GetNhits()); - - // TODO: move these values to Parameters namespace (S.Zharko) - - // length of sub-TS - const fscal minProtonMomentum = 0.1; - const fscal preFactor = sqrt(1. + ProtonMassD * ProtonMassD / (minProtonMomentum * minProtonMomentum)); - const fscal targX = fParameters.GetTargetPositionX()[0]; - const fscal targY = fParameters.GetTargetPositionY()[0]; - const fscal targZ = fParameters.GetTargetPositionZ()[0]; - - fStatTsStart = std::numeric_limits<fscal>::max(); // end time of the TS - fStatTsEnd = 0.; // end time of the TS - fStatNhitsTotal = 0; - - // calculate possible event time for the hits (fHitTimeInfo array) - for (int iStream = 0; iStream < input.GetNdataStreams(); ++iStream) { - - fscal maxTimeBeforeHit = std::numeric_limits<fscal>::lowest(); - const int nStreamHits = input.GetStreamNhits(iStream); - fStatNhitsTotal += nStreamHits; + TrackFinder::Output_t TrackFinder::FindTracks(const InputData& input, TimesliceHeader& tsHeader) + { + Output_t output; + Vector<Track>& recoTracks = output.first; //reconstructed tracks + Vector<ca::HitIndex_t>& recoHits = output.second; //packed hits of reconstructed tracks - for (int ih = 0; ih < nStreamHits; ++ih) { + if (input.GetNhits() < 1) { + LOG(warn) << "No hits were passed to the ca::TrackFinder. Stopping the routine"; + return output; + } - ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih; - const ca::Hit& h = input.GetHit(caHitId); - const ca::Station<fvec>& st = fParameters.GetStation(h.Station()); - const fscal dx = h.X() - targX; - const fscal dy = h.Y() - targY; - const fscal dz = h.Z() - targZ; - const fscal l = sqrt(dx * dx + dy * dy + dz * dz); - const fscal timeOfFlightMin = l * SpeedOfLightInv; - const fscal timeOfFlightMax = 1.5 * l * preFactor * SpeedOfLightInvD; - const fscal dt = h.RangeT(); - // TODO: Is it possible, that the proton mass selection affects the search of heavier particles? + // + // The main CaTrackFinder routine + // It splits the input data into sub-timeslices + // and runs the track finder over the sub-slices + // + fMonitorData.StartTimer(ETimer::Tracking); + fMonitorData.StartTimer(ETimer::PrepareTimeslice); + fMonitorData.IncrementCounter(ECounter::TrackingCall); + fMonitorData.IncrementCounter(ECounter::RecoHit, input.GetNhits()); + + auto timerStart = std::chrono::high_resolution_clock::now(); + + auto& wDataThread0 = fvWData[0]; // NOTE: Thread 0 must be always defined + + // ----- Reset data arrays ----------------------------------------------------------------------------------------- + + wDataThread0.HitKeyFlags().reset(input.GetNhitKeys(), 0); + + fHitTimeInfo.reset(input.GetNhits()); + + // TODO: move these values to Parameters namespace (S.Zharko) + + // length of sub-TS + const fscal minProtonMomentum = 0.1; + const fscal preFactor = sqrt(1. + ProtonMassD * ProtonMassD / (minProtonMomentum * minProtonMomentum)); + const fscal targX = fParameters.GetTargetPositionX()[0]; + const fscal targY = fParameters.GetTargetPositionY()[0]; + const fscal targZ = fParameters.GetTargetPositionZ()[0]; + + fStatTsStart = std::numeric_limits<fscal>::max(); // end time of the TS + fStatTsEnd = 0.; // end time of the TS + fStatNhitsTotal = 0; + + // calculate possible event time for the hits (fHitTimeInfo array) + for (int iStream = 0; iStream < input.GetNdataStreams(); ++iStream) { + + fscal maxTimeBeforeHit = std::numeric_limits<fscal>::lowest(); + const int nStreamHits = input.GetStreamNhits(iStream); + fStatNhitsTotal += nStreamHits; + + for (int ih = 0; ih < nStreamHits; ++ih) { + + ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih; + const ca::Hit& h = input.GetHit(caHitId); + const ca::Station<fvec>& st = fParameters.GetStation(h.Station()); + const fscal dx = h.X() - targX; + const fscal dy = h.Y() - targY; + const fscal dz = h.Z() - targZ; + const fscal l = sqrt(dx * dx + dy * dy + dz * dz); + const fscal timeOfFlightMin = l * SpeedOfLightInv; + const fscal timeOfFlightMax = 1.5 * l * preFactor * SpeedOfLightInvD; + const fscal dt = h.RangeT(); + // TODO: Is it possible, that the proton mass selection affects the search of heavier particles? + + CaHitTimeInfo& info = fHitTimeInfo[caHitId]; + info.fEventTimeMin = st.timeInfo ? (h.T() - dt - timeOfFlightMax) : -1.e10; + info.fEventTimeMax = st.timeInfo ? (h.T() + dt - timeOfFlightMin) : 1.e10; + + // NOTE: if not a MT part, use wDataThread0.IsHitKeyUsed, it will be later copied to other threads + if (info.fEventTimeMin > 500.e6 || info.fEventTimeMax < -500.) { // cut hits with bogus start time > 500 ms + wDataThread0.IsHitKeyUsed(h.FrontKey()) = 1; + wDataThread0.IsHitKeyUsed(h.BackKey()) = 1; + LOG(error) << "CATrackFinder: skip bogus hit " << h.ToString(); + continue; + } + maxTimeBeforeHit = std::max(maxTimeBeforeHit, info.fEventTimeMax); + info.fMaxTimeBeforeHit = maxTimeBeforeHit; + fStatTsStart = std::min(fStatTsStart, info.fEventTimeMax); + fStatTsEnd = std::max(fStatTsEnd, info.fEventTimeMin); + } - CaHitTimeInfo& info = fHitTimeInfo[caHitId]; - info.fEventTimeMin = st.timeInfo ? (h.T() - dt - timeOfFlightMax) : -1.e10; - info.fEventTimeMax = st.timeInfo ? (h.T() + dt - timeOfFlightMin) : 1.e10; + fscal minTimeAfterHit = std::numeric_limits<fscal>::max(); + // loop in the reverse order to fill CaHitTimeInfo::fMinTimeAfterHit fields - // NOTE: if not a MT part, use wDataThread0.IsHitKeyUsed, it will be later copied to other threads - if (info.fEventTimeMin > 500.e6 || info.fEventTimeMax < -500.) { // cut hits with bogus start time > 500 ms - wDataThread0.IsHitKeyUsed(h.FrontKey()) = 1; - wDataThread0.IsHitKeyUsed(h.BackKey()) = 1; - LOG(error) << "CATrackFinder: skip bogus hit " << h.ToString(); - continue; + for (int ih = nStreamHits - 1; ih >= 0; --ih) { + ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih; + const ca::Hit& h = input.GetHit(caHitId); + if (wDataThread0.IsHitKeyUsed(h.FrontKey()) || wDataThread0.IsHitKeyUsed(h.BackKey())) { + continue; + } // the hit is skipped + CaHitTimeInfo& info = fHitTimeInfo[caHitId]; + minTimeAfterHit = std::min(minTimeAfterHit, info.fEventTimeMin); + info.fMinTimeAfterHit = minTimeAfterHit; } - maxTimeBeforeHit = std::max(maxTimeBeforeHit, info.fEventTimeMax); - info.fMaxTimeBeforeHit = maxTimeBeforeHit; - fStatTsStart = std::min(fStatTsStart, info.fEventTimeMax); - fStatTsEnd = std::max(fStatTsEnd, info.fEventTimeMin); - } - fscal minTimeAfterHit = std::numeric_limits<fscal>::max(); - // loop in the reverse order to fill CaHitTimeInfo::fMinTimeAfterHit fields - - for (int ih = nStreamHits - 1; ih >= 0; --ih) { - ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih; - const ca::Hit& h = input.GetHit(caHitId); - if (wDataThread0.IsHitKeyUsed(h.FrontKey()) || wDataThread0.IsHitKeyUsed(h.BackKey())) { - continue; - } // the hit is skipped - CaHitTimeInfo& info = fHitTimeInfo[caHitId]; - minTimeAfterHit = std::min(minTimeAfterHit, info.fEventTimeMin); - info.fMinTimeAfterHit = minTimeAfterHit; - } - - if (0) { - static int tmp = 0; - if (tmp < 10000) { - tmp++; - LOG(warning) << "\n\n stream " << iStream << " hits " << nStreamHits << "\n\n"; - for (int ih = 0; (ih < nStreamHits) && (tmp < 10000); ++ih) { - ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih; - const ca::Hit& h = input.GetHit(caHitId); - if (wDataThread0.IsHitKeyUsed(h.FrontKey()) || wDataThread0.IsHitKeyUsed(h.BackKey())) { - continue; - } // the hit is skipped - CaHitTimeInfo& info = fHitTimeInfo[caHitId]; - if (h.Station() < 4) { - tmp++; - LOG(warning) << " hit sta " << h.Station() << " stream " << iStream << " time " << h.T() << " event time " - << info.fEventTimeMin << " .. " << info.fEventTimeMax << " max time before hit " - << info.fMaxTimeBeforeHit << " min time after hit " << info.fMinTimeAfterHit; + if (0) { + static int tmp = 0; + if (tmp < 10000) { + tmp++; + LOG(warning) << "\n\n stream " << iStream << " hits " << nStreamHits << "\n\n"; + for (int ih = 0; (ih < nStreamHits) && (tmp < 10000); ++ih) { + ca::HitIndex_t caHitId = input.GetStreamStartIndex(iStream) + ih; + const ca::Hit& h = input.GetHit(caHitId); + if (wDataThread0.IsHitKeyUsed(h.FrontKey()) || wDataThread0.IsHitKeyUsed(h.BackKey())) { + continue; + } // the hit is skipped + CaHitTimeInfo& info = fHitTimeInfo[caHitId]; + if (h.Station() < 4) { + tmp++; + LOG(warning) << " hit sta " << h.Station() << " stream " << iStream << " time " << h.T() << " event time " + << info.fEventTimeMin << " .. " << info.fEventTimeMax << " max time before hit " + << info.fMaxTimeBeforeHit << " min time after hit " << info.fMinTimeAfterHit; + } } } } } - } - // all hits belong to one sub-timeslice; 1 s is the maximal length of the TS - fStatTsEnd = std::clamp(fStatTsEnd, fStatTsStart, fStatTsStart + 1.e9f); + // all hits belong to one sub-timeslice; 1 s is the maximal length of the TS + fStatTsEnd = std::clamp(fStatTsEnd, fStatTsStart, fStatTsStart + 1.e9f); - LOG(debug) << "CA tracker process time slice " << fStatTsStart * 1.e-6 << " -- " << fStatTsEnd * 1.e-6 - << " [ms] with " << fStatNhitsTotal << " hits"; + LOG(debug) << "CA tracker process time slice " << fStatTsStart * 1.e-6 << " -- " << fStatTsEnd * 1.e-6 + << " [ms] with " << fStatNhitsTotal << " hits"; - int nWindows = static_cast<int>((fStatTsEnd - fStatTsStart) / fWindowLength) + 1; - if (nWindows < 1) { // Situation, when fStatTsEnd == fStatTsStart - nWindows = 1; - } + int nWindows = static_cast<int>((fStatTsEnd - fStatTsStart) / fWindowLength) + 1; + if (nWindows < 1) { // Situation, when fStatTsEnd == fStatTsStart + nWindows = 1; + } - // int nWindowsThread = nWindows / fNofThreads; - // LOG(info) << "CA: estimated number of time windows: " << nWindows; - - std::vector<std::pair<fscal, fscal>> vWindowRangeThread(fNofThreads); - { // Estimation of number of hits in time windows - //Timer time; - //time.Start(); - const HitIndex_t nHitsTot = input.GetNhits(); - const int nSt = fParameters.GetNstationsActive(); - - // Count number of hits per window and station - std::vector<HitIndex_t> nHitsWindowSta(nWindows * nSt, 0); - - for (HitIndex_t iHit = 0; iHit < nHitsTot; ++iHit) { - const auto& hit = input.GetHit(iHit); - const auto& info = fHitTimeInfo[iHit]; - int iWindow = static_cast<int>((info.fEventTimeMin - fStatTsStart) / fWindowLength); - if (iWindow < 0) { - iWindow = 0; - } - if (iWindow >= nWindows) { - LOG(error) << "ca: Hit out of range: iHit = " << iHit << ", min. event time = " << info.fEventTimeMin * 1.e-6 - << " ms, window = " << iWindow; - continue; + // int nWindowsThread = nWindows / fNofThreads; + // LOG(info) << "CA: estimated number of time windows: " << nWindows; + + std::vector<std::pair<fscal, fscal>> vWindowRangeThread(fNofThreads); + { // Estimation of number of hits in time windows + //Timer time; + //time.Start(); + const HitIndex_t nHitsTot = input.GetNhits(); + const int nSt = fParameters.GetNstationsActive(); + + // Count number of hits per window and station + std::vector<HitIndex_t> nHitsWindowSta(nWindows * nSt, 0); + + for (HitIndex_t iHit = 0; iHit < nHitsTot; ++iHit) { + const auto& hit = input.GetHit(iHit); + const auto& info = fHitTimeInfo[iHit]; + int iWindow = static_cast<int>((info.fEventTimeMin - fStatTsStart) / fWindowLength); + if (iWindow < 0) { + iWindow = 0; + } + if (iWindow >= nWindows) { + LOG(error) << "ca: Hit out of range: iHit = " << iHit << ", min. event time = " << info.fEventTimeMin * 1.e-6 + << " ms, window = " << iWindow; + continue; + } + ++nHitsWindowSta[hit.Station() + iWindow * nSt]; } - ++nHitsWindowSta[hit.Station() + iWindow * nSt]; - } - // Remove hits from the "monster events" - if (ca::TrackingMode::kMcbm == fTrackingMode) { - const auto maxNofHitsSta = static_cast<HitIndex_t>(50 * fWindowLength / 1.e3); - for (auto& content : nHitsWindowSta) { - if (content > maxNofHitsSta) { - content = 0; + // Remove hits from the "monster events" + if (ca::TrackingMode::kMcbm == fTrackingMode) { + const auto maxNofHitsSta = static_cast<HitIndex_t>(50 * fWindowLength / 1.e3); + for (auto& content : nHitsWindowSta) { + if (content > maxNofHitsSta) { + content = 0; + } } } - } - // Integrate number of hits per window - std::vector<HitIndex_t> nHitsWindow; - nHitsWindow.reserve(nWindows); - HitIndex_t nHitsCollected = 0; - for (auto it = nHitsWindowSta.begin(); it != nHitsWindowSta.end(); it += nSt) { - nHitsCollected = nHitsWindow.emplace_back(std::accumulate(it, it + nSt, nHitsCollected)); - } + // Integrate number of hits per window + std::vector<HitIndex_t> nHitsWindow; + nHitsWindow.reserve(nWindows); + HitIndex_t nHitsCollected = 0; + for (auto it = nHitsWindowSta.begin(); it != nHitsWindowSta.end(); it += nSt) { + nHitsCollected = nHitsWindow.emplace_back(std::accumulate(it, it + nSt, nHitsCollected)); + } - // Get time range for threads - const HitIndex_t nHitsPerThread = nHitsCollected / fNofThreads; - auto windowIt = nHitsWindow.begin(); - vWindowRangeThread[0].first = fStatTsStart; - for (int iTh = 1; iTh < fNofThreads; ++iTh) { - windowIt = std::lower_bound(windowIt, nHitsWindow.end(), iTh * nHitsPerThread); - const size_t iWbegin = std::distance(nHitsWindow.begin(), windowIt) + 1; - vWindowRangeThread[iTh].first = fStatTsStart + iWbegin * fWindowLength; - vWindowRangeThread[iTh - 1].second = vWindowRangeThread[iTh].first; + // Get time range for threads + const HitIndex_t nHitsPerThread = nHitsCollected / fNofThreads; + auto windowIt = nHitsWindow.begin(); + vWindowRangeThread[0].first = fStatTsStart; + for (int iTh = 1; iTh < fNofThreads; ++iTh) { + windowIt = std::lower_bound(windowIt, nHitsWindow.end(), iTh * nHitsPerThread); + const size_t iWbegin = std::distance(nHitsWindow.begin(), windowIt) + 1; + vWindowRangeThread[iTh].first = fStatTsStart + iWbegin * fWindowLength; + vWindowRangeThread[iTh - 1].second = vWindowRangeThread[iTh].first; + } + vWindowRangeThread[fNofThreads - 1].second = fStatTsEnd; + + //time.Stop(); + //LOG(info) << "Thread boarders estimation time: " << time.GetTotalMs() << " ms"; + LOG(debug) << "Fraction of hits from monster events: " + << static_cast<double>(nHitsTot - nHitsCollected) / nHitsTot; } - vWindowRangeThread[fNofThreads - 1].second = fStatTsEnd; - //time.Stop(); - //LOG(info) << "Thread boarders estimation time: " << time.GetTotalMs() << " ms"; - LOG(debug) << "Fraction of hits from monster events: " << static_cast<double>(nHitsTot - nHitsCollected) / nHitsTot; - } + // cut data into sub-timeslices and process them one by one + //for (int iThread = 0; iThread < fNofThreads; ++iThread) { + // vWindowStartThread[iThread] = fStatTsStart + iThread * nWindowsThread * fWindowLength; + // vWindowEndThread[iThread] = + // vWindowStartThread[iThread] + nWindowsThread * fWindowLength; + //} - // cut data into sub-timeslices and process them one by one - //for (int iThread = 0; iThread < fNofThreads; ++iThread) { - // vWindowStartThread[iThread] = fStatTsStart + iThread * nWindowsThread * fWindowLength; - // vWindowEndThread[iThread] = - // vWindowStartThread[iThread] + nWindowsThread * fWindowLength; - //} - - for (int iThread = 0; iThread < fNofThreads; ++iThread) { - auto& entry = vWindowRangeThread[iThread]; - double start = entry.first * 1.e-6; - double end = entry.second * 1.e-6; - LOG(debug) << "Thread: " << iThread << " from " << start << " ms to " << end << " ms (delta = " << end - start - << " ms)"; - } + for (int iThread = 0; iThread < fNofThreads; ++iThread) { + auto& entry = vWindowRangeThread[iThread]; + double start = entry.first * 1.e-6; + double end = entry.second * 1.e-6; + LOG(debug) << "Thread: " << iThread << " from " << start << " ms to " << end << " ms (delta = " << end - start + << " ms)"; + } - // Statistics for monitoring - std::vector<int> vStatNwindows(fNofThreads), vStatNhitsProcessed(fNofThreads); - - fMonitorData.StopTimer(ETimer::PrepareTimeslice); - // Save tracks - if (fNofThreads == 1) { - this->FindTracksThread(input, 0, std::ref(vWindowRangeThread[0]), std::ref(vStatNwindows[0]), - std::ref(vStatNhitsProcessed[0])); - fMonitorData.StartTimer(ETimer::StoreTracksFinal); - recoTracks = std::move(fvRecoTracks[0]); - recoHits = std::move(fvRecoHitIndices[0]); - fMonitorData.StopTimer(ETimer::StoreTracksFinal); - } - else { - std::vector<std::thread> vThreadList; - vThreadList.reserve(fNofThreads); - for (int iTh = 0; iTh < fNofThreads; ++iTh) { - vThreadList.emplace_back(&TrackFinder::FindTracksThread, this, std::ref(input), iTh, - std::ref(vWindowRangeThread[iTh]), std::ref(vStatNwindows[iTh]), - std::ref(vStatNhitsProcessed[iTh])); + // Statistics for monitoring + std::vector<int> vStatNwindows(fNofThreads), vStatNhitsProcessed(fNofThreads); + + fMonitorData.StopTimer(ETimer::PrepareTimeslice); + // Save tracks + if (fNofThreads == 1) { + this->FindTracksThread(input, 0, std::ref(vWindowRangeThread[0]), std::ref(vStatNwindows[0]), + std::ref(vStatNhitsProcessed[0])); + fMonitorData.StartTimer(ETimer::StoreTracksFinal); + recoTracks = std::move(fvRecoTracks[0]); + recoHits = std::move(fvRecoHitIndices[0]); + fMonitorData.StopTimer(ETimer::StoreTracksFinal); } - for (auto& th : vThreadList) { - if (th.joinable()) { - th.join(); + else { + std::vector<std::thread> vThreadList; + vThreadList.reserve(fNofThreads); + for (int iTh = 0; iTh < fNofThreads; ++iTh) { + vThreadList.emplace_back(&TrackFinder::FindTracksThread, this, std::ref(input), iTh, + std::ref(vWindowRangeThread[iTh]), std::ref(vStatNwindows[iTh]), + std::ref(vStatNhitsProcessed[iTh])); } + for (auto& th : vThreadList) { + if (th.joinable()) { + th.join(); + } + } + fMonitorData.StartTimer(ETimer::StoreTracksFinal); + auto Operation = [](size_t acc, const auto& v) { return acc + v.size(); }; + int nRecoTracks = std::accumulate(fvRecoTracks.begin(), fvRecoTracks.end(), 0, Operation); + int nRecoHits = std::accumulate(fvRecoHitIndices.begin(), fvRecoHitIndices.end(), 0, Operation); + recoTracks.reserve(nRecoTracks); + recoHits.reserve(nRecoHits); + for (int iTh = 0; iTh < fNofThreads; ++iTh) { + recoTracks.insert(recoTracks.end(), fvRecoTracks[iTh].begin(), fvRecoTracks[iTh].end()); + recoHits.insert(recoHits.end(), fvRecoHitIndices[iTh].begin(), fvRecoHitIndices[iTh].end()); + } + fMonitorData.StopTimer(ETimer::StoreTracksFinal); } - fMonitorData.StartTimer(ETimer::StoreTracksFinal); - auto Operation = [](size_t acc, const auto& v) { return acc + v.size(); }; - int nRecoTracks = std::accumulate(fvRecoTracks.begin(), fvRecoTracks.end(), 0, Operation); - int nRecoHits = std::accumulate(fvRecoHitIndices.begin(), fvRecoHitIndices.end(), 0, Operation); - recoTracks.reserve(nRecoTracks); - recoHits.reserve(nRecoHits); - for (int iTh = 0; iTh < fNofThreads; ++iTh) { - recoTracks.insert(recoTracks.end(), fvRecoTracks[iTh].begin(), fvRecoTracks[iTh].end()); - recoHits.insert(recoHits.end(), fvRecoHitIndices[iTh].begin(), fvRecoHitIndices[iTh].end()); - } - fMonitorData.StopTimer(ETimer::StoreTracksFinal); - } - fMonitorData.IncrementCounter(ECounter::RecoTrack, recoTracks.size()); - fMonitorData.IncrementCounter(ECounter::RecoHitUsed, recoHits.size()); + fMonitorData.IncrementCounter(ECounter::RecoTrack, recoTracks.size()); + fMonitorData.IncrementCounter(ECounter::RecoHitUsed, recoHits.size()); - auto timerEnd = std::chrono::high_resolution_clock::now(); - fCaRecoTime = (double) (std::chrono::duration<double>(timerEnd - timerStart).count()); - - // Add thread monitors to the main monitor - for (auto& monitor : fvMonitorDataThread) { - fMonitorData.AddMonitorData(monitor, true); - //fMonitorData.AddMonitorData(monitor); - monitor.Reset(); - } + auto timerEnd = std::chrono::high_resolution_clock::now(); + fCaRecoTime = (double) (std::chrono::duration<double>(timerEnd - timerStart).count()); - const int statNhitsProcessedTotal = std::accumulate(vStatNhitsProcessed.begin(), vStatNhitsProcessed.end(), 0); - const int statNwindowsTotal = std::accumulate(vStatNwindows.begin(), vStatNwindows.end(), 0); + // Add thread monitors to the main monitor + for (auto& monitor : fvMonitorDataThread) { + fMonitorData.AddMonitorData(monitor, true); + //fMonitorData.AddMonitorData(monitor); + monitor.Reset(); + } - // Filling TS headear - tsHeader.Start() = fStatTsStart; - tsHeader.End() = fStatTsEnd; + const int statNhitsProcessedTotal = std::accumulate(vStatNhitsProcessed.begin(), vStatNhitsProcessed.end(), 0); + const int statNwindowsTotal = std::accumulate(vStatNwindows.begin(), vStatNwindows.end(), 0); - fMonitorData.StopTimer(ETimer::Tracking); + // Filling TS headear + tsHeader.Start() = fStatTsStart; + tsHeader.End() = fStatTsEnd; - LOG(debug) << "CA tracker: time slice finished. Reconstructed " << recoTracks.size() << " tracks with " - << recoHits.size() << " hits. Processed " << statNhitsProcessedTotal << " hits in " << statNwindowsTotal - << " time windows. Reco time " << fCaRecoTime / 1.e9 << " s"; - return output; -} + fMonitorData.StopTimer(ETimer::Tracking); -// --------------------------------------------------------------------------------------------------------------------- -// -void TrackFinder::FindTracksThread(const InputData& input, int iThread, std::pair<fscal, fscal>& windowRange, - int& statNwindows, int& statNhitsProcessed) -{ - //std::stringstream filename; - //filename << "./dbg_caTrackFinder::FindTracksThread_" << iThread << ".txt"; - //std::ofstream out(filename.str()); - Timer timer; - timer.Start(); - - auto& monitor = fvMonitorDataThread[iThread]; - monitor.StartTimer(ETimer::TrackingThread); - monitor.StartTimer(ETimer::PrepareThread); - - // Init vectors - auto& tracks = fvRecoTracks[iThread]; - auto& hitIndices = fvRecoHitIndices[iThread]; - auto& wData = fvWData[iThread]; - { - const int nStations = fParameters.GetNstationsActive(); - const size_t nHitsTot = input.GetNhits(); - const size_t nHitsExpected = 2 * nHitsTot; - const size_t nTracksExpected = 2 * nHitsTot / nStations; - tracks.clear(); - tracks.reserve(nTracksExpected / fNofThreads); - hitIndices.clear(); - hitIndices.reserve(nHitsExpected / fNofThreads); - if (iThread != 0) { - wData.HitKeyFlags() = fvWData[0].HitKeyFlags(); - } - for (int iS = 0; iS < nStations; ++iS) { - wData.TsHitIndices(iS).clear(); - wData.TsHitIndices(iS).reserve(nHitsTot); - } + LOG(debug) << "CA tracker: time slice finished. Reconstructed " << recoTracks.size() << " tracks with " + << recoHits.size() << " hits. Processed " << statNhitsProcessedTotal << " hits in " << statNwindowsTotal + << " time windows. Reco time " << fCaRecoTime / 1.e9 << " s"; + return output; } - // Begin and end index of hit-range for streams - std::vector<std::pair<HitIndex_t, HitIndex_t>> streamHitRanges(input.GetNdataStreams(), {0, 0}); - - // Define first hit, skip all the hits, which are before the first window - for (size_t iStream = 0; iStream < streamHitRanges.size(); ++iStream) { - auto& range = streamHitRanges[iStream]; - range.first = input.GetStreamStartIndex(iStream); - range.second = input.GetStreamStopIndex(iStream); - - for (HitIndex_t caHitId = range.first; caHitId < range.second; ++caHitId) { - const ca::Hit& h = input.GetHit(caHitId); - if (wData.IsHitKeyUsed(h.FrontKey()) || wData.IsHitKeyUsed(h.BackKey())) { - continue; - } - const CaHitTimeInfo& info = fHitTimeInfo[caHitId]; - if (info.fMaxTimeBeforeHit < windowRange.first) { - range.first = caHitId + 1; + // ------------------------------------------------------------------------------------------------------------------- + // + void TrackFinder::FindTracksThread(const InputData& input, int iThread, std::pair<fscal, fscal>& windowRange, + int& statNwindows, int& statNhitsProcessed) + { + //std::stringstream filename; + //filename << "./dbg_caTrackFinder::FindTracksThread_" << iThread << ".txt"; + //std::ofstream out(filename.str()); + Timer timer; + timer.Start(); + + auto& monitor = fvMonitorDataThread[iThread]; + monitor.StartTimer(ETimer::TrackingThread); + monitor.StartTimer(ETimer::PrepareThread); + + // Init vectors + auto& tracks = fvRecoTracks[iThread]; + auto& hitIndices = fvRecoHitIndices[iThread]; + auto& wData = fvWData[iThread]; + { + const int nStations = fParameters.GetNstationsActive(); + const size_t nHitsTot = input.GetNhits(); + const size_t nHitsExpected = 2 * nHitsTot; + const size_t nTracksExpected = 2 * nHitsTot / nStations; + tracks.clear(); + tracks.reserve(nTracksExpected / fNofThreads); + hitIndices.clear(); + hitIndices.reserve(nHitsExpected / fNofThreads); + if (iThread != 0) { + wData.HitKeyFlags() = fvWData[0].HitKeyFlags(); } - if (info.fMinTimeAfterHit > windowRange.second) { - range.second = caHitId; + for (int iS = 0; iS < nStations; ++iS) { + wData.TsHitIndices(iS).clear(); + wData.TsHitIndices(iS).reserve(nHitsTot); } } - } - - int statLastLogTimeChunk = -1; - - // Track finder algorithm for the time window - ca::TrackFinderWindow trackFinderWindow(fParameters, fDefaultMass, fTrackingMode, monitor); - trackFinderWindow.InitTimeslice(input.GetNhitKeys()); - - monitor.StopTimer(ETimer::PrepareThread); - - while (true) { - monitor.IncrementCounter(ECounter::SubTS); - // select the sub-slice hits - for (int iS = 0; iS < fParameters.GetNstationsActive(); ++iS) { - wData.TsHitIndices(iS).clear(); - } - bool areUntouchedDataLeft = false; // is the whole TS processed - // TODO: SG: skip empty regions and start the subslice with the earliest hit + // Begin and end index of hit-range for streams + std::vector<std::pair<HitIndex_t, HitIndex_t>> streamHitRanges(input.GetNdataStreams(), {0, 0}); - statNwindows++; - //out << statNwindows << ' '; + // Define first hit, skip all the hits, which are before the first window + for (size_t iStream = 0; iStream < streamHitRanges.size(); ++iStream) { + auto& range = streamHitRanges[iStream]; + range.first = input.GetStreamStartIndex(iStream); + range.second = input.GetStreamStopIndex(iStream); - monitor.StartTimer(ETimer::PrepareWindow); - - for (auto& range : streamHitRanges) { for (HitIndex_t caHitId = range.first; caHitId < range.second; ++caHitId) { const ca::Hit& h = input.GetHit(caHitId); if (wData.IsHitKeyUsed(h.FrontKey()) || wData.IsHitKeyUsed(h.BackKey())) { - // the hit is already reconstructed continue; } const CaHitTimeInfo& info = fHitTimeInfo[caHitId]; - if (info.fEventTimeMax < windowRange.first) { - // the hit belongs to previous sub-slices - continue; + if (info.fMaxTimeBeforeHit < windowRange.first) { + range.first = caHitId + 1; } - if (info.fMinTimeAfterHit > windowRange.first + fWindowLength) { - // this hit and all later hits are out of the sub-slice - areUntouchedDataLeft = true; - break; - } - if (info.fEventTimeMin > windowRange.first + fWindowLength) { - // the hit is too late for the sub slice - areUntouchedDataLeft = true; - continue; - } - - // the hit belongs to the sub-slice - wData.TsHitIndices(h.Station()).push_back(caHitId); - if (info.fMaxTimeBeforeHit < windowRange.first + fWindowLength) { - range.first = caHitId + 1; // this hit and all hits before are before the overlap + if (info.fMinTimeAfterHit > windowRange.second) { + range.second = caHitId; } } } - //out << statNwindowHits << ' '; - //if (statNwindowHits == 0) { // Empty window - // monitor.StopTimer(ETimer::PrepareWindow); - // out << 0 << ' ' << 0 << ' ' << 0 << '\n'; - // continue; - //} + int statLastLogTimeChunk = -1; - if (ca::TrackingMode::kMcbm == fTrackingMode) { - // cut at 50 hits per station per 1 us. - int maxStationHits = (int) (50 * fWindowLength / 1.e3); - for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) { - int nHitsSta = static_cast<int>(wData.TsHitIndices(ista).size()); - if (nHitsSta > maxStationHits) { - wData.TsHitIndices(ista).clear(); + // Track finder algorithm for the time window + ca::TrackFinderWindow trackFinderWindow(fParameters, fDefaultMass, fTrackingMode, monitor); + trackFinderWindow.InitTimeslice(input.GetNhitKeys()); + + monitor.StopTimer(ETimer::PrepareThread); + + while (true) { + monitor.IncrementCounter(ECounter::SubTS); + // select the sub-slice hits + for (int iS = 0; iS < fParameters.GetNstationsActive(); ++iS) { + wData.TsHitIndices(iS).clear(); + } + bool areUntouchedDataLeft = false; // is the whole TS processed + + // TODO: SG: skip empty regions and start the subslice with the earliest hit + + statNwindows++; + //out << statNwindows << ' '; + + monitor.StartTimer(ETimer::PrepareWindow); + + for (auto& range : streamHitRanges) { + for (HitIndex_t caHitId = range.first; caHitId < range.second; ++caHitId) { + const ca::Hit& h = input.GetHit(caHitId); + if (wData.IsHitKeyUsed(h.FrontKey()) || wData.IsHitKeyUsed(h.BackKey())) { + // the hit is already reconstructed + continue; + } + const CaHitTimeInfo& info = fHitTimeInfo[caHitId]; + if (info.fEventTimeMax < windowRange.first) { + // the hit belongs to previous sub-slices + continue; + } + if (info.fMinTimeAfterHit > windowRange.first + fWindowLength) { + // this hit and all later hits are out of the sub-slice + areUntouchedDataLeft = true; + break; + } + if (info.fEventTimeMin > windowRange.first + fWindowLength) { + // the hit is too late for the sub slice + areUntouchedDataLeft = true; + continue; + } + + // the hit belongs to the sub-slice + wData.TsHitIndices(h.Station()).push_back(caHitId); + if (info.fMaxTimeBeforeHit < windowRange.first + fWindowLength) { + range.first = caHitId + 1; // this hit and all hits before are before the overlap + } } } - } - int statNwindowHits = 0; - for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) { - statNwindowHits += wData.TsHitIndices(ista).size(); - } - statNhitsProcessed += statNwindowHits; - - // print the LOG for every 10 ms of data processed - if constexpr (0) { - int currentChunk = (int) ((windowRange.first - fStatTsStart) / 10.e6); - if (!areUntouchedDataLeft || currentChunk > statLastLogTimeChunk) { - statLastLogTimeChunk = currentChunk; - double dataRead = 100. * (windowRange.first + fWindowLength - fStatTsStart) / (fStatTsEnd - fStatTsStart); - if (dataRead > 100.) { - dataRead = 100.; + //out << statNwindowHits << ' '; + //if (statNwindowHits == 0) { // Empty window + // monitor.StopTimer(ETimer::PrepareWindow); + // out << 0 << ' ' << 0 << ' ' << 0 << '\n'; + // continue; + //} + + if (ca::TrackingMode::kMcbm == fTrackingMode) { + // cut at 50 hits per station per 1 us. + int maxStationHits = (int) (50 * fWindowLength / 1.e3); + for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) { + int nHitsSta = static_cast<int>(wData.TsHitIndices(ista).size()); + if (nHitsSta > maxStationHits) { + wData.TsHitIndices(ista).clear(); + } } - LOG(debug) << "CA tracker process sliding window N " << statNwindows << ": time " << windowRange.first / 1.e6 - << " ms + " << fWindowLength / 1.e3 << " us) with " << statNwindowHits << " hits. " - << " Processing " << dataRead << " % of the TS time and " - << 100. * statNhitsProcessed / fStatNhitsTotal << " % of TS hits." - << " Already reconstructed " << tracks.size() << " tracks on thread #" << iThread; } - } - //out << statNwindowHits << ' '; - monitor.StopTimer(ETimer::PrepareWindow); - - //Timer trackingInWindow; //DBG - //trackingInWindow.Start(); - monitor.StartTimer(ETimer::TrackingWindow); - trackFinderWindow.CaTrackFinderSlice(input, wData); - monitor.StopTimer(ETimer::TrackingWindow); - //trackingInWindow.Stop(); - //out << trackingInWindow.GetTotalMs() << ' '; - - // save reconstructed tracks with no hits in the overlap region - //if (windowRange.first > 13.23e6 && windowRange.first < 13.26e6) { - windowRange.first += fWindowLength; - // we should add hits from reconstructed but not stored tracks to the new sub-timeslice - // we do it in a simple way by extending the tsStartNew - // TODO: only add those hits from the region before tsStartNew that belong to the not stored tracks - //out << fvWData[iThread].RecoHitIndices().size() << ' '; - //out << fvWData[iThread].RecoTracks().size() << '\n'; - - monitor.StartTimer(ETimer::StoreTracksWindow); - auto trackFirstHit = wData.RecoHitIndices().begin(); - - for (const auto& track : wData.RecoTracks()) { - - const bool isTrackCompletelyInOverlap = - std::all_of(trackFirstHit, trackFirstHit + track.fNofHits, [&](int caHitId) { - CaHitTimeInfo& info = fHitTimeInfo[caHitId]; - return info.fEventTimeMax >= windowRange.first; - }); - - // Don't save tracks from the overlap region, since they might have additional hits in the next subslice. - // Don't reject tracks in the overlap when no more data are left - const bool useFlag = !isTrackCompletelyInOverlap || !areUntouchedDataLeft; - - for (int i = 0; i < track.fNofHits; i++) { - const int caHitId = *(trackFirstHit + i); - const auto& h = input.GetHit(caHitId); - wData.IsHitKeyUsed(h.FrontKey()) = static_cast<int>(useFlag); - wData.IsHitKeyUsed(h.BackKey()) = static_cast<int>(useFlag); + int statNwindowHits = 0; + for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) { + statNwindowHits += wData.TsHitIndices(ista).size(); + } + statNhitsProcessed += statNwindowHits; + + // print the LOG for every 10 ms of data processed + if constexpr (0) { + int currentChunk = (int) ((windowRange.first - fStatTsStart) / 10.e6); + if (!areUntouchedDataLeft || currentChunk > statLastLogTimeChunk) { + statLastLogTimeChunk = currentChunk; + double dataRead = 100. * (windowRange.first + fWindowLength - fStatTsStart) / (fStatTsEnd - fStatTsStart); + if (dataRead > 100.) { + dataRead = 100.; + } + LOG(debug) << "CA tracker process sliding window N " << statNwindows << ": time " << windowRange.first / 1.e6 + << " ms + " << fWindowLength / 1.e3 << " us) with " << statNwindowHits << " hits. " + << " Processing " << dataRead << " % of the TS time and " + << 100. * statNhitsProcessed / fStatNhitsTotal << " % of TS hits." + << " Already reconstructed " << tracks.size() << " tracks on thread #" << iThread; + } + } + //out << statNwindowHits << ' '; + monitor.StopTimer(ETimer::PrepareWindow); + + //Timer trackingInWindow; //DBG + //trackingInWindow.Start(); + monitor.StartTimer(ETimer::TrackingWindow); + trackFinderWindow.CaTrackFinderSlice(input, wData); + monitor.StopTimer(ETimer::TrackingWindow); + //trackingInWindow.Stop(); + //out << trackingInWindow.GetTotalMs() << ' '; + + // save reconstructed tracks with no hits in the overlap region + //if (windowRange.first > 13.23e6 && windowRange.first < 13.26e6) { + windowRange.first += fWindowLength; + // we should add hits from reconstructed but not stored tracks to the new sub-timeslice + // we do it in a simple way by extending the tsStartNew + // TODO: only add those hits from the region before tsStartNew that belong to the not stored tracks + //out << fvWData[iThread].RecoHitIndices().size() << ' '; + //out << fvWData[iThread].RecoTracks().size() << '\n'; + + monitor.StartTimer(ETimer::StoreTracksWindow); + auto trackFirstHit = wData.RecoHitIndices().begin(); + + for (const auto& track : wData.RecoTracks()) { + + const bool isTrackCompletelyInOverlap = + std::all_of(trackFirstHit, trackFirstHit + track.fNofHits, [&](int caHitId) { + CaHitTimeInfo& info = fHitTimeInfo[caHitId]; + return info.fEventTimeMax >= windowRange.first; + }); + + // Don't save tracks from the overlap region, since they might have additional hits in the next subslice. + // Don't reject tracks in the overlap when no more data are left + const bool useFlag = !isTrackCompletelyInOverlap || !areUntouchedDataLeft; + + for (int i = 0; i < track.fNofHits; i++) { + const int caHitId = *(trackFirstHit + i); + const auto& h = input.GetHit(caHitId); + wData.IsHitKeyUsed(h.FrontKey()) = static_cast<int>(useFlag); + wData.IsHitKeyUsed(h.BackKey()) = static_cast<int>(useFlag); + + if (useFlag) { + hitIndices.push_back(caHitId); + } + } if (useFlag) { - hitIndices.push_back(caHitId); + tracks.push_back(track); } - } - if (useFlag) { - tracks.push_back(track); - } - trackFirstHit += track.fNofHits; - } // sub-timeslice tracks - monitor.StopTimer(ETimer::StoreTracksWindow); + trackFirstHit += track.fNofHits; + } // sub-timeslice tracks + monitor.StopTimer(ETimer::StoreTracksWindow); - if (windowRange.first > windowRange.second) { - break; - } - if (!areUntouchedDataLeft) { - break; - } - } // while(true) - monitor.StopTimer(ETimer::TrackingThread); - //timer.Stop(); - //LOG(info) << "CA: finishing tracking on thread " << iThread << " (time: " << timer.GetTotalMs() << " ms, " - // << "hits processed: " << statNhitsProcessed << ", " - // << "hits used: " << hitIndices.size() << ')'; -} + if (windowRange.first > windowRange.second) { + break; + } + if (!areUntouchedDataLeft) { + break; + } + } // while(true) + monitor.StopTimer(ETimer::TrackingThread); + //timer.Stop(); + //LOG(info) << "CA: finishing tracking on thread " << iThread << " (time: " << timer.GetTotalMs() << " ms, " + // << "hits processed: " << statNhitsProcessed << ", " + // << "hits used: " << hitIndices.size() << ')'; + } +} // namespace cbm::algo::ca \ No newline at end of file diff --git a/algo/ca/core/tracking/CaTrackFinderWindow.cxx b/algo/ca/core/tracking/CaTrackFinderWindow.cxx index ab40955282594fe8e049d994ecf767ef9b832db2..1dd20f404078249a7411d275b6c80fa337416e1f 100644 --- a/algo/ca/core/tracking/CaTrackFinderWindow.cxx +++ b/algo/ca/core/tracking/CaTrackFinderWindow.cxx @@ -39,723 +39,723 @@ // #include "CaToolsDebugger.h" -using Track = cbm::algo::ca::Track; - -using namespace cbm::algo::ca; - -// --------------------------------------------------------------------------------------------------------------------- -TrackFinderWindow::TrackFinderWindow(const ca::Parameters<fvec>& pars, const fscal mass, const ca::TrackingMode& mode, - ca::TrackingMonitorData& monitorData) - : fParameters(pars) - , fDefaultMass(mass) - , fTrackingMode(mode) - , frMonitorData(monitorData) - , fTrackExtender(pars, mass) - , fCloneMerger(pars, mass) - , fTrackFitter(pars, mass, mode) +namespace cbm::algo::ca { -} + // ------------------------------------------------------------------------------------------------------------------- + TrackFinderWindow::TrackFinderWindow(const ca::Parameters<fvec>& pars, const fscal mass, const ca::TrackingMode& mode, + ca::TrackingMonitorData& monitorData) + : fParameters(pars) + , fDefaultMass(mass) + , fTrackingMode(mode) + , frMonitorData(monitorData) + , fTrackExtender(pars, mass) + , fCloneMerger(pars, mass) + , fTrackFitter(pars, mass, mode) + { + } -// --------------------------------------------------------------------------------------------------------------------- -bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2, - WindowData& wData) const -{ - dchi2 = 1.e20; + // ------------------------------------------------------------------------------------------------------------------- + bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triplet& r, fscal& dchi2, + WindowData& wData) const + { + dchi2 = 1.e20; - if (r.GetMHit() != l.GetRHit()) return false; - if (r.GetLHit() != l.GetMHit()) return false; + if (r.GetMHit() != l.GetRHit()) return false; + if (r.GetLHit() != l.GetMHit()) return false; - if (r.GetMSta() != l.GetRSta()) return false; - if (r.GetLSta() != l.GetMSta()) return false; + if (r.GetMSta() != l.GetRSta()) return false; + if (r.GetLSta() != l.GetMSta()) return false; - const fscal tripletLinkChi2 = wData.CurrentIteration()->GetTripletLinkChi2(); - if (r.IsMomentumFitted()) { - assert(l.IsMomentumFitted()); + const fscal tripletLinkChi2 = wData.CurrentIteration()->GetTripletLinkChi2(); + if (r.IsMomentumFitted()) { + assert(l.IsMomentumFitted()); - fscal dqp = l.GetQp() - r.GetQp(); - fscal Cqp = l.GetCqp() + r.GetCqp(); + fscal dqp = l.GetQp() - r.GetQp(); + fscal Cqp = l.GetCqp() + r.GetCqp(); - if (!std::isfinite(dqp)) return false; - if (!std::isfinite(Cqp)) return false; + if (!std::isfinite(dqp)) return false; + if (!std::isfinite(Cqp)) return false; - if (dqp * dqp > tripletLinkChi2 * Cqp) { - return false; // bad neighbour // CHECKME why do we need recheck it?? (it really change result) + if (dqp * dqp > tripletLinkChi2 * Cqp) { + return false; // bad neighbour // CHECKME why do we need recheck it?? (it really change result) + } + dchi2 = dqp * dqp / Cqp; } - dchi2 = dqp * dqp / Cqp; - } - else { - fscal dtx = l.GetTx() - r.GetTx(); - fscal Ctx = l.GetCtx() + r.GetCtx(); + else { + fscal dtx = l.GetTx() - r.GetTx(); + fscal Ctx = l.GetCtx() + r.GetCtx(); - fscal dty = l.GetTy() - r.GetTy(); - fscal Cty = l.GetCty() + r.GetCty(); + fscal dty = l.GetTy() - r.GetTy(); + fscal Cty = l.GetCty() + r.GetCty(); - // it shouldn't happen, but happens sometimes + // it shouldn't happen, but happens sometimes - if (!std::isfinite(dtx)) return false; - if (!std::isfinite(dty)) return false; - if (!std::isfinite(Ctx)) return false; - if (!std::isfinite(Cty)) return false; + if (!std::isfinite(dtx)) return false; + if (!std::isfinite(dty)) return false; + if (!std::isfinite(Ctx)) return false; + if (!std::isfinite(Cty)) return false; - if (dty * dty > tripletLinkChi2 * Cty) return false; - if (dtx * dtx > tripletLinkChi2 * Ctx) return false; + if (dty * dty > tripletLinkChi2 * Cty) return false; + if (dtx * dtx > tripletLinkChi2 * Ctx) return false; - //dchi2 = 0.5f * (dtx * dtx / Ctx + dty * dty / Cty); - dchi2 = 0.; - } + //dchi2 = 0.5f * (dtx * dtx / Ctx + dty * dty / Cty); + dchi2 = 0.; + } - if (!std::isfinite(dchi2)) return false; + if (!std::isfinite(dchi2)) return false; - return true; -} + return true; + } -// ************************************************************************************************** -// * * -// * ------ CATrackFinder procedure ------ * -// * * -// ************************************************************************************************** + // ************************************************************************************************** + // * * + // * ------ CATrackFinder procedure ------ * + // * * + // ************************************************************************************************** -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::CaTrackFinderSlice(const ca::InputData& input, WindowData& wData) -{ - // Init windows - frMonitorData.StartTimer(ETimer::InitWindow); - ReadWindowData(input.GetHits(), wData); - frMonitorData.StopTimer(ETimer::InitWindow); - - // Init grids - frMonitorData.StartTimer(ETimer::PrepareGrid); - PrepareGrid(input.GetHits(), wData); - frMonitorData.StopTimer(ETimer::PrepareGrid); - - // Run CA iterations - frMonitorData.StartTimer(ETimer::FindTracks); - auto& caIterations = fParameters.GetCAIterations(); - for (auto iter = caIterations.begin(); iter != caIterations.end(); ++iter) { - - // ----- Prepare iteration - frMonitorData.StartTimer(ETimer::PrepareIteration); - PrepareCAIteration(*iter, wData, iter == caIterations.begin()); - frMonitorData.StopTimer(ETimer::PrepareIteration); - - // ----- Triplets construction ----- - frMonitorData.StartTimer(ETimer::ConstructTriplets); - ConstructTriplets(wData); - frMonitorData.StopTimer(ETimer::ConstructTriplets); - - // ----- Search for neighbouring triplets ----- - frMonitorData.StartTimer(ETimer::SearchNeighbours); - SearchNeighbors(wData); - frMonitorData.StopTimer(ETimer::SearchNeighbours); - - // ----- Collect track candidates and create tracks - frMonitorData.StartTimer(ETimer::CreateTracks); - CreateTracks(wData, *iter, std::get<2>(fTripletData)); - frMonitorData.StopTimer(ETimer::CreateTracks); - - // ----- Suppress strips of suppressed hits - frMonitorData.StartTimer(ETimer::SuppressHitKeys); - for (unsigned int ih = 0; ih < wData.Hits().size(); ih++) { - if (wData.IsHitSuppressed(ih)) { - const ca::Hit& hit = wData.Hit(ih); - wData.IsHitKeyUsed(hit.FrontKey()) = 1; - wData.IsHitKeyUsed(hit.BackKey()) = 1; + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::CaTrackFinderSlice(const ca::InputData& input, WindowData& wData) + { + // Init windows + frMonitorData.StartTimer(ETimer::InitWindow); + ReadWindowData(input.GetHits(), wData); + frMonitorData.StopTimer(ETimer::InitWindow); + + // Init grids + frMonitorData.StartTimer(ETimer::PrepareGrid); + PrepareGrid(input.GetHits(), wData); + frMonitorData.StopTimer(ETimer::PrepareGrid); + + // Run CA iterations + frMonitorData.StartTimer(ETimer::FindTracks); + auto& caIterations = fParameters.GetCAIterations(); + for (auto iter = caIterations.begin(); iter != caIterations.end(); ++iter) { + + // ----- Prepare iteration + frMonitorData.StartTimer(ETimer::PrepareIteration); + PrepareCAIteration(*iter, wData, iter == caIterations.begin()); + frMonitorData.StopTimer(ETimer::PrepareIteration); + + // ----- Triplets construction ----- + frMonitorData.StartTimer(ETimer::ConstructTriplets); + ConstructTriplets(wData); + frMonitorData.StopTimer(ETimer::ConstructTriplets); + + // ----- Search for neighbouring triplets ----- + frMonitorData.StartTimer(ETimer::SearchNeighbours); + SearchNeighbors(wData); + frMonitorData.StopTimer(ETimer::SearchNeighbours); + + // ----- Collect track candidates and create tracks + frMonitorData.StartTimer(ETimer::CreateTracks); + CreateTracks(wData, *iter, std::get<2>(fTripletData)); + frMonitorData.StopTimer(ETimer::CreateTracks); + + // ----- Suppress strips of suppressed hits + frMonitorData.StartTimer(ETimer::SuppressHitKeys); + for (unsigned int ih = 0; ih < wData.Hits().size(); ih++) { + if (wData.IsHitSuppressed(ih)) { + const ca::Hit& hit = wData.Hit(ih); + wData.IsHitKeyUsed(hit.FrontKey()) = 1; + wData.IsHitKeyUsed(hit.BackKey()) = 1; + } } - } - frMonitorData.StopTimer(ETimer::SuppressHitKeys); - } // ---- Loop over Track Finder iterations: END ----// - frMonitorData.StopTimer(ETimer::FindTracks); - - // Fit tracks - frMonitorData.StartTimer(ETimer::FitTracks); - fTrackFitter.FitCaTracks(input, wData); - frMonitorData.StopTimer(ETimer::FitTracks); - - // Merge clones - frMonitorData.StartTimer(ETimer::MergeClones); - fCloneMerger.Exec(input, wData); - frMonitorData.StopTimer(ETimer::MergeClones); - - // Fit tracks - frMonitorData.StartTimer(ETimer::FitTracks); - fTrackFitter.FitCaTracks(input, wData); - frMonitorData.StopTimer(ETimer::FitTracks); -} - -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::ReadWindowData(const Vector<Hit>& hits, WindowData& wData) -{ - int nHits = 0; - for (int iS = 0; iS < fParameters.GetNstationsActive(); iS++) { - wData.HitStartIndexOnStation(iS) = nHits; - wData.NofHitsOnStation(iS) = wData.TsHitIndices(iS).size(); - nHits += wData.NofHitsOnStation(iS); + frMonitorData.StopTimer(ETimer::SuppressHitKeys); + } // ---- Loop over Track Finder iterations: END ----// + frMonitorData.StopTimer(ETimer::FindTracks); + + // Fit tracks + frMonitorData.StartTimer(ETimer::FitTracks); + fTrackFitter.FitCaTracks(input, wData); + frMonitorData.StopTimer(ETimer::FitTracks); + + // Merge clones + frMonitorData.StartTimer(ETimer::MergeClones); + fCloneMerger.Exec(input, wData); + frMonitorData.StopTimer(ETimer::MergeClones); + + // Fit tracks + frMonitorData.StartTimer(ETimer::FitTracks); + fTrackFitter.FitCaTracks(input, wData); + frMonitorData.StopTimer(ETimer::FitTracks); } - wData.HitStartIndexOnStation(fParameters.GetNstationsActive()) = nHits; - wData.ResetHitData(nHits); - - for (int iS = 0; iS < fParameters.GetNstationsActive(); iS++) { - int iFstHit = wData.HitStartIndexOnStation(iS); - for (ca::HitIndex_t ih = 0; ih < wData.TsHitIndices(iS).size(); ++ih) { - ca::Hit h = hits[wData.TsHitIndex(iS, ih)]; /// D.S. 29.7.24: There is a copy operation here. Can be avoided? - h.SetId(wData.TsHitIndex(iS, ih)); - wData.Hit(iFstHit + ih) = h; + + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::ReadWindowData(const Vector<Hit>& hits, WindowData& wData) + { + int nHits = 0; + for (int iS = 0; iS < fParameters.GetNstationsActive(); iS++) { + wData.HitStartIndexOnStation(iS) = nHits; + wData.NofHitsOnStation(iS) = wData.TsHitIndices(iS).size(); + nHits += wData.NofHitsOnStation(iS); + } + wData.HitStartIndexOnStation(fParameters.GetNstationsActive()) = nHits; + wData.ResetHitData(nHits); + + for (int iS = 0; iS < fParameters.GetNstationsActive(); iS++) { + int iFstHit = wData.HitStartIndexOnStation(iS); + for (ca::HitIndex_t ih = 0; ih < wData.TsHitIndices(iS).size(); ++ih) { + ca::Hit h = hits[wData.TsHitIndex(iS, ih)]; /// D.S. 29.7.24: There is a copy operation here. Can be avoided? + h.SetId(wData.TsHitIndex(iS, ih)); + wData.Hit(iFstHit + ih) = h; + } } - } - if constexpr (fDebug) { - LOG(info) << "===== Sliding Window hits: "; - for (int i = 0; i < nHits; ++i) { - LOG(info) << " " << wData.Hit(i).ToString(); + if constexpr (fDebug) { + LOG(info) << "===== Sliding Window hits: "; + for (int i = 0; i < nHits; ++i) { + LOG(info) << " " << wData.Hit(i).ToString(); + } + LOG(info) << "===== "; } - LOG(info) << "===== "; - } - wData.RecoTracks().clear(); - wData.RecoTracks().reserve(2 * nHits / fParameters.GetNstationsActive()); + wData.RecoTracks().clear(); + wData.RecoTracks().reserve(2 * nHits / fParameters.GetNstationsActive()); + + wData.RecoHitIndices().clear(); + wData.RecoHitIndices().reserve(2 * nHits); + } - wData.RecoHitIndices().clear(); - wData.RecoHitIndices().reserve(2 * nHits); -} + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::PrepareGrid(const Vector<Hit>& hits, WindowData& wData) + { + for (int iS = 0; iS < fParameters.GetNstationsActive(); ++iS) { + + fscal lasttime = std::numeric_limits<fscal>::infinity(); + fscal starttime = -std::numeric_limits<fscal>::infinity(); + fscal gridMinX = -0.1; + fscal gridMaxX = 0.1; + fscal gridMinY = -0.1; + fscal gridMaxY = 0.1; + + for (ca::HitIndex_t ih = 0; ih < wData.TsHitIndices(iS).size(); ++ih) { + const ca::Hit& h = hits[wData.TsHitIndex(iS, ih)]; + + gridMinX = std::min(gridMinX, h.X()); + gridMinY = std::min(gridMinY, h.Y()); + gridMaxX = std::max(gridMaxX, h.X()); + gridMaxY = std::max(gridMaxY, h.Y()); + + const fscal time = h.T(); + assert(std::isfinite(time)); + lasttime = std::min(lasttime, time); + starttime = std::max(starttime, time); + } -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::PrepareGrid(const Vector<Hit>& hits, WindowData& wData) -{ - for (int iS = 0; iS < fParameters.GetNstationsActive(); ++iS) { - - fscal lasttime = std::numeric_limits<fscal>::infinity(); - fscal starttime = -std::numeric_limits<fscal>::infinity(); - fscal gridMinX = -0.1; - fscal gridMaxX = 0.1; - fscal gridMinY = -0.1; - fscal gridMaxY = 0.1; - - for (ca::HitIndex_t ih = 0; ih < wData.TsHitIndices(iS).size(); ++ih) { - const ca::Hit& h = hits[wData.TsHitIndex(iS, ih)]; - - gridMinX = std::min(gridMinX, h.X()); - gridMinY = std::min(gridMinY, h.Y()); - gridMaxX = std::max(gridMaxX, h.X()); - gridMaxY = std::max(gridMaxY, h.Y()); - - const fscal time = h.T(); - assert(std::isfinite(time)); - lasttime = std::min(lasttime, time); - starttime = std::max(starttime, time); + // TODO: changing the grid also changes the result. Investigate why it happens. + // TODO: find the optimal grid size + + const int nSliceHits = wData.TsHitIndices(iS).size(); + const fscal sizeY = gridMaxY - gridMinY; + const fscal sizeX = gridMaxX - gridMinX; + const int nBins2D = 1 + nSliceHits; + + // TODO: SG: the coefficients should be removed + const fscal scale = fParameters.GetStation(iS).GetZ<fscal>() - fParameters.GetTargetPositionZ()[0]; + const fscal maxScale = 0.3 * scale; + const fscal minScale = 0.01 * scale; + + fscal yStep = 0.3 * sizeY / sqrt(nBins2D); + fscal xStep = 0.8 * sizeX / sqrt(nBins2D); + yStep = std::clamp(yStep, minScale, maxScale); + xStep = std::clamp(xStep, minScale, maxScale); + + auto& grid = wData.Grid(iS); + grid.BuildBins(gridMinX, gridMaxX, gridMinY, gridMaxY, xStep, yStep); + /* clang-format off */ + grid.StoreHits(wData.Hits(), + wData.HitStartIndexOnStation(iS), + wData.NofHitsOnStation(iS), + wData.HitKeyFlags()); + /* clang-format on */ } - - // TODO: changing the grid also changes the result. Investigate why it happens. - // TODO: find the optimal grid size - - const int nSliceHits = wData.TsHitIndices(iS).size(); - const fscal sizeY = gridMaxY - gridMinY; - const fscal sizeX = gridMaxX - gridMinX; - const int nBins2D = 1 + nSliceHits; - - // TODO: SG: the coefficients should be removed - const fscal scale = fParameters.GetStation(iS).GetZ<fscal>() - fParameters.GetTargetPositionZ()[0]; - const fscal maxScale = 0.3 * scale; - const fscal minScale = 0.01 * scale; - - fscal yStep = 0.3 * sizeY / sqrt(nBins2D); - fscal xStep = 0.8 * sizeX / sqrt(nBins2D); - yStep = std::clamp(yStep, minScale, maxScale); - xStep = std::clamp(xStep, minScale, maxScale); - - auto& grid = wData.Grid(iS); - grid.BuildBins(gridMinX, gridMaxX, gridMinY, gridMaxY, xStep, yStep); - /* clang-format off */ - grid.StoreHits(wData.Hits(), - wData.HitStartIndexOnStation(iS), - wData.NofHitsOnStation(iS), - wData.HitKeyFlags()); - /* clang-format on */ } -} -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::PrepareCAIteration(const ca::Iteration& caIteration, WindowData& wData, const bool isFirst) -{ - wData.SetCurrentIteration(&caIteration); + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::PrepareCAIteration(const ca::Iteration& caIteration, WindowData& wData, const bool isFirst) + { + wData.SetCurrentIteration(&caIteration); - // Check if it is not the first element - if (!isFirst) { - for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) { - wData.Grid(ista).RemoveUsedHits(wData.Hits(), wData.HitKeyFlags()); + // Check if it is not the first element + if (!isFirst) { + for (int ista = 0; ista < fParameters.GetNstationsActive(); ++ista) { + wData.Grid(ista).RemoveUsedHits(wData.Hits(), wData.HitKeyFlags()); + } } - } - // --> frAlgo.fIsWindowHitSuppressed.reset(frAlgo.fWindowHits.size(), 0); - wData.ResetHitSuppressionFlags(); // TODO: ??? No effect? + // --> frAlgo.fIsWindowHitSuppressed.reset(frAlgo.fWindowHits.size(), 0); + wData.ResetHitSuppressionFlags(); // TODO: ??? No effect? - // --- SET PARAMETERS FOR THE ITERATION --- - // define the target - const fscal SigmaTargetX = caIteration.GetTargetPosSigmaX(); - const fscal SigmaTargetY = caIteration.GetTargetPosSigmaY(); // target constraint [cm] + // --- SET PARAMETERS FOR THE ITERATION --- + // define the target + const fscal SigmaTargetX = caIteration.GetTargetPosSigmaX(); + const fscal SigmaTargetY = caIteration.GetTargetPosSigmaY(); // target constraint [cm] - // Select magnetic field. For primary tracks - fVtxFieldValue, for secondary tracks - st.fieldSlice - if (caIteration.GetPrimaryFlag()) { - wData.TargB() = fParameters.GetVertexFieldValue(); + // Select magnetic field. For primary tracks - fVtxFieldValue, for secondary tracks - st.fieldSlice + if (caIteration.GetPrimaryFlag()) { + wData.TargB() = fParameters.GetVertexFieldValue(); + } + else { + wData.TargB() = fParameters.GetStation(0).fieldSlice.GetFieldValue(0, 0); + } // NOTE: calculates field frAlgo.fTargB in the center of 0th station + + wData.TargetMeasurement().SetX(fParameters.GetTargetPositionX()); + wData.TargetMeasurement().SetY(fParameters.GetTargetPositionY()); + wData.TargetMeasurement().SetDx2(SigmaTargetX * SigmaTargetX); + wData.TargetMeasurement().SetDxy(0); + wData.TargetMeasurement().SetDy2(SigmaTargetY * SigmaTargetY); + wData.TargetMeasurement().SetNdfX(1); + wData.TargetMeasurement().SetNdfY(1); } - else { - wData.TargB() = fParameters.GetStation(0).fieldSlice.GetFieldValue(0, 0); - } // NOTE: calculates field frAlgo.fTargB in the center of 0th station - - wData.TargetMeasurement().SetX(fParameters.GetTargetPositionX()); - wData.TargetMeasurement().SetY(fParameters.GetTargetPositionY()); - wData.TargetMeasurement().SetDx2(SigmaTargetX * SigmaTargetX); - wData.TargetMeasurement().SetDxy(0); - wData.TargetMeasurement().SetDy2(SigmaTargetY * SigmaTargetY); - wData.TargetMeasurement().SetNdfX(1); - wData.TargetMeasurement().SetNdfY(1); -} - -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::ConstructTriplets(WindowData& wData) -{ - auto& [vHitFirstTriplet, vHitNofTriplets, vTriplets] = fTripletData; - vHitFirstTriplet.reset(wData.Hits().size(), 0); /// link hit -> first triplet { hit, *, *} - vHitNofTriplets.reset(wData.Hits().size(), 0); /// link hit ->n triplets { hit, *, *} - ca::TripletConstructor constructor(fParameters, wData, fDefaultMass, fTrackingMode); + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::ConstructTriplets(WindowData& wData) + { + auto& [vHitFirstTriplet, vHitNofTriplets, vTriplets] = fTripletData; + vHitFirstTriplet.reset(wData.Hits().size(), 0); /// link hit -> first triplet { hit, *, *} + vHitNofTriplets.reset(wData.Hits().size(), 0); /// link hit ->n triplets { hit, *, *} - // prepare triplet storage - for (int j = 0; j < fParameters.GetNstationsActive(); j++) { - const size_t nHitsStation = wData.TsHitIndices(j).size(); - vTriplets[j].clear(); - vTriplets[j].reserve(2 * nHitsStation); - } + ca::TripletConstructor constructor(fParameters, wData, fDefaultMass, fTrackingMode); - // indices of the two neighbouring station, taking into account allowed gaps - std::vector<std::pair<int, int>> staPattern; - for (int gap = 0; gap <= wData.CurrentIteration()->GetMaxStationGap(); gap++) { - for (int i = 0; i <= gap; i++) { - staPattern.push_back(std::make_pair(1 + i, 2 + gap)); + // prepare triplet storage + for (int j = 0; j < fParameters.GetNstationsActive(); j++) { + const size_t nHitsStation = wData.TsHitIndices(j).size(); + vTriplets[j].clear(); + vTriplets[j].reserve(2 * nHitsStation); } - } - for (int istal = fParameters.GetNstationsActive() - 2; istal >= wData.CurrentIteration()->GetFirstStationIndex(); - istal--) { - // start with downstream chambers - const auto& grid = wData.Grid(istal); - for (auto& entry : grid.GetEntries()) { - ca::HitIndex_t ihitl = entry.GetObjectId(); - const size_t oldSize = vTriplets[istal].size(); - for (auto& pattern : staPattern) { - constructor.CreateTripletsForHit(fvTriplets, istal, istal + pattern.first, istal + pattern.second, ihitl); - vTriplets[istal].insert(vTriplets[istal].end(), fvTriplets.begin(), fvTriplets.end()); + // indices of the two neighbouring station, taking into account allowed gaps + std::vector<std::pair<int, int>> staPattern; + for (int gap = 0; gap <= wData.CurrentIteration()->GetMaxStationGap(); gap++) { + for (int i = 0; i <= gap; i++) { + staPattern.push_back(std::make_pair(1 + i, 2 + gap)); } - vHitFirstTriplet[ihitl] = PackTripletId(istal, oldSize); - vHitNofTriplets[ihitl] = vTriplets[istal].size() - oldSize; } - } // istal -} -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::SearchNeighbors(WindowData& wData) -{ - auto& [vHitFirstTriplet, vHitNofTriplets, vTriplets] = fTripletData; + for (int istal = fParameters.GetNstationsActive() - 2; istal >= wData.CurrentIteration()->GetFirstStationIndex(); + istal--) { + // start with downstream chambers + const auto& grid = wData.Grid(istal); + for (auto& entry : grid.GetEntries()) { + ca::HitIndex_t ihitl = entry.GetObjectId(); + const size_t oldSize = vTriplets[istal].size(); + for (auto& pattern : staPattern) { + constructor.CreateTripletsForHit(fvTriplets, istal, istal + pattern.first, istal + pattern.second, ihitl); + vTriplets[istal].insert(vTriplets[istal].end(), fvTriplets.begin(), fvTriplets.end()); + } + vHitFirstTriplet[ihitl] = PackTripletId(istal, oldSize); + vHitNofTriplets[ihitl] = vTriplets[istal].size() - oldSize; + } + } // istal + } - for (int istal = fParameters.GetNstationsActive() - 2; istal >= wData.CurrentIteration()->GetFirstStationIndex(); - istal--) { - // start with downstream chambers + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::SearchNeighbors(WindowData& wData) + { + auto& [vHitFirstTriplet, vHitNofTriplets, vTriplets] = fTripletData; - for (ca::Triplet& tr : vTriplets[istal]) { - unsigned int nNeighbours = vHitNofTriplets[tr.GetMHit()]; - unsigned int neighLocation = vHitFirstTriplet[tr.GetMHit()]; - unsigned int neighStation = TripletId2Station(neighLocation); - unsigned int neighTriplet = TripletId2Triplet(neighLocation); + for (int istal = fParameters.GetNstationsActive() - 2; istal >= wData.CurrentIteration()->GetFirstStationIndex(); + istal--) { + // start with downstream chambers - if (nNeighbours > 0) { - assert((int) neighStation >= istal + 1 - && (int) neighStation <= istal + 1 + wData.CurrentIteration()->GetMaxStationGap()); - } + for (ca::Triplet& tr : vTriplets[istal]) { + unsigned int nNeighbours = vHitNofTriplets[tr.GetMHit()]; + unsigned int neighLocation = vHitFirstTriplet[tr.GetMHit()]; + unsigned int neighStation = TripletId2Station(neighLocation); + unsigned int neighTriplet = TripletId2Triplet(neighLocation); - unsigned char level = 0; + if (nNeighbours > 0) { + assert((int) neighStation >= istal + 1 + && (int) neighStation <= istal + 1 + wData.CurrentIteration()->GetMaxStationGap()); + } - for (unsigned int iN = 0; iN < nNeighbours; ++iN, ++neighTriplet, ++neighLocation) { + unsigned char level = 0; - ca::Triplet& neighbour = vTriplets[neighStation][neighTriplet]; + for (unsigned int iN = 0; iN < nNeighbours; ++iN, ++neighTriplet, ++neighLocation) { - fscal dchi2 = 0.; - if (!checkTripletMatch(tr, neighbour, dchi2, wData)) continue; + ca::Triplet& neighbour = vTriplets[neighStation][neighTriplet]; - if (tr.GetFNeighbour() == 0) { - tr.SetFNeighbour(neighLocation); - } - tr.SetNNeighbours(neighLocation - tr.GetFNeighbour() + 1); + fscal dchi2 = 0.; + if (!checkTripletMatch(tr, neighbour, dchi2, wData)) continue; - level = std::max(level, static_cast<unsigned char>(neighbour.GetLevel() + 1)); + if (tr.GetFNeighbour() == 0) { + tr.SetFNeighbour(neighLocation); + } + tr.SetNNeighbours(neighLocation - tr.GetFNeighbour() + 1); + + level = std::max(level, static_cast<unsigned char>(neighbour.GetLevel() + 1)); + } + tr.SetLevel(level); } - tr.SetLevel(level); + frMonitorData.IncrementCounter(ECounter::Triplet, vTriplets[istal].size()); } - frMonitorData.IncrementCounter(ECounter::Triplet, vTriplets[istal].size()); } -} -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::CreateTracks(WindowData& wData, const ca::Iteration& caIteration, TripletArray_t& vTriplets) -{ - // min level to start triplet. So min track length = min_level+3. - const int min_level = wData.CurrentIteration()->GetTrackFromTripletsFlag() - ? 0 - : std::min(caIteration.GetMinNhits(), caIteration.GetMinNhitsStation0()) - 3; - - // collect consequtive: the longest tracks, shorter, more shorter and so on - for (int firstTripletLevel = fParameters.GetNstationsActive() - 3; firstTripletLevel >= min_level; - firstTripletLevel--) { - // choose length in triplets number - firstTripletLevel - the maximum possible triplet level among all triplets in the searched candidate - CreateTrackCandidates(wData, vTriplets, min_level, firstTripletLevel); - DoCompetitionLoop(wData); - SelectTracks(wData); + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::CreateTracks(WindowData& wData, const ca::Iteration& caIteration, TripletArray_t& vTriplets) + { + // min level to start triplet. So min track length = min_level+3. + const int min_level = wData.CurrentIteration()->GetTrackFromTripletsFlag() + ? 0 + : std::min(caIteration.GetMinNhits(), caIteration.GetMinNhitsStation0()) - 3; + + // collect consequtive: the longest tracks, shorter, more shorter and so on + for (int firstTripletLevel = fParameters.GetNstationsActive() - 3; firstTripletLevel >= min_level; + firstTripletLevel--) { + // choose length in triplets number - firstTripletLevel - the maximum possible triplet level among all triplets in the searched candidate + CreateTrackCandidates(wData, vTriplets, min_level, firstTripletLevel); + DoCompetitionLoop(wData); + SelectTracks(wData); + } } -} -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::CreateTrackCandidates(WindowData& wData, TripletArray_t& vTriplets, const int min_level, - const int firstTripletLevel) -{ - // how many levels to check - int nlevel = (fParameters.GetNstationsActive() - 2) - firstTripletLevel + 1; + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::CreateTrackCandidates(WindowData& wData, TripletArray_t& vTriplets, const int min_level, + const int firstTripletLevel) + { + // how many levels to check + int nlevel = (fParameters.GetNstationsActive() - 2) - firstTripletLevel + 1; - const unsigned char min_best_l = - (firstTripletLevel > min_level) ? firstTripletLevel + 2 : min_level + 3; // loose maximum + const unsigned char min_best_l = + (firstTripletLevel > min_level) ? firstTripletLevel + 2 : min_level + 3; // loose maximum - // Uses persistent field to save memory allocations. - // fNewTr is only used here! - ca::Branch(&new_tr)[constants::size::MaxNstations] = fNewTr; + // Uses persistent field to save memory allocations. + // fNewTr is only used here! + ca::Branch(&new_tr)[constants::size::MaxNstations] = fNewTr; - fvTrackCandidates.clear(); - fvTrackCandidates.reserve(wData.Hits().size() / 10); + fvTrackCandidates.clear(); + fvTrackCandidates.reserve(wData.Hits().size() / 10); - for (const auto& h : wData.Hits()) { - fvHitKeyToTrack[h.FrontKey()] = -1; - fvHitKeyToTrack[h.BackKey()] = -1; - } + for (const auto& h : wData.Hits()) { + fvHitKeyToTrack[h.FrontKey()] = -1; + fvHitKeyToTrack[h.BackKey()] = -1; + } - //== Loop over triplets with the required level, find and store track candidates - for (int istaF = wData.CurrentIteration()->GetFirstStationIndex(); - istaF <= fParameters.GetNstationsActive() - 3 - firstTripletLevel; ++istaF) { + //== Loop over triplets with the required level, find and store track candidates + for (int istaF = wData.CurrentIteration()->GetFirstStationIndex(); + istaF <= fParameters.GetNstationsActive() - 3 - firstTripletLevel; ++istaF) { - if (--nlevel == 0) break; //TODO: SG: this is not needed + if (--nlevel == 0) break; //TODO: SG: this is not needed - for (ca::Triplet& first_trip : vTriplets[istaF]) { + for (ca::Triplet& first_trip : vTriplets[istaF]) { - const auto& fstTripLHit = wData.Hit(first_trip.GetLHit()); - if (wData.IsHitKeyUsed(fstTripLHit.FrontKey()) || wData.IsHitKeyUsed(fstTripLHit.BackKey())) { - continue; - } + const auto& fstTripLHit = wData.Hit(first_trip.GetLHit()); + if (wData.IsHitKeyUsed(fstTripLHit.FrontKey()) || wData.IsHitKeyUsed(fstTripLHit.BackKey())) { + continue; + } - // skip track candidates that are too short + // skip track candidates that are too short - int minNhits = wData.CurrentIteration()->GetMinNhits(); + int minNhits = wData.CurrentIteration()->GetMinNhits(); - if (fstTripLHit.Station() == 0) { - minNhits = wData.CurrentIteration()->GetMinNhitsStation0(); - } - if (wData.CurrentIteration()->GetTrackFromTripletsFlag()) { - minNhits = 0; - } + if (fstTripLHit.Station() == 0) { + minNhits = wData.CurrentIteration()->GetMinNhitsStation0(); + } + if (wData.CurrentIteration()->GetTrackFromTripletsFlag()) { + minNhits = 0; + } - if (3 + first_trip.GetLevel() < minNhits) { - continue; - } + if (3 + first_trip.GetLevel() < minNhits) { + continue; + } - // Collect triplets, which can start a track with length equal to firstTipletLevel + 3. This cut suppresses - // ghost tracks, but does not affect the efficiency - if (first_trip.GetLevel() < firstTripletLevel) { - continue; - } + // Collect triplets, which can start a track with length equal to firstTipletLevel + 3. This cut suppresses + // ghost tracks, but does not affect the efficiency + if (first_trip.GetLevel() < firstTripletLevel) { + continue; + } - ca::Branch curr_tr; - curr_tr.AddHit(first_trip.GetLHit()); - curr_tr.SetChi2(first_trip.GetChi2()); + ca::Branch curr_tr; + curr_tr.AddHit(first_trip.GetLHit()); + curr_tr.SetChi2(first_trip.GetChi2()); - ca::Branch best_tr = curr_tr; + ca::Branch best_tr = curr_tr; - /// reqursive func to build a tree of possible track-candidates and choose the best - CAFindTrack(istaF, best_tr, &first_trip, curr_tr, min_best_l, new_tr, wData, vTriplets); + /// reqursive func to build a tree of possible track-candidates and choose the best + CAFindTrack(istaF, best_tr, &first_trip, curr_tr, min_best_l, new_tr, wData, vTriplets); - if (best_tr.NofHits() < firstTripletLevel + 2) continue; // loose maximum one hit + if (best_tr.NofHits() < firstTripletLevel + 2) continue; // loose maximum one hit - if (best_tr.NofHits() < min_level + 3) continue; // should find all hits for min_level + if (best_tr.NofHits() < min_level + 3) continue; // should find all hits for min_level - if (best_tr.NofHits() < minNhits) { - continue; - } + if (best_tr.NofHits() < minNhits) { + continue; + } - int ndf = best_tr.NofHits() * 2 - 5; + int ndf = best_tr.NofHits() * 2 - 5; - // TODO: automatize the NDF calculation + // TODO: automatize the NDF calculation - if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) { - ndf = best_tr.NofHits() * 2 - 4; - } + if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) { + ndf = best_tr.NofHits() * 2 - 4; + } - best_tr.SetChi2(best_tr.Chi2() / ndf); - if (fParameters.GetGhostSuppression()) { - if (3 == best_tr.NofHits()) { - if (!wData.CurrentIteration()->GetPrimaryFlag() && (istaF != 0)) continue; // too /*short*/ non-MAPS track - if (wData.CurrentIteration()->GetPrimaryFlag() && (best_tr.Chi2() > 5.0)) continue; + best_tr.SetChi2(best_tr.Chi2() / ndf); + if (fParameters.GetGhostSuppression()) { + if (3 == best_tr.NofHits()) { + if (!wData.CurrentIteration()->GetPrimaryFlag() && (istaF != 0)) continue; // too /*short*/ non-MAPS track + if (wData.CurrentIteration()->GetPrimaryFlag() && (best_tr.Chi2() > 5.0)) continue; + } } - } - fvTrackCandidates.push_back(best_tr); - ca::Branch& tr = fvTrackCandidates.back(); - tr.SetStation(istaF); - tr.SetId(fvTrackCandidates.size() - 1); - // Mark the candidate as dead. To became alive it should first pass the competition in DoCompetitionLoop - tr.SetAlive(false); - if constexpr (fDebug) { - std::stringstream s; - s << "iter " << wData.CurrentIteration()->GetName() << ", track candidate " << fvTrackCandidates.size() - 1 - << " found, L = " << best_tr.NofHits() << " chi2= " << best_tr.Chi2() << " hits: "; - for (auto hitIdLoc : tr.Hits()) { - const auto hitId = wData.Hit(hitIdLoc).Id(); - s << hitId << " (mc " << ca::Framework::GetMcTrackIdForCaHit(hitId) << ") "; + fvTrackCandidates.push_back(best_tr); + ca::Branch& tr = fvTrackCandidates.back(); + tr.SetStation(istaF); + tr.SetId(fvTrackCandidates.size() - 1); + // Mark the candidate as dead. To became alive it should first pass the competition in DoCompetitionLoop + tr.SetAlive(false); + if constexpr (fDebug) { + std::stringstream s; + s << "iter " << wData.CurrentIteration()->GetName() << ", track candidate " << fvTrackCandidates.size() - 1 + << " found, L = " << best_tr.NofHits() << " chi2= " << best_tr.Chi2() << " hits: "; + for (auto hitIdLoc : tr.Hits()) { + const auto hitId = wData.Hit(hitIdLoc).Id(); + s << hitId << " (mc " << ca::Framework::GetMcTrackIdForCaHit(hitId) << ") "; + } + LOG(info) << s.str(); } - LOG(info) << s.str(); - } - } // itrip - } // istaF -} - -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::DoCompetitionLoop(const WindowData& wData) -{ + } // itrip + } // istaF + } - // look at the dead track candidates in fvTrackCandidates pool; select the best ones and make them alive + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::DoCompetitionLoop(const WindowData& wData) + { - for (int iComp = 0; (iComp < 100); ++iComp) { + // look at the dead track candidates in fvTrackCandidates pool; select the best ones and make them alive - bool repeatCompetition = false; + for (int iComp = 0; (iComp < 100); ++iComp) { - // == Loop over track candidates and mark their strips - for (ca::Branch& tr : fvTrackCandidates) { - if (tr.IsAlive()) { - continue; - } - for (auto& hitId : tr.Hits()) { + bool repeatCompetition = false; - auto updateStrip = [&](int& strip) { - if ((strip >= 0) && (strip != tr.Id())) { // strip is used by other candidate - const auto& other = fvTrackCandidates[strip]; - if (!other.IsAlive() && tr.IsBetterThan(other)) { - strip = tr.Id(); + // == Loop over track candidates and mark their strips + for (ca::Branch& tr : fvTrackCandidates) { + if (tr.IsAlive()) { + continue; + } + for (auto& hitId : tr.Hits()) { + + auto updateStrip = [&](int& strip) { + if ((strip >= 0) && (strip != tr.Id())) { // strip is used by other candidate + const auto& other = fvTrackCandidates[strip]; + if (!other.IsAlive() && tr.IsBetterThan(other)) { + strip = tr.Id(); + } + else { + return false; + } } else { - return false; + strip = tr.Id(); } + return true; + }; + + const ca::Hit& h = wData.Hit(hitId); + if (!updateStrip(fvHitKeyToTrack[h.FrontKey()])) { // front strip + break; } - else { - strip = tr.Id(); + if (!updateStrip(fvHitKeyToTrack[h.BackKey()])) { // back strip + break; } - return true; - }; + } // loop over hits + } // itrack + + // == Check if some suppressed candidates are still alive - const ca::Hit& h = wData.Hit(hitId); - if (!updateStrip(fvHitKeyToTrack[h.FrontKey()])) { // front strip - break; + for (ca::Branch& tr : fvTrackCandidates) { + if (tr.IsAlive()) { + continue; } - if (!updateStrip(fvHitKeyToTrack[h.BackKey()])) { // back strip - break; + + tr.SetAlive(true); + for (const auto& hitIndex : tr.Hits()) { + if (!tr.IsAlive()) break; + const ca::Hit& h = wData.Hit(hitIndex); + tr.SetAlive((fvHitKeyToTrack[h.FrontKey()] == tr.Id()) && (fvHitKeyToTrack[h.BackKey()] == tr.Id())); } - } // loop over hits - } // itrack - // == Check if some suppressed candidates are still alive + if (!tr.IsAlive()) { // release strips + for (auto hitId : tr.Hits()) { + const ca::Hit& h = wData.Hit(hitId); + if (fvHitKeyToTrack[h.FrontKey()] == tr.Id()) { + fvHitKeyToTrack[h.FrontKey()] = -1; + } + if (fvHitKeyToTrack[h.BackKey()] == tr.Id()) { + fvHitKeyToTrack[h.BackKey()] = -1; + } + } + } + else { + repeatCompetition = true; + } + } // itrack - for (ca::Branch& tr : fvTrackCandidates) { - if (tr.IsAlive()) { - continue; - } + if (!repeatCompetition) break; + } // competitions + } + + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::SelectTracks(WindowData& wData) + { + for (Tindex iCandidate = 0; iCandidate < (Tindex) fvTrackCandidates.size(); ++iCandidate) { + ca::Branch& tr = fvTrackCandidates[iCandidate]; - tr.SetAlive(true); - for (const auto& hitIndex : tr.Hits()) { - if (!tr.IsAlive()) break; - const ca::Hit& h = wData.Hit(hitIndex); - tr.SetAlive((fvHitKeyToTrack[h.FrontKey()] == tr.Id()) && (fvHitKeyToTrack[h.BackKey()] == tr.Id())); + if constexpr (fDebug) { + LOG(info) << "iter " << wData.CurrentIteration()->GetName() << ", track candidate " << iCandidate + << ": alive = " << tr.IsAlive(); } + if (!tr.IsAlive()) continue; - if (!tr.IsAlive()) { // release strips - for (auto hitId : tr.Hits()) { - const ca::Hit& h = wData.Hit(hitId); - if (fvHitKeyToTrack[h.FrontKey()] == tr.Id()) { - fvHitKeyToTrack[h.FrontKey()] = -1; - } - if (fvHitKeyToTrack[h.BackKey()] == tr.Id()) { - fvHitKeyToTrack[h.BackKey()] = -1; - } + if (wData.CurrentIteration()->GetExtendTracksFlag()) { + if (tr.NofHits() < fParameters.GetNstationsActive()) { + fTrackExtender.ExtendBranch(tr, wData); } } - else { - repeatCompetition = true; - } - } // itrack - if (!repeatCompetition) break; - } // competitions -} + for (auto iHit : tr.Hits()) { + const ca::Hit& hit = wData.Hit(iHit); + /// used strips are marked + wData.IsHitKeyUsed(hit.FrontKey()) = 1; + wData.IsHitKeyUsed(hit.BackKey()) = 1; + wData.RecoHitIndices().push_back(hit.Id()); + } + Track t; + t.fNofHits = tr.NofHits(); + wData.RecoTracks().push_back(t); + if (0) { // SG debug + std::stringstream s; + s << "store track " << iCandidate << " chi2= " << tr.Chi2() << "\n"; + s << " hits: "; + for (auto hitLoc : tr.Hits()) { + auto hitId = wData.Hit(hitLoc).Id(); + s << ca::Framework::GetMcTrackIdForCaHit(hitId) << " "; + } + LOG(info) << s.str(); + } + } // tracks + } -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::SelectTracks(WindowData& wData) -{ - for (Tindex iCandidate = 0; iCandidate < (Tindex) fvTrackCandidates.size(); ++iCandidate) { - ca::Branch& tr = fvTrackCandidates[iCandidate]; + /** ************************************************************* + * * + * The routine performs recursive search for tracks * + * * + * I. Kisel 06.03.05 * + * I.Kulakov 2012 * + * * + ****************************************************************/ + + // ------------------------------------------------------------------------------------------------------------------- + void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Triplet* curr_trip, ca::Branch& curr_tr, + unsigned char min_best_l, ca::Branch* new_tr, WindowData& wData, + TripletArray_t& vTriplets) + /// recursive search for tracks + /// input: @ista - station index, @&best_tr - best track for the privious call + /// output: @&NCalls - number of function calls + { - if constexpr (fDebug) { - LOG(info) << "iter " << wData.CurrentIteration()->GetName() << ", track candidate " << iCandidate - << ": alive = " << tr.IsAlive(); - } - if (!tr.IsAlive()) continue; + if (curr_trip->GetLevel() == 0) // the end of the track -> check and store + { + // -- finish with current track + // add rest of hits + const auto& hitM = wData.Hit(curr_trip->GetMHit()); + const auto& hitR = wData.Hit(curr_trip->GetRHit()); - if (wData.CurrentIteration()->GetExtendTracksFlag()) { - if (tr.NofHits() < fParameters.GetNstationsActive()) { - fTrackExtender.ExtendBranch(tr, wData); + if (!(wData.IsHitKeyUsed(hitM.FrontKey()) || wData.IsHitKeyUsed(hitM.BackKey()))) { + curr_tr.AddHit(curr_trip->GetMHit()); } - } - - for (auto iHit : tr.Hits()) { - const ca::Hit& hit = wData.Hit(iHit); - /// used strips are marked - wData.IsHitKeyUsed(hit.FrontKey()) = 1; - wData.IsHitKeyUsed(hit.BackKey()) = 1; - wData.RecoHitIndices().push_back(hit.Id()); - } - Track t; - t.fNofHits = tr.NofHits(); - wData.RecoTracks().push_back(t); - if (0) { // SG debug - std::stringstream s; - s << "store track " << iCandidate << " chi2= " << tr.Chi2() << "\n"; - s << " hits: "; - for (auto hitLoc : tr.Hits()) { - auto hitId = wData.Hit(hitLoc).Id(); - s << ca::Framework::GetMcTrackIdForCaHit(hitId) << " "; + if (!(wData.IsHitKeyUsed(hitR.FrontKey()) || wData.IsHitKeyUsed(hitR.BackKey()))) { + curr_tr.AddHit(curr_trip->GetRHit()); } - LOG(info) << s.str(); - } - } // tracks -} - -/** ************************************************************* - * * - * The routine performs recursive search for tracks * - * * - * I. Kisel 06.03.05 * - * I.Kulakov 2012 * - * * - ****************************************************************/ - -// --------------------------------------------------------------------------------------------------------------------- -void TrackFinderWindow::CAFindTrack(int ista, ca::Branch& best_tr, const ca::Triplet* curr_trip, ca::Branch& curr_tr, - unsigned char min_best_l, ca::Branch* new_tr, WindowData& wData, - TripletArray_t& vTriplets) -/// recursive search for tracks -/// input: @ista - station index, @&best_tr - best track for the privious call -/// output: @&NCalls - number of function calls -{ - if (curr_trip->GetLevel() == 0) // the end of the track -> check and store - { - // -- finish with current track - // add rest of hits - const auto& hitM = wData.Hit(curr_trip->GetMHit()); - const auto& hitR = wData.Hit(curr_trip->GetRHit()); + //if( curr_tr.NofHits() < min_best_l - 1 ) return; // suppouse that only one hit can be added by extender + // TODO: SZh 21.08.2023: Replace hard-coded value with a parameter + int ndf = curr_tr.NofHits() * 2 - 5; - if (!(wData.IsHitKeyUsed(hitM.FrontKey()) || wData.IsHitKeyUsed(hitM.BackKey()))) { - curr_tr.AddHit(curr_trip->GetMHit()); - } - if (!(wData.IsHitKeyUsed(hitR.FrontKey()) || wData.IsHitKeyUsed(hitR.BackKey()))) { - curr_tr.AddHit(curr_trip->GetRHit()); - } - - //if( curr_tr.NofHits() < min_best_l - 1 ) return; // suppouse that only one hit can be added by extender - // TODO: SZh 21.08.2023: Replace hard-coded value with a parameter - int ndf = curr_tr.NofHits() * 2 - 5; + if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) { + ndf = curr_tr.NofHits() * 2 - 4; + } + if (curr_tr.Chi2() > wData.CurrentIteration()->GetTrackChi2Cut() * ndf) { + return; + } - if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) { - ndf = curr_tr.NofHits() * 2 - 4; - } - if (curr_tr.Chi2() > wData.CurrentIteration()->GetTrackChi2Cut() * ndf) { + // -- select the best + if ((curr_tr.NofHits() > best_tr.NofHits()) + || ((curr_tr.NofHits() == best_tr.NofHits()) && (curr_tr.Chi2() < best_tr.Chi2()))) { + best_tr = curr_tr; + } return; } + else //MEANS level ! = 0 + { + int N_neighbour = (curr_trip->GetNNeighbours()); - // -- select the best - if ((curr_tr.NofHits() > best_tr.NofHits()) - || ((curr_tr.NofHits() == best_tr.NofHits()) && (curr_tr.Chi2() < best_tr.Chi2()))) { - best_tr = curr_tr; - } - return; - } - else //MEANS level ! = 0 - { - int N_neighbour = (curr_trip->GetNNeighbours()); - - for (Tindex in = 0; in < N_neighbour; in++) { + for (Tindex in = 0; in < N_neighbour; in++) { - unsigned int ID = curr_trip->GetFNeighbour() + in; - unsigned int Station = TripletId2Station(ID); - unsigned int Triplet = TripletId2Triplet(ID); + unsigned int ID = curr_trip->GetFNeighbour() + in; + unsigned int Station = TripletId2Station(ID); + unsigned int Triplet = TripletId2Triplet(ID); - const ca::Triplet& new_trip = vTriplets[Station][Triplet]; + const ca::Triplet& new_trip = vTriplets[Station][Triplet]; - fscal dchi2 = 0.; - if (!checkTripletMatch(*curr_trip, new_trip, dchi2, wData)) continue; - - const auto& hitL = wData.Hit(new_trip.GetLHit()); // left hit of new triplet - if (wData.IsHitKeyUsed(hitL.FrontKey()) || wData.IsHitKeyUsed(hitL.BackKey())) { //hits are used - // no used hits allowed -> compare and store track - if ((curr_tr.NofHits() > best_tr.NofHits()) - || ((curr_tr.NofHits() == best_tr.NofHits()) && (curr_tr.Chi2() < best_tr.Chi2()))) { - best_tr = curr_tr; - } - } - else { // hit is not used: add the left hit from the new triplet to the current track - - unsigned char new_L = curr_tr.NofHits() + 1; - fscal new_chi2 = curr_tr.Chi2() + dchi2; - - if constexpr (0) { //SGtrd2d debug!! - int mc01 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetLHit()); - int mc02 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetMHit()); - int mc03 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetRHit()); - int mc11 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetLHit()); - int mc12 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetMHit()); - int mc13 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetRHit()); - - if ((mc01 == mc02) && (mc02 == mc03)) { - LOG(info) << " sta " << ista << " mc0 " << mc01 << " " << mc02 << " " << mc03 << " mc1 " << mc11 << " " - << mc12 << " " << mc13 << " chi2 " << curr_tr.Chi2() / (2 * (curr_tr.NofHits() + 2) - 4) - << " new " << new_chi2 / (2 * (new_L + 2) - 4); - LOG(info) << " hits " << curr_trip->GetLHit() << " " << curr_trip->GetMHit() << " " - << curr_trip->GetRHit() << " " << new_trip.GetLHit(); + fscal dchi2 = 0.; + if (!checkTripletMatch(*curr_trip, new_trip, dchi2, wData)) continue; + + const auto& hitL = wData.Hit(new_trip.GetLHit()); // left hit of new triplet + if (wData.IsHitKeyUsed(hitL.FrontKey()) || wData.IsHitKeyUsed(hitL.BackKey())) { //hits are used + // no used hits allowed -> compare and store track + if ((curr_tr.NofHits() > best_tr.NofHits()) + || ((curr_tr.NofHits() == best_tr.NofHits()) && (curr_tr.Chi2() < best_tr.Chi2()))) { + best_tr = curr_tr; } } + else { // hit is not used: add the left hit from the new triplet to the current track + + unsigned char new_L = curr_tr.NofHits() + 1; + fscal new_chi2 = curr_tr.Chi2() + dchi2; + + if constexpr (0) { //SGtrd2d debug!! + int mc01 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetLHit()); + int mc02 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetMHit()); + int mc03 = ca::Framework::GetMcTrackIdForWindowHit(curr_trip->GetRHit()); + int mc11 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetLHit()); + int mc12 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetMHit()); + int mc13 = ca::Framework::GetMcTrackIdForWindowHit(new_trip.GetRHit()); + + if ((mc01 == mc02) && (mc02 == mc03)) { + LOG(info) << " sta " << ista << " mc0 " << mc01 << " " << mc02 << " " << mc03 << " mc1 " << mc11 << " " + << mc12 << " " << mc13 << " chi2 " << curr_tr.Chi2() / (2 * (curr_tr.NofHits() + 2) - 4) + << " new " << new_chi2 / (2 * (new_L + 2) - 4); + LOG(info) << " hits " << curr_trip->GetLHit() << " " << curr_trip->GetMHit() << " " + << curr_trip->GetRHit() << " " << new_trip.GetLHit(); + } + } - int ndf = 2 * (new_L + 2) - 5; + int ndf = 2 * (new_L + 2) - 5; - if (ca::TrackingMode::kGlobal == fTrackingMode) { //SGtrd2d!!! - ndf = 2 * (new_L + 2) - 4; - } - else if (ca::TrackingMode::kMcbm == fTrackingMode) { - ndf = 2 * (new_L + 2) - 4; - } - else { - ndf = new_L; // TODO: SG: 2 * (new_L + 2) - 5 - } + if (ca::TrackingMode::kGlobal == fTrackingMode) { //SGtrd2d!!! + ndf = 2 * (new_L + 2) - 4; + } + else if (ca::TrackingMode::kMcbm == fTrackingMode) { + ndf = 2 * (new_L + 2) - 4; + } + else { + ndf = new_L; // TODO: SG: 2 * (new_L + 2) - 5 + } - if (new_chi2 > wData.CurrentIteration()->GetTrackChi2Cut() * ndf) continue; + if (new_chi2 > wData.CurrentIteration()->GetTrackChi2Cut() * ndf) continue; - // add new hit - new_tr[ista] = curr_tr; - new_tr[ista].AddHit(new_trip.GetLHit()); + // add new hit + new_tr[ista] = curr_tr; + new_tr[ista].AddHit(new_trip.GetLHit()); - const int new_ista = ista + new_trip.GetMSta() - new_trip.GetLSta(); - new_tr[ista].SetChi2(new_chi2); + const int new_ista = ista + new_trip.GetMSta() - new_trip.GetLSta(); + new_tr[ista].SetChi2(new_chi2); + + CAFindTrack(new_ista, best_tr, &new_trip, new_tr[ista], min_best_l, new_tr, wData, vTriplets); + } // add triplet to track + } // for neighbours + } // level = 0 + } - CAFindTrack(new_ista, best_tr, &new_trip, new_tr[ista], min_best_l, new_tr, wData, vTriplets); - } // add triplet to track - } // for neighbours - } // level = 0 -} +} // namespace cbm::algo::ca diff --git a/algo/ca/core/tracking/CaTrackFitter.cxx b/algo/ca/core/tracking/CaTrackFitter.cxx index 4f6d2e089ce2259b01d7835d45e4b8a3acc7deff..9d716e6da66bb2294a2515fdde728a469ca369fc 100644 --- a/algo/ca/core/tracking/CaTrackFitter.cxx +++ b/algo/ca/core/tracking/CaTrackFitter.cxx @@ -11,389 +11,386 @@ #include <iostream> #include <vector> -using std::vector; -using Track = cbm::algo::ca::Track; -using namespace cbm::algo::ca; -using namespace cbm::algo; - - -// --------------------------------------------------------------------------------------------------------------------- -// -TrackFitter::TrackFitter(const ca::Parameters<fvec>& pars, const fscal mass, const ca::TrackingMode& mode) - : fParameters(pars) - , fSetup(fParameters.GetActiveSetup()) - , fDefaultMass(mass) - , fTrackingMode(mode) +namespace cbm::algo::ca { -} + // ------------------------------------------------------------------------------------------------------------------- + // + TrackFitter::TrackFitter(const ca::Parameters<fvec>& pars, const fscal mass, const ca::TrackingMode& mode) + : fParameters(pars) + , fSetup(fParameters.GetActiveSetup()) + , fDefaultMass(mass) + , fTrackingMode(mode) + { + } -// --------------------------------------------------------------------------------------------------------------------- -// -TrackFitter::~TrackFitter() {} + // ------------------------------------------------------------------------------------------------------------------- + // + TrackFitter::~TrackFitter() {} -// --------------------------------------------------------------------------------------------------------------------- -// -void TrackFitter::FitCaTracks(const ca::InputData& input, WindowData& wData) -{ - // LOG(info) << " Start CA Track Fitter "; - int start_hit = 0; // for interation in wData.RecoHitIndices() + // ------------------------------------------------------------------------------------------------------------------- + // + void TrackFitter::FitCaTracks(const ca::InputData& input, WindowData& wData) + { + // LOG(info) << " Start CA Track Fitter "; + int start_hit = 0; // for interation in wData.RecoHitIndices() - // static kf::FieldValue fldB0, fldB1, fldB2 _fvecalignment; - // static kf::FieldRegion fld _fvecalignment; - kf::FieldValue<fvec> fldB0, fldB1, fldB2 _fvecalignment; - kf::FieldRegion<fvec> fld _fvecalignment; + // static kf::FieldValue fldB0, fldB1, fldB2 _fvecalignment; + // static kf::FieldRegion fld _fvecalignment; + kf::FieldValue<fvec> fldB0, fldB1, fldB2 _fvecalignment; + kf::FieldRegion<fvec> fld _fvecalignment; - kf::FieldValue<fvec> fldB01, fldB11, fldB21 _fvecalignment; - kf::FieldRegion<fvec> fld1 _fvecalignment; + kf::FieldValue<fvec> fldB01, fldB11, fldB21 _fvecalignment; + kf::FieldRegion<fvec> fld1 _fvecalignment; - const int nStations = fParameters.GetNstationsActive(); - int nTracks_SIMD = fvec::size(); + const int nStations = fParameters.GetNstationsActive(); + int nTracks_SIMD = fvec::size(); - kf::TrackKalmanFilter<fvec> fit; // fit parameters coresponding to the current track - TrackParamV& tr = fit.Tr(); - fit.SetParticleMass(fDefaultMass); - fit.SetDoFitVelocity(true); + kf::TrackKalmanFilter<fvec> fit; // fit parameters coresponding to the current track + TrackParamV& tr = fit.Tr(); + fit.SetParticleMass(fDefaultMass); + fit.SetDoFitVelocity(true); - Track* t[fvec::size()]{nullptr}; + Track* t[fvec::size()]{nullptr}; - const ca::Station<fvec>* sta = fParameters.GetStations().begin(); + const ca::Station<fvec>* sta = fParameters.GetStations().begin(); - // Spatial-time position of a hit vs. station and track in the portion + // Spatial-time position of a hit vs. station and track in the portion - fvec x[constants::size::MaxNstations]; // Hit position along the x-axis [cm] - fvec y[constants::size::MaxNstations]; // Hit position along the y-axis [cm] - kf::MeasurementXy<fvec> mxy[constants::size::MaxNstations]; // Covariance matrix for x,y + fvec x[constants::size::MaxNstations]; // Hit position along the x-axis [cm] + fvec y[constants::size::MaxNstations]; // Hit position along the y-axis [cm] + kf::MeasurementXy<fvec> mxy[constants::size::MaxNstations]; // Covariance matrix for x,y - fvec z[constants::size::MaxNstations]; // Hit position along the z-axis (precised) [cm] + fvec z[constants::size::MaxNstations]; // Hit position along the z-axis (precised) [cm] - fvec time[constants::size::MaxNstations]; // Hit time [ns] - fvec dt2[constants::size::MaxNstations]; // Hit time uncertainty [ns] squared + fvec time[constants::size::MaxNstations]; // Hit time [ns] + fvec dt2[constants::size::MaxNstations]; // Hit time uncertainty [ns] squared - fvec x_first; - fvec y_first; - kf::MeasurementXy<fvec> mxy_first; + fvec x_first; + fvec y_first; + kf::MeasurementXy<fvec> mxy_first; - fvec time_first; - fvec wtime_first; - fvec dt2_first; + fvec time_first; + fvec wtime_first; + fvec dt2_first; - fvec x_last; - fvec y_last; - kf::MeasurementXy<fvec> mxy_last; + fvec x_last; + fvec y_last; + kf::MeasurementXy<fvec> mxy_last; - fvec time_last; - fvec wtime_last; - fvec dt2_last; + fvec time_last; + fvec wtime_last; + fvec dt2_last; - fvec By[constants::size::MaxNstations]; - fmask w[constants::size::MaxNstations]; - fmask w_time[constants::size::MaxNstations]; // !!! + fvec By[constants::size::MaxNstations]; + fmask w[constants::size::MaxNstations]; + fmask w_time[constants::size::MaxNstations]; // !!! - fvec y_temp; - fvec x_temp; - fvec fldZ0; - fvec fldZ1; - fvec fldZ2; - fvec z_start; - fvec z_end; + fvec y_temp; + fvec x_temp; + fvec fldZ0; + fvec fldZ1; + fvec fldZ2; + fvec z_start; + fvec z_end; - kf::FieldValue<fvec> fB[constants::size::MaxNstations], fB_temp _fvecalignment; + kf::FieldValue<fvec> fB[constants::size::MaxNstations], fB_temp _fvecalignment; - fvec ZSta[constants::size::MaxNstations]; - for (int ista = 0; ista < nStations; ista++) { - ZSta[ista] = sta[ista].fZ; - mxy[ista].SetCov(1., 0., 1.); - } + fvec ZSta[constants::size::MaxNstations]; + for (int ista = 0; ista < nStations; ista++) { + ZSta[ista] = sta[ista].fZ; + mxy[ista].SetCov(1., 0., 1.); + } - unsigned short N_vTracks = wData.RecoTracks().size(); // number of tracks processed per one SSE register + unsigned short N_vTracks = wData.RecoTracks().size(); // number of tracks processed per one SSE register - for (unsigned short itrack = 0; itrack < N_vTracks; itrack += fvec::size()) { + for (unsigned short itrack = 0; itrack < N_vTracks; itrack += fvec::size()) { - if (N_vTracks - itrack < static_cast<unsigned short>(fvec::size())) nTracks_SIMD = N_vTracks - itrack; + if (N_vTracks - itrack < static_cast<unsigned short>(fvec::size())) nTracks_SIMD = N_vTracks - itrack; - for (int i = 0; i < nTracks_SIMD; i++) { - t[i] = &wData.RecoTrack(itrack + i); - } + for (int i = 0; i < nTracks_SIMD; i++) { + t[i] = &wData.RecoTrack(itrack + i); + } - // fill the rest of the SIMD vectors with something reasonable - for (uint i = nTracks_SIMD; i < fvec::size(); i++) { - t[i] = &wData.RecoTrack(itrack); - } + // fill the rest of the SIMD vectors with something reasonable + for (uint i = nTracks_SIMD; i < fvec::size(); i++) { + t[i] = &wData.RecoTrack(itrack); + } - // get hits of current track - for (int ista = 0; ista < nStations; ista++) { - w[ista] = fmask::Zero(); - w_time[ista] = fmask::Zero(); - z[ista] = ZSta[ista]; - } + // get hits of current track + for (int ista = 0; ista < nStations; ista++) { + w[ista] = fmask::Zero(); + w_time[ista] = fmask::Zero(); + z[ista] = ZSta[ista]; + } - //fmask isFieldPresent = fmask::Zero(); + //fmask isFieldPresent = fmask::Zero(); - for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { + for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { - int nHitsTrack = t[iVec]->fNofHits; - int iSta[constants::size::MaxNstations]; + int nHitsTrack = t[iVec]->fNofHits; + int iSta[constants::size::MaxNstations]; - for (int ih = 0; ih < nHitsTrack; ih++) { + for (int ih = 0; ih < nHitsTrack; ih++) { - const ca::Hit& hit = input.GetHit(wData.RecoHitIndex(start_hit++)); - const int ista = hit.Station(); + const ca::Hit& hit = input.GetHit(wData.RecoHitIndex(start_hit++)); + const int ista = hit.Station(); - //if (sta[ista].fieldStatus) { isFieldPresent[iVec] = true; } + //if (sta[ista].fieldStatus) { isFieldPresent[iVec] = true; } - iSta[ih] = ista; - w[ista][iVec] = true; - if (sta[ista].timeInfo) { - w_time[ista][iVec] = true; - } + iSta[ih] = ista; + w[ista][iVec] = true; + if (sta[ista].timeInfo) { + w_time[ista][iVec] = true; + } - x[ista][iVec] = hit.X(); //x_temp[iVec]; - y[ista][iVec] = hit.Y(); //y_temp[iVec]; - time[ista][iVec] = hit.T(); - dt2[ista][iVec] = hit.dT2(); - if (!sta[ista].timeInfo) { - dt2[ista][iVec] = 1.e4; - } - z[ista][iVec] = hit.Z(); - fB_temp = sta[ista].fieldSlice.GetFieldValue(x[ista], y[ista]); - mxy[ista].X()[iVec] = hit.X(); - mxy[ista].Y()[iVec] = hit.Y(); - mxy[ista].Dx2()[iVec] = hit.dX2(); - mxy[ista].Dy2()[iVec] = hit.dY2(); - mxy[ista].Dxy()[iVec] = hit.dXY(); - mxy[ista].NdfX()[iVec] = 1.; - mxy[ista].NdfY()[iVec] = 1.; - - fB[ista].SetSimdEntry(fB_temp.GetBx()[iVec], fB_temp.GetBy()[iVec], fB_temp.GetBz()[iVec], iVec); - - if (ih == 0) { - z_start[iVec] = z[ista][iVec]; - x_first[iVec] = x[ista][iVec]; - y_first[iVec] = y[ista][iVec]; - time_first[iVec] = time[ista][iVec]; - wtime_first[iVec] = sta[ista].timeInfo ? 1. : 0.; - dt2_first[iVec] = dt2[ista][iVec]; - mxy_first.X()[iVec] = mxy[ista].X()[iVec]; - mxy_first.Y()[iVec] = mxy[ista].Y()[iVec]; - mxy_first.Dx2()[iVec] = mxy[ista].Dx2()[iVec]; - mxy_first.Dy2()[iVec] = mxy[ista].Dy2()[iVec]; - mxy_first.Dxy()[iVec] = mxy[ista].Dxy()[iVec]; - mxy_first.NdfX()[iVec] = mxy[ista].NdfX()[iVec]; - mxy_first.NdfY()[iVec] = mxy[ista].NdfY()[iVec]; - } - else if (ih == nHitsTrack - 1) { - z_end[iVec] = z[ista][iVec]; - x_last[iVec] = x[ista][iVec]; - y_last[iVec] = y[ista][iVec]; - mxy_last.X()[iVec] = mxy[ista].X()[iVec]; - mxy_last.Y()[iVec] = mxy[ista].Y()[iVec]; - mxy_last.Dx2()[iVec] = mxy[ista].Dx2()[iVec]; - mxy_last.Dy2()[iVec] = mxy[ista].Dy2()[iVec]; - mxy_last.Dxy()[iVec] = mxy[ista].Dxy()[iVec]; - mxy_last.NdfX()[iVec] = mxy[ista].NdfX()[iVec]; - mxy_last.NdfY()[iVec] = mxy[ista].NdfY()[iVec]; - time_last[iVec] = time[ista][iVec]; - dt2_last[iVec] = dt2[ista][iVec]; - wtime_last[iVec] = sta[ista].timeInfo ? 1. : 0.; + x[ista][iVec] = hit.X(); //x_temp[iVec]; + y[ista][iVec] = hit.Y(); //y_temp[iVec]; + time[ista][iVec] = hit.T(); + dt2[ista][iVec] = hit.dT2(); + if (!sta[ista].timeInfo) { + dt2[ista][iVec] = 1.e4; + } + z[ista][iVec] = hit.Z(); + fB_temp = sta[ista].fieldSlice.GetFieldValue(x[ista], y[ista]); + mxy[ista].X()[iVec] = hit.X(); + mxy[ista].Y()[iVec] = hit.Y(); + mxy[ista].Dx2()[iVec] = hit.dX2(); + mxy[ista].Dy2()[iVec] = hit.dY2(); + mxy[ista].Dxy()[iVec] = hit.dXY(); + mxy[ista].NdfX()[iVec] = 1.; + mxy[ista].NdfY()[iVec] = 1.; + + fB[ista].SetSimdEntry(fB_temp.GetBx()[iVec], fB_temp.GetBy()[iVec], fB_temp.GetBz()[iVec], iVec); + + if (ih == 0) { + z_start[iVec] = z[ista][iVec]; + x_first[iVec] = x[ista][iVec]; + y_first[iVec] = y[ista][iVec]; + time_first[iVec] = time[ista][iVec]; + wtime_first[iVec] = sta[ista].timeInfo ? 1. : 0.; + dt2_first[iVec] = dt2[ista][iVec]; + mxy_first.X()[iVec] = mxy[ista].X()[iVec]; + mxy_first.Y()[iVec] = mxy[ista].Y()[iVec]; + mxy_first.Dx2()[iVec] = mxy[ista].Dx2()[iVec]; + mxy_first.Dy2()[iVec] = mxy[ista].Dy2()[iVec]; + mxy_first.Dxy()[iVec] = mxy[ista].Dxy()[iVec]; + mxy_first.NdfX()[iVec] = mxy[ista].NdfX()[iVec]; + mxy_first.NdfY()[iVec] = mxy[ista].NdfY()[iVec]; + } + else if (ih == nHitsTrack - 1) { + z_end[iVec] = z[ista][iVec]; + x_last[iVec] = x[ista][iVec]; + y_last[iVec] = y[ista][iVec]; + mxy_last.X()[iVec] = mxy[ista].X()[iVec]; + mxy_last.Y()[iVec] = mxy[ista].Y()[iVec]; + mxy_last.Dx2()[iVec] = mxy[ista].Dx2()[iVec]; + mxy_last.Dy2()[iVec] = mxy[ista].Dy2()[iVec]; + mxy_last.Dxy()[iVec] = mxy[ista].Dxy()[iVec]; + mxy_last.NdfX()[iVec] = mxy[ista].NdfX()[iVec]; + mxy_last.NdfY()[iVec] = mxy[ista].NdfY()[iVec]; + time_last[iVec] = time[ista][iVec]; + dt2_last[iVec] = dt2[ista][iVec]; + wtime_last[iVec] = sta[ista].timeInfo ? 1. : 0.; + } } - } - for (int ih = nHitsTrack - 1; ih >= 0; ih--) { - const int ista = iSta[ih]; - const ca::Station<fvec>& st = fParameters.GetStation(ista); - By[ista][iVec] = st.fieldSlice.GetFieldValue(0., 0.).GetBy()[0]; + for (int ih = nHitsTrack - 1; ih >= 0; ih--) { + const int ista = iSta[ih]; + const ca::Station<fvec>& st = fParameters.GetStation(ista); + By[ista][iVec] = st.fieldSlice.GetFieldValue(0., 0.).GetBy()[0]; + } } - } - - fit.GuessTrack(z_end, x, y, z, time, By, w, w_time, nStations); - - if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) { - tr.Qp() = fvec(1. / 1.1); - } - - // tr.Qp() = iif(isFieldPresent, tr.Qp(), fvec(1. / 0.25)); - for (int iter = 0; iter < 2; iter++) { // 1.5 iterations + fit.GuessTrack(z_end, x, y, z, time, By, w, w_time, nStations); - fit.SetQp0(tr.Qp()); + if (ca::TrackingMode::kGlobal == fTrackingMode || ca::TrackingMode::kMcbm == fTrackingMode) { + tr.Qp() = fvec(1. / 1.1); + } - // fit backward + // tr.Qp() = iif(isFieldPresent, tr.Qp(), fvec(1. / 0.25)); - int ista = nStations - 1; + for (int iter = 0; iter < 2; iter++) { // 1.5 iterations - time_last = iif(w_time[ista], time_last, fvec::Zero()); - dt2_last = iif(w_time[ista], dt2_last, fvec(1.e6)); + fit.SetQp0(tr.Qp()); - tr.ResetErrors(mxy_last.Dx2(), mxy_last.Dy2(), 0.1, 0.1, 1.0, dt2_last, 1.e-2); - tr.C10() = mxy_last.Dxy(); - tr.X() = mxy_last.X(); - tr.Y() = mxy_last.Y(); - tr.Time() = time_last; - tr.Vi() = constants::phys::SpeedOfLightInv; - tr.InitVelocityRange(0.5); - tr.Ndf() = fvec(-5.) + fvec(2.); - tr.NdfTime() = fvec(-2.) + wtime_last; + // fit backward - fldZ1 = z[ista]; + int ista = nStations - 1; - fldB1 = sta[ista].fieldSlice.GetFieldValue(tr.X(), tr.Y()); + time_last = iif(w_time[ista], time_last, fvec::Zero()); + dt2_last = iif(w_time[ista], dt2_last, fvec(1.e6)); - fldB1.SetSimdEntries(fB[ista], w[ista]); + tr.ResetErrors(mxy_last.Dx2(), mxy_last.Dy2(), 0.1, 0.1, 1.0, dt2_last, 1.e-2); + tr.C10() = mxy_last.Dxy(); + tr.X() = mxy_last.X(); + tr.Y() = mxy_last.Y(); + tr.Time() = time_last; + tr.Vi() = constants::phys::SpeedOfLightInv; + tr.InitVelocityRange(0.5); + tr.Ndf() = fvec(-5.) + fvec(2.); + tr.NdfTime() = fvec(-2.) + wtime_last; - fldZ2 = z[ista - 2]; - fvec dz = fldZ2 - fldZ1; - fldB2 = sta[ista].fieldSlice.GetFieldValue(tr.X() + tr.Tx() * dz, tr.Y() + tr.Ty() * dz); - fldB2.SetSimdEntries(fB[ista - 2], w[ista - 2]); - fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); + fldZ1 = z[ista]; - for (--ista; ista >= 0; ista--) { + fldB1 = sta[ista].fieldSlice.GetFieldValue(tr.X(), tr.Y()); - fldZ0 = z[ista]; - dz = (fldZ1 - fldZ0); - fldB0 = sta[ista].fieldSlice.GetFieldValue(tr.X() - tr.Tx() * dz, tr.Y() - tr.Ty() * dz); - fldB0.SetSimdEntries(fB[ista], w[ista]); - fld.Set(fldB0, fldZ0, fldB1, fldZ1, fldB2, fldZ2); + fldB1.SetSimdEntries(fB[ista], w[ista]); - fmask initialised = (z[ista] < z_end) & (z_start <= z[ista]); + fldZ2 = z[ista - 2]; + fvec dz = fldZ2 - fldZ1; + fldB2 = sta[ista].fieldSlice.GetFieldValue(tr.X() + tr.Tx() * dz, tr.Y() + tr.Ty() * dz); + fldB2.SetSimdEntries(fB[ista - 2], w[ista - 2]); + fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); - fld1 = fld; + for (--ista; ista >= 0; ista--) { - fit.SetMask(initialised); - fit.Extrapolate(z[ista], fld1); - auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(tr.X(), tr.Y()); - fit.MultipleScattering(radThick); - fit.EnergyLossCorrection(radThick, kf::FitDirection::kUpstream); + fldZ0 = z[ista]; + dz = (fldZ1 - fldZ0); + fldB0 = sta[ista].fieldSlice.GetFieldValue(tr.X() - tr.Tx() * dz, tr.Y() - tr.Ty() * dz); + fldB0.SetSimdEntries(fB[ista], w[ista]); + fld.Set(fldB0, fldZ0, fldB1, fldZ1, fldB2, fldZ2); - fit.SetMask(initialised && w[ista]); - fit.FilterXY(mxy[ista]); - fit.FilterTime(time[ista], dt2[ista], fmask(sta[ista].timeInfo)); + fmask initialised = (z[ista] < z_end) & (z_start <= z[ista]); + fld1 = fld; - fldB2 = fldB1; - fldZ2 = fldZ1; - fldB1 = fldB0; - fldZ1 = fldZ0; - } + fit.SetMask(initialised); + fit.Extrapolate(z[ista], fld1); + auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(tr.X(), tr.Y()); + fit.MultipleScattering(radThick); + fit.EnergyLossCorrection(radThick, kf::FitDirection::kUpstream); - // extrapolate to the PV region + fit.SetMask(initialised && w[ista]); + fit.FilterXY(mxy[ista]); + fit.FilterTime(time[ista], dt2[ista], fmask(sta[ista].timeInfo)); - kf::TrackKalmanFilter fitpv = fit; - { - fitpv.SetMask(fmask::One()); - kf::MeasurementXy<fvec> vtxInfo = wData.TargetMeasurement(); - vtxInfo.SetDx2(1.e-8); - vtxInfo.SetDxy(0.); - vtxInfo.SetDy2(1.e-8); + fldB2 = fldB1; + fldZ2 = fldZ1; + fldB1 = fldB0; + fldZ1 = fldZ0; + } - if (ca::TrackingMode::kGlobal == fTrackingMode) { - kf::FieldRegion<fvec> fldFull(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField); - fitpv.SetMaxExtrapolationStep(1.); - for (int vtxIter = 0; vtxIter < 2; vtxIter++) { + // extrapolate to the PV region + + kf::TrackKalmanFilter fitpv = fit; + { + fitpv.SetMask(fmask::One()); + + kf::MeasurementXy<fvec> vtxInfo = wData.TargetMeasurement(); + vtxInfo.SetDx2(1.e-8); + vtxInfo.SetDxy(0.); + vtxInfo.SetDy2(1.e-8); + + if (ca::TrackingMode::kGlobal == fTrackingMode) { + kf::FieldRegion<fvec> fldFull(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField); + fitpv.SetMaxExtrapolationStep(1.); + for (int vtxIter = 0; vtxIter < 2; vtxIter++) { + fitpv.SetQp0(fitpv.Tr().Qp()); + fitpv.Tr() = fit.Tr(); + fitpv.Tr().Qp() = fitpv.Qp0(); + fitpv.Extrapolate(fParameters.GetTargetPositionZ(), fldFull); + fitpv.FilterXY(vtxInfo); + } + } + else { fitpv.SetQp0(fitpv.Tr().Qp()); - fitpv.Tr() = fit.Tr(); - fitpv.Tr().Qp() = fitpv.Qp0(); - fitpv.Extrapolate(fParameters.GetTargetPositionZ(), fldFull); - fitpv.FilterXY(vtxInfo); + fitpv.Extrapolate(fParameters.GetTargetPositionZ(), fld); } } - else { - fitpv.SetQp0(fitpv.Tr().Qp()); - fitpv.Extrapolate(fParameters.GetTargetPositionZ(), fld); - } - } - //fit.SetQp0(tr.Qp()); - //fit.SetMask(fmask::One()); - //fit.MeasureVelocityWithQp(); - //fit.FilterVi(TrackParamV::kClightNsInv); + //fit.SetQp0(tr.Qp()); + //fit.SetMask(fmask::One()); + //fit.MeasureVelocityWithQp(); + //fit.FilterVi(TrackParamV::kClightNsInv); - TrackParamV Tf = fit.Tr(); - if (ca::TrackingMode::kGlobal == fTrackingMode) { - Tf.Qp() = fitpv.Tr().Qp(); - } + TrackParamV Tf = fit.Tr(); + if (ca::TrackingMode::kGlobal == fTrackingMode) { + Tf.Qp() = fitpv.Tr().Qp(); + } - for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { - t[iVec]->fParFirst.Set(Tf, iVec); - } + for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { + t[iVec]->fParFirst.Set(Tf, iVec); + } - for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { - t[iVec]->fParPV.Set(fitpv.Tr(), iVec); - } + for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { + t[iVec]->fParPV.Set(fitpv.Tr(), iVec); + } - if (iter == 1) { - break; - } // only 1.5 iterations + if (iter == 1) { + break; + } // only 1.5 iterations - // fit forward + // fit forward - ista = 0; + ista = 0; - tr.ResetErrors(mxy_first.Dx2(), mxy_first.Dy2(), 0.1, 0.1, 1., dt2_first, 1.e-2); - tr.C10() = mxy_first.Dxy(); + tr.ResetErrors(mxy_first.Dx2(), mxy_first.Dy2(), 0.1, 0.1, 1., dt2_first, 1.e-2); + tr.C10() = mxy_first.Dxy(); - tr.X() = mxy_first.X(); - tr.Y() = mxy_first.Y(); - tr.Time() = time_first; - tr.Vi() = constants::phys::SpeedOfLightInv; - tr.InitVelocityRange(0.5); + tr.X() = mxy_first.X(); + tr.Y() = mxy_first.Y(); + tr.Time() = time_first; + tr.Vi() = constants::phys::SpeedOfLightInv; + tr.InitVelocityRange(0.5); - tr.Ndf() = fvec(-5. + 2.); - tr.NdfTime() = fvec(-2.) + wtime_first; + tr.Ndf() = fvec(-5. + 2.); + tr.NdfTime() = fvec(-2.) + wtime_first; - fit.SetQp0(tr.Qp()); + fit.SetQp0(tr.Qp()); - fldZ1 = z[ista]; - fldB1 = sta[ista].fieldSlice.GetFieldValue(tr.X(), tr.Y()); - fldB1.SetSimdEntries(fB[ista], w[ista]); + fldZ1 = z[ista]; + fldB1 = sta[ista].fieldSlice.GetFieldValue(tr.X(), tr.Y()); + fldB1.SetSimdEntries(fB[ista], w[ista]); - fldZ2 = z[ista + 2]; - dz = fldZ2 - fldZ1; - fldB2 = sta[ista].fieldSlice.GetFieldValue(tr.X() + tr.Tx() * dz, tr.Y() + tr.Ty() * dz); - fldB2.SetSimdEntries(fB[ista + 2], w[ista + 2]); - fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); + fldZ2 = z[ista + 2]; + dz = fldZ2 - fldZ1; + fldB2 = sta[ista].fieldSlice.GetFieldValue(tr.X() + tr.Tx() * dz, tr.Y() + tr.Ty() * dz); + fldB2.SetSimdEntries(fB[ista + 2], w[ista + 2]); + fld.Set(fldB2, fldZ2, fldB1, fldZ1, fldB0, fldZ0); - for (++ista; ista < nStations; ista++) { - fldZ0 = z[ista]; - dz = (fldZ1 - fldZ0); - fldB0 = sta[ista].fieldSlice.GetFieldValue(tr.X() - tr.Tx() * dz, tr.Y() - tr.Ty() * dz); - fldB0.SetSimdEntries(fB[ista], w[ista]); - fld.Set(fldB0, fldZ0, fldB1, fldZ1, fldB2, fldZ2); + for (++ista; ista < nStations; ista++) { + fldZ0 = z[ista]; + dz = (fldZ1 - fldZ0); + fldB0 = sta[ista].fieldSlice.GetFieldValue(tr.X() - tr.Tx() * dz, tr.Y() - tr.Ty() * dz); + fldB0.SetSimdEntries(fB[ista], w[ista]); + fld.Set(fldB0, fldZ0, fldB1, fldZ1, fldB2, fldZ2); - fmask initialised = (z[ista] <= z_end) & (z_start < z[ista]); + fmask initialised = (z[ista] <= z_end) & (z_start < z[ista]); - fit.SetMask(initialised); - fit.Extrapolate(z[ista], fld); - auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(tr.X(), tr.Y()); - fit.MultipleScattering(radThick); - fit.EnergyLossCorrection(radThick, kf::FitDirection::kDownstream); - fit.SetMask(initialised && w[ista]); - fit.FilterXY(mxy[ista]); - fit.FilterTime(time[ista], dt2[ista], fmask(sta[ista].timeInfo)); + fit.SetMask(initialised); + fit.Extrapolate(z[ista], fld); + auto radThick = fSetup.GetMaterial(ista).GetThicknessX0(tr.X(), tr.Y()); + fit.MultipleScattering(radThick); + fit.EnergyLossCorrection(radThick, kf::FitDirection::kDownstream); + fit.SetMask(initialised && w[ista]); + fit.FilterXY(mxy[ista]); + fit.FilterTime(time[ista], dt2[ista], fmask(sta[ista].timeInfo)); - fldB2 = fldB1; - fldZ2 = fldZ1; - fldB1 = fldB0; - fldZ1 = fldZ0; - } + fldB2 = fldB1; + fldZ2 = fldZ1; + fldB1 = fldB0; + fldZ1 = fldZ0; + } - //fit.SetQp0(tr.Qp()); - //fit.SetMask(fmask::One()); - //fit.MeasureVelocityWithQp(); - //fit.FilterVi(TrackParamV::kClightNsInv); + //fit.SetQp0(tr.Qp()); + //fit.SetMask(fmask::One()); + //fit.MeasureVelocityWithQp(); + //fit.FilterVi(TrackParamV::kClightNsInv); - TrackParamV Tl = fit.Tr(); - if (ca::TrackingMode::kGlobal == fTrackingMode) { - Tl.Qp() = fitpv.Tr().Qp(); - } + TrackParamV Tl = fit.Tr(); + if (ca::TrackingMode::kGlobal == fTrackingMode) { + Tl.Qp() = fitpv.Tr().Qp(); + } - for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { - t[iVec]->fParLast.Set(Tl, iVec); - } + for (int iVec = 0; iVec < nTracks_SIMD; iVec++) { + t[iVec]->fParLast.Set(Tl, iVec); + } - } // iter + } // iter + } } -} +} // namespace cbm::algo::ca \ No newline at end of file diff --git a/algo/ca/core/tracking/CaTripletConstructor.cxx b/algo/ca/core/tracking/CaTripletConstructor.cxx index bcf80ffa2ab47790522629e74945e7c4f4ed6d40..1bb1298808d393240fc44db30a23cf254f1d32ae 100644 --- a/algo/ca/core/tracking/CaTripletConstructor.cxx +++ b/algo/ca/core/tracking/CaTripletConstructor.cxx @@ -17,750 +17,751 @@ // using cbm::ca::tools::Debugger; -using namespace cbm::algo::ca; - -TripletConstructor::TripletConstructor(const ca::Parameters<fvec>& pars, WindowData& wData, const fscal mass, - const ca::TrackingMode& mode) - : fParameters(pars) - , fSetup(fParameters.GetActiveSetup()) - , frWData(wData) - , fDefaultMass(mass) - , fTrackingMode(mode) +namespace cbm::algo::ca { - // FIXME: SZh 24.08.2022 - // This approach is suitable only for a case, when all the stations inside a magnetic field come right before - // all the stations outside of the field! - fNfieldStations = std::lower_bound(fParameters.GetStations().cbegin(), - fParameters.GetStations().cbegin() + fParameters.GetNstationsActive(), - 0, // we are looking for the first zero element - [](const ca::Station<fvec>& s, int edge) { return bool(s.fieldStatus) > edge; }) - - fParameters.GetStations().cbegin(); + TripletConstructor::TripletConstructor(const ca::Parameters<fvec>& pars, WindowData& wData, const fscal mass, + const ca::TrackingMode& mode) + : fParameters(pars) + , fSetup(fParameters.GetActiveSetup()) + , frWData(wData) + , fDefaultMass(mass) + , fTrackingMode(mode) + { + // FIXME: SZh 24.08.2022 + // This approach is suitable only for a case, when all the stations inside a magnetic field come right before + // all the stations outside of the field! + fNfieldStations = std::lower_bound(fParameters.GetStations().cbegin(), + fParameters.GetStations().cbegin() + fParameters.GetNstationsActive(), + 0, // we are looking for the first zero element + [](const ca::Station<fvec>& s, int edge) { return bool(s.fieldStatus) > edge; }) + - fParameters.GetStations().cbegin(); + + fIsTargetField = !frWData.TargB().IsZero(); + } - fIsTargetField = !frWData.TargB().IsZero(); -} + bool TripletConstructor::InitStations(int istal, int istam, int istar) + { + fIstaL = istal; + fIstaM = istam; + fIstaR = istar; -bool TripletConstructor::InitStations(int istal, int istam, int istar) -{ - fIstaL = istal; - fIstaM = istam; - fIstaR = istar; + if (fIstaM >= fParameters.GetNstationsActive()) { + return false; + } + fStaL = &fParameters.GetStation(fIstaL); + fStaM = &fParameters.GetStation(fIstaM); + fStaR = &fParameters.GetStation(fIstaR); - if (fIstaM >= fParameters.GetNstationsActive()) { - return false; - } - fStaL = &fParameters.GetStation(fIstaL); - fStaM = &fParameters.GetStation(fIstaM); - fStaR = &fParameters.GetStation(fIstaR); + { // two stations for approximating the field between the target and the left hit + const int sta1 = (fNfieldStations <= 1) ? 1 : std::clamp(fIstaL, 1, fNfieldStations - 1); + const int sta0 = sta1 / 2; // station between fIstaL and the target - { // two stations for approximating the field between the target and the left hit - const int sta1 = (fNfieldStations <= 1) ? 1 : std::clamp(fIstaL, 1, fNfieldStations - 1); - const int sta0 = sta1 / 2; // station between fIstaL and the target + assert(0 <= sta0 && sta0 < sta1 && sta1 < fParameters.GetNstationsActive()); + fFld0Sta[0] = &fParameters.GetStation(sta0); + fFld0Sta[1] = &fParameters.GetStation(sta1); + } - assert(0 <= sta0 && sta0 < sta1 && sta1 < fParameters.GetNstationsActive()); - fFld0Sta[0] = &fParameters.GetStation(sta0); - fFld0Sta[1] = &fParameters.GetStation(sta1); - } + { // three stations for approximating the field between the left and the right hit - { // three stations for approximating the field between the left and the right hit + int sta0 = fIstaL; + int sta1 = fIstaM; + int sta2 = fIstaM + 1; + if (sta2 >= fParameters.GetNstationsActive()) { + sta2 = fIstaM; + sta1 = fIstaM - 1; + sta0 = (sta1 <= 0) ? 0 : std::clamp(sta0, 0, sta1 - 1); + } + if (fParameters.GetNstationsActive() >= 3) { + assert(0 <= sta0 && sta0 < sta1 && sta1 < sta2 && sta2 < fParameters.GetNstationsActive()); + } - int sta0 = fIstaL; - int sta1 = fIstaM; - int sta2 = fIstaM + 1; - if (sta2 >= fParameters.GetNstationsActive()) { - sta2 = fIstaM; - sta1 = fIstaM - 1; - sta0 = (sta1 <= 0) ? 0 : std::clamp(sta0, 0, sta1 - 1); - } - if (fParameters.GetNstationsActive() >= 3) { - assert(0 <= sta0 && sta0 < sta1 && sta1 < sta2 && sta2 < fParameters.GetNstationsActive()); + fFld1Sta[0] = &fParameters.GetStation(sta0); + fFld1Sta[1] = &fParameters.GetStation(sta1); + fFld1Sta[2] = &fParameters.GetStation(sta2); } - - fFld1Sta[0] = &fParameters.GetStation(sta0); - fFld1Sta[1] = &fParameters.GetStation(sta1); - fFld1Sta[2] = &fParameters.GetStation(sta2); + return true; } - return true; -} - -void TripletConstructor::CreateTripletsForHit(Vector<ca::Triplet>& tripletsOut, int istal, int istam, int istar, - ca::HitIndex_t iHitL) -{ - if (!InitStations(istal, istam, istar)) { - tripletsOut.clear(); - return; - } - kf::TrackKalmanFilter<fvec> fit(fmask::One(), true); - fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass); - fit.SetQp0(frWData.CurrentIteration()->GetMaxQp()); + void TripletConstructor::CreateTripletsForHit(Vector<ca::Triplet>& tripletsOut, int istal, int istam, int istar, + ca::HitIndex_t iHitL) + { + if (!InitStations(istal, istam, istar)) { + tripletsOut.clear(); + return; + } - fIhitL = iHitL; - const auto& hitl = frWData.Hit(fIhitL); + kf::TrackKalmanFilter<fvec> fit(fmask::One(), true); + fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass); + fit.SetQp0(frWData.CurrentIteration()->GetMaxQp()); - // fit a straight line through the target and the left hit. - TrackParamV& T = fit.Tr(); - { - /// Get the field approximation. Add the target to parameters estimation. - /// Propagaete to the middle station of a triplet. - //kf::FieldValue<fvec> lB, mB, cB, rB _fvecalignment; currently not used - //kf::FieldValue<fvec> l_B_global, centB_global _fvecalignment; currently not used + fIhitL = iHitL; + const auto& hitl = frWData.Hit(fIhitL); - // get the magnetic field along the track. - // (suppose track is straight line with origin in the target) + // fit a straight line through the target and the left hit. + TrackParamV& T = fit.Tr(); { - const fvec dzli = 1.f / (hitl.Z() - fParameters.GetTargetPositionZ()); - - T.X() = hitl.X(); - T.Y() = hitl.Y(); - T.Z() = hitl.Z(); - T.Tx() = (hitl.X() - fParameters.GetTargetPositionX()) * dzli; - T.Ty() = (hitl.Y() - fParameters.GetTargetPositionY()) * dzli; - T.Qp() = fvec(0.); - T.Time() = hitl.T(); - T.Vi() = constants::phys::SpeedOfLightInv; - - const fvec maxSlopePV = frWData.CurrentIteration()->GetMaxSlopePV(); - const fvec maxQp = frWData.CurrentIteration()->GetMaxQp(); - const fvec txErr2 = maxSlopePV * maxSlopePV / fvec(9.); - const fvec qpErr2 = maxQp * maxQp / fvec(9.); - - T.ResetErrors(1., 1., txErr2, txErr2, qpErr2, (fStaL->timeInfo ? hitl.dT2() : 1.e6), 1.e10); - T.InitVelocityRange(1. / frWData.CurrentIteration()->GetMaxQp()); - - T.C00() = hitl.dX2(); - T.C10() = hitl.dXY(); - T.C11() = hitl.dY2(); - T.Ndf() = (frWData.CurrentIteration()->GetPrimaryFlag()) ? fvec(2.) : fvec(0.); - T.NdfTime() = (fStaL->timeInfo ? 0 : -1); - } + /// Get the field approximation. Add the target to parameters estimation. + /// Propagaete to the middle station of a triplet. + //kf::FieldValue<fvec> lB, mB, cB, rB _fvecalignment; currently not used + //kf::FieldValue<fvec> l_B_global, centB_global _fvecalignment; currently not used + + // get the magnetic field along the track. + // (suppose track is straight line with origin in the target) + { + const fvec dzli = 1.f / (hitl.Z() - fParameters.GetTargetPositionZ()); + + T.X() = hitl.X(); + T.Y() = hitl.Y(); + T.Z() = hitl.Z(); + T.Tx() = (hitl.X() - fParameters.GetTargetPositionX()) * dzli; + T.Ty() = (hitl.Y() - fParameters.GetTargetPositionY()) * dzli; + T.Qp() = fvec(0.); + T.Time() = hitl.T(); + T.Vi() = constants::phys::SpeedOfLightInv; + + const fvec maxSlopePV = frWData.CurrentIteration()->GetMaxSlopePV(); + const fvec maxQp = frWData.CurrentIteration()->GetMaxQp(); + const fvec txErr2 = maxSlopePV * maxSlopePV / fvec(9.); + const fvec qpErr2 = maxQp * maxQp / fvec(9.); + + T.ResetErrors(1., 1., txErr2, txErr2, qpErr2, (fStaL->timeInfo ? hitl.dT2() : 1.e6), 1.e10); + T.InitVelocityRange(1. / frWData.CurrentIteration()->GetMaxQp()); + + T.C00() = hitl.dX2(); + T.C10() = hitl.dXY(); + T.C11() = hitl.dY2(); + T.Ndf() = (frWData.CurrentIteration()->GetPrimaryFlag()) ? fvec(2.) : fvec(0.); + T.NdfTime() = (fStaL->timeInfo ? 0 : -1); + } - // NDF = number of track parameters (6: x, y, tx, ty, qp, time) - // - number of measured parameters (3: x, y, time) on station or (2: x, y) on target + // NDF = number of track parameters (6: x, y, tx, ty, qp, time) + // - number of measured parameters (3: x, y, time) on station or (2: x, y) on target - // field made by the left hit, the target and the station istac in-between. - // is used for extrapolation to the target and to the middle hit - kf::FieldRegion<fvec> fld0; - { - kf::FieldValue<fvec> B0 = fFld0Sta[0]->fieldSlice.GetFieldValueForLine(T); - kf::FieldValue<fvec> B1 = fFld0Sta[1]->fieldSlice.GetFieldValueForLine(T); - fld0.Set(frWData.TargB(), fParameters.GetTargetPositionZ(), B0, fFld0Sta[0]->fZ, B1, fFld0Sta[1]->fZ); - } + // field made by the left hit, the target and the station istac in-between. + // is used for extrapolation to the target and to the middle hit + kf::FieldRegion<fvec> fld0; + { + kf::FieldValue<fvec> B0 = fFld0Sta[0]->fieldSlice.GetFieldValueForLine(T); + kf::FieldValue<fvec> B1 = fFld0Sta[1]->fieldSlice.GetFieldValueForLine(T); + fld0.Set(frWData.TargB(), fParameters.GetTargetPositionZ(), B0, fFld0Sta[0]->fZ, B1, fFld0Sta[1]->fZ); + } + + { // field, made by the left hit, the middle station and the right station + // Will be used for extrapolation to the right hit + kf::FieldValue<fvec> B0 = fFld1Sta[0]->fieldSlice.GetFieldValueForLine(T); + kf::FieldValue<fvec> B1 = fFld1Sta[1]->fieldSlice.GetFieldValueForLine(T); + kf::FieldValue<fvec> B2 = fFld1Sta[2]->fieldSlice.GetFieldValueForLine(T); + fFldL.Set(B0, fFld1Sta[0]->fZ, B1, fFld1Sta[1]->fZ, B2, fFld1Sta[2]->fZ); + } + + // add the target constraint + fit.FilterWithTargetAtLine(fParameters.GetTargetPositionZ(), frWData.TargetMeasurement(), fld0); + fit.MultipleScattering(fSetup.GetMaterial(fIstaL).GetThicknessX0(T.GetX(), T.GetY())); - { // field, made by the left hit, the middle station and the right station - // Will be used for extrapolation to the right hit - kf::FieldValue<fvec> B0 = fFld1Sta[0]->fieldSlice.GetFieldValueForLine(T); - kf::FieldValue<fvec> B1 = fFld1Sta[1]->fieldSlice.GetFieldValueForLine(T); - kf::FieldValue<fvec> B2 = fFld1Sta[2]->fieldSlice.GetFieldValueForLine(T); - fFldL.Set(B0, fFld1Sta[0]->fZ, B1, fFld1Sta[1]->fZ, B2, fFld1Sta[2]->fZ); + // extrapolate to the middle hit + fit.ExtrapolateLine(fStaM->fZ, fFldL); } - // add the target constraint - fit.FilterWithTargetAtLine(fParameters.GetTargetPositionZ(), frWData.TargetMeasurement(), fld0); - fit.MultipleScattering(fSetup.GetMaterial(fIstaL).GetThicknessX0(T.GetX(), T.GetY())); + /// Find the doublets. Reformat data into portions of doublets. + auto FindDoubletHits = [&]() { + const bool matchMc = fParameters.DevIsMatchDoubletsViaMc(); + const int iMC = matchMc ? ca::Framework::GetMcTrackIdForWindowHit(fIhitL) : -1; + fDoubletData.second.clear(); + if (iMC < 0 && matchMc) { + return; + } + CollectHits(fDoubletData.second, fit, fIstaM, frWData.CurrentIteration()->GetDoubletChi2Cut(), iMC, + fParameters.GetMaxDoubletsPerSinglet()); + }; - // extrapolate to the middle hit - fit.ExtrapolateLine(fStaM->fZ, fFldL); - } + FindDoubletHits(); + FindDoublets(fit); - /// Find the doublets. Reformat data into portions of doublets. - auto FindDoubletHits = [&]() { - const bool matchMc = fParameters.DevIsMatchDoubletsViaMc(); - const int iMC = matchMc ? ca::Framework::GetMcTrackIdForWindowHit(fIhitL) : -1; - fDoubletData.second.clear(); - if (iMC < 0 && matchMc) { + //D.Smith 28.8.24: Moving this upward (before doublet finding) changes QA output slightly + if (fIstaR >= fParameters.GetNstationsActive()) { + tripletsOut.clear(); return; } - CollectHits(fDoubletData.second, fit, fIstaM, frWData.CurrentIteration()->GetDoubletChi2Cut(), iMC, - fParameters.GetMaxDoubletsPerSinglet()); - }; - FindDoubletHits(); - FindDoublets(fit); - - //D.Smith 28.8.24: Moving this upward (before doublet finding) changes QA output slightly - if (fIstaR >= fParameters.GetNstationsActive()) { - tripletsOut.clear(); - return; + FindTripletHits(); + FindTriplets(); + SelectTriplets(tripletsOut); } - FindTripletHits(); - FindTriplets(); - SelectTriplets(tripletsOut); -} + void TripletConstructor::FindDoublets(kf::TrackKalmanFilter<fvec>& fit) + { + // ---- Add the middle hits to parameters estimation ---- + Vector<TrackParamV>& tracks = fDoubletData.first; + Vector<ca::HitIndex_t>& hitsM = fDoubletData.second; -void TripletConstructor::FindDoublets(kf::TrackKalmanFilter<fvec>& fit) -{ - // ---- Add the middle hits to parameters estimation ---- - Vector<TrackParamV>& tracks = fDoubletData.first; - Vector<ca::HitIndex_t>& hitsM = fDoubletData.second; + tracks.clear(); + tracks.reserve(hitsM.size()); - tracks.clear(); - tracks.reserve(hitsM.size()); + const bool isMomentumFitted = (fIsTargetField || (fStaL->fieldStatus != 0) || (fStaM->fieldStatus != 0)); - const bool isMomentumFitted = (fIsTargetField || (fStaL->fieldStatus != 0) || (fStaM->fieldStatus != 0)); + const TrackParamV Tr = fit.Tr(); // copy contents of fit - const TrackParamV Tr = fit.Tr(); // copy contents of fit + auto it2 = hitsM.begin(); + for (auto it = hitsM.begin(); it != hitsM.end(); it++) { - auto it2 = hitsM.begin(); - for (auto it = hitsM.begin(); it != hitsM.end(); it++) { + const ca::HitIndex_t indM = *it; + const ca::Hit& hitm = frWData.Hit(indM); - const ca::HitIndex_t indM = *it; - const ca::Hit& hitm = frWData.Hit(indM); + if (frWData.IsHitSuppressed(indM)) { + continue; + } - if (frWData.IsHitSuppressed(indM)) { - continue; - } + TrackParamV& T2 = fit.Tr(); + T2 = Tr; + fit.SetQp0(fvec(0.f)); - TrackParamV& T2 = fit.Tr(); - T2 = Tr; - fit.SetQp0(fvec(0.f)); + fvec z_2 = hitm.Z(); + kf::MeasurementXy<fvec> m_2(hitm.X(), hitm.Y(), hitm.dX2(), hitm.dY2(), hitm.dXY(), fvec::One(), fvec::One()); + fvec t_2 = hitm.T(); + fvec dt2_2 = hitm.dT2(); - fvec z_2 = hitm.Z(); - kf::MeasurementXy<fvec> m_2(hitm.X(), hitm.Y(), hitm.dX2(), hitm.dY2(), hitm.dXY(), fvec::One(), fvec::One()); - fvec t_2 = hitm.T(); - fvec dt2_2 = hitm.dT2(); + // add the middle hit + fit.ExtrapolateLineNoField(z_2); + fit.FilterXY(m_2); + fit.FilterTime(t_2, dt2_2, fmask(fStaM->timeInfo)); + fit.SetQp0(isMomentumFitted ? fit.Tr().GetQp() : frWData.CurrentIteration()->GetMaxQp()); + fit.MultipleScattering(fSetup.GetMaterial(fIstaM).GetThicknessX0(T2.GetX(), T2.Y())); + fit.SetQp0(fit.Tr().Qp()); - // add the middle hit - fit.ExtrapolateLineNoField(z_2); - fit.FilterXY(m_2); - fit.FilterTime(t_2, dt2_2, fmask(fStaM->timeInfo)); - fit.SetQp0(isMomentumFitted ? fit.Tr().GetQp() : frWData.CurrentIteration()->GetMaxQp()); - fit.MultipleScattering(fSetup.GetMaterial(fIstaM).GetThicknessX0(T2.GetX(), T2.Y())); - fit.SetQp0(fit.Tr().Qp()); + // check if there are other hits close to the doublet on the same station + if (ca::kMcbm != fTrackingMode) { + // TODO: SG: adjust cuts, put them to parameters - // check if there are other hits close to the doublet on the same station - if (ca::kMcbm != fTrackingMode) { - // TODO: SG: adjust cuts, put them to parameters + const fscal tx = T2.Tx()[0]; + const fscal ty = T2.Ty()[0]; + const fscal tt = T2.Vi()[0] * sqrt(1. + tx * tx + ty * ty); // dt/dl * dl/dz - const fscal tx = T2.Tx()[0]; - const fscal ty = T2.Ty()[0]; - const fscal tt = T2.Vi()[0] * sqrt(1. + tx * tx + ty * ty); // dt/dl * dl/dz + for (auto itClone = it + 1; itClone != hitsM.end(); itClone++) { - for (auto itClone = it + 1; itClone != hitsM.end(); itClone++) { + const int indClone = *itClone; + const ca::Hit& hitClone = frWData.Hit(indClone); - const int indClone = *itClone; - const ca::Hit& hitClone = frWData.Hit(indClone); + const fscal dz = hitClone.Z() - T2.Z()[0]; - const fscal dz = hitClone.Z() - T2.Z()[0]; + if ((fStaM->timeInfo) && (T2.NdfTime()[0] >= 0)) { + const fscal dt = T2.Time()[0] + tt * dz - hitClone.T(); + if (!(fabs(dt) <= 3.5 * sqrt(T2.C55()[0]) + hitClone.RangeT())) { + continue; + } + } - if ((fStaM->timeInfo) && (T2.NdfTime()[0] >= 0)) { - const fscal dt = T2.Time()[0] + tt * dz - hitClone.T(); - if (!(fabs(dt) <= 3.5 * sqrt(T2.C55()[0]) + hitClone.RangeT())) { + const fscal dx = T2.GetX()[0] + tx * dz - hitClone.X(); + if (!(fabs(dx) <= 3.5 * sqrt(T2.C00()[0]) + hitClone.RangeX())) { continue; } - } - - const fscal dx = T2.GetX()[0] + tx * dz - hitClone.X(); - if (!(fabs(dx) <= 3.5 * sqrt(T2.C00()[0]) + hitClone.RangeX())) { - continue; - } - - const fscal dy = T2.Y()[0] + ty * dz - hitClone.Y(); - if (!(fabs(dy) <= 3.5 * sqrt(T2.C11()[0]) + hitClone.RangeY())) { - continue; - } - if (fParameters.DevIsSuppressOverlapHitsViaMc()) { - const int iMC = ca::Framework::GetMcTrackIdForWindowHit(fIhitL); - if ((iMC != ca::Framework::GetMcTrackIdForWindowHit(indM)) - || (iMC != ca::Framework::GetMcTrackIdForWindowHit(indClone))) { + const fscal dy = T2.Y()[0] + ty * dz - hitClone.Y(); + if (!(fabs(dy) <= 3.5 * sqrt(T2.C11()[0]) + hitClone.RangeY())) { continue; } - } - frWData.SuppressHit(indClone); + if (fParameters.DevIsSuppressOverlapHitsViaMc()) { + const int iMC = ca::Framework::GetMcTrackIdForWindowHit(fIhitL); + if ((iMC != ca::Framework::GetMcTrackIdForWindowHit(indM)) + || (iMC != ca::Framework::GetMcTrackIdForWindowHit(indClone))) { + continue; + } + } + + frWData.SuppressHit(indClone); + } } - } - tracks.push_back(T2); - *it2 = indM; - it2++; - } // it - hitsM.shrink(std::distance(hitsM.begin(), it2)); -} + tracks.push_back(T2); + *it2 = indM; + it2++; + } // it + hitsM.shrink(std::distance(hitsM.begin(), it2)); + } -void TripletConstructor::FindTripletHits() -{ - //auto& [tracks_2, hitsM_2] = doublets; TO DO: Reactivate when MacOS compiler bug is fixed. - Vector<TrackParamV>& tracks_2 = fDoubletData.first; - Vector<ca::HitIndex_t>& hitsM_2 = fDoubletData.second; + void TripletConstructor::FindTripletHits() + { + //auto& [tracks_2, hitsM_2] = doublets; TO DO: Reactivate when MacOS compiler bug is fixed. + Vector<TrackParamV>& tracks_2 = fDoubletData.first; + Vector<ca::HitIndex_t>& hitsM_2 = fDoubletData.second; - Vector<ca::HitIndex_t>& hitsM_3 = std::get<1>(fTripletData); - Vector<ca::HitIndex_t>& hitsR_3 = std::get<2>(fTripletData); + Vector<ca::HitIndex_t>& hitsM_3 = std::get<1>(fTripletData); + Vector<ca::HitIndex_t>& hitsR_3 = std::get<2>(fTripletData); - /// Add the middle hits to parameters estimation. Propagate to right station. - /// Find the triplets(right hit). Reformat data in the portion of triplets. - kf::TrackKalmanFilter<fvec> fit(fmask::One(), true); - fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass); - fit.SetQp0(fvec(0.)); + /// Add the middle hits to parameters estimation. Propagate to right station. + /// Find the triplets(right hit). Reformat data in the portion of triplets. + kf::TrackKalmanFilter<fvec> fit(fmask::One(), true); + fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass); + fit.SetQp0(fvec(0.)); - { - const int maxTriplets = hitsM_2.size() * fParameters.GetMaxTripletPerDoublets(); - hitsM_3.clear(); - hitsR_3.clear(); - hitsM_3.reserve(maxTriplets); - hitsR_3.reserve(maxTriplets); - } - // ---- Add the middle hits to parameters estimation. Propagate to right station. ---- + { + const int maxTriplets = hitsM_2.size() * fParameters.GetMaxTripletPerDoublets(); + hitsM_3.clear(); + hitsR_3.clear(); + hitsM_3.reserve(maxTriplets); + hitsR_3.reserve(maxTriplets); + } + // ---- Add the middle hits to parameters estimation. Propagate to right station. ---- - const double maxSlope = frWData.CurrentIteration()->GetMaxSlope(); - const double tripletChi2Cut = frWData.CurrentIteration()->GetTripletChi2Cut(); - for (unsigned int i2 = 0; i2 < hitsM_2.size(); i2++) { + const double maxSlope = frWData.CurrentIteration()->GetMaxSlope(); + const double tripletChi2Cut = frWData.CurrentIteration()->GetTripletChi2Cut(); + for (unsigned int i2 = 0; i2 < hitsM_2.size(); i2++) { - fit.SetTrack(tracks_2[i2]); - TrackParamV& T2 = fit.Tr(); + fit.SetTrack(tracks_2[i2]); + TrackParamV& T2 = fit.Tr(); - // extrapolate to the right hit station - fit.Extrapolate(fStaR->fZ, fFldL); + // extrapolate to the right hit station + fit.Extrapolate(fStaR->fZ, fFldL); - if constexpr (fDebugDublets) { - ca::HitIndex_t iwhit[2] = {fIhitL, hitsM_2[i2]}; - ca::HitIndex_t ihit[2] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id()}; + if constexpr (fDebugDublets) { + ca::HitIndex_t iwhit[2] = {fIhitL, hitsM_2[i2]}; + ca::HitIndex_t ihit[2] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id()}; - const int ih0 = ihit[0]; - const int ih1 = ihit[1]; - const ca::Hit& h0 = frWData.Hit(iwhit[0]); - const ca::Hit& h1 = frWData.Hit(iwhit[1]); + const int ih0 = ihit[0]; + const int ih1 = ihit[1]; + const ca::Hit& h0 = frWData.Hit(iwhit[0]); + const ca::Hit& h1 = frWData.Hit(iwhit[1]); - LOG(info) << "\n====== Extrapolated Doublet : " - << " iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " " - << fIstaM << "/" << ih1 << " " << fIstaR << "/?} xyz: {" << h0.X() << " " << h0.Y() << " " << h0.Z() - << "}, {" << h1.X() << " " << h1.Y() << " " << h1.Z() << "} chi2 " << T2.GetChiSq()[0] << " ndf " - << T2.Ndf()[0] << " chi2time " << T2.ChiSqTime()[0] << " ndfTime " << T2.NdfTime()[0]; - LOG(info) << " extr. track: " << T2.ToString(0); - } + LOG(info) << "\n====== Extrapolated Doublet : " + << " iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " " + << fIstaM << "/" << ih1 << " " << fIstaR << "/?} xyz: {" << h0.X() << " " << h0.Y() << " " << h0.Z() + << "}, {" << h1.X() << " " << h1.Y() << " " << h1.Z() << "} chi2 " << T2.GetChiSq()[0] << " ndf " + << T2.Ndf()[0] << " chi2time " << T2.ChiSqTime()[0] << " ndfTime " << T2.NdfTime()[0]; + LOG(info) << " extr. track: " << T2.ToString(0); + } - // ---- Find the triplets(right hit). Reformat data in the portion of triplets. ---- - int iMC = -1; + // ---- Find the triplets(right hit). Reformat data in the portion of triplets. ---- + int iMC = -1; - auto rejectDoublet = [&]() -> bool { - if (ca::TrackingMode::kSts == fTrackingMode && (T2.C44()[0] < 0)) { - return true; - } - if (T2.C00()[0] < 0 || T2.C11()[0] < 0 || T2.C22()[0] < 0 || T2.C33()[0] < 0 || T2.C55()[0] < 0) { - return true; - } - if (fabs(T2.Tx()[0]) > maxSlope) { - return true; - } - if (fabs(T2.Ty()[0]) > maxSlope) { - return true; - } - if (fParameters.DevIsMatchTripletsViaMc()) { - int indM = hitsM_2[i2]; - iMC = ca::Framework::GetMcTrackIdForWindowHit(fIhitL); - if (iMC < 0 || iMC != ca::Framework::GetMcTrackIdForWindowHit(indM)) { + auto rejectDoublet = [&]() -> bool { + if (ca::TrackingMode::kSts == fTrackingMode && (T2.C44()[0] < 0)) { return true; } - } - return false; - }; - const bool isDoubletGood = !rejectDoublet(); + if (T2.C00()[0] < 0 || T2.C11()[0] < 0 || T2.C22()[0] < 0 || T2.C33()[0] < 0 || T2.C55()[0] < 0) { + return true; + } + if (fabs(T2.Tx()[0]) > maxSlope) { + return true; + } + if (fabs(T2.Ty()[0]) > maxSlope) { + return true; + } + if (fParameters.DevIsMatchTripletsViaMc()) { + int indM = hitsM_2[i2]; + iMC = ca::Framework::GetMcTrackIdForWindowHit(fIhitL); + if (iMC < 0 || iMC != ca::Framework::GetMcTrackIdForWindowHit(indM)) { + return true; + } + } + return false; + }; + const bool isDoubletGood = !rejectDoublet(); - if constexpr (fDebugDublets) { - if (isDoubletGood) { - LOG(info) << " extrapolated doublet accepted"; - } - else { - LOG(info) << " extrapolated doublet rejected"; - LOG(info) << "======== end of extrapolated doublet ==== \n"; + if constexpr (fDebugDublets) { + if (isDoubletGood) { + LOG(info) << " extrapolated doublet accepted"; + } + else { + LOG(info) << " extrapolated doublet rejected"; + LOG(info) << "======== end of extrapolated doublet ==== \n"; + } } - } - if (!isDoubletGood) { - continue; - } + if (!isDoubletGood) { + continue; + } - Vector<ca::HitIndex_t> collectedHits; - CollectHits(collectedHits, fit, fIstaR, tripletChi2Cut, iMC, fParameters.GetMaxTripletPerDoublets()); + Vector<ca::HitIndex_t> collectedHits; + CollectHits(collectedHits, fit, fIstaR, tripletChi2Cut, iMC, fParameters.GetMaxTripletPerDoublets()); - if (collectedHits.size() >= fParameters.GetMaxTripletPerDoublets()) { - // FU, 28.08.2024, Comment the following log lines since it spams the output - // of our tests and finally results in crashes on run4 - // LOG(debug) << "Ca: GetMaxTripletPerDoublets==" << fParameters.GetMaxTripletPerDoublets() - // << " reached in findTripletsStep0()"; - // reject already created triplets for this doublet - collectedHits.clear(); - } - if constexpr (fDebugDublets) { - LOG(info) << " collected " << collectedHits.size() << " hits on the right station "; - } - for (ca::HitIndex_t& irh : collectedHits) { + if (collectedHits.size() >= fParameters.GetMaxTripletPerDoublets()) { + // FU, 28.08.2024, Comment the following log lines since it spams the output + // of our tests and finally results in crashes on run4 + // LOG(debug) << "Ca: GetMaxTripletPerDoublets==" << fParameters.GetMaxTripletPerDoublets() + // << " reached in findTripletsStep0()"; + // reject already created triplets for this doublet + collectedHits.clear(); + } if constexpr (fDebugDublets) { - const ca::Hit& h = frWData.Hit(irh); - ca::HitIndex_t ihit = h.Id(); - LOG(info) << " hit " << ihit << " " << h.ToString(); + LOG(info) << " collected " << collectedHits.size() << " hits on the right station "; } - if (frWData.IsHitSuppressed(irh)) { + for (ca::HitIndex_t& irh : collectedHits) { if constexpr (fDebugDublets) { - LOG(info) << " the hit is suppressed"; + const ca::Hit& h = frWData.Hit(irh); + ca::HitIndex_t ihit = h.Id(); + LOG(info) << " hit " << ihit << " " << h.ToString(); } - continue; + if (frWData.IsHitSuppressed(irh)) { + if constexpr (fDebugDublets) { + LOG(info) << " the hit is suppressed"; + } + continue; + } + // pack the triplet + hitsM_3.push_back(hitsM_2[i2]); + hitsR_3.push_back(irh); + } // search area + if constexpr (fDebugDublets) { + LOG(info) << "======== end of extrapolated doublet ==== \n"; } - // pack the triplet - hitsM_3.push_back(hitsM_2[i2]); - hitsR_3.push_back(irh); - } // search area - if constexpr (fDebugDublets) { - LOG(info) << "======== end of extrapolated doublet ==== \n"; - } - } // i2 -} - -void TripletConstructor::FindTriplets() -{ - constexpr int nIterations = 2; - - Vector<TrackParamV>& tracks = std::get<0>(fTripletData); - Vector<ca::HitIndex_t>& hitsM = std::get<1>(fTripletData); - Vector<ca::HitIndex_t>& hitsR = std::get<2>(fTripletData); - assert(hitsM.size() == hitsR.size()); - - tracks.clear(); - tracks.reserve(hitsM.size()); - - /// Refit Triplets - if constexpr (fDebugTriplets) { - //cbm::ca::tools::Debugger::Instance().AddNtuple( - // "triplets", "ev:iter:i0:x0:y0:z0:i1:x1:y1:z1:i2:x2:y2:z2:mc:sta:p:vx:vy:vz:chi2:ndf:chi2time:ndfTime"); + } // i2 } - kf::TrackKalmanFilter<fvec> fit; - fit.SetMask(fmask::One()); - fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass); + void TripletConstructor::FindTriplets() + { + constexpr int nIterations = 2; - // prepare data - const int NHits = 3; // triplets - const int ista[NHits] = {fIstaL, fIstaM, fIstaR}; + Vector<TrackParamV>& tracks = std::get<0>(fTripletData); + Vector<ca::HitIndex_t>& hitsM = std::get<1>(fTripletData); + Vector<ca::HitIndex_t>& hitsR = std::get<2>(fTripletData); + assert(hitsM.size() == hitsR.size()); - const ca::Station<fvec> sta[NHits] = {fParameters.GetStation(ista[0]), fParameters.GetStation(ista[1]), - fParameters.GetStation(ista[2])}; + tracks.clear(); + tracks.reserve(hitsM.size()); - const bool isMomentumFitted = ((fStaL->fieldStatus != 0) || (fStaM->fieldStatus != 0) || (fStaR->fieldStatus != 0)); - const fvec ndfTrackModel = 4 + (isMomentumFitted ? 1 : 0); // straight line or track with momentum + /// Refit Triplets + if constexpr (fDebugTriplets) { + //cbm::ca::tools::Debugger::Instance().AddNtuple( + // "triplets", "ev:iter:i0:x0:y0:z0:i1:x1:y1:z1:i2:x2:y2:z2:mc:sta:p:vx:vy:vz:chi2:ndf:chi2time:ndfTime"); + } - for (size_t i3 = 0; i3 < hitsM.size(); ++i3) { + kf::TrackKalmanFilter<fvec> fit; + fit.SetMask(fmask::One()); + fit.SetParticleMass(frWData.CurrentIteration()->GetElectronFlag() ? constants::phys::ElectronMass : fDefaultMass); // prepare data - const ca::HitIndex_t iwhit[NHits] = {fIhitL, hitsM[i3], hitsR[i3]}; - - const ca::HitIndex_t ihit[NHits] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id(), - frWData.Hit(iwhit[2]).Id()}; - - if (fParameters.DevIsMatchTripletsViaMc()) { - int mc1 = ca::Framework::GetMcTrackIdForCaHit(ihit[0]); - int mc2 = ca::Framework::GetMcTrackIdForCaHit(ihit[1]); - int mc3 = ca::Framework::GetMcTrackIdForCaHit(ihit[2]); - if ((mc1 != mc2) || (mc1 != mc3)) { - // D.S.: Added to preserve the ordering when switching from index-based - // access to push_back(). Discuss with SZ. - tracks.push_back(TrackParamV()); - continue; - } - } + const int NHits = 3; // triplets + const int ista[NHits] = {fIstaL, fIstaM, fIstaR}; - fscal x[NHits], y[NHits], z[NHits], t[NHits]; - fscal dt2[NHits]; - kf::MeasurementXy<fvec> mxy[NHits]; + const ca::Station<fvec> sta[NHits] = {fParameters.GetStation(ista[0]), fParameters.GetStation(ista[1]), + fParameters.GetStation(ista[2])}; - for (int ih = 0; ih < NHits; ++ih) { - const ca::Hit& hit = frWData.Hit(iwhit[ih]); - mxy[ih] = kf::MeasurementXy<fvec>(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One()); + const bool isMomentumFitted = ((fStaL->fieldStatus != 0) || (fStaM->fieldStatus != 0) || (fStaR->fieldStatus != 0)); + const fvec ndfTrackModel = 4 + (isMomentumFitted ? 1 : 0); // straight line or track with momentum - x[ih] = hit.X(); - y[ih] = hit.Y(); - z[ih] = hit.Z(); - t[ih] = hit.T(); - dt2[ih] = hit.dT2(); - }; + for (size_t i3 = 0; i3 < hitsM.size(); ++i3) { - // find the field along the track + // prepare data + const ca::HitIndex_t iwhit[NHits] = {fIhitL, hitsM[i3], hitsR[i3]}; - kf::FieldValue<fvec> B[3] _fvecalignment; - kf::FieldRegion<fvec> fld _fvecalignment; - kf::FieldRegion<fvec> fldTarget _fvecalignment; + const ca::HitIndex_t ihit[NHits] = {frWData.Hit(iwhit[0]).Id(), frWData.Hit(iwhit[1]).Id(), + frWData.Hit(iwhit[2]).Id()}; - fvec tx[3] = {(x[1] - x[0]) / (z[1] - z[0]), (x[2] - x[0]) / (z[2] - z[0]), (x[2] - x[1]) / (z[2] - z[1])}; - fvec ty[3] = {(y[1] - y[0]) / (z[1] - z[0]), (y[2] - y[0]) / (z[2] - z[0]), (y[2] - y[1]) / (z[2] - z[1])}; + if (fParameters.DevIsMatchTripletsViaMc()) { + int mc1 = ca::Framework::GetMcTrackIdForCaHit(ihit[0]); + int mc2 = ca::Framework::GetMcTrackIdForCaHit(ihit[1]); + int mc3 = ca::Framework::GetMcTrackIdForCaHit(ihit[2]); + if ((mc1 != mc2) || (mc1 != mc3)) { + // D.S.: Added to preserve the ordering when switching from index-based + // access to push_back(). Discuss with SZ. + tracks.push_back(TrackParamV()); + continue; + } + } - for (int ih = 0; ih < NHits; ++ih) { - fvec dz = (sta[ih].fZ - z[ih]); - B[ih] = sta[ih].fieldSlice.GetFieldValue(x[ih] + tx[ih] * dz, y[ih] + ty[ih] * dz); - }; + fscal x[NHits], y[NHits], z[NHits], t[NHits]; + fscal dt2[NHits]; + kf::MeasurementXy<fvec> mxy[NHits]; - fld.Set(B[0], sta[0].fZ, B[1], sta[1].fZ, B[2], sta[2].fZ); - fldTarget.Set(frWData.TargB(), fParameters.GetTargetPositionZ(), B[0], sta[0].fZ, B[1], sta[1].fZ); + for (int ih = 0; ih < NHits; ++ih) { + const ca::Hit& hit = frWData.Hit(iwhit[ih]); + mxy[ih] = kf::MeasurementXy<fvec>(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One()); - TrackParamV& T = fit.Tr(); + x[ih] = hit.X(); + y[ih] = hit.Y(); + z[ih] = hit.Z(); + t[ih] = hit.T(); + dt2[ih] = hit.dT2(); + }; - // initial parameters - { - fvec dz01 = 1. / (z[1] - z[0]); - T.Tx() = (x[1] - x[0]) * dz01; - T.Ty() = (y[1] - y[0]) * dz01; - T.Qp() = 0.; - T.Vi() = 0.; - } + // find the field along the track - // repeat several times in order to improve the precision - for (int iiter = 0; iiter < nIterations; ++iiter) { - - auto fitTrack = [&](int startIdx, int endIdx, int step, kf::FitDirection direction) { - const fvec maxQp = frWData.CurrentIteration()->GetMaxQp(); - fit.SetQp0(T.Qp()); - fit.Qp0()(fit.Qp0() > maxQp) = maxQp; - fit.Qp0()(fit.Qp0() < -maxQp) = -maxQp; - - int ih0 = startIdx; - T.X() = x[ih0]; - T.Y() = y[ih0]; - T.Z() = z[ih0]; - T.Time() = t[ih0]; - T.Qp() = 0.; - T.Vi() = 0.; - - T.ResetErrors(1., 1., 1., 1., 100., (sta[ih0].timeInfo ? dt2[ih0] : 1.e6), 1.e2); - T.C00() = mxy[ih0].Dx2(); - T.C10() = mxy[ih0].Dxy(); - T.C11() = mxy[ih0].Dy2(); - - T.Ndf() = -ndfTrackModel + 2; - T.NdfTime() = sta[ih0].timeInfo ? 0 : -1; - - if (startIdx == 0) { //only for the forward fit - fit.FilterWithTargetAtLine(fParameters.GetTargetPositionZ(), frWData.TargetMeasurement(), fldTarget); - } + kf::FieldValue<fvec> B[3] _fvecalignment; + kf::FieldRegion<fvec> fld _fvecalignment; + kf::FieldRegion<fvec> fldTarget _fvecalignment; - for (int ih = startIdx + step; ih != endIdx; ih += step) { - fit.Extrapolate(z[ih], fld); - auto radThick = fSetup.GetMaterial(ista[ih]).GetThicknessX0(T.X(), T.Y()); - fit.MultipleScattering(radThick); - fit.EnergyLossCorrection(radThick, direction); - fit.FilterXY(mxy[ih]); - fit.FilterTime(t[ih], dt2[ih], fmask(sta[ih].timeInfo)); - } + fvec tx[3] = {(x[1] - x[0]) / (z[1] - z[0]), (x[2] - x[0]) / (z[2] - z[0]), (x[2] - x[1]) / (z[2] - z[1])}; + fvec ty[3] = {(y[1] - y[0]) / (z[1] - z[0]), (y[2] - y[0]) / (z[2] - z[0]), (y[2] - y[1]) / (z[2] - z[1])}; + + for (int ih = 0; ih < NHits; ++ih) { + fvec dz = (sta[ih].fZ - z[ih]); + B[ih] = sta[ih].fieldSlice.GetFieldValue(x[ih] + tx[ih] * dz, y[ih] + ty[ih] * dz); }; - // Fit downstream - fitTrack(0, NHits, 1, kf::FitDirection::kDownstream); + fld.Set(B[0], sta[0].fZ, B[1], sta[1].fZ, B[2], sta[2].fZ); + fldTarget.Set(frWData.TargB(), fParameters.GetTargetPositionZ(), B[0], sta[0].fZ, B[1], sta[1].fZ); - if (iiter == nIterations - 1) break; + TrackParamV& T = fit.Tr(); - // Fit upstream - fitTrack(NHits - 1, -1, -1, kf::FitDirection::kUpstream); - } // for iiter + // initial parameters + { + fvec dz01 = 1. / (z[1] - z[0]); + T.Tx() = (x[1] - x[0]) * dz01; + T.Ty() = (y[1] - y[0]) * dz01; + T.Qp() = 0.; + T.Vi() = 0.; + } - tracks.push_back(T); + // repeat several times in order to improve the precision + for (int iiter = 0; iiter < nIterations; ++iiter) { + + auto fitTrack = [&](int startIdx, int endIdx, int step, kf::FitDirection direction) { + const fvec maxQp = frWData.CurrentIteration()->GetMaxQp(); + fit.SetQp0(T.Qp()); + fit.Qp0()(fit.Qp0() > maxQp) = maxQp; + fit.Qp0()(fit.Qp0() < -maxQp) = -maxQp; + + int ih0 = startIdx; + T.X() = x[ih0]; + T.Y() = y[ih0]; + T.Z() = z[ih0]; + T.Time() = t[ih0]; + T.Qp() = 0.; + T.Vi() = 0.; + + T.ResetErrors(1., 1., 1., 1., 100., (sta[ih0].timeInfo ? dt2[ih0] : 1.e6), 1.e2); + T.C00() = mxy[ih0].Dx2(); + T.C10() = mxy[ih0].Dxy(); + T.C11() = mxy[ih0].Dy2(); + + T.Ndf() = -ndfTrackModel + 2; + T.NdfTime() = sta[ih0].timeInfo ? 0 : -1; + + if (startIdx == 0) { //only for the forward fit + fit.FilterWithTargetAtLine(fParameters.GetTargetPositionZ(), frWData.TargetMeasurement(), fldTarget); + } - if constexpr (fDebugTriplets) { - int ih0 = ihit[0]; - int ih1 = ihit[1]; - int ih2 = ihit[2]; - int mc1 = ca::Framework::GetMcTrackIdForCaHit(ih0); - int mc2 = ca::Framework::GetMcTrackIdForCaHit(ih1); - int mc3 = ca::Framework::GetMcTrackIdForCaHit(ih2); - - if (1 || (mc1 >= 0) && (mc1 == mc2) && (mc1 == mc3)) { - const ca::Hit& h0 = frWData.Hit(iwhit[0]); - const ca::Hit& h1 = frWData.Hit(iwhit[1]); - const ca::Hit& h2 = frWData.Hit(iwhit[2]); - //const CbmL1MCTrack& mctr = CbmL1::Instance()->GetMcTracks()[mc1]; - LOG(info) << "== fitted triplet: " - << " iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " " - << fIstaM << "/" << ih1 << " " << fIstaR << "/" << ih2 << "} xyz: {" << h0.X() << " " << h0.Y() << " " - << h0.Z() << "}, {" << h1.X() << " " << h1.Y() << " " << h1.Z() << "}, {" << h2.X() << ", " << h2.Y() - << ", " << h2.Z() << "} chi2 " << T.GetChiSq()[0] << " ndf " << T.Ndf()[0] << " chi2time " - << T.ChiSqTime()[0] << " ndfTime " << T.NdfTime()[0]; - /* - cbm::ca::tools::Debugger::Instance().FillNtuple( - "triplets", mctr.iEvent, frAlgo.fCurrentIterationIndex, ih0, h0.X(), h0.Y(), h0.Z(), ih1, h1.X(), h1.Y(), - h1.Z(), ih2, h2.X(), h2.Y(), h2.Z(), mc1, fIstaL, mctr.p, mctr.x, mctr.y, mctr.z, (fscal) T.GetChiSq()[0], - (fscal) T.Ndf()[0], (fscal) T.ChiSqTime()[0], (fscal) T.NdfTime()[0]); - */ + for (int ih = startIdx + step; ih != endIdx; ih += step) { + fit.Extrapolate(z[ih], fld); + auto radThick = fSetup.GetMaterial(ista[ih]).GetThicknessX0(T.X(), T.Y()); + fit.MultipleScattering(radThick); + fit.EnergyLossCorrection(radThick, direction); + fit.FilterXY(mxy[ih]); + fit.FilterTime(t[ih], dt2[ih], fmask(sta[ih].timeInfo)); + } + }; + + // Fit downstream + fitTrack(0, NHits, 1, kf::FitDirection::kDownstream); + + if (iiter == nIterations - 1) break; + + // Fit upstream + fitTrack(NHits - 1, -1, -1, kf::FitDirection::kUpstream); + } // for iiter + + tracks.push_back(T); + + if constexpr (fDebugTriplets) { + int ih0 = ihit[0]; + int ih1 = ihit[1]; + int ih2 = ihit[2]; + int mc1 = ca::Framework::GetMcTrackIdForCaHit(ih0); + int mc2 = ca::Framework::GetMcTrackIdForCaHit(ih1); + int mc3 = ca::Framework::GetMcTrackIdForCaHit(ih2); + + if (1 || (mc1 >= 0) && (mc1 == mc2) && (mc1 == mc3)) { + const ca::Hit& h0 = frWData.Hit(iwhit[0]); + const ca::Hit& h1 = frWData.Hit(iwhit[1]); + const ca::Hit& h2 = frWData.Hit(iwhit[2]); + //const CbmL1MCTrack& mctr = CbmL1::Instance()->GetMcTracks()[mc1]; + LOG(info) << "== fitted triplet: " + << " iter " << frWData.CurrentIteration()->GetName() << " hits: {" << fIstaL << "/" << ih0 << " " + << fIstaM << "/" << ih1 << " " << fIstaR << "/" << ih2 << "} xyz: {" << h0.X() << " " << h0.Y() + << " " << h0.Z() << "}, {" << h1.X() << " " << h1.Y() << " " << h1.Z() << "}, {" << h2.X() << ", " + << h2.Y() << ", " << h2.Z() << "} chi2 " << T.GetChiSq()[0] << " ndf " << T.Ndf()[0] << " chi2time " + << T.ChiSqTime()[0] << " ndfTime " << T.NdfTime()[0]; + /* + cbm::ca::tools::Debugger::Instance().FillNtuple( + "triplets", mctr.iEvent, frAlgo.fCurrentIterationIndex, ih0, h0.X(), h0.Y(), h0.Z(), ih1, h1.X(), h1.Y(), + h1.Z(), ih2, h2.X(), h2.Y(), h2.Z(), mc1, fIstaL, mctr.p, mctr.x, mctr.y, mctr.z, (fscal) T.GetChiSq()[0], + (fscal) T.Ndf()[0], (fscal) T.ChiSqTime()[0], (fscal) T.NdfTime()[0]); + */ + } } - } - } //i3 -} // FindTriplets + } //i3 + } // FindTriplets -void TripletConstructor::SelectTriplets(Vector<ca::Triplet>& tripletsOut) -{ - /// Selects good triplets and saves them into tripletsOut. - /// Finds neighbouring triplets at the next station. + void TripletConstructor::SelectTriplets(Vector<ca::Triplet>& tripletsOut) + { + /// Selects good triplets and saves them into tripletsOut. + /// Finds neighbouring triplets at the next station. - Vector<TrackParamV>& tracks = std::get<0>(fTripletData); - Vector<ca::HitIndex_t>& hitsM = std::get<1>(fTripletData); - Vector<ca::HitIndex_t>& hitsR = std::get<2>(fTripletData); + Vector<TrackParamV>& tracks = std::get<0>(fTripletData); + Vector<ca::HitIndex_t>& hitsM = std::get<1>(fTripletData); + Vector<ca::HitIndex_t>& hitsR = std::get<2>(fTripletData); - bool isMomentumFitted = ((fStaL->fieldStatus != 0) || (fStaM->fieldStatus != 0) || (fStaR->fieldStatus != 0)); + bool isMomentumFitted = ((fStaL->fieldStatus != 0) || (fStaM->fieldStatus != 0) || (fStaR->fieldStatus != 0)); - tripletsOut.clear(); - tripletsOut.reserve(hitsM.size()); + tripletsOut.clear(); + tripletsOut.reserve(hitsM.size()); - for (size_t i3 = 0; i3 < hitsM.size(); ++i3) { + for (size_t i3 = 0; i3 < hitsM.size(); ++i3) { - TrackParamV& T3 = tracks[i3]; + TrackParamV& T3 = tracks[i3]; - // TODO: SG: normalize chi2, separate cuts on time and space + // TODO: SG: normalize chi2, separate cuts on time and space - const fscal chi2 = T3.GetChiSq()[0] + T3.GetChiSqTime()[0]; + const fscal chi2 = T3.GetChiSq()[0] + T3.GetChiSqTime()[0]; - const ca::HitIndex_t ihitl = fIhitL; - const ca::HitIndex_t ihitm = hitsM[i3]; - const ca::HitIndex_t ihitr = hitsR[i3]; + const ca::HitIndex_t ihitl = fIhitL; + const ca::HitIndex_t ihitm = hitsM[i3]; + const ca::HitIndex_t ihitr = hitsR[i3]; - CBMCA_DEBUG_ASSERT(ihitl < frWData.HitStartIndexOnStation(fIstaL + 1)); - CBMCA_DEBUG_ASSERT(ihitm < frWData.HitStartIndexOnStation(fIstaM + 1)); - CBMCA_DEBUG_ASSERT(ihitr < frWData.HitStartIndexOnStation(fIstaR + 1)); + CBMCA_DEBUG_ASSERT(ihitl < frWData.HitStartIndexOnStation(fIstaL + 1)); + CBMCA_DEBUG_ASSERT(ihitm < frWData.HitStartIndexOnStation(fIstaM + 1)); + CBMCA_DEBUG_ASSERT(ihitr < frWData.HitStartIndexOnStation(fIstaR + 1)); - if (!frWData.CurrentIteration()->GetTrackFromTripletsFlag()) { - if (chi2 > frWData.CurrentIteration()->GetTripletFinalChi2Cut()) { - continue; + if (!frWData.CurrentIteration()->GetTrackFromTripletsFlag()) { + if (chi2 > frWData.CurrentIteration()->GetTripletFinalChi2Cut()) { + continue; + } } - } - // assert(std::isfinite(chi2) && chi2 > 0); + // assert(std::isfinite(chi2) && chi2 > 0); - if (!std::isfinite(chi2) || chi2 < 0) { - continue; - } - //if (!T3.IsEntryConsistent(true, 0)) { continue; } + if (!std::isfinite(chi2) || chi2 < 0) { + continue; + } + //if (!T3.IsEntryConsistent(true, 0)) { continue; } - fscal qp = T3.Qp()[0]; - fscal Cqp = T3.C44()[0]; + fscal qp = T3.Qp()[0]; + fscal Cqp = T3.C44()[0]; - // TODO: SG: a magic correction that comes from the legacy code - // removing it leads to a higher ghost ratio - Cqp += 0.001; + // TODO: SG: a magic correction that comes from the legacy code + // removing it leads to a higher ghost ratio + Cqp += 0.001; - tripletsOut.emplace_back(ihitl, ihitm, ihitr, fIstaL, fIstaM, fIstaR, 0, 0, 0, chi2, qp, Cqp, T3.Tx()[0], - T3.C22()[0], T3.Ty()[0], T3.C33()[0], isMomentumFitted); + tripletsOut.emplace_back(ihitl, ihitm, ihitr, fIstaL, fIstaM, fIstaR, 0, 0, 0, chi2, qp, Cqp, T3.Tx()[0], + T3.C22()[0], T3.Ty()[0], T3.C33()[0], isMomentumFitted); + } } -} - -void TripletConstructor::CollectHits(Vector<ca::HitIndex_t>& collectedHits, kf::TrackKalmanFilter<fvec>& fit, - const int iSta, const double chi2Cut, const int iMC, const int maxNhits) -{ - /// Collect hits on a station - collectedHits.clear(); - collectedHits.reserve(maxNhits); - - const ca::Station<fvec>& sta = fParameters.GetStation(iSta); - - TrackParamV& T = fit.Tr(); - //LOG(info) << T.chi2[0] ; - T.ChiSq() = 0.; - - // if make it bigger the found hits will be rejected later because of the chi2 cut. - const fvec Pick_m22 = (fvec(chi2Cut) - T.GetChiSq()); - const fscal timeError2 = T.C55()[0]; - const fscal time = T.Time()[0]; - - const auto& grid = frWData.Grid(iSta); - const fvec maxDZ = frWData.CurrentIteration()->GetMaxDZ(); - ca::GridArea area(grid, T.X()[0], T.Y()[0], - (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(T.Tx()))[0], - (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(T.Ty()))[0]); - if constexpr (fDebugCollectHits) { - LOG(info) << "search area: " << T.X()[0] << " " << T.Y()[0] << " " - << (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(T.Tx()))[0] << " " - << (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(T.Ty()))[0]; - } - if (fParameters.DevIsIgnoreHitSearchAreas()) { - area.DoLoopOverEntireGrid(); - } - // loop over station hits (index incremented in condition) - for (ca::HitIndex_t ih = 0; area.GetNextObjectId(ih) && ((int) collectedHits.size() < maxNhits);) { + void TripletConstructor::CollectHits(Vector<ca::HitIndex_t>& collectedHits, kf::TrackKalmanFilter<fvec>& fit, + const int iSta, const double chi2Cut, const int iMC, const int maxNhits) + { + /// Collect hits on a station + collectedHits.clear(); + collectedHits.reserve(maxNhits); - if (frWData.IsHitSuppressed(ih)) { - continue; - } + const ca::Station<fvec>& sta = fParameters.GetStation(iSta); - const ca::Hit& hit = frWData.Hit(ih); + TrackParamV& T = fit.Tr(); + //LOG(info) << T.chi2[0] ; + T.ChiSq() = 0.; + + // if make it bigger the found hits will be rejected later because of the chi2 cut. + const fvec Pick_m22 = (fvec(chi2Cut) - T.GetChiSq()); + const fscal timeError2 = T.C55()[0]; + const fscal time = T.Time()[0]; + + const auto& grid = frWData.Grid(iSta); + const fvec maxDZ = frWData.CurrentIteration()->GetMaxDZ(); + ca::GridArea area(grid, T.X()[0], T.Y()[0], + (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(T.Tx()))[0], + (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(T.Ty()))[0]); if constexpr (fDebugCollectHits) { - LOG(info) << "hit in the search area: " << hit.ToString(); - LOG(info) << " check the hit.. "; + LOG(info) << "search area: " << T.X()[0] << " " << T.Y()[0] << " " + << (sqrt(Pick_m22 * T.C00()) + grid.GetMaxRangeX() + maxDZ * kf::utils::fabs(T.Tx()))[0] << " " + << (sqrt(Pick_m22 * T.C11()) + grid.GetMaxRangeY() + maxDZ * kf::utils::fabs(T.Ty()))[0]; } - - if (iMC >= 0) { // match via MC - if (iMC != ca::Framework::GetMcTrackIdForWindowHit(ih)) { - if constexpr (fDebugCollectHits) { - LOG(info) << " hit mc does not match"; - } - continue; - } + if (fParameters.DevIsIgnoreHitSearchAreas()) { + area.DoLoopOverEntireGrid(); } - // check time-boundaries + // loop over station hits (index incremented in condition) + for (ca::HitIndex_t ih = 0; area.GetNextObjectId(ih) && ((int) collectedHits.size() < maxNhits);) { - //TODO: move hardcoded cuts to parameters - if ((sta.timeInfo) && (T.NdfTime()[0] >= 0)) { - if (fabs(time - hit.T()) > 1.4 * (3.5 * sqrt(timeError2) + hit.RangeT())) { - if constexpr (fDebugCollectHits) { - LOG(info) << " hit time does not match"; - } + if (frWData.IsHitSuppressed(ih)) { continue; } - // if (fabs(time - hit.T()) > 30) continue; - } - - // - check whether hit belong to the window ( track position +\- errors ) - - const fscal z = hit.Z(); - - // check y-boundaries - const auto [y, C11] = fit.ExtrapolateLineYdY2(z); - const fscal dy_est = sqrt(Pick_m22[0] * C11[0]) + hit.RangeY(); - const fscal dY = hit.Y() - y[0]; - if (fabs(dY) > dy_est) { + const ca::Hit& hit = frWData.Hit(ih); if constexpr (fDebugCollectHits) { - LOG(info) << " hit Y does not match"; + LOG(info) << "hit in the search area: " << hit.ToString(); + LOG(info) << " check the hit.. "; } - continue; - } - // check x-boundaries - const auto [x, C00] = fit.ExtrapolateLineXdX2(z); - const fscal dx_est = sqrt(Pick_m22[0] * C00[0]) + hit.RangeX(); - const fscal dX = hit.X() - x[0]; + if (iMC >= 0) { // match via MC + if (iMC != ca::Framework::GetMcTrackIdForWindowHit(ih)) { + if constexpr (fDebugCollectHits) { + LOG(info) << " hit mc does not match"; + } + continue; + } + } - if (fabs(dX) > dx_est) { - if constexpr (fDebugCollectHits) { - LOG(info) << " hit X does not match"; + // check time-boundaries + + //TODO: move hardcoded cuts to parameters + if ((sta.timeInfo) && (T.NdfTime()[0] >= 0)) { + if (fabs(time - hit.T()) > 1.4 * (3.5 * sqrt(timeError2) + hit.RangeT())) { + if constexpr (fDebugCollectHits) { + LOG(info) << " hit time does not match"; + } + continue; + } + // if (fabs(time - hit.T()) > 30) continue; } - continue; - } - // check chi2 - kf::MeasurementXy<fvec> mxy(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One()); + // - check whether hit belong to the window ( track position +\- errors ) - + const fscal z = hit.Z(); - const fvec C10 = fit.ExtrapolateLineDxy(z); - const auto [chi2x, chi2u] = kf::TrackKalmanFilter<fvec>::GetChi2XChi2U(mxy, x, y, C00, C10, C11); + // check y-boundaries + const auto [y, C11] = fit.ExtrapolateLineYdY2(z); + const fscal dy_est = sqrt(Pick_m22[0] * C11[0]) + hit.RangeY(); + const fscal dY = hit.Y() - y[0]; - // TODO: adjust the cut, cut on chi2x & chi2u separately - if (!frWData.CurrentIteration()->GetTrackFromTripletsFlag()) { - if (chi2x[0] > chi2Cut) { + if (fabs(dY) > dy_est) { if constexpr (fDebugCollectHits) { - LOG(info) << " hit chi2X is too large"; + LOG(info) << " hit Y does not match"; } continue; } - if (chi2u[0] > chi2Cut) { + + // check x-boundaries + const auto [x, C00] = fit.ExtrapolateLineXdX2(z); + const fscal dx_est = sqrt(Pick_m22[0] * C00[0]) + hit.RangeX(); + const fscal dX = hit.X() - x[0]; + + if (fabs(dX) > dx_est) { if constexpr (fDebugCollectHits) { - LOG(info) << " hit chi2U is too large"; + LOG(info) << " hit X does not match"; } continue; } - } - if constexpr (fDebugCollectHits) { - LOG(info) << " hit passed all the checks"; - } - collectedHits.push_back(ih); - } // loop over the hits in the area -} + // check chi2 + kf::MeasurementXy<fvec> mxy(hit.X(), hit.Y(), hit.dX2(), hit.dY2(), hit.dXY(), fvec::One(), fvec::One()); + + const fvec C10 = fit.ExtrapolateLineDxy(z); + const auto [chi2x, chi2u] = kf::TrackKalmanFilter<fvec>::GetChi2XChi2U(mxy, x, y, C00, C10, C11); + + // TODO: adjust the cut, cut on chi2x & chi2u separately + if (!frWData.CurrentIteration()->GetTrackFromTripletsFlag()) { + if (chi2x[0] > chi2Cut) { + if constexpr (fDebugCollectHits) { + LOG(info) << " hit chi2X is too large"; + } + continue; + } + if (chi2u[0] > chi2Cut) { + if constexpr (fDebugCollectHits) { + LOG(info) << " hit chi2U is too large"; + } + continue; + } + } + if constexpr (fDebugCollectHits) { + LOG(info) << " hit passed all the checks"; + } + collectedHits.push_back(ih); + + } // loop over the hits in the area + } +} // namespace cbm::algo::ca diff --git a/algo/kf/core/geo/KfFieldRegion.cxx b/algo/kf/core/geo/KfFieldRegion.cxx index 340e22a18d6b5378857c434fd3bf61473ef04bde..55c518c6db0cf98f3b81c07af64397f5b9472466 100644 --- a/algo/kf/core/geo/KfFieldRegion.cxx +++ b/algo/kf/core/geo/KfFieldRegion.cxx @@ -17,236 +17,223 @@ #include <fmt/format.h> -using cbm::algo::kf::EFieldMode; -using cbm::algo::kf::FieldFn_t; -using cbm::algo::kf::FieldRegion; -using cbm::algo::kf::FieldValue; -using cbm::algo::kf::GlobalField; - -using cbm::algo::kf::detail::FieldRegionBase; -using namespace cbm::algo; - -FieldFn_t GlobalField::fgOriginalField = &GlobalField::UndefField; - -kf::EFieldType GlobalField::fgOriginalFieldType{kf::EFieldType::Null}; - - -bool GlobalField::fgForceUseOfOriginalField = false; - - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldRegionBase<T, EFieldMode::Intrpl>::Set(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, - const T& z1, const FieldValue<T>& b2, const T& z2) +namespace cbm::algo::kf { - fZfirst = z0; - - auto dz1 = z1 - z0; - auto dz2 = z2 - z0; - auto det = utils::simd::One<T>() / (dz1 * dz2 * (z2 - z1)); - auto w21 = -dz2 * det; - auto w22 = dz1 * det; - auto w11 = -dz2 * w21; - auto w12 = -dz1 * w22; - - for (int iD = 0; iD < 3; ++iD) { - auto db1 = b1.GetComponent(iD) - b0.GetComponent(iD); - auto db2 = b2.GetComponent(iD) - b0.GetComponent(iD); - auto& coeff = fCoeff[iD]; - coeff[0] = b0.GetComponent(iD); - coeff[1] = db1 * w11 + db2 * w12; - coeff[2] = db1 * w21 + db2 * w22; + using detail::FieldRegionBase; + FieldFn_t GlobalField::fgOriginalField{&GlobalField::UndefField}; + EFieldType GlobalField::fgOriginalFieldType{EFieldType::Null}; + bool GlobalField::fgForceUseOfOriginalField{false}; + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldRegionBase<T, EFieldMode::Intrpl>::Set(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, + const T& z1, const FieldValue<T>& b2, const T& z2) + { + fZfirst = z0; + + auto dz1 = z1 - z0; + auto dz2 = z2 - z0; + auto det = utils::simd::One<T>() / (dz1 * dz2 * (z2 - z1)); + auto w21 = -dz2 * det; + auto w22 = dz1 * det; + auto w11 = -dz2 * w21; + auto w12 = -dz1 * w22; + + for (int iD = 0; iD < 3; ++iD) { + auto db1 = b1.GetComponent(iD) - b0.GetComponent(iD); + auto db2 = b2.GetComponent(iD) - b0.GetComponent(iD); + auto& coeff = fCoeff[iD]; + coeff[0] = b0.GetComponent(iD); + coeff[1] = db1 * w11 + db2 * w12; + coeff[2] = db1 * w21 + db2 * w22; + } } -} -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -FieldValue<T> FieldRegionBase<T, EFieldMode::Intrpl>::Get(const T& x, const T& y, const T& z) const -{ - if (GlobalField::IsUsingOriginalFieldForced()) { - return GlobalField::GetFieldValue(GlobalField::fgOriginalField, x, y, z); + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + FieldValue<T> FieldRegionBase<T, EFieldMode::Intrpl>::Get(const T& x, const T& y, const T& z) const + { + if (GlobalField::IsUsingOriginalFieldForced()) { + return GlobalField::GetFieldValue(GlobalField::fgOriginalField, x, y, z); + } + auto dz = z - this->fZfirst; + return FieldValue<T>{this->fCoeff[0][0] + dz * (this->fCoeff[0][1] + dz * this->fCoeff[0][2]), + this->fCoeff[1][0] + dz * (this->fCoeff[1][1] + dz * this->fCoeff[1][2]), + this->fCoeff[2][0] + dz * (this->fCoeff[2][1] + dz * this->fCoeff[2][2])}; } - auto dz = z - this->fZfirst; - return FieldValue<T>{this->fCoeff[0][0] + dz * (this->fCoeff[0][1] + dz * this->fCoeff[0][2]), - this->fCoeff[1][0] + dz * (this->fCoeff[1][1] + dz * this->fCoeff[1][2]), - this->fCoeff[2][0] + dz * (this->fCoeff[2][1] + dz * this->fCoeff[2][2])}; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -std::tuple<T, T, T> -FieldRegionBase<T, EFieldMode::Intrpl>::GetDoubleIntegrals(const T& /*x1*/, const T& /*y1*/, const T& z1, // - const T& /*x2*/, const T& /*y2*/, const T& z2) const -{ - // double integral of the field along z - if (GlobalField::IsUsingOriginalFieldForced()) { - // TODO: implement the double integral for the original field - } - auto fld = *this; - fld.Shift(z1); - T dz = z2 - z1; - T dz2 = dz * dz; - T c0 = dz2 * T(1. / 2.); - T c1 = dz2 * dz * T(1. / 6.); - T c2 = dz2 * dz2 * T(1. / 12.); - return {c0 * fld.fCoeff[0][0] + c1 * fld.fCoeff[0][1] + c2 * fld.fCoeff[0][2], - c0 * fld.fCoeff[1][0] + c1 * fld.fCoeff[1][1] + c2 * fld.fCoeff[1][2], - c0 * fld.fCoeff[2][0] + c1 * fld.fCoeff[2][1] + c2 * fld.fCoeff[2][2]}; -} - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldRegionBase<T, EFieldMode::Intrpl>::Shift(const T& z) -{ - auto dz = z - fZfirst; - for (int iD = 0; iD < 3; ++iD) { - auto& coeff = fCoeff[iD]; - auto c2dz = coeff[2] * dz; - coeff[0] += (coeff[1] + c2dz) * dz; - coeff[1] += (2 * c2dz); + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + std::tuple<T, T, T> + FieldRegionBase<T, EFieldMode::Intrpl>::GetDoubleIntegrals(const T& /*x1*/, const T& /*y1*/, const T& z1, // + const T& /*x2*/, const T& /*y2*/, const T& z2) const + { + // double integral of the field along z + + if (GlobalField::IsUsingOriginalFieldForced()) { + // TODO: implement the double integral for the original field + } + auto fld = *this; + fld.Shift(z1); + T dz = z2 - z1; + T dz2 = dz * dz; + T c0 = dz2 * T(1. / 2.); + T c1 = dz2 * dz * T(1. / 6.); + T c2 = dz2 * dz2 * T(1. / 12.); + return {c0 * fld.fCoeff[0][0] + c1 * fld.fCoeff[0][1] + c2 * fld.fCoeff[0][2], + c0 * fld.fCoeff[1][0] + c1 * fld.fCoeff[1][1] + c2 * fld.fCoeff[1][2], + c0 * fld.fCoeff[2][0] + c1 * fld.fCoeff[2][1] + c2 * fld.fCoeff[2][2]}; } - fZfirst = z; -} -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldRegionBase<T, EFieldMode::Intrpl>::CheckConsistency() const -{ - // Check SIMD data vectors for consistent initialization - for (int iD = 0; iD < 3; ++iD) { - for (int iC = 0; iC < 3; ++iC) { - utils::CheckSimdVectorEquality(fCoeff[iD][iC], fmt::format("FieldRegion::fCoeff[{}][{}]", iD, iC).c_str()); + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldRegionBase<T, EFieldMode::Intrpl>::Shift(const T& z) + { + auto dz = z - fZfirst; + for (int iD = 0; iD < 3; ++iD) { + auto& coeff = fCoeff[iD]; + auto c2dz = coeff[2] * dz; + coeff[0] += (coeff[1] + c2dz) * dz; + coeff[1] += (2 * c2dz); } + fZfirst = z; } - utils::CheckSimdVectorEquality(fZfirst, "FieldRegion::fZfirst"); -} -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -std::string FieldRegionBase<T, EFieldMode::Intrpl>::ToString(int indentLevel, int) const -{ - constexpr char IndentChar = '\t'; - std::stringstream msg; - std::string indent(indentLevel, IndentChar); - using fmt::format; - auto Cnv = [&](const auto& val) { return utils::simd::Cast<T, Literal_t<T>>(val); }; // alias for the conversion fn - const auto& coeff = this->fCoeff; - msg << indent << format("Field Region: dz = z - ({})", Cnv(this->fZfirst)); - msg << '\n' - << indent << IndentChar - << format("Bx(dz) = {:>12} + {:>12} dz + {:>12} dz2", Cnv(coeff[0][0]), Cnv(coeff[0][1]), Cnv(coeff[0][2])); - msg << '\n' - << indent << IndentChar - << format("Bx(dz) = {:>12} + {:>12} dz + {:>12} dz2", Cnv(coeff[1][0]), Cnv(coeff[1][1]), Cnv(coeff[1][2])); - msg << '\n' - << indent << IndentChar - << format("Bx(dz) = {:>12} + {:>12} dz + {:>12} dz2", Cnv(coeff[2][0]), Cnv(coeff[2][1]), Cnv(coeff[2][2])); - if (GlobalField::IsUsingOriginalFieldForced()) { - msg - << indent - << "\nWARNING: the GlobalField::ForceUseOfOriginalField() is enabled, so the magnetic field interpolation " - << indent - << "\nis replaced with the global magnetic function for debugging purposes. If you see this message and are " - << indent - << "\nnot sure, what is going on, please call GlobalField::ForceUseOfOriginalField(false) and re-run the routine"; + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldRegionBase<T, EFieldMode::Intrpl>::CheckConsistency() const + { + // Check SIMD data vectors for consistent initialization + for (int iD = 0; iD < 3; ++iD) { + for (int iC = 0; iC < 3; ++iC) { + utils::CheckSimdVectorEquality(fCoeff[iD][iC], fmt::format("FieldRegion::fCoeff[{}][{}]", iD, iC).c_str()); + } + } + utils::CheckSimdVectorEquality(fZfirst, "FieldRegion::fZfirst"); } - return msg.str(); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldRegionBase<T, EFieldMode::Orig>::CheckConsistency() const -{ - // Check SIMD data vectors for consistent initialization -} + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + std::string FieldRegionBase<T, EFieldMode::Intrpl>::ToString(int indentLevel, int) const + { + constexpr char IndentChar = '\t'; + std::stringstream msg; + std::string indent(indentLevel, IndentChar); + using fmt::format; + auto Cnv = [&](const auto& val) { return utils::simd::Cast<T, Literal_t<T>>(val); }; // alias for the conversion fn + const auto& coeff = this->fCoeff; + msg << indent << format("Field Region: dz = z - ({})", Cnv(this->fZfirst)); + msg << '\n' + << indent << IndentChar + << format("Bx(dz) = {:>12} + {:>12} dz + {:>12} dz2", Cnv(coeff[0][0]), Cnv(coeff[0][1]), Cnv(coeff[0][2])); + msg << '\n' + << indent << IndentChar + << format("Bx(dz) = {:>12} + {:>12} dz + {:>12} dz2", Cnv(coeff[1][0]), Cnv(coeff[1][1]), Cnv(coeff[1][2])); + msg << '\n' + << indent << IndentChar + << format("Bx(dz) = {:>12} + {:>12} dz + {:>12} dz2", Cnv(coeff[2][0]), Cnv(coeff[2][1]), Cnv(coeff[2][2])); + if (GlobalField::IsUsingOriginalFieldForced()) { + msg << indent + << "\nWARNING: the GlobalField::ForceUseOfOriginalField() is enabled, so the magnetic field interpolation " + << indent + << "\nis replaced with the global magnetic function for debugging purposes. If you see this message and are " + << indent + << "\nnot sure, what is going on, please call GlobalField::ForceUseOfOriginalField(false) and re-run the " + "routine"; + } + return msg.str(); + } -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -std::string FieldRegionBase<T, EFieldMode::Orig>::ToString(int indentLevel, int) const -{ - constexpr char IndentChar = '\t'; - std::stringstream msg; - std::string indent(indentLevel, IndentChar); - msg << indent << "Field region: created from the original field function"; - return msg.str(); -} + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldRegionBase<T, EFieldMode::Orig>::CheckConsistency() const + { + // Check SIMD data vectors for consistent initialization + } -namespace cbm::algo::kf::detail -{ - template class FieldRegionBase<float, EFieldMode::Intrpl>; - template class FieldRegionBase<double, EFieldMode::Intrpl>; - template class FieldRegionBase<fvec, EFieldMode::Intrpl>; - template class FieldRegionBase<float, EFieldMode::Orig>; - template class FieldRegionBase<double, EFieldMode::Orig>; - template class FieldRegionBase<fvec, EFieldMode::Orig>; -} // namespace cbm::algo::kf::detail - - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldRegion<T>::Shift(const T& z) -{ - if (fFieldMode == EFieldMode::Intrpl) { - foFldIntrpl->Shift(z); + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + std::string FieldRegionBase<T, EFieldMode::Orig>::ToString(int indentLevel, int) const + { + constexpr char IndentChar = '\t'; + std::stringstream msg; + std::string indent(indentLevel, IndentChar); + msg << indent << "Field region: created from the original field function"; + return msg.str(); } -} -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -std::string FieldRegion<T>::ToString(int indentLevel, int) const -{ - constexpr char IndentChar = '\t'; - std::stringstream msg; - std::string indent(indentLevel, IndentChar); - msg << indent << "FieldType: " << static_cast<int>(fFieldType) << '\n'; - msg << indent << "FieldMode: " << static_cast<int>(fFieldMode) << '\n'; - msg << indent - << (fFieldMode == EFieldMode::Intrpl ? foFldIntrpl->ToString(indentLevel) : foFldOrig->ToString(indentLevel)); - return msg.str(); -} - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldRegion<T>::CheckConsistency() const -{ - // Check SIMD data vectors for consistent initialization - if (fFieldMode == EFieldMode::Intrpl) { - foFldIntrpl->CheckConsistency(); + namespace detail + { + template class FieldRegionBase<float, EFieldMode::Intrpl>; + template class FieldRegionBase<double, EFieldMode::Intrpl>; + template class FieldRegionBase<fvec, EFieldMode::Intrpl>; + template class FieldRegionBase<float, EFieldMode::Orig>; + template class FieldRegionBase<double, EFieldMode::Orig>; + template class FieldRegionBase<fvec, EFieldMode::Orig>; + } // namespace detail + + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldRegion<T>::Shift(const T& z) + { + if (fFieldMode == EFieldMode::Intrpl) { + foFldIntrpl->Shift(z); + } } - else { - foFldOrig->CheckConsistency(); + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + std::string FieldRegion<T>::ToString(int indentLevel, int) const + { + constexpr char IndentChar = '\t'; + std::stringstream msg; + std::string indent(indentLevel, IndentChar); + msg << indent << "FieldType: " << static_cast<int>(fFieldType) << '\n'; + msg << indent << "FieldMode: " << static_cast<int>(fFieldMode) << '\n'; + msg << indent + << (fFieldMode == EFieldMode::Intrpl ? foFldIntrpl->ToString(indentLevel) : foFldOrig->ToString(indentLevel)); + return msg.str(); } -} -// --------------------------------------------------------------------------------------------------------------------- -// -std::tuple<double, double, double> GlobalField::UndefField(double, double, double) -{ - assert(!GlobalField::IsUsingOriginalFieldForced() - && "cbm::algo::kf::GlobalField: The original globa magnetic field is required by " - "kf::defs::dbg::ForceOriginalField = true. Please provide it with the " - "kf::GlobalField::SetGlobalField() function."); - return std::make_tuple(defs::Undef<double>, defs::Undef<double>, defs::Undef<double>); -} + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldRegion<T>::CheckConsistency() const + { + // Check SIMD data vectors for consistent initialization + if (fFieldMode == EFieldMode::Intrpl) { + foFldIntrpl->CheckConsistency(); + } + else { + foFldOrig->CheckConsistency(); + } + } + + // ------------------------------------------------------------------------------------------------------------------- + // + std::tuple<double, double, double> GlobalField::UndefField(double, double, double) + { + assert(!GlobalField::IsUsingOriginalFieldForced() + && "cbm::algo::kf::GlobalField: The original globa magnetic field is required by " + "kf::defs::dbg::ForceOriginalField = true. Please provide it with the " + "kf::GlobalField::SetGlobalField() function."); + return std::make_tuple(defs::Undef<double>, defs::Undef<double>, defs::Undef<double>); + } -namespace cbm::algo::kf -{ template class FieldRegion<float>; template class FieldRegion<double>; template class FieldRegion<fvec>; diff --git a/algo/kf/core/geo/KfFieldValue.cxx b/algo/kf/core/geo/KfFieldValue.cxx index 3054b8579e7a54c2951d0656a81683454b633cad..eb7e637ab562738d2fd6492fe8bf4794e9f1332b 100644 --- a/algo/kf/core/geo/KfFieldValue.cxx +++ b/algo/kf/core/geo/KfFieldValue.cxx @@ -11,33 +11,34 @@ #include <sstream> -using namespace cbm::algo::kf; - -// --------------------------------------------------------------------------------------------------------------------- -// -template<typename T> -void FieldValue<T>::CheckConsistency() const +namespace cbm::algo::kf { - // Check SIMD data vectors for consistent initialization - utils::CheckSimdVectorEquality(fB[0], "FieldValue::x"); - utils::CheckSimdVectorEquality(fB[1], "FieldValue::y"); - utils::CheckSimdVectorEquality(fB[2], "FieldValue::z"); - - // TODO: Any other checks? (S.Zharko) -} -template<typename T> -std::string FieldValue<T>::ToString(int indentLevel) const -{ - constexpr char IndentChar = '\t'; - std::stringstream msg; - std::string indent(indentLevel, IndentChar); - msg << indent << "B = {" << fB[0] << ", " << fB[1] << ", " << fB[2] << "} [kG]"; - return msg.str(); -} + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + void FieldValue<T>::CheckConsistency() const + { + // Check SIMD data vectors for consistent initialization + utils::CheckSimdVectorEquality(fB[0], "FieldValue::x"); + utils::CheckSimdVectorEquality(fB[1], "FieldValue::y"); + utils::CheckSimdVectorEquality(fB[2], "FieldValue::z"); + + // TODO: Any other checks? (S.Zharko) + } + + // ------------------------------------------------------------------------------------------------------------------- + // + template<typename T> + std::string FieldValue<T>::ToString(int indentLevel) const + { + constexpr char IndentChar = '\t'; + std::stringstream msg; + std::string indent(indentLevel, IndentChar); + msg << indent << "B = {" << fB[0] << ", " << fB[1] << ", " << fB[2] << "} [kG]"; + return msg.str(); + } -namespace cbm::algo::kf -{ template class FieldValue<float>; template class FieldValue<double>; template class FieldValue<fvec>; diff --git a/reco/KF/ParticleFitter/CbmL1PFFitter.h b/reco/KF/ParticleFitter/CbmL1PFFitter.h index 420d2a20933ce5e7f3b9f074305a6a1d0cbd2d94..050f2dfb8626d137de9e33e7e043e56d1a997488 100644 --- a/reco/KF/ParticleFitter/CbmL1PFFitter.h +++ b/reco/KF/ParticleFitter/CbmL1PFFitter.h @@ -28,9 +28,6 @@ class CbmMvdHit; class CbmStsHit; class CbmStsTrack; - -using namespace cbm::algo; - class CbmKFVertex; class TClonesArray; @@ -39,9 +36,9 @@ class CbmL1PFFitter { // A container for parameters of kf::FieldRegion struct PFFieldRegion { PFFieldRegion() {} - PFFieldRegion(const kf::FieldRegion<kf::fvec>&, int i); - void setFromL1FieldRegion(const kf::FieldRegion<ca::fvec>&, int i); - void getL1FieldRegion(kf::FieldRegion<kf::fvec>&, int i); + PFFieldRegion(const cbm::algo::kf::FieldRegion<cbm::algo::kf::fvec>&, int i); + void setFromL1FieldRegion(const cbm::algo::kf::FieldRegion<cbm::algo::kf::fvec>&, int i); + void getL1FieldRegion(cbm::algo::kf::FieldRegion<cbm::algo::kf::fvec>&, int i); float fP[10]{0.}; }; diff --git a/reco/L1/CbmL1.cxx b/reco/L1/CbmL1.cxx index a66957edd371d1ba14d94fcc58e34290e9a20be4..593b3527286f672420ea5bee4b3813acb93ba670 100644 --- a/reco/L1/CbmL1.cxx +++ b/reco/L1/CbmL1.cxx @@ -20,6 +20,7 @@ #include "CbmL1.h" +#include "CbmKfTarget.h" #include "CbmMCDataManager.h" #include "CbmMuchTrackingInterface.h" #include "CbmMvdTrackingInterface.h" @@ -254,6 +255,10 @@ try { // *************************** { + const auto& pTarget = cbm::kf::Target::Instance(); + fTargetX = pTarget->GetX(); + fTargetY = pTarget->GetY(); + fTargetZ = pTarget->GetZ(); } fInitManager.SetTargetPosition(fTargetX, fTargetY, fTargetZ);