Skip to content
Merged
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
69 changes: 61 additions & 8 deletions PWGCF/Femto/Core/baseSelection.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,46 @@ class BaseSelection
// set bitmask for given observable
mSelectionContainers.at(observableIndex).evaluate(value);
// check if minimal selction for this observable holds
// if one minimal selection is not fullfilled, the condition failes
if (mSelectionContainers.at(observableIndex).passesAsMinimalCut() == false) {
mPassesMinimalSelections = false;
}
// check if any optional selection holds
// if one optional selection is fullfilled, the condition succeeds
if (mSelectionContainers.at(observableIndex).passesAsOptionalCut() == true) {
mPassesOptionalSelections = true;
}
}

/// \brief Evaluate a single observable against its configured selections.
/// \param observableIndex Index of the observable.
/// \param values vector of values of the observable.
void evaluateObservable(int observableIndex, std::vector<T> values)
{
// if there are no selections configured, bail out
if (mSelectionContainers.at(observableIndex).isEmpty()) {
return;
}
// if any previous observable did not pass minimal selections, there is no point in setting bitmask for other observables
// minimal selection for each observable is computed after adding it
if (mPassesMinimalSelections == false) {
return;
}
// set bitmask for given observable
mSelectionContainers.at(observableIndex).evaluate(values);
// check if minimal selction for this observable holds
if (mSelectionContainers.at(observableIndex).passesAsMinimalCut() == false) {
mPassesMinimalSelections = false;
}
// check if any optional selection holds
if (mSelectionContainers.at(observableIndex).passesAsOptionalCut() == true) {
mPassesOptionalSelections = true;
}
}

/// \brief Add comments to specific observabel
void addComments(int observableIndex, std::vector<std::string> const& comments) { mSelectionContainers.at(observableIndex).addComments(comments); }

/// \brief Check if all required (minimal) and optional cuts are passed.
/// \return True if all required and at least one optional cut (if present) is passed.
bool passesAllRequiredSelections() const
Expand Down Expand Up @@ -223,20 +254,38 @@ class BaseSelection
/// \return The combined selection bitmask.
BitmaskType getBitmask(int observableIndex) const { return static_cast<BitmaskType>(mSelectionContainers.at(observableIndex).getBitmask().to_ullong()); }

/// \brief Retrieve the assembled bitmask as an integer value.
/// \brief Set the assembled bitmask for on observable
/// \return The combined selection bitmask.
template <typename R>
void setBitmask(int observableIndex, R bitmask)
{
// if there are no selections configured, bail out
if (mSelectionContainers.at(observableIndex).isEmpty()) {
return;
}
// if any previous observable did not pass minimal selections, there is no point in setting bitmask for other observables
// minimal selection for each observable is computed after adding it
if (mPassesMinimalSelections == false) {
return;
}
// set bitmask for given observable
mSelectionContainers.at(observableIndex).setBitmask(bitmask);
// check if minimal selction for this observable holds
if (mSelectionContainers.at(observableIndex).passesAsMinimalCut() == false) {
mPassesMinimalSelections = false;
}
// check if any optional selection holds
if (mSelectionContainers.at(observableIndex).passesAsOptionalCut() == true) {
mPassesOptionalSelections = true;
}
}

/// \brief Print detailed information about all configured selections.
/// \tparam MapType Type used in the observable name map (usually an enum or int).
/// \param objectName Name of the current object (e.g. particle species).
/// \param observableNames Map from observable index to human-readable names.
template <typename MapType>
void printSelections(const std::string& objectName, const std::unordered_map<MapType, std::string>& observableNames) const
template <typename R>
void printSelections(const std::string& objectName, const std::unordered_map<R, std::string>& observableNames) const
{
LOG(info) << "Printing Configuration of " << objectName;

Expand All @@ -248,7 +297,7 @@ class BaseSelection
continue;
}

const MapType key = static_cast<MapType>(idx);
R key = static_cast<R>(idx);
const std::string& name = observableNames.count(key) ? observableNames.at(key) : "[Unknown]";

LOG(info) << "Observable: " << name << " (index " << idx << ")";
Expand All @@ -260,9 +309,11 @@ class BaseSelection

const auto& values = container.getSelectionValues();
const auto& functions = container.getSelectionFunction();
const bool useFunctions = !functions.empty();
const size_t numSelections = useFunctions ? functions.size() : values.size();
const bool skipMostPermissive = container.skipMostPermissiveBit();
bool useFunctions = !functions.empty();
size_t numSelections = useFunctions ? functions.size() : values.size();
bool skipMostPermissive = container.skipMostPermissiveBit();
const auto& comments = container.getComments();
bool hasComments = !comments.empty();

int valWidth = 20;
int bitWidth = 30;
Expand All @@ -273,7 +324,9 @@ class BaseSelection
// Selection string (either value or function)
const std::string& sel = useFunctions ? std::string(functions[j].GetFormula()->GetExpFormula().Data()) : std::to_string(values[j]);
line << " " << std::left << std::setw(valWidth) << sel;

