Skip to content

Commit 8bcb66f

Browse files
committed
Preserve DPL orbit in CMV TFs when FLP orbit is missing
1 parent b05ee5d commit 8bcb66f

4 files changed

Lines changed: 30 additions & 27 deletions

File tree

Detectors/TPC/calibration/include/TPCCalibration/CMVContainer.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ struct CMVEncoding {
5858
/// kZigzag + kVarint → varint(zigzag(signed(raw)))
5959
/// kZigzag + kHuffman → [Huffman table] + [bitstream] of zigzag(signed(raw))
6060
struct CMVPerTFCompressed {
61-
uint32_t firstOrbit{0}; ///< First orbit of this TF
62-
uint16_t firstBC{0}; ///< First bunch crossing of this TF
63-
uint8_t mFlags{0}; ///< Bitmask of CMVEncoding values
61+
uint32_t firstOrbit{0}; ///< First orbit of this TF
62+
uint32_t firstOrbitDPL{0}; ///< First orbit of this TF
63+
uint8_t mFlags{0}; ///< Bitmask of CMVEncoding values
6464

6565
std::vector<uint8_t> mData; ///< Encoded payload
6666

@@ -88,14 +88,14 @@ struct CMVPerTFCompressed {
8888
static void decodeDenseValues(const std::vector<uint32_t>& symbols, uint8_t flags, CMVPerTF* cmv);
8989

9090
public:
91-
ClassDefNV(CMVPerTFCompressed, 1)
91+
ClassDefNV(CMVPerTFCompressed, 2)
9292
};
9393

9494
/// CMV data for one TF across all CRUs
9595
/// Raw 16-bit CMV values are stored in a flat C array indexed as [cru * NTimeBinsPerTF + timeBin]
9696
struct CMVPerTF {
97-
uint32_t firstOrbit{0}; ///< First orbit of this TF, from heartbeatOrbit of the first CMV packet
98-
uint16_t firstBC{0}; ///< First bunch crossing of this TF, from heartbeatBC of the first CMV packet
97+
uint32_t firstOrbit{0}; ///< First orbit of this TF, from heartbeatOrbit of the first CMV packet
98+
uint32_t firstOrbitDPL{0}; ///< First orbit of this TF, from DPL
9999

100100
// Raw 16-bit CMV values, flat array indexed as [cru * NTimeBinsPerTF + timeBin]
101101
uint16_t mDataPerTF[CRU::MaxCRU * cmv::NTimeBinsPerTF]{};
@@ -133,7 +133,7 @@ struct CMVPerTF {
133133
static void encodeVarintInto(uint32_t value, std::vector<uint8_t>& out); ///< Varint encode
134134

135135
public:
136-
ClassDefNV(CMVPerTF, 1)
136+
ClassDefNV(CMVPerTF, 2)
137137
};
138138

139139
} // namespace o2::tpc

Detectors/TPC/calibration/macro/drawCMV.C

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ using namespace o2::tpc;
3232
/// \param filename input ROOT file containing the ccdb_object TTree
3333
/// \param outDir output directory for saved plots; nothing is saved if empty
3434
/// \return array of canvases
35-
TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
35+
TObjArray* drawCMV(std::string_view filename, std::string_view outDir, std::string_view rootFileName = "CMVCanvases.root")
3636
{
3737
TObjArray* arrCanvases = new TObjArray;
3838
arrCanvases->SetName("CMV");
@@ -82,7 +82,7 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
8282
110, -100.5, 9.5);
8383
h2d->SetStats(1);
8484
TH1F* h1d = new TH1F("hCMV", ";Common Mode Values (ADC);Counts",
85-
1100, -100.5, 9.5);
85+
110, -100.5, 9.5);
8686
h1d->SetStats(1);
8787

8888
// auto-detect branch format: compressed or raw
@@ -105,6 +105,7 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
105105
}
106106

107107
long firstOrbit = -1;
108+
long firstOrbitDPL = -1;
108109

