Skip to content
Merged
8 changes: 8 additions & 0 deletions PWGUD/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,11 @@ o2physics_add_library(decayTree
o2physics_target_root_dictionary(decayTree
HEADERS decayTree.h
LINKDEF decayTreeLinkDef.h)

o2physics_add_library(FITCutParHolder
SOURCES FITCutParHolder.cxx
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore)

o2physics_target_root_dictionary(FITCutParHolder
HEADERS FITCutParHolder.h
LINKDEF FITCutParHolderLinkDef.h)
55 changes: 55 additions & 0 deletions PWGUD/Core/FITCutParHolder.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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.
//
// \FIT bit thresholds
// \author Sandor Lokos, sandor.lokos@cern.ch
// \since March 2026

#include "FITCutParHolder.h"

// setter
void FITCutParHolder::SetSaveFITbitsets(bool saveFITbitsets)
{
mSaveFITbitsets = saveFITbitsets;
}
void FITCutParHolder::SetThr1FV0A(float thr1_FV0A)
{
mThr1FV0A = thr1_FV0A;
}
void FITCutParHolder::SetThr1FT0A(float thr1_FT0A)
{
mThr1FT0A = thr1_FT0A;
}
void FITCutParHolder::SetThr1FT0C(float thr1_FT0C)
{
mThr1FT0C = thr1_FT0C;
}
void FITCutParHolder::SetThr2FV0A(float thr2_FV0A)
{
mThr2FV0A = thr2_FV0A;
}
void FITCutParHolder::SetThr2FT0A(float thr2_FT0A)
{
mThr2FT0A = thr2_FT0A;
}
void FITCutParHolder::SetThr2FT0C(float thr2_FT0C)
{
mThr2FT0C = thr2_FT0C;
}

// getter
bool FITCutParHolder::saveFITbitsets() const { return mSaveFITbitsets; }
float FITCutParHolder::thr1_FV0A() const { return mThr1FV0A; }
float FITCutParHolder::thr1_FT0A() const { return mThr1FT0A; }
float FITCutParHolder::thr1_FT0C() const { return mThr1FT0C; }
float FITCutParHolder::thr2_FV0A() const { return mThr2FV0A; }
float FITCutParHolder::thr2_FT0A() const { return mThr2FT0A; }
float FITCutParHolder::thr2_FT0C() const { return mThr2FT0C; }
75 changes: 75 additions & 0 deletions PWGUD/Core/FITCutParHolder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// 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.
//
// \FIT bit thresholds
// \author Sandor Lokos, sandor.lokos@cern.ch
// \since March 2026

#ifndef PWGUD_CORE_FITCUTPARHOLDER_H_
#define PWGUD_CORE_FITCUTPARHOLDER_H_

#include <Rtypes.h>

// object to hold customizable FIT bit thresholds
class FITCutParHolder
{
public:
// constructor
FITCutParHolder(bool saveFITbitsets = true,
float thr1_FV0A = 8.,
float thr1_FT0A = 8.,
float thr1_FT0C = 8.,
float thr2_FV0A = 20.,
float thr2_FT0A = 20.,
float thr2_FT0C = 20.)
: mSaveFITbitsets{saveFITbitsets},
mThr1FV0A{thr1_FV0A},
mThr1FT0A{thr1_FT0A},
mThr1FT0C{thr1_FT0C},
mThr2FV0A{thr2_FV0A},
mThr2FT0A{thr2_FT0A},
mThr2FT0C{thr2_FT0C}
{
}

// setters
void SetSaveFITbitsets(bool);
void SetThr1FV0A(float);
void SetThr1FT0A(float);
void SetThr1FT0C(float);
void SetThr2FV0A(float);
void SetThr2FT0A(float);
void SetThr2FT0C(float);

// getters
bool saveFITbitsets() const;
float thr1_FV0A() const;
float thr1_FT0A() const;
float thr1_FT0C() const;
float thr2_FV0A() const;
float thr2_FT0A() const;
float thr2_FT0C() const;

private:
bool mSaveFITbitsets;

float mThr1FV0A;
float mThr1FT0A;
float mThr1FT0C;

float mThr2FV0A;
float mThr2FT0A;
float mThr2FT0C;

ClassDefNV(FITCutParHolder, 1);
};

#endif // PWGUD_CORE_FITCUTPARHOLDER_H_
24 changes: 24 additions & 0 deletions PWGUD/Core/FITCutParHolderLinkDef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.
//
// \FIT bit thresholds
// \author Sandor Lokos, sandor.lokos@cern.ch
// \since March 2026

#ifndef PWGUD_CORE_FITCUTPARHOLDERLINKDEF_H_
#define PWGUD_CORE_FITCUTPARHOLDERLINKDEF_H_

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ class FITCutParHolder + ;

#endif // PWGUD_CORE_FITCUTPARHOLDERLINKDEF_H_
1 change: 1 addition & 0 deletions PWGUD/Core/SGCutParHolderLinkDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// 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 PWGUD_CORE_SGCUTPARHOLDERLINKDEF_H_
#define PWGUD_CORE_SGCUTPARHOLDERLINKDEF_H_

Expand Down
156 changes: 156 additions & 0 deletions PWGUD/Core/UDHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "PWGUD/Core/DGCutparHolder.h"
#include "PWGUD/Core/UPCHelpers.h"

#include "Common/Core/RecoDecay.h"
#include "Common/DataModel/EventSelection.h"
#include "Common/DataModel/TrackSelectionTables.h"

Expand All @@ -29,6 +30,7 @@

#include "TLorentzVector.h"

#include <algorithm>
#include <bitset>
#include <vector>

Expand Down Expand Up @@ -533,6 +535,160 @@ bool FITveto(T const& bc, DGCutparHolder const& diffCuts)
return false;
}

