Skip to content
1 change: 1 addition & 0 deletions Detectors/ITSMFT/ITS/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_subdirectory(simulation)
add_subdirectory(reconstruction)
add_subdirectory(tracking)
add_subdirectory(workflow)
add_subdirectory(workflow-ca)
add_subdirectory(postprocessing)
add_subdirectory(macros)
add_subdirectory(QC)
48 changes: 48 additions & 0 deletions Detectors/ITSMFT/ITS/workflow-ca/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2019-2020 CERN and copyright holders of ALICE O2.
# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
# All rights not expressly granted are reserved.
#
# This software is distributed under the terms of the GNU General Public
# License v3 (GPL Version 3), copied verbatim in the file "COPYING".
#
# In applying this license CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization
# or submit itself to any jurisdiction.

o2_add_library(ITSCAWorkflow
TARGETVARNAME targetName
SOURCES src/ConfigPreflight.cxx
src/CATrackerSpec.cxx
PUBLIC_LINK_LIBRARIES O2::Framework
O2::SimulationDataFormat
O2::DataFormatsITS
O2::DataFormatsITSMFT
O2::ITSBase
O2::ITSMFTTracking
O2::ITSMFTCAWriter
O2::MFTTracking
O2::Steer
O2::CCDB)

o2_add_executable(ca-tracker-workflow
SOURCES src/its-ca-tracker-workflow.cxx
COMPONENT_NAME its
PUBLIC_LINK_LIBRARIES O2::ITSCAWorkflow)

o2_add_test(its-ca-config-preflight
COMPONENT_NAME its
LABELS "its;workflow;itsmft"
SOURCES test/testITSCAConfigPreflight.cxx
PUBLIC_LINK_LIBRARIES O2::ITSCAWorkflow)

o2_add_test(its-ca-tracker-dpl-contract
COMPONENT_NAME its
LABELS "its;workflow;itsmft"
SOURCES test/testITSCATrackerDPLContract.cxx
PUBLIC_LINK_LIBRARIES O2::ITSCAWorkflow)

o2_add_test(its-ca-truth-seeding
COMPONENT_NAME its
LABELS "its;workflow;itsmft"
SOURCES test/testITSCATruthSeeding.cxx
PUBLIC_LINK_LIBRARIES O2::ITSCAWorkflow)
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
///
/// \file CATrackerSpec.h
/// \brief ITS common-CA tracker DPL device with tracker-only outputs.

#ifndef O2_ITS_CA_WORKFLOW_CATRACKERSPEC_H_
#define O2_ITS_CA_WORKFLOW_CATRACKERSPEC_H_

#include <cstdint>
#include <memory>
#include <optional>
#include <vector>

#include <gsl/span>

#include "DataFormatsITSMFT/ROFRecord.h"
#include "DetectorsBase/GRPGeomHelper.h"
#include "Framework/DataProcessorSpec.h"
#include "Framework/Task.h"
#include "ITSMFTTracking/Configuration.h"
#include "ITSCAWorkflow/ConfigPreflight.h"
#include "ITSCAWorkflow/PublicationAdapter.h"
#include "ITSMFTTracking/Tracker.h"
#include "ITSMFTTracking/TrackerTraits.h"
#include "ITSMFTTracking/WorkflowSession.h"
#include "ITSMFTTracking/IOUtils.h"
#include "ITSMFTTracking/ITSMFTDetectorDefinitions.h"
#include "ITSMFTTracking/ROFViews.h"
#include "ITSMFTTracking/ROFLookupTables.h"
#include "DataFormatsITSMFT/TopologyDictionary.h"
#include "SimulationDataFormat/MCCompLabel.h"