109110
for (int i = 0; i < nEntries; ++i) {
110111
tree->GetEntry(i);
@@ -118,16 +119,15 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
118119
tf = tfRaw;
119120
}
120121

121-
if (i == 0) {
122-
firstOrbit = tf->firstOrbit;
123-
}
122+
firstOrbit = tf->firstOrbit;
123+
firstOrbitDPL = tf->firstOrbitDPL;
124+
fmt::print("firstOrbit: {}, firstOrbitDPL: {}\n", firstOrbit, firstOrbitDPL);
124125

125126
for (int cru = 0; cru < nCRUs; ++cru) {
126127
for (int tb = 0; tb < nTimeBins; ++tb) {
127128
const float cmvValue = tf->getCMVFloat(cru, tb);
128129
h2d->Fill(tb, cmvValue);
129130
h1d->Fill(cmvValue);
130-
// fmt::print("cru: {}, tb: {}, cmv: {}\n", cru, tb, cmvValue);
131131
}
132132
}
133133
}
@@ -136,8 +136,6 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
136136
tree->ResetBranchAddresses();
137137
delete tfCompressed;
138138

139-
fmt::print("firstOrbit: {}\n", firstOrbit);
140-
141139
// draw
142140
auto* c = new TCanvas("cCMVvsTimeBin", "");
143141
c->SetLogz();
@@ -152,7 +150,7 @@ TObjArray* drawCMV(std::string_view filename, std::string_view outDir)
152150
arrCanvases->Add(c1);
153151

154152
if (outDir.size()) {
155-
utils::saveCanvases(*arrCanvases, outDir, "png,pdf", "CMVCanvases.root");
153+
utils::saveCanvases(*arrCanvases, outDir, "", rootFileName);
156154
}
157155

158156
f.Close();