if (hasComments) {
line << "(" << comments.at(j) << ")";
}
// Bitmask
if (skipMostPermissive && j == 0) {
line << std::setw(bitWidth) << "-> loosest minimal selection, no bit saved";
Expand Down
99 changes: 70 additions & 29 deletions PWGCF/Femto/Core/collisionBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@
#include "Common/CCDB/EventSelectionParams.h"
#include "EventFiltering/Zorro.h"

#include "DataFormatsParameters/GRPMagField.h"
#include "Framework/AnalysisHelpers.h"
#include "Framework/Configurable.h"

#include "fairlogger/Logger.h"

#include <algorithm>
#include <cmath>
#include <string>
#include <unordered_map>
#include <vector>

namespace o2::analysis::femto
{
Expand Down Expand Up @@ -73,13 +76,14 @@ struct ConfCollisionBits : o2::framework::ConfigurableGroup {
o2::framework::Configurable<std::vector<float>> occupancyMax{"occupancyMax", {}, "Maximum occpancy"};
o2::framework::Configurable<std::vector<float>> sphericityMin{"sphericityMin", {}, "Minimum sphericity"};
o2::framework::Configurable<std::vector<float>> sphericityMax{"sphericityMax", {}, "Maximum sphericity"};
o2::framework::Configurable<std::vector<std::string>> triggers{"triggers", {}, "List of all triggers to be used"};
};

struct ConfCollisionTriggers : o2::framework::ConfigurableGroup {
std::string prefix = std::string("CollisionTriggers");
o2::framework::Configurable<bool> useTrigger{"useTrigger", false, "Set to true to only selected triggered collisions"};
o2::framework::Configurable<std::string> ccdbPath{"ccdbPath", std::string("EventFiltering/Zorro/"), "CCDB path for trigger information"};
o2::framework::Configurable<std::string> triggers{"triggers", std::string("fPPP,fPPL"), "Comma seperated list of all triggers to be used"};
struct ConfCcdb : o2::framework::ConfigurableGroup {
std::string prefix = std::string("ConfCcdb");
o2::framework::Configurable<std::string> ccdbUrl{"ccdbUrl", "http://alice-ccdb.cern.ch", "URL to ccdb"};
o2::framework::Configurable<std::string> grpPath{"grpPath", "GLO/Config/GRPMagField", "Path to GRP object (Run3 -> GLO/Config/GRPMagField/Run2 -> GLO/GRP/GRP"};
o2::framework::Configurable<std::string> triggerPath{"triggerPath", "EventFiltering/Zorro/", "CCDB path for trigger information"};
};

struct ConfCollisionRctFlags : o2::framework::ConfigurableGroup {
Expand Down Expand Up @@ -125,6 +129,8 @@ enum CollisionSels {
kSphericityMin, ///< Min. sphericity
kSphericityMax, ///< Max. sphericity

kTriggers,

kCollisionSelsMax
};

Expand All @@ -146,14 +152,16 @@ const std::unordered_map<CollisionSels, std::string> colSelsToString = {
{kOccupancyMin, "Minimum Occupancy"},
{kOccupancyMax, "Maximum Occupancy"},
{kSphericityMin, "Minimum Sphericity"},
{kSphericityMax, "Maximum Sphericity"}
{kSphericityMax, "Maximum Sphericity"},

{kTriggers, "Triggers"}

};

class CollisionSelection : public BaseSelection<float, o2::aod::femtodatatypes::CollisionMaskType, kCollisionSelsMax>
{
public:
CollisionSelection() {}
CollisionSelection() = default;
virtual ~CollisionSelection() = default;

template <typename T1, typename T2>
Expand Down Expand Up @@ -188,6 +196,10 @@ class CollisionSelection : public BaseSelection<float, o2::aod::femtodatatypes::
this->addSelection(config.occupancyMax.value, kOccupancyMax, limits::kUpperLimit, true, true);
this->addSelection(config.sphericityMin.value, kSphericityMin, limits::kLowerLimit, true, true);
this->addSelection(config.sphericityMax.value, kSphericityMax, limits::kUpperLimit, true, true);

std::vector<float> triggerValues(config.triggers.value.size(), 1.f);
this->addSelection(triggerValues, kTriggers, limits::kEqualArray, false, true);
this->addComments(kTriggers, config.triggers.value);
};

void setMagneticField(int MagField)
Expand Down Expand Up @@ -255,13 +267,12 @@ class CollisionSelection : public BaseSelection<float, o2::aod::femtodatatypes::
}

template <typename T>
void applySelections(T const& col)
void applySelections(T const& col, std::vector<bool> const& triggerDecisions)
{
this->reset();

// casting bool to float gurantees
// false -> 0
// true -> 1
// casting bool to float gurantees false -> 0 and true -> 1
// and we check for equality to 1, so evaluation succeeds if the selection bit is true
this->evaluateObservable(kSel8, static_cast<float>(col.sel8()));
this->evaluateObservable(kNoSameBunchPileUp, static_cast<float>(col.selection_bit(o2::aod::evsel::kNoSameBunchPileup)));
this->evaluateObservable(kIsVertexItsTpc, static_cast<float>(col.selection_bit(o2::aod::evsel::kIsVertexITSTPC)));
Expand All @@ -280,6 +291,13 @@ class CollisionSelection : public BaseSelection<float, o2::aod::femtodatatypes::
this->evaluateObservable(kSphericityMin, mSphericity);
this->evaluateObservable(kSphericityMax, mSphericity);

// for the trigger we need to pass an vector of 0 (false) and 1 (true) for all configured trigger selections
if (!triggerDecisions.empty()) {
std::vector<float> trigger(triggerDecisions.size());
std::transform(triggerDecisions.begin(), triggerDecisions.end(), trigger.begin(), [](bool b) { return b ? 1.0f : 0.0f; });
this->evaluateObservable(kTriggers, trigger);
}

this->assembleBitmask();
};

Expand Down Expand Up @@ -330,18 +348,24 @@ class CollisionBuilder
virtual ~CollisionBuilder() = default;

template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
void init(T1& confFilter, T2& confBits, T3& confRct, T4& confTrigger, T5& confTable, T6& initContext)
void init(T1& confFilter, T2& confBits, T3& confRct, T4& confCcdb, T5& confTable, T6& initContext)
{
mCollisionSelection.configure(confFilter, confBits);
if (confTrigger.useTrigger.value) {
if (!confBits.triggers.value.empty()) {
mUseTrigger = true;
mTriggerNames = confTrigger.triggers.value;
mZorro.setBaseCCDBPath(confTrigger.ccdbPath.value);
for (size_t i = 0; i < confBits.triggers.value.size(); ++i) {
mTriggerNames += confBits.triggers.value[i];
if (i != confBits.triggers.value.size() - 1) {
mTriggerNames += ",";
}
}
mZorro.setBaseCCDBPath(confCcdb.triggerPath.value);
}
if (confRct.useRctFlags.value) {
mUseRctFlags = true;
mRctFlagsChecker.init(confRct.label.value, confRct.useZdc.value, confRct.treatLimitedAcceptanceAsBad.value);
}
mGrpPath = confCcdb.grpPath.value;

LOG(info) << "Initialize femto collision builder...";
mProducedCollisions = utils::enableTable("FCols_001", confTable.produceCollisions.value, initContext);
Expand All @@ -360,31 +384,45 @@ class CollisionBuilder
LOG(info) << "Initialization done...";
}

template <modes::System system, typename T1, typename T2, typename T3, typename T4>
void buildCollision(T1& bc, T2& col, T3& tracks, T4& ccdb, int magField)
template <modes::System system, typename T1, typename T2, typename T3, typename T4, typename T5>
void initCollision(T1& bc, T2& col, T3& tracks, T4& ccdb, T5& histRegistry)
{
if (mUseTrigger) {
mZorro.initCCDB(ccdb.service, bc.runNumber(), bc.timestamp(), mTriggerNames);
if (mRunNumber != bc.runNumber()) {
mRunNumber = bc.runNumber();
static o2::parameters::GRPMagField* grpo = nullptr;
grpo = ccdb->template getForRun<o2::parameters::GRPMagField>(mGrpPath, mRunNumber);
if (grpo == nullptr) {
LOG(fatal) << "GRP object not found for Run " << mRunNumber;
}
mMagField = static_cast<int>(grpo->getNominalL3Field()); // get magnetic field in kG

if (mUseTrigger) {
mZorro.initCCDB(ccdb.service, mRunNumber, bc.timestamp(), mTriggerNames);
mZorro.populateHistRegistry(histRegistry, mRunNumber);
}
}
mCollisionSelection.setMagneticField(magField);

mCollisionSelection.setMagneticField(mMagField);
mCollisionSelection.setSphericity(tracks);
mCollisionSelection.setMultiplicity<system>(col);
mCollisionSelection.setCentrality<system>(col);
mCollisionSelection.applySelections(col);

std::vector<bool> triggerDecisions = {};
if (mUseTrigger) {
triggerDecisions = mZorro.getTriggerOfInterestResults(bc.globalBC());
}

mCollisionSelection.applySelections(col, triggerDecisions);
}

template <typename T1, typename T2>
bool checkCollision(T1 const& bc, T2 const& col)
template <typename T1>
bool checkCollision(T1 const& col)
{
// First: if triggers are enabled, the object must be selected
if (mUseTrigger && !mZorro.isSelected(bc.globalBC())) {
return false;
}
// Then: if RCT flags are enabled, check them
// check RCT flags first
if (mUseRctFlags && !mRctFlagsChecker(col)) {
return false;
}
// Finally: do the expensive checks
// make other checks
return mCollisionSelection.checkFilters(col) &&
mCollisionSelection.passesAllRequiredSelections();
}
Expand Down Expand Up @@ -438,6 +476,9 @@ class CollisionBuilder
CollisionSelection mCollisionSelection;
Zorro mZorro;
bool mUseTrigger = false;
int mRunNumber = -1;
std::string mGrpPath = std::string("");
int mMagField = 0;
aod::rctsel::RCTFlagsChecker mRctFlagsChecker;
bool mUseRctFlags = false;
std::string mTriggerNames = std::string("");
Expand Down
Loading
Loading