inline void setBit(uint64_t w[4], int bit, bool val)
{
if (!val) {
return;
}
const int word = bit >> 6;
const int offs = bit & 63;
w[word] |= (static_cast<uint64_t>(1) << offs);
}

template <typename TFT0, typename TFV0A>
inline void buildFT0FV0Words(TFT0 const& ft0, TFV0A const& fv0a,
uint64_t thr1[4], uint64_t thr2[4],
float thr1_FT0A = 25., float thr1_FT0C = 50., float thr1_FV0A = 50.,
float thr2_FT0A = 50., float thr2_FT0C = 100., float thr2_FV0A = 100.)
{
thr1[0] = thr1[1] = thr1[2] = thr1[3] = 0ull;
thr2[0] = thr2[1] = thr2[2] = thr2[3] = 0ull;

constexpr int kFT0AOffset = 0;
constexpr int kFT0COffset = 96;
constexpr int kFV0Offset = 208;

auto ampsA = ft0.amplitudeA();
const int nA = std::min<int>(ampsA.size(), 96);
for (int i = 0; i < nA; ++i) {
const auto a = ampsA[i];
setBit(thr1, kFT0AOffset + i, a >= thr1_FT0A);
setBit(thr2, kFT0AOffset + i, a >= thr2_FT0A);
}

auto ampsC = ft0.amplitudeC();
const int nC = std::min<int>(ampsC.size(), 112);
for (int i = 0; i < nC; ++i) {
const auto a = ampsC[i];
setBit(thr1, kFT0COffset + i, a >= thr1_FT0C);
setBit(thr2, kFT0COffset + i, a >= thr2_FT0C);
}

auto ampsV = fv0a.amplitude();
const int nV = std::min<int>(ampsV.size(), 48);
for (int i = 0; i < nV; ++i) {
const auto a = ampsV[i];
setBit(thr1, kFV0Offset + i, a >= thr1_FV0A);
setBit(thr2, kFV0Offset + i, a >= thr2_FV0A);
}
}

// -----------------------------------------------------------------------------
// return eta and phi of a given FIT channel based on the bitset
// Bit layout contract:
constexpr int kFT0Bits = 208; // FT0 total channels
constexpr int kFV0Bits = 48; // FV0A channels
constexpr int kTotalBits = 256; // 4*64

// FT0 side split
constexpr int kFT0AChannels = 96; // FT0A channels are [0..95]
constexpr int kFT0CChannels = 112; // FT0C channels are [96..207]
static_assert(kFT0AChannels + kFT0CChannels == kFT0Bits);

using Bits256 = std::array<uint64_t, 4>;

inline Bits256 makeBits256(uint64_t w0, uint64_t w1, uint64_t w2, uint64_t w3)
{
return {w0, w1, w2, w3};
}

inline bool testBit(Bits256 const& w, int bit)
{
if (bit < 0 || bit >= kTotalBits) {
return false;
}
return (w[bit >> 6] >> (bit & 63)) & 1ULL;
}

struct FitBitRef {
enum class Det : uint8_t { FT0,
FV0,
Unknown };
Det det = Det::Unknown;
int ch = -1; // FT0: 0..207, FV0: 0..47
bool isC = false; // only meaningful for FT0
};

inline FitBitRef decodeFitBit(int bit)
{
FitBitRef out;
if (bit >= 0 && bit < kFT0Bits) {
out.det = FitBitRef::Det::FT0;
out.ch = bit; // FT0 channel id
out.isC = (bit >= kFT0AChannels); // C side if in upper range
return out;
}
if (bit >= kFT0Bits && bit < kTotalBits) {
out.det = FitBitRef::Det::FV0;
out.ch = bit - kFT0Bits; // FV0A channel id 0..47
return out;
}
return out;
}

template <typename FT0DetT, typename OffsetsT>
inline double getPhiFT0_fromChannel(FT0DetT& ft0Det, int ft0Ch, OffsetsT const& offsetFT0, int i)
{
ft0Det.calculateChannelCenter();
auto chPos = ft0Det.getChannelCenter(ft0Ch);

const double x = chPos.X() + offsetFT0[i].getX();
const double y = chPos.Y() + offsetFT0[i].getY();

return RecoDecay::phi(x, y);
}

