Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions .claude/commands/migrate-ccdb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
Migrate the specified file (or all files mentioned in the conversation) from `Service<o2::ccdb::BasicCCDBManager>` to the declarative CCDB table approach.

## Background

The old approach uses `Service<o2::ccdb::BasicCCDBManager>` and calls `ccdb->getForTimeStamp<T>(path, timestamp)` at runtime. The new approach declares CCDB columns and timestamped tables using macros, so the framework fetches objects automatically and exposes them as columns on BC rows.

**New API summary:**

```cpp
// In namespace o2::aod (or a sub-namespace):
DECLARE_SOA_CCDB_COLUMN(StructName, getterName, ConcreteType, "CCDB/Object/Path");

DECLARE_SOA_TIMESTAMPED_TABLE(TableName, aod::Timestamps, o2::aod::timestamp::Timestamp, 1, "TABLEDESC",
ns::StructName, ns::OtherColumn);

// In the task — basic usage:
using MyBCs = soa::Join<aod::BCsWithTimestamps, aod::TableName>;
void process(MyBCs const& bcs) {
for (auto const& bc : bcs) {
auto const& obj = bc.getterName(); // reference to cached deserialized object; treat as immutable
}
}
```

**Configurable CCDB paths** (`ConfigurableCCDBPath<Column>`):

If the original task used a `Configurable<std::string>` to supply the CCDB path, the path can remain user-overridable after migration using `ConfigurableCCDBPath<Column>`. This is a typed `Configurable<std::string>` whose option name is automatically set to `"ccdb:" + Column::mLabel` (where `mLabel = "f" + StructName`), defaulting to the compile-time path in the column declaration. The framework reads this option name when resolving CCDB URLs, so users can still redirect the path via JSON config.

The Configurable is purely declarative for the path-override mechanism: declaring it is sufficient — you do **not** pass `.value` to a getter or fetcher. The accessor remains `bc.getterName()`. The `.value` member is still available if the task wants to log the resolved path.

```cpp
struct MyTask {
// Replaces: Configurable<std::string> grpmagPath{"grpmagPath", "GLO/Config/GRPMagField", "..."};
ConfigurableCCDBPath<ns::GRPMagField> grpMagFieldPath; // option name = "ccdb:fGRPMagField"

void process(MyBCs const& bcs) {
auto const& grpmag = bcs.iteratorAt(0).grpMagField(); // path override is honoured automatically
LOGP(info, "Using GRPMagField path: {}", grpMagFieldPath.value);
}
};
```

Required headers (add if missing): `<Framework/ASoA.h>`, `<Framework/AnalysisDataModel.h>`, `<Framework/Configurable.h>`
Headers to remove (if no longer needed): `<CCDB/BasicCCDBManager.h>`

## What to do

Read the target file(s) and perform the following migration. Do NOT do a complete migration if the patterns are ambiguous or out of scope — instead note what was skipped and why.

### Step 1 — Inventory

