23#include "MFTBase/GeometryTGeo.h"
29template <o2::detectors::DetID::ID DetId,
typename GeomT>
32 gsl::span<const unsigned char>::iterator& patterns,
35 if (dict ==
nullptr) {
36 throw std::runtime_error(
"Cluster dictionary is not available");
38 if (geom ==
nullptr) {
39 throw std::runtime_error(
"Cluster geometry is not available");
43 if (sensorID >= geom->getSize()) {
44 throw std::runtime_error(
"Cluster sensor ID is outside the detector geometry");
46 const int layer = geom->getLayer(sensorID);
48 if (layer < 0 || layer >= nLayers) {
49 throw std::runtime_error(
"Cluster layer is outside the detector");
53 const float sigma2Row = clusterData.sig2Row;
54 const float sigma2Col = clusterData.sig2Col;
56 if constexpr (DetId == o2::detectors::DetID::ITS) {
57 const auto trkXYZ = geom->getMatrixT2L(sensorID) ^ clusterData.coordinates;
58 const auto gloXYZ = geom->getMatrixL2G(sensorID) * clusterData.coordinates;
59 return {{gloXYZ.x(), gloXYZ.y(), gloXYZ.z()},
60 {trkXYZ.x(), trkXYZ.y(), trkXYZ.z(), geom->getSensorRefAlpha(sensorID)},
61 {sigma2Row, 0.f, sigma2Col},
65 if (!geom->getCacheL2G().isFilled() || geom->getCacheL2G().getSize() <= sensorID) {
66 throw std::runtime_error(
"Cluster geometry is not available");
68 const auto gloXYZ = geom->getMatrixL2G(sensorID) * clusterData.coordinates;
69 return {{gloXYZ.x(), gloXYZ.y(), gloXYZ.z()}, {}, {sigma2Row, 0.f, sigma2Col}, clusterData.nPixels,
layer};
73template <o2::detectors::DetID::ID DetId,
typename Consume>
76 using Geometry = std::conditional_t<DetId == o2::detectors::DetID::ITS, o2::its::GeometryTGeo, o2::mft::GeometryTGeo>;
77 Geometry* geometry =
nullptr;
78 if (!
source.clusters.empty()) {
79 geometry = Geometry::Instance();
80 geometry->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G));
82 consume([&](
const auto& cluster,
auto& patterns) {
83 return decodeCluster<DetId>(geometry, cluster, patterns,
source.dictionary);
94GlobalMeasurement makeCylinderGlobalMeasurement(
const DecodedCluster& decoded, uint32_t clusterId)
96 const float sine = std::sin(decoded.cylinderFrame.frameAngle);
97 const float cosine = std::cos(decoded.cylinderFrame.frameAngle);
98 const auto& covariance = decoded.rowColumnCovariance;
99 return GlobalMeasurement{
103 {sine * sine * covariance.uu,
104 -sine * cosine * covariance.uu,
105 -sine * covariance.uv,
106 cosine * cosine * covariance.uu,
107 cosine * covariance.uv,
117GlobalMeasurement makeDiskGlobalMeasurement(
const DecodedCluster& decoded, uint32_t clusterId)
119 return GlobalMeasurement{
123 {decoded.rowColumnCovariance.uu, decoded.rowColumnCovariance.uv, 0.f,
124 decoded.rowColumnCovariance.vv, 0.f, 0.f},
130SurfaceMeasurement makeCylinderSurfaceMeasurement(
const DecodedCluster& decoded)
132 return {decoded.cylinderFrame, decoded.rowColumnCovariance};
135SurfaceMeasurement makeDiskSurfaceMeasurement(
const DecodedCluster& decoded)
137 return {{decoded.global.z, decoded.global.x, decoded.global.y, 0.f},
138 decoded.rowColumnCovariance};
141bool covariance2DIsPositiveSemidefinite(
float cxx,
float cxy,
float cyy)
noexcept
143 if (cxx < 0.f || cyy < 0.f) {
146 const double diagonalProduct =
static_cast<double>(cxx) * cyy;
147 const double cxySquared =
static_cast<double>(cxy) * cxy;
148 const double tolerance = 16. * std::numeric_limits<float>::epsilon() *
149 std::max(diagonalProduct, cxySquared);
150 return diagonalProduct - cxySquared >= -tolerance;
153bool globalCovarianceIsPositiveSemidefinite(
const GlobalCovariance3F& covariance)
noexcept
161 if (!covariance2DIsPositiveSemidefinite(xx, xy, yy) ||
162 !covariance2DIsPositiveSemidefinite(xx, xz, zz) ||
163 !covariance2DIsPositiveSemidefinite(yy, yz, zz)) {
166 const double determinant =
167 static_cast<double>(xx) * yy * zz + 2. *
static_cast<double>(xy) * xz * yz -
168 static_cast<double>(xx) * yz * yz -
static_cast<double>(yy) * xz * xz -
169 static_cast<double>(zz) * xy * xy;
170 const double scale = std::max({std::abs(
static_cast<double>(xx) * yy * zz),
171 std::abs(2. *
static_cast<double>(xy) * xz * yz),
172 std::abs(
static_cast<double>(xx) * yz * yz),
173 std::abs(
static_cast<double>(yy) * xz * xz),
174 std::abs(
static_cast<double>(zz) * xy * xy)});
175 return o2::gpu::GPUCommonMath::Finite(
static_cast<float>(determinant)) &&
176 determinant >= -32. * std::numeric_limits<float>::epsilon() * scale;
179bool decodedMeasurementIsValid(
const GlobalMeasurement& global,
180 const SurfaceMeasurement& local)
noexcept
182 return globalCovarianceIsPositiveSemidefinite(global.covariance) &&
183 covariance2DIsPositiveSemidefinite(local.covariance.uu, local.covariance.uv, local.covariance.vv);
186void clearFrameAndSidecars(TimeFrame& frame,
187 std::vector<std::vector<uint32_t>>* externalIndicesBySurface,
188 std::vector<std::vector<uint32_t>>* clusterSizesBySurface)
noexcept
190 frame.resetTimeFrame();
191 if (externalIndicesBySurface !=
nullptr) {
192 externalIndicesBySurface->clear();
194 if (clusterSizesBySurface !=
nullptr) {
195 clusterSizesBySurface->clear();
204 gsl::span<const ClusterSourceInput>
sources,
205 std::vector<std::vector<uint32_t>>* externalIndicesBySurface,
206 std::vector<std::vector<uint32_t>>* clusterSizesBySurface,
bool requireCompleteMapping)
208 clearFrameAndSidecars(frame, externalIndicesBySurface, clusterSizesBySurface);
210 throw std::runtime_error(
"TimeFrame is not configured");
212 if (requireCompleteMapping &&
sources.empty()) {
213 throw std::runtime_error(
"Malformed cluster loading input");
215 const auto nSources =
static_cast<uint32_t
>(
sources.size());
217 std::vector<bool> seen(nSources,
false);
218 std::vector<ClusterSourceId> sourceBySurface(catalog.
nSurfaces, ClusterSourceId::invalid());
220 if (!
src.id.isValid() ||
src.id.value() >= nSources) {
221 throw std::runtime_error(std::format(
"Source IDs must be dense source={}",
src.id.value()));
223 if (seen[
src.id.value()]) {
224 throw std::runtime_error(std::format(
"Duplicate source ID source={}",
src.id.value()));
226 seen[
src.id.value()] =
true;
227 if (
src.detector != o2::detectors::DetID::ITS &&
src.detector != o2::detectors::DetID::MFT) {
228 throw std::runtime_error(std::format(
"Unsupported source detector source={}",
src.id.value()));
230 if (!
src.clusters.empty() &&
src.dictionary ==
nullptr) {
231 throw std::runtime_error(std::format(
"Cluster dictionary is not available source={} rof={} clusterIndex={}",
src.id.value(), 0, 0));
233 for (
const auto surface :
src.layerToSurface) {
235 throw std::runtime_error(std::format(
"Invalid source-to-surface layer mapping source={}",
src.id.value()));
237 if (sourceBySurface[surface.value()].isValid()) {
238 throw std::runtime_error(std::format(
"Invalid source-to-surface layer mapping source={}",
src.id.value()));
240 if (catalog.getSurface(surface).detectorId !=
static_cast<uint8_t
>(
src.detector)) {
241 throw std::runtime_error(std::format(
"Source detector does not match its surface source={}",
src.id.value()));
243 sourceBySurface[surface.value()] =
src.id;
246 if (requireCompleteMapping) {
248 if (position < sourceBySurface.size() && sourceBySurface[position].isValid()) {
257 if (owner.isValid()) {
258 throw std::runtime_error(
"Invalid source-to-surface layer mapping");
262 throw std::runtime_error(std::format(
"Invalid source-to-surface layer mapping source={}", owner.value()));
269 for (uint32_t
r = 0;
r <
src.rofs.size(); ++
r) {
270 const auto& rof =
src.rofs[
r];
272 const int64_t n = rof.getNEntries();
273 if (
n < 0 ||
first != expectedNext) {
274 throw std::runtime_error(std::format(
"Invalid ROF cluster range source={} rof={}",
src.id.value(),
r));
277 if (expectedNext >
static_cast<int64_t>(
src.clusters.size())) {
278 throw std::runtime_error(std::format(
"Invalid ROF cluster range source={} rof={}",
src.id.value(),
r));
281 if (expectedNext !=
static_cast<int64_t>(
src.clusters.size())) {
282 throw std::runtime_error(std::format(
"Invalid ROF cluster range source={} rof={}",
src.id.value(),
static_cast<uint32_t
>(
src.rofs.size())));
287 uint32_t
r, uint32_t externalIndex,
288 std::vector<std::vector<uint32_t>>& externalIndices,
289 std::vector<std::vector<uint32_t>>& clusterSizes)
291 if (decoded.
layer < 0 ||
static_cast<size_t>(decoded.
layer) >=
src.layerToSurface.size()) {
292 throw std::runtime_error(std::format(
"Invalid source-to-surface layer mapping source={} rof={} clusterIndex={}",
src.id.value(),
r, externalIndex));
294 const auto expectedSurface =
src.layerToSurface[decoded.
layer];
295 const auto& surfaceDescriptor = catalog.getSurface(expectedSurface);
296 const auto localClusterId =
static_cast<uint32_t
>(frame.
getGlobalMeasurements(expectedSurface).size());
300 auto corrected = decoded;
302 corrected.rowColumnCovariance.uu += configuration.
systError2Row.empty() ? 0.f : configuration.systError2Row.at(expectedSurface.value());
303 corrected.rowColumnCovariance.vv += configuration.systError2Col.empty() ? 0.f : configuration.systError2Col.at(expectedSurface.value());
307 global = makeCylinderGlobalMeasurement(corrected, localClusterId);
308 measurement = makeCylinderSurfaceMeasurement(corrected);
310 global = makeDiskGlobalMeasurement(corrected, localClusterId);
311 measurement = makeDiskSurfaceMeasurement(corrected);
313 if (!decodedMeasurementIsValid(global, measurement)) {
314 throw std::runtime_error(std::format(
"Malformed cluster loading input source={} rof={} clusterIndex={}",
src.id.value(),
r, externalIndex));
318 global.
radius = std::hypot(global.
x, global.
y);
319 global.
phi = o2::its::math_utils::computePhi(global.
x, global.
y);
320 if (
src.labels !=
nullptr) {
321 frame.
addMeasurement(expectedSurface, global, measurement,
src.labels->getLabels(externalIndex));
325 clusterSizes[expectedSurface.value()].push_back(decoded.
nPixels);
326 externalIndices[expectedSurface.value()].push_back(externalIndex);
329 const std::vector<std::vector<int>>& boundaries)
339 std::vector<std::vector<uint32_t>>* externalIndicesBySurface,
340 std::vector<std::vector<uint32_t>>* clusterSizesBySurface)
343 std::vector<std::vector<uint32_t>> externalIndices(catalog.
nSurfaces);
344 std::vector<std::vector<uint32_t>> clusterSizes(catalog.
nSurfaces);
345 bool hasMCInformation =
false;
348 const auto load = [&](
const auto&
decode) {
351 if (
source.detector == o2::detectors::DetID::ITS) {
352 decodeDetectorSource<o2::detectors::DetID::ITS>(
source, load);
354 decodeDetectorSource<o2::detectors::DetID::MFT>(
source, load);
356 hasMCInformation |=
source.labels !=
nullptr;
359 if (externalIndicesBySurface !=
nullptr) {
360 *externalIndicesBySurface = std::move(externalIndices);
362 if (clusterSizesBySurface !=
nullptr) {
363 *clusterSizesBySurface = std::move(clusterSizes);
General auxilliary methods.
Passive common TimeFrame owner.
Definition of the GeometryTGeo class.
Shared cluster I/O utilities for ITS and MFT (based on ITStracking/IOUtils.h)
UShort_t getSensorID() const
SurfaceCatalogView getSurfaceCatalog() const noexcept
std::vector< float > systError2Row
std::size_t size() const noexcept
GLsizei GLsizei GLchar * source
GLenum GLuint GLint GLint layer
const bool const int nLayers
ClusterData< T > extractClusterData(const CompClusterExt &c, gsl::span< const unsigned char >::iterator &patterns, const TopologyDictionary *dict)
void loadDecodedSource(TimeFrame &frame, const SurfaceCatalogView &catalog, const ClusterSourceInput &src, const Decode &decode, std::vector< std::vector< uint32_t > > &externalIndices, std::vector< std::vector< uint32_t > > &clusterSizes)
void validateClusterRanges(const ClusterSourceInput &)
void storeSourceROFClusters(TimeFrame &, const ClusterSourceInput &, const std::vector< std::vector< int > > &)
void appendCluster(TimeFrame &, const SurfaceCatalogView &, const ClusterSourceInput &, const DecodedCluster &, uint32_t, uint32_t, std::vector< std::vector< uint32_t > > &, std::vector< std::vector< uint32_t > > &)
void prepareSources(TimeFrame &, const SurfaceCatalogView &, gsl::span< const ClusterSourceInput >, std::vector< std::vector< uint32_t > > *, std::vector< std::vector< uint32_t > > *, bool requireCompleteMapping=false)
void loadTimeFrameSources(TimeFrame &, gsl::span< const ClusterSourceInput >, SurfaceCatalogView, std::vector< std::vector< uint32_t > > *externalIndicesBySurface=nullptr, std::vector< std::vector< uint32_t > > *clusterSizesBySurface=nullptr)
constexpr int MFTNLayers
MFT CA half-disk layer count.
constexpr int ITSNLayers
ITS CA layer count.
void setROFClusters(std::size_t position, gsl::span< const int > boundaries)
void setHasMCInformation(bool value) noexcept
const DetectorConfiguration & getDetectorConfiguration() const noexcept
void addMeasurement(LayerId surface, GlobalMeasurement global, const SurfaceMeasurement &measurement)
bool isConfigured() const noexcept
gsl::span< const GlobalMeasurement > getGlobalMeasurements(LayerId surface) const
coder decode(ctfImage, triggersD, clustersD)