template <typename FT0DetT, typename OffsetsT>
inline double getEtaFT0_fromChannel(FT0DetT& ft0Det, int ft0Ch, OffsetsT const& offsetFT0, int i)
{
ft0Det.calculateChannelCenter();
auto chPos = ft0Det.getChannelCenter(ft0Ch);

double x = chPos.X() + offsetFT0[i].getX();
double y = chPos.Y() + offsetFT0[i].getY();
double z = chPos.Z() + offsetFT0[i].getZ();

// If this channel belongs to FT0C, flip z (matches your original intent)
const bool isC = (ft0Ch >= kFT0AChannels);
if (isC) {
z = -z;
}

const double r = std::sqrt(x * x + y * y);
const double theta = std::atan2(r, z);
return -std::log(std::tan(0.5 * theta));
}

template <typename FT0DetT, typename OffsetsT>
inline bool getPhiEtaFromFitBit(FT0DetT& ft0Det,
int bit,
OffsetsT const& offsetFT0,
int iRunOffset,
double& phi,
double& eta)
{
auto ref = decodeFitBit(bit);
if (ref.det != FitBitRef::Det::FT0) {
return false;
}

// FT0A: 0..95, FT0C: 96..207
const int ft0Ch = bit;
phi = getPhiFT0_fromChannel(ft0Det, ft0Ch, offsetFT0, iRunOffset);
eta = getEtaFT0_fromChannel(ft0Det, ft0Ch, offsetFT0, iRunOffset);
return true;
}

// -----------------------------------------------------------------------------

template <typename T>
Expand Down
25 changes: 25 additions & 0 deletions PWGUD/DataModel/UDTables.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,31 @@ DECLARE_SOA_TABLE(UDTracksFlags, "AOD", "UDTRACKFLAG",
DECLARE_SOA_TABLE(UDTracksLabels, "AOD", "UDTRACKLABEL",
udtrack::TrackId);

namespace udcollfitbits
{
DECLARE_SOA_COLUMN(Thr1W0, thr1W0, uint64_t); /// 1 MIP thresholds for FT0A ch 0 - ch 63
DECLARE_SOA_COLUMN(Thr1W1, thr1W1, uint64_t); /// 1 MIP thresholds for FT0A ch 64 - ch 96 & FT0C ch 0 - ch 31
DECLARE_SOA_COLUMN(Thr1W2, thr1W2, uint64_t); /// 1 MIP thresholds for FT0C ch 32 - ch 96
DECLARE_SOA_COLUMN(Thr1W3, thr1W3, uint64_t); /// 1 MIP thresholds for FT0C ch 97 - 112 & FV0 0 - 47

DECLARE_SOA_COLUMN(Thr2W0, thr2W0, uint64_t); /// 2 MIP thresholds for FT0A ch 0 - ch 63
DECLARE_SOA_COLUMN(Thr2W1, thr2W1, uint64_t); /// 2 MIP thresholds for FT0A ch 63 - ch 96 & FT0C ch 0 - ch 31
DECLARE_SOA_COLUMN(Thr2W2, thr2W2, uint64_t); /// 2 MIP thresholds for FT0C ch 32 - ch 96
DECLARE_SOA_COLUMN(Thr2W3, thr2W3, uint64_t); /// 2 MIP thresholds for FT0C ch 97 - 112 & FV0 0 - 47
} // namespace udcollfitbits

DECLARE_SOA_TABLE(UDCollisionFITBits, "AOD", "UDCOLLFITBITS",
o2::soa::Index<>,
udcollfitbits::Thr1W0, /// 1 MIP thresholds for FT0A ch 0 - ch 63
udcollfitbits::Thr1W1, /// 1 MIP thresholds for FT0A ch 63 - ch 96 & FT0C ch 0 - ch 31
udcollfitbits::Thr1W2, /// 1 MIP thresholds for FT0C ch 32 - ch 96
udcollfitbits::Thr1W3, /// 1 MIP thresholds for FT0C ch 97 - 112 & FV0 0 - 47
udcollfitbits::Thr2W0, /// 2 MIP thresholds for FT0A ch 0 - ch 63
udcollfitbits::Thr2W1, /// 2 MIP thresholds for FT0A ch 63 - ch 96 & FT0C ch 0 - ch 31
udcollfitbits::Thr2W2, /// 2 MIP thresholds for FT0C ch 32 - ch 96
udcollfitbits::Thr2W3 /// 2 MIP thresholds for FT0C ch 97 - 112 & FV0 0 - 47
);

using UDTrack = UDTracks::iterator;
using UDTrackCov = UDTracksCov::iterator;
using UDTrackExtra = UDTracksExtra::iterator;
Expand Down
2 changes: 1 addition & 1 deletion PWGUD/TableProducer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ o2physics_add_dpl_workflow(dg-cand-producer

o2physics_add_dpl_workflow(sgcand-producer
SOURCES SGCandProducer.cxx
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::AnalysisCCDB
PUBLIC_LINK_LIBRARIES O2::Framework O2Physics::AnalysisCore O2Physics::SGCutParHolder O2Physics::AnalysisCCDB O2Physics::FITCutParHolder
COMPONENT_NAME Analysis)

o2physics_add_dpl_workflow(dgbccand-producer
Expand Down
Loading
Loading