namespace o2::its::ca
{

using o2::itsmft::tracking::CATrackerPublicationAction;
using o2::itsmft::tracking::decideCATrackerPublicationAction;

/// ITS common-CA tracker DPL task. Owns the TimeFrame and composes the
/// workflow input/timing/publication edge with Tracker.
class CATrackerDPL : public o2::framework::Task
{
public:
CATrackerDPL(std::shared_ptr<o2::base::GRPGeomRequest> gr, WorkflowOptions options);
~CATrackerDPL() override = default;

void init(framework::InitContext& ic) final;
void run(framework::ProcessingContext& pc) final;
void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj) final;

private:
void updateTimeDependentParams(framework::ProcessingContext& pc);
void addTruthSeedingVertices(const o2::InteractionRecord& origin, gsl::span<const o2::itsmft::ROFRecord> rofs);
void configureROFViews(gsl::span<const o2::itsmft::ROFRecord> rofs);
void initialiseTracking();
o2::itsmft::tracking::TrackingOutcome processTimeFrame(
gsl::span<const o2::itsmft::ROFRecord> rofs,
gsl::span<const o2::itsmft::CompClusterExt> clusters,
gsl::span<const unsigned char> patterns,
const o2::dataformats::MCTruthContainer<MCCompLabel>* labels);
bool isActive() const noexcept { return mTracker != nullptr && mTracker->isConfiguredFor(mSession.frame); }

std::shared_ptr<o2::base::GRPGeomRequest> mGGCCDBRequest;
bool mUseMC = false;
bool mTrackingInitialised = false;
WorkflowOptions mOptions;
o2::itsmft::tracking::WorkflowSession mSession{"ITS", o2::itsmft::tracking::ITSNLayers};
std::unique_ptr<o2::itsmft::tracking::TrackerTraits> mTrackerTraits;
std::unique_ptr<o2::itsmft::tracking::Tracker> mTracker;
const o2::itsmft::TopologyDictionary* mDictionary = nullptr;
PublicationAdapter mPublication;
};

o2::framework::DataProcessorSpec getCATrackerSpec(const WorkflowOptions& options);

} // namespace o2::its::ca

#endif // O2_ITS_CA_WORKFLOW_CATRACKERSPEC_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
///
/// \file ConfigPreflight.h
/// \brief Driver-level configuration and vertex-constraint preflight for the
/// ITS common-CA tracker workflow.
///
/// Resolve driver options before constructing any DPL device.

#ifndef ALICEO2_ITS_CA_WORKFLOW_CONFIGPREFLIGHT_H_
#define ALICEO2_ITS_CA_WORKFLOW_CONFIGPREFLIGHT_H_

#include <string>

#include "ITSMFTTracking/Configuration.h"

namespace o2::framework
{
class ConfigContext;
}

namespace o2::its::ca
{

/// Rejects a raw --configKeyValues string carrying an ITSCATrackerParam.*
/// override before applying the accepted string to ConfigurableParam.
void applyConfigKeyValuesOrFatal(const std::string& configKeyValues);

/// Fatals unless mode is Sync or Async, naming the rejected mode explicitly,
/// before device construction.
void requireSupportedTrackingModeOrFatal(o2::itsmft::TrackingMode::Type mode);

enum class VertexSource { Diamond,
Truth };
struct WorkflowOptions {
bool useMC = true;
bool useFullGeometry = false;
bool writeRootOutput = true;
o2::itsmft::TrackingMode::Type mode = o2::itsmft::TrackingMode::Sync;
int nThreads = 1;
VertexSource vertexSource = VertexSource::Diamond;
std::string truthContext = "collisioncontext.root";
};

// An empty explicit source requires exactly one legacy alias. No physics
// constraint is enabled by default, and MC output labels are independent.
VertexSource resolveVertexSource(const std::string& explicitSource, bool useDiamond, bool useTruth);
WorkflowOptions readWorkflowOptions(const o2::framework::ConfigContext&);

} // namespace o2::its::ca

#endif // ALICEO2_ITS_CA_WORKFLOW_CONFIGPREFLIGHT_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#ifndef ALICEO2_ITS_CA_PUBLICATIONADAPTER_H_
#define ALICEO2_ITS_CA_PUBLICATIONADAPTER_H_

#ifndef GPUCA_GPUCODE

#include <algorithm>
#include <cstdint>
#include <cmath>
#include <limits>
#include <optional>
#include <vector>
#include <gsl/span>

#include "DetectorsCommonDataFormats/DetID.h"
#include "GPUCommonMath.h"
#include "ITSMFTTracking/GenericTrack.h"
#include "ITSMFTTracking/TimeFrame.h"
#include "ITSMFTTracking/MathUtils.h"