Find every `ccdb->getForTimeStamp<T>(path, ts)` call (and variants like `fCCDB->getForTimeStamp`, `mCcdb->getForTimeStamp`). For each call record:
- The concrete C++ type `T`
- The CCDB path string (may be a `Configurable` variable — record the default value and the Configurable's name)
- The timestamp source (BC timestamp, computed value, etc.)
- Where the result is used

**Deduplicate**: for the same (type, path) pair, declare only one CCDB column. Multiple call sites collapse into multiple uses of the same getter.

### Step 2 — Identify scope

Determine whether each fetch is:
- **Per-BC/per-collision** (called inside `process()` with a timestamp from a BC) — these can be migrated
- **Per-run** (called once when `runNumber` changes, guarded by `mRunNumber == ...`) — these can be migrated; the framework caches per unique timestamp automatically
- **Global/init-time** (called in `init()` with a fixed timestamp, not keyed to a BC) — these **cannot** be migrated to CCDB tables; leave them as-is and note this

Skip the migration for any global/init-time fetches. Skip the whole file if all fetches are global.

### Step 3 — Declare CCDB columns and table

In the `o2::aod` namespace (or a private sub-namespace inside the file, before the task struct), declare:

```cpp
namespace o2::aod
{
namespace myccdbtask // use a short, unique snake_case name derived from the task name
{
DECLARE_SOA_CCDB_COLUMN(StructName, getterName, fully::qualified::ConcreteType, "CCDB/Path"); //!
// one per unique (type, path) pair
} // namespace myccdbtask

DECLARE_SOA_TIMESTAMPED_TABLE(MyTaskCCDBObjects, aod::Timestamps, o2::aod::timestamp::Timestamp, 1, "MYTASKCCDB", //!
myccdbtask::StructName /*, ... */);
} // namespace o2::aod
```

Rules for naming:
- `StructName` / `getterName`: derive from the type name, e.g. `GRPMagField` / `grpMagField`, `MeanVertex` / `meanVertex`
- Table name: `<TaskStruct>CCDBObjects`, e.g. `SkimmerDalitzEECCDBObjects`
- `_Desc_` string: short ALL-CAPS string unique within the binary (≤ 16 chars to fit the AOD descriptor), e.g. `"DALZECC"`, `"TOFCALIB"`
- Namespace: lowercase snake-case derived from the task name (avoid collisions with other CCDB column namespaces in the file)
- Use the **default value** of any `Configurable` path as the compile-time path in the `DECLARE_SOA_CCDB_COLUMN` macro; if the path has no obvious default, leave a `// TODO: verify path` comment

### Step 4 — Update the task struct

1. **Remove** `Service<o2::ccdb::BasicCCDBManager> ccdb;` (and any variant field name)
2. **Remove** `int mRunNumber;` (or similar run-caching variables) **only if** their sole purpose was to guard CCDB re-fetches
3. **Remove** `ccdb->setURL(...)`, `ccdb->setCaching(...)`, `ccdb->setLocalObjectValidityChecking()`, `ccdb->setCreatedNotAfter(...)`, `ccdb->setFatalWhenNull(...)` from `init()`
4. **Remove** the entire `initCCDB()`/`initMagField()` helper method if it only did CCDB fetching; otherwise remove just the CCDB lines from it
5. **Handle path Configurables** — for each `Configurable<std::string>` that held a CCDB path:
- If the path was used as the sole argument to `getForTimeStamp` and the user may want to override it at runtime: **replace** it with `ConfigurableCCDBPath<ns::ColumnName>` (e.g. `ConfigurableCCDBPath<ns::GRPMagField> grpMagFieldPath;`). The member name should match the getter for clarity. Keep a comment explaining what path it controls.
- If the path was never intended to be user-facing (e.g. internal fixed paths): **remove** it outright; the compile-time path in `DECLARE_SOA_CCDB_COLUMN` is sufficient.
- Always remove Configurables that were only used for CCDB manager setup and not for paths: `ccdb-url`, `ccdb-no-later-than`, `skipGRPOquery`, `d_bz_input` (if only used to bypass CCDB), etc.
6. **Remove** cached pointer member variables (e.g. `GRPMagField* grpmag = nullptr`) if they were only populated by CCDB fetches that are now replaced

### Step 5 — Update process() signatures

Define one alias near the top of the task or just below the table declaration:
```cpp
using MyBCs = soa::Join<aod::BCsWithTimestamps, aod::MyTaskCCDBObjects>;
```

Then for each `process()` that used to call `getForTimeStamp`:

- If `process()` already takes `aod::BCsWithTimestamps const&` directly: change it to `MyBCs const&`.
- If `process()` accesses BCs via `collision.bc_as<aod::BCsWithTimestamps>()`: add `MyBCs const&` to the process signature (so the framework knows to provide it) and replace the `bc_as<>` type with `MyBCs`.
- If `process()` does not currently mention BCs but called `ccdb->getForTimeStamp(path, collision.bc_as<...>().timestamp())`: add `MyBCs const&` to the signature and obtain the BC via `collision.bc_as<MyBCs>()`.
- Replace every `ccdb->getForTimeStamp<T>(path, ts)` call with `bc.getterName()`. The returned reference is to a cached deserialized object; treat it as immutable.
- Null-pointer checks (`if (!grpmag)`) on the result become unnecessary — the framework guarantees the object is present (or the task fails early). Remove them.
- If a helper template like `initCCDB(collision)` was called per-collision, inline its remaining (non-CCDB) work or drop it.

### Step 6 — Fix includes

- Remove `#include <CCDB/BasicCCDBManager.h>` if no other code in the file still uses `BasicCCDBManager`
- Ensure `#include <Framework/ASoA.h>` is present (may already be included transitively)
- Keep all type headers (e.g. `<DataFormatsParameters/GRPMagField.h>`) since they are still needed for the concrete type

### Step 7 — Final review

After making changes:
- Check that every remaining use of `ccdb` / `fCCDB` / `mCcdb` has been handled
- Check that `mRunNumber` (or similar) is fully removed if unused
- Check that any leftover `Configurable<std::string>` for a path is either replaced by `ConfigurableCCDBPath<>` or removed
- Search for stale references to removed Configurables (e.g. `grpmagPath.value` lingering in log messages — switch to `grpMagFieldPath.value`)
- If `init()` is now empty, it can be removed
- Note any patterns that were intentionally skipped

## Important limitations — tell the user if any apply

- **Configurable paths**: CCDB column paths are compile-time constants in the macro. Add `ConfigurableCCDBPath<Column>` to allow runtime override; its default is `Column::query` so it always agrees with the macro by construction.
- **`getRunDuration()` calls**: these use `BasicCCDBManager` statically and are unrelated to per-BC fetching — do not touch them.
- **`ctpRateFetcher` / other helpers**: out of scope.
- **Multiple tasks in one file**: tasks can share a single CCDB table declaration if they need the same objects; otherwise each task gets its own with a unique `_Desc_`.
- **Non-BC timestamps**: if the timestamp comes from something other than a BC (e.g. computed manually), the migration is non-trivial — flag it instead of forcing it.
- **Global/init-time fetches** (e.g. `efficiencyGlobal.cxx` style): not migratable — the timestamped-table mechanism requires a row in a BC-keyed table.
- **Magnetic-field side effects**: tasks that compute `d_bz` from a fetched `GRPMagField` and seed a propagator can keep that logic, just sourcing the object from `bc.grpMagField()` instead of `ccdb->getForTimeStamp(...)`.

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

/// \file GloCCDBObjects.h
/// \brief Declarative CCDB columns for the most-commonly needed GLO/ objects.
///
/// Provides a single shared timestamped table (`aod::GloCCDBObjects`) that
/// tasks can join with `aod::BCsWithTimestamps` to obtain the four GLO/
/// calibration objects without using `Service<BasicCCDBManager>`.
///
/// Usage:
/// \code
/// #include "Common/DataModel/GloCCDBObjects.h"
/// // ...
/// using BCsWithCCDB = soa::Join<aod::BCsWithTimestamps, aod::GloCCDBObjects>;
/// void process(BCsWithCCDB const& bcs) {
/// const auto& grpmag = bcs.begin().grpMagField();
/// const auto& meanvtx = bcs.begin().meanVertex();
/// const auto& grpecs = bcs.begin().grpECS();
/// const auto& grplhcif= bcs.begin().grpLHCIF();
/// }
/// \endcode
///
/// If you need only a subset of the four objects, declare your own
/// `DECLARE_SOA_TIMESTAMPED_TABLE` with the relevant subset of columns from
/// the `o2::aod::ccdbGlo` namespace rather than joining `aod::GloCCDBObjects`.
///
/// Note: MatLayerCylSet is intentionally omitted — it requires
/// `MatLayerCylSet::rectifyPtrFromFile()` after deserialisation, which the
/// CCDB column mechanism does not perform.

#ifndef COMMON_DATAMODEL_GLOCCDBOBJECTS_H_
#define COMMON_DATAMODEL_GLOCCDBOBJECTS_H_

#include <DataFormatsCalibration/MeanVertexObject.h>
#include <DataFormatsParameters/GRPECSObject.h>
#include <DataFormatsParameters/GRPLHCIFData.h>
#include <DataFormatsParameters/GRPMagField.h>
#include <Framework/ASoA.h>
#include <Framework/AnalysisDataModel.h>

namespace o2::aod
{
namespace ccdbGlo
{
DECLARE_SOA_CCDB_COLUMN(GRPMagField, grpMagField, o2::parameters::GRPMagField, "GLO/Config/GRPMagField"); //!

Check failure on line 54 in Common/DataModel/GloCCDBObjects.h

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-column]

Use UpperCamelCase for names of O2 columns and matching lowerCamelCase names for their getters.
DECLARE_SOA_CCDB_COLUMN(MeanVertex, meanVertex, o2::dataformats::MeanVertexObject, "GLO/Calib/MeanVertex"); //!
DECLARE_SOA_CCDB_COLUMN(GRPECSObject, grpECS, o2::parameters::GRPECSObject, "GLO/Config/GRPECS"); //!

Check failure on line 56 in Common/DataModel/GloCCDBObjects.h

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-column]

Use UpperCamelCase for names of O2 columns and matching lowerCamelCase names for their getters.
DECLARE_SOA_CCDB_COLUMN(GRPLHCIFData, grpLHCIF, o2::parameters::GRPLHCIFData, "GLO/Config/GRPLHCIF"); //!

Check failure on line 57 in Common/DataModel/GloCCDBObjects.h

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-column]

