Skip to content

Commit b523d93

Browse files
committed
DPL Analysis: support configurables in string expressions
1 parent cd8e576 commit b523d93

File tree

4 files changed

+120
-5
lines changed

4 files changed

+120
-5
lines changed

Framework/Core/include/Framework/Expressions.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,14 @@ struct PlaceholderNode : LiteralNode {
165165
retrieve = [](InitContext& context, char const* name) { return LiteralNode::var_t{static_cast<AT>(context.options().get<T>(name))}; };
166166
}
167167

168+
template <typename T>
169+
PlaceholderNode(T defaultValue, std::string&& path)
170+
: LiteralNode{defaultValue},
171+
name{path}
172+
{
173+
retrieve = [](InitContext& context, char const* name){ return LiteralNode::var_t{context.options().get<T>(name)}; };
174+
}
175+
168176
void reset(InitContext& context)
169177
{
170178
value = retrieve(context, name.data());
@@ -596,6 +604,13 @@ inline Node protect0(Node&& expr)
596604
return ifnode(nabs(Node{copy}) < o2::constants::math::Almost0, o2::constants::math::Almost0, Node{copy});
597605
}
598606

607+
/// context-independent configurable
608+
template <typename T>
609+
inline Node ncfg(T defaultValue, std::string path)
610+
{
611+
return PlaceholderNode(defaultValue, path);
612+
}
613+
599614
/// A struct, containing the root of the expression tree
600615
struct Filter {
601616
Filter() = default;

Framework/Core/src/Expressions.cxx

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ constexpr std::array<std::string_view, BasicOp::Conditional + 1> mapping{
6464
"nbitwise_not",
6565
"ifnode"};
6666

67+
constexpr std::array<std::string_view, 8> cfgtypes{
68+
"uint16_t", // 0
69+
"int16_t", // 1
70+
"uint32_t", // 2
71+
"int32_t", // 3
72+
"uint64_t", // 4
73+
"int64_t", // 5
74+
"float", // 6
75+
"double" // 7
76+
};
77+
6778
/// math constants to recognize in string expressions
6879
constexpr std::array<std::string_view, 9> mathConstants{
6980
"Almost0",
@@ -813,7 +824,8 @@ Tokenizer::Tokenizer(std::string const& input)
813824
{
814825
LastChar = ' ';
815826
if (!source.empty()) {
816-
source.erase(std::remove_if(source.begin(), source.end(), ::isspace), source.end());
827+
source.erase(std::remove_if(source.begin(), source.end(), ::isspace), source.end()); // strip whitespaces
828+
source.erase(std::remove(source.begin(), source.end(), '\"'), source.end()); // strip quotes
817829
}
818830
current = source.begin();
819831
}
@@ -827,7 +839,8 @@ void Tokenizer::reset(std::string const& input)
827839
FloatValue = 0.f;
828840
source = input;
829841
if (!source.empty()) {
830-
source.erase(std::remove_if(source.begin(), source.end(), ::isspace), source.end());
842+
source.erase(std::remove_if(source.begin(), source.end(), ::isspace), source.end()); // strip whitespaces
843+
source.erase(std::remove(source.begin(), source.end(), '\"'), source.end()); // strip quotes
831844
}
832845
current = source.begin();
833846
currentToken = Token::Unexpected;
@@ -1202,6 +1215,78 @@ std::unique_ptr<Node> Parser::parseBase(Tokenizer& tk)
12021215
}
12031216
tk.nextToken();
12041217
return node;
1218+
} else if (id == "ncfg") { // configurable placeholder, 3 args none of them can be expressions
1219+
int args = 0;
1220+
std::string type;
1221+
std::string value;
1222+
std::string path;
1223+
while (tk.currentToken != ')') {
1224+
do {
1225+
tk.nextToken();
1226+
if (args == 0) { // type
1227+
type = tk.TokenStr;
1228+
tk.nextToken();
1229+
} else if (args == 1) { // value
1230+
value = tk.TokenStr;
1231+
tk.nextToken();
1232+
} else if (args == 2) { // path
1233+
path = tk.TokenStr;
1234+
tk.nextToken();
1235+
} else {
1236+
throw runtime_error_f("Extra argument in configurable: %s", tk.TokenStr.c_str());
1237+
}
1238+
++args;
1239+
} while (tk.currentToken == ',');
1240+
}
1241+
tk.nextToken();
1242+
auto locate = std::find(cfgtypes.begin(), cfgtypes.end(), type);
1243+
if (locate == cfgtypes.end()) {
1244+
throw runtime_error_f("Unsupported type in configurable: %s", type.c_str());
1245+
}
1246+
switch (std::distance(cfgtypes.begin(), locate)) {
1247+
case 0:
1248+
return std::make_unique<Node>(
1249+
PlaceholderNode(
1250+
static_cast<uint16_t>(std::stoi(value)),
1251+
std::move(path)));
1252+
case 1:
1253+
return std::make_unique<Node>(
1254+
PlaceholderNode(
1255+
static_cast<int16_t>(std::stoi(value)),
1256+
std::move(path)));
1257+
case 2:
1258+
return std::make_unique<Node>(
1259+
PlaceholderNode(
1260+
static_cast<uint32_t>(std::stoi(value)),
1261+
std::move(path)));
1262+
case 3:
1263+
return std::make_unique<Node>(
1264+
PlaceholderNode(
1265+
static_cast<int32_t>(std::stoi(value)),
1266+
std::move(path)));
1267+
case 4:
1268+
return std::make_unique<Node>(
1269+
PlaceholderNode(
1270+
static_cast<uint64_t>(std::stoll(value)),
1271+
std::move(path)));
1272+
case 5:
1273+
return std::make_unique<Node>(
1274+
PlaceholderNode(
1275+
static_cast<int64_t>(std::stol(value)),
1276+
std::move(path)));
1277+
case 6:
1278+
return std::make_unique<Node>(
1279+
PlaceholderNode(
1280+
std::stof(value),
1281+
std::move(path)));
1282+
case 7:
1283+
return std::make_unique<Node>(
1284+
PlaceholderNode(
1285+
std::stod(value),
1286+
std::move(path)));
1287+
default:
1288+
throw runtime_error_f("Unsupported type in configurable: %s", type.c_str());
1289+
}
12051290
} else { // normal function
12061291
auto node = std::make_unique<Node>(opFromToken(id), LiteralNode{-1}, LiteralNode{-1});
12071292
int args = 0;

Framework/Core/test/test_Expressions.cxx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,4 +375,19 @@ TEST_CASE("TestStringExpressionsParsing")
375375
auto treef2 = createExpressionTree(tf2, schema);
376376

377377
REQUIRE(treef1->ToString() == treef2->ToString());
378+
379+
Configurable<float> pTCut{"pTCut", 0.5f, "Lower pT limit"};
380+
Filter pcfg1 = o2::aod::track::pt > pTCut;
381+
Filter pcfg2 = Parser::parse("o2::aod::track::pt > ncfg(float, 0.5, \"pTCut\")");
382+
auto pcfg1specs = createOperations(pcfg1);
383+
auto pcfg2specs = createOperations(pcfg2);
384+
385+
REQUIRE(pcfg2.node->right->self.index() == 3);
386+
REQUIRE(pcfg2specs[0].right == (DatumSpec{LiteralNode::var_t{0.5f}, atype::FLOAT}));
387+
388+
schema = std::make_shared<arrow::Schema>(std::vector{o2::aod::track::Pt::asArrowField()});
389+
auto tree1c = createExpressionTree(pcfg1specs, schema);
390+
auto tree2c = createExpressionTree(pcfg2specs, schema);
391+
392+
REQUIRE(tree1c->ToString() == tree2c->ToString());
378393
}

Framework/TestWorkflows/src/o2TestHistograms.cxx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct EtaAndClsHistogramsSimple {
4545
void init(InitContext&)
4646
{
4747
if (!trackFilterString->empty()) {
48-
trackFilter = trackFilterString;
48+
trackFilter = Parser::parse((std::string)trackFilterString);
4949
}
5050
}
5151

@@ -68,7 +68,7 @@ struct EtaAndClsHistogramsIUSimple {
6868
void init(InitContext&)
6969
{
7070
if (!trackFilterString->empty()) {
71-
trackFilter = trackFilterString;
71+
trackFilter = Parser::parse((std::string)trackFilterString);
7272
}
7373
}
7474

@@ -90,7 +90,7 @@ struct EtaAndClsHistogramsFull {
9090
void init(InitContext&)
9191
{
9292
if (!trackFilterString->empty()) {
93-
trackFilter = trackFilterString;
93+
trackFilter = Parser::parse((std::string)trackFilterString);
9494
}
9595
}
9696

0 commit comments

Comments
 (0)