Detectors/TPC/calibration/src/CMVContainer.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ CMVPerTFCompressed CMVPerTF::compress(uint8_t flags) const
447447
{
448448
CMVPerTFCompressed out;
449449
out.firstOrbit = firstOrbit;
450-
out.firstBC = firstBC;
450+
out.firstOrbitDPL = firstOrbitDPL;
451451
out.mFlags = flags;
452452

453453
if (flags & CMVEncoding::kSparse) {
@@ -670,7 +670,7 @@ void CMVPerTFCompressed::decompress(CMVPerTF* cmv) const
670670
throw std::invalid_argument("CMVPerTFCompressed::decompress: cmv pointer is null");
671671
}
672672
cmv->firstOrbit = firstOrbit;
673-
cmv->firstBC = firstBC;
673+
cmv->firstOrbitDPL = firstOrbitDPL;
674674
std::fill(std::begin(cmv->mDataPerTF), std::end(cmv->mDataPerTF), uint16_t(0));
675675

676676
const uint8_t* ptr = mData.data();

Detectors/TPC/workflow/include/TPCWorkflow/TPCAggregateCMVSpec.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class TPCAggregateCMVDevice : public o2::framework::Task
211211
// independent of the GRPECS/config nHBFPerTF value.
212212
const auto batchLastOrbit = static_cast<uint32_t>(pc.services().get<o2::framework::TimingInfo>().firstTForbit);
213213
const auto defaultOrbitStep = static_cast<uint32_t>(o2::base::GRPGeomHelper::instance().getNHBFPerTF());
214-
mOrbitStep[relTF] = (mNTFsBuffer > 1 && batchLastOrbit > batchFirstOrbit) ? (batchLastOrbit - batchFirstOrbit) / static_cast<uint32_t>(mNTFsBuffer - 1) : defaultOrbitStep;
214+
mOrbitStep[relTF] = ((batchFirstOrbit > 0) && (mNTFsBuffer > 1) && (batchLastOrbit > batchFirstOrbit)) ? (batchLastOrbit - batchFirstOrbit) / static_cast<uint32_t>(mNTFsBuffer - 1) : defaultOrbitStep;
215215
mLastOrbitStep = mOrbitStep[relTF];
216216
mOrbitInfoSeen[relTF] = true;
217217
break;
@@ -307,6 +307,7 @@ class TPCAggregateCMVDevice : public o2::framework::Task
307307
uint64_t mRun{0}; ///< run number, captured once per run
308308
uint32_t mIntervalFirstOrbit{0}; ///< first orbit of the first TF in the current interval
309309
uint32_t mIntervalLastOrbit{0}; ///< first orbit of the last TF in the current interval
310+
uint32_t mFirstOrbitDPL{0}; ///< first orbit of the first TF in the current interval
310311
bool mIntervalOrbitSet{false}; ///< true once first orbit has been captured for the current interval
311312
dataformats::Pair<long, int> mTFInfo{}; ///< orbit-reset time (ms) and NHBFPerTF forwarded by distribute lane 0 for precise timestamps
312313
std::shared_ptr<o2::base::GRPGeomRequest> mCCDBRequest; ///< GRPECS request so GRPGeomHelper::getNHBFPerTF() is valid in this process
@@ -396,8 +397,9 @@ class TPCAggregateCMVDevice : public o2::framework::Task
396397
// prefer the measured stride; fall back to NHBFPerTF from GRPECS
397398
const int nHBFPerTF = (orbitStep > 0) ? static_cast<int>(orbitStep) : o2::base::GRPGeomHelper::instance().getNHBFPerTF();
398399
const auto nOrbitsOffset = (relTF * mNTFsBuffer + (mNTFsBuffer - 1)) * nHBFPerTF;
400+
mFirstOrbitDPL = tinfo.firstTForbit - nOrbitsOffset;
399401
mTimestampStart = mUsePreciseTimestamp ? (mTFInfo.first + (tinfo.firstTForbit - nOrbitsOffset) * o2::constants::lhc::LHCOrbitMUS * 0.001) : tinfo.creation;
400-
LOGP(detail, "Setting time stamp reset reference to: {}, at tfCounter: {}, firstTForbit: {}, NHBFPerTF: {}, relTF: {}, nOrbitsOffset: {}",
402+
LOGP(info, "Setting timestamp reset reference to: {}, at tfCounter: {}, firstTForbit: {}, NHBFPerTF: {}, relTF: {}, nOrbitsOffset: {}",
401403
mTFInfo.first, tinfo.tfCounter, tinfo.firstTForbit, nHBFPerTF, relTF, nOrbitsOffset);
402404
}
403405

@@ -480,11 +482,13 @@ class TPCAggregateCMVDevice : public o2::framework::Task
480482

481483
const auto firstOrbit = static_cast<uint32_t>(orbitInfo >> 32);
482484
const auto firstBC = static_cast<uint16_t>(orbitInfo & 0xFFFFu);
485+
// Use the DPL-derived orbit as fallback when the FLP orbit info is missing (firstOrbit == 0)
486+
const auto batchFirstOrbitDPL = (firstOrbit > 0) ? firstOrbit : mFirstOrbitDPL;
483487
if (!mIntervalOrbitSet) {
484-
mIntervalFirstOrbit = firstOrbit;
488+
mIntervalFirstOrbit = batchFirstOrbitDPL;
485489
mIntervalOrbitSet = true;
486490
}
487-
mIntervalLastOrbit = firstOrbit + static_cast<uint32_t>(nTFsInBatch - 1) * orbitStep;
491+
mIntervalLastOrbit = batchFirstOrbitDPL + static_cast<uint32_t>(nTFsInBatch - 1) * orbitStep;
488492
const uint8_t flags = buildCompressionFlags();
489493
std::vector<PreparedTF> prepared(nTFsInBatch);
490494
const int nThreads = std::max(1, std::min(mThreads, nTFsInBatch));
@@ -497,7 +501,7 @@ class TPCAggregateCMVDevice : public o2::framework::Task
497501

498502
auto& preparedTF = prepared[tfIndex];
499503
preparedTF.tf.firstOrbit = firstOrbit + static_cast<uint32_t>(tfIndex) * orbitStep;
500-
preparedTF.tf.firstBC = (tfIndex == 0) ? firstBC : 0;
504+
preparedTF.tf.firstOrbitDPL = batchFirstOrbitDPL + static_cast<uint32_t>(tfIndex) * orbitStep;
501505

502506
for (const auto& [cru, values] : rawCMVs) {
503507
const uint32_t offset = static_cast<uint32_t>(tfIndex) * cmv::NTimeBinsPerTF;
@@ -558,7 +562,7 @@ class TPCAggregateCMVDevice : public o2::framework::Task
558562
mIntervalTree->GetUserInfo()->Add(new TParameter<long>("firstTF", mIntervalFirstTF));
559563
mIntervalTree->GetUserInfo()->Add(new TParameter<long>("lastTF", lastTF));
560564

561-
LOGP(detail, "CMVPerTF TTree lane {}: {} entries, firstTF={}, lastTF={}", mLaneId, mIntervalTFCount, mIntervalFirstTF, lastTF);
565+
LOGP(info, "CMVPerTF TTree lane {}: {} entries, firstTF={}, lastTF={}", mLaneId, mIntervalTFCount, mIntervalFirstTF, lastTF);
562566
auto start = timer::now();
563567

564568
const int nHBFPerTF = o2::base::GRPGeomHelper::instance().getNHBFPerTF();
@@ -569,7 +573,7 @@ class TPCAggregateCMVDevice : public o2::framework::Task
569573
mRun, mIntervalFirstOrbit, mIntervalLastOrbit, mTimestampStart, timeStampEnd);
570574
try {
571575
CMVPerTF::writeToFile(mOutputDir + calibFName, mIntervalTree);
572-
LOGP(detail, "CMV file written to {}", mOutputDir + calibFName);
576+
LOGP(info, "CMV file written to {}", mOutputDir + calibFName);
573577
} catch (const std::exception& e) {
574578
LOGP(error, "Failed to write CMV file {}: {}", mOutputDir + calibFName, e.what());
575579
}
@@ -614,13 +618,13 @@ class TPCAggregateCMVDevice : public o2::framework::Task
614618
mf.Close();
615619
}
616620

617-
LOGP(detail, "Sending object {} / {} of size {} bytes, valid for {} : {}", ccdbInfoCMV.getPath(), ccdbInfoCMV.getFileName(), image->size(), ccdbInfoCMV.getStartValidityTimestamp(), ccdbInfoCMV.getEndValidityTimestamp());
621+
LOGP(info, "Sending object {} / {} of size {} bytes, valid for {} : {}", ccdbInfoCMV.getPath(), ccdbInfoCMV.getFileName(), image->size(), ccdbInfoCMV.getStartValidityTimestamp(), ccdbInfoCMV.getEndValidityTimestamp());
618622
output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, getDataDescriptionCCDBCMV(), 0}, *image);
619623
output.snapshot(Output{o2::calibration::Utils::gDataOriginCDBWrapper, getDataDescriptionCCDBCMV(), 0}, ccdbInfoCMV);
620624

621625
auto stop = timer::now();
622626
std::chrono::duration<float> elapsed = stop - start;
623-
LOGP(detail, "CMV CCDB serialisation time: {:.3f} s", elapsed.count());
627+
LOGP(info, "CMV CCDB serialisation time: {:.3f} s", elapsed.count());
624628
}
625629

626630
/// Reset all per-interval state after a successful sendOutput(); prepares for the next interval
@@ -652,6 +656,7 @@ class TPCAggregateCMVDevice : public o2::framework::Task
652656
mIntervalTFCount = 0;
653657
mIntervalFirstOrbit = 0;
654658
mIntervalLastOrbit = 0;
659+
mFirstOrbitDPL = 0;
655660
mIntervalOrbitSet = false;
656661
mCurrentTF = CMVPerTF{};
657662
mCurrentCompressedTF = CMVPerTFCompressed{};

0 commit comments

Comments
 (0)