Use UpperCamelCase for names of O2 columns and matching lowerCamelCase names for their getters.
} // namespace ccdbGlo

/// Full table — join with aod::BCsWithTimestamps to obtain all four objects.
DECLARE_SOA_TIMESTAMPED_TABLE(GloCCDBObjects, aod::Timestamps, o2::aod::timestamp::Timestamp, 1, "GLOCCDBOBJ", //!
ccdbGlo::GRPMagField, ccdbGlo::MeanVertex, ccdbGlo::GRPECSObject, ccdbGlo::GRPLHCIFData);
} // namespace o2::aod

#endif // COMMON_DATAMODEL_GLOCCDBOBJECTS_H_
6 changes: 6 additions & 0 deletions Common/TableProducer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(multcenttable

Check failure on line 42 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name multcenttable does not match its file name multCentTable.cxx. (Matches multcenttable.cxx.)
SOURCES multCentTable.cxx
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
COMPONENT_NAME Analysis)
Expand Down Expand Up @@ -74,12 +74,18 @@
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
COMPONENT_NAME Analysis)


o2physics_add_dpl_workflow(propagationservice

Check failure on line 78 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name propagationservice does not match its file name propagationService.cxx. (Matches propagationservice.cxx.)
SOURCES propagationService.cxx
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(propagationservice-v2

Check failure on line 83 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name propagationservice-v2 does not match its file name propagationServiceV2.cxx. (Matches propagationserviceV2.cxx.)
SOURCES propagationServiceV2.cxx
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(propagationservice-run2

Check failure on line 88 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name propagationservice-run2 does not match its file name propagationServiceRun2.cxx. (Matches propagationserviceRun2.cxx.)
SOURCES propagationServiceRun2.cxx
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore O2::DCAFitter KFParticle::KFParticle O2Physics::TPCDriftManager
COMPONENT_NAME Analysis)
Expand All @@ -89,7 +95,7 @@
PUBLIC_LINK_LIBRARIES O2::DetectorsBase O2Physics::AnalysisCore
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(calo-clusters

Check failure on line 98 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name calo-clusters does not match its file name caloClusterProducer.cxx. (Matches caloClusters.cxx.)
SOURCES caloClusterProducer.cxx
PUBLIC_LINK_LIBRARIES O2::DataFormatsPHOS O2::PHOSBase O2::PHOSReconstruction O2Physics::DataModel
COMPONENT_NAME Analysis)
Expand All @@ -112,12 +118,12 @@
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(mccollisionextra

Check failure on line 121 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name mccollisionextra does not match its file name mcCollsExtra.cxx. (Matches mccollisionextra.cxx.)
SOURCES mcCollsExtra.cxx
PUBLIC_LINK_LIBRARIES O2Physics::AnalysisCore
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(qvector-table

Check failure on line 126 in Common/TableProducer/CMakeLists.txt

View workflow job for this annotation

GitHub Actions / O2 linter

[name/o2-workflow]

Workflow name qvector-table does not match its file name qVectorsTable.cxx. (Matches qvectorTable.cxx.)
SOURCES qVectorsTable.cxx
PUBLIC_LINK_LIBRARIES O2::Framework
O2Physics::AnalysisCore
Expand Down
Loading
Loading