namespace o2::its::ca
{

// Workflow-owned shared-cluster flags indexed by the global GenericTrack index.
class PublicationAdapter
{
public:
gsl::span<const uint8_t> sharedClusterFlags() const noexcept
{
return mComplete ? gsl::span<const uint8_t>{mSharedClusterFlags} : gsl::span<const uint8_t>{};
}

bool completeAccepted(gsl::span<const uint32_t> trackIndices,
const o2::itsmft::IterationParameters& params,
const o2::itsmft::tracking::TimeFrame& frame,
bool final)
{
mComplete = false;
if (!stageSharedClusterFlags(trackIndices, params, frame)) {
return false;
}
mComplete = final;
return true;
}

void reset() noexcept
{
mSharedClusterFlags.clear();
mComplete = false;
}

class Cleanup
{
public:
explicit Cleanup(PublicationAdapter& adapter) : mAdapter(adapter) { mAdapter.reset(); }
Cleanup(const Cleanup&) = delete;
Cleanup& operator=(const Cleanup&) = delete;
~Cleanup() noexcept { mAdapter.reset(); }

private:
PublicationAdapter& mAdapter;
};
Cleanup cleanupOnExit() { return Cleanup{*this}; }

private:
struct SharedClusterTrackInfo {
int layer{-1};
uint32_t clusterId{std::numeric_limits<uint32_t>::max()};
int rof{-1};
float phi{0.f};
float eta{0.f};
int charge{0};
};

static std::optional<SharedClusterTrackInfo> makeSharedClusterTrackInfo(const o2::itsmft::tracking::GenericTrack& track,
const o2::itsmft::tracking::TimeFrame& frame)
{
const int layer = track.hitLayers.first();
const auto& references = frame.getTrackClusterIndices();
if (layer < 0 || !isValidTrackRange(track, static_cast<uint32_t>(references.size())) ||
track.firstClusterRef == track.clusterRefEnd ||
static_cast<std::size_t>(layer) >= frame.getLayout().size()) {
return std::nullopt;
}
const auto& reference = references[track.firstClusterRef];
if (reference.layer != o2::itsmft::tracking::LayerId{static_cast<uint16_t>(layer)} || !reference.isValid()) {
return std::nullopt;
}
const auto& state = track.innerState;
if (!state.hasRecognizedKind() || !o2::gpu::GPUCommonMath::Finite(state.parameters[3]) ||
!o2::gpu::GPUCommonMath::Finite(state.parameters[4])) {
return std::nullopt;
}
const float phi = state.kind == o2::itsmft::tracking::SurfaceKind::Cylinder ? std::asin(state.parameters[2]) + state.alpha : state.parameters[2];
const float eta = std::asinh(state.parameters[3]);
if (!o2::gpu::GPUCommonMath::Finite(phi) || !o2::gpu::GPUCommonMath::Finite(eta)) {
return std::nullopt;
}
return SharedClusterTrackInfo{layer, reference.clusterId, frame.getClusterROF(layer, static_cast<int>(reference.clusterId)),
phi, eta, state.parameters[4] < 0.f ? -1 : 1};
}

bool stageSharedClusterFlags(gsl::span<const uint32_t> trackIndices,
const o2::itsmft::IterationParameters& params,
const o2::itsmft::tracking::TimeFrame& frame)
{
auto nextIndex = mSharedClusterFlags.size();
for (const auto index : trackIndices) {
if (index >= frame.getGenericTracks().size() || index < nextIndex) {
return false;
}
nextIndex = static_cast<std::size_t>(index) + 1;
}
// Gaps belong to tracks not accepted by this adapter, and must not be
// mistaken for accepted tracks without shared clusters at publication.
mSharedClusterFlags.resize(nextIndex, std::numeric_limits<uint8_t>::max());
for (const auto index : trackIndices) {
mSharedClusterFlags[index] = 0;
}
if (!params.AllowSharingFirstCluster) {
return true;
}
std::vector<SharedClusterTrackInfo> trackInfo;
trackInfo.reserve(trackIndices.size());
for (const auto index : trackIndices) {
const auto info = makeSharedClusterTrackInfo(frame.getGenericTracks()[index], frame);
if (!info) {
return false;
}
trackInfo.push_back(*info);
}
for (size_t first = 0; first < trackInfo.size(); ++first) {
for (size_t second = first + 1; second < trackInfo.size(); ++second) {
if (trackInfo[second].layer != trackInfo[first].layer || trackInfo[second].clusterId != trackInfo[first].clusterId) {
continue;
}
if (trackInfo[first].rof != trackInfo[second].rof) {
continue;
}
if (!o2::its::math_utils::isPhiDifferenceBelow(trackInfo[first].phi, trackInfo[second].phi, params.SharedClusterMaxDeltaPhi)) {
continue;
}
if (std::abs(trackInfo[first].eta - trackInfo[second].eta) > params.SharedClusterMaxDeltaEta) {
continue;
}
if (params.SharedClusterOppositeSign && trackInfo[first].charge == trackInfo[second].charge) {
continue;
}
mSharedClusterFlags[trackIndices[first]] = 1;
mSharedClusterFlags[trackIndices[second]] = 1;
}
}
return true;
}

std::vector<uint8_t> mSharedClusterFlags;
bool mComplete = false;
};

} // namespace o2::its::ca

#endif // !GPUCA_GPUCODE

#endif // ALICEO2_ITS_CA_PUBLICATIONADAPTER_H_
Loading