Migrate the specified file (or all files mentioned in the conversation) from Service<o2::ccdb::BasicCCDBManager> to the declarative CCDB table approach.
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:
// 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.
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>
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.
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
Configurablevariable — 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.
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
runNumberchanges, guarded bymRunNumber == ...) — 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.
In the o2::aod namespace (or a private sub-namespace inside the file, before the task struct), declare:
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::aodRules 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
Configurablepath as the compile-time path in theDECLARE_SOA_CCDB_COLUMNmacro; if the path has no obvious default, leave a// TODO: verify pathcomment
- Remove
Service<o2::ccdb::BasicCCDBManager> ccdb;(and any variant field name) - Remove
int mRunNumber;(or similar run-caching variables) only if their sole purpose was to guard CCDB re-fetches - Remove
ccdb->setURL(...),ccdb->setCaching(...),ccdb->setLocalObjectValidityChecking(),ccdb->setCreatedNotAfter(...),ccdb->setFatalWhenNull(...)frominit() - Remove the entire
initCCDB()/initMagField()helper method if it only did CCDB fetching; otherwise remove just the CCDB lines from it - Handle path Configurables — for each
Configurable<std::string>that held a CCDB path:- If the path was used as the sole argument to
getForTimeStampand the user may want to override it at runtime: replace it withConfigurableCCDBPath<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_COLUMNis 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.
- If the path was used as the sole argument to
- Remove cached pointer member variables (e.g.
GRPMagField* grpmag = nullptr) if they were only populated by CCDB fetches that are now replaced
Define one alias near the top of the task or just below the table declaration:
using MyBCs = soa::Join<aod::BCsWithTimestamps, aod::MyTaskCCDBObjects>;Then for each process() that used to call getForTimeStamp:
- If
process()already takesaod::BCsWithTimestamps const&directly: change it toMyBCs const&. - If
process()accesses BCs viacollision.bc_as<aod::BCsWithTimestamps>(): addMyBCs const&to the process signature (so the framework knows to provide it) and replace thebc_as<>type withMyBCs. - If
process()does not currently mention BCs but calledccdb->getForTimeStamp(path, collision.bc_as<...>().timestamp()): addMyBCs const&to the signature and obtain the BC viacollision.bc_as<MyBCs>(). - Replace every
ccdb->getForTimeStamp<T>(path, ts)call withbc.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.
- Remove
#include <CCDB/BasicCCDBManager.h>if no other code in the file still usesBasicCCDBManager - 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
After making changes:
- Check that every remaining use of
ccdb/fCCDB/mCcdbhas 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 byConfigurableCCDBPath<>or removed - Search for stale references to removed Configurables (e.g.
grpmagPath.valuelingering in log messages — switch togrpMagFieldPath.value) - If
init()is now empty, it can be removed - Note any patterns that were intentionally skipped
- Configurable paths: CCDB column paths are compile-time constants in the macro. Add
ConfigurableCCDBPath<Column>to allow runtime override; its default isColumn::queryso it always agrees with the macro by construction. getRunDuration()calls: these useBasicCCDBManagerstatically 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.cxxstyle): not migratable — the timestamped-table mechanism requires a row in a BC-keyed table. - Magnetic-field side effects: tasks that compute
d_bzfrom a fetchedGRPMagFieldand seed a propagator can keep that logic, just sourcing the object frombc.grpMagField()instead ofccdb->getForTimeStamp(...).
$ARGUMENTS