Skip to content

Commit 7082d0a

Browse files
authored
DPL Analysis: adapt the internals to Configurable<vector> (#4869)
1 parent 86a61ac commit 7082d0a

14 files changed

Lines changed: 319 additions & 48 deletions

Analysis/Tutorials/src/configurableObjects.cxx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "Framework/AnalysisDataModel.h"
1313
#include "Analysis/configurableCut.h"
1414

15+
#include <sstream>
16+
1517
using namespace o2;
1618
using namespace o2::framework;
1719
using namespace o2::framework::expressions;
@@ -22,10 +24,27 @@ using namespace o2::framework::expressions;
2224
struct ConfigurableObjectDemo {
2325
Configurable<configurableCut> cut{"cut", {0.5, 1, true}, "generic cut"};
2426
MutableConfigurable<configurableCut> mutable_cut{"mutable_cut", {1., 2, false}, "generic cut"};
27+
28+
// note that size is fixed by this declaration - externally supplied vector needs to be the same size!
29+
Configurable<std::vector<int>> array{"array", {1, 2, 3, 4, 5}, "generic array"};
30+
2531
void init(InitContext const&){};
2632
void process(aod::Collision const&, aod::Tracks const& tracks)
2733
{
2834
LOGF(INFO, "Cut1: %.3f; Cut2: %.3f", cut, mutable_cut);
35+
auto vec = (std::vector<int>)array;
36+
std::stringstream ss;
37+
ss << "[";
38+
auto count = 0u;
39+
for (auto& entry : vec) {
40+
ss << entry;
41+
if (count < vec.size() - 1) {
42+
ss << ",";
43+
}
44+
++count;
45+
}
46+
ss << "]";
47+
LOGF(INFO, "Array: %s", ss.str().c_str());
2948
for (auto& track : tracks) {
3049
if (track.globalIndex() % 500 == 0) {
3150
std::string decision1;

Framework/Core/include/Framework/ConfigParamRegistry.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "Framework/ParamRetriever.h"
1414
#include "Framework/ConfigParamStore.h"
15+
#include "Framework/Traits.h"
1516

1617
#include <boost/property_tree/ptree.hpp>
1718
#include <memory>
@@ -21,6 +22,20 @@
2122
namespace o2::framework
2223
{
2324

25+
namespace
26+
{
27+
template <typename T>
28+
std::vector<T> extractVector(boost::property_tree::ptree& tree)
29+
{
30+
std::vector<T> result(tree.size());
31+
auto count = 0u;
32+
for (auto& entry : tree) {
33+
result[count++] = entry.second.get_value<T>();
34+
}
35+
return result;
36+
}
37+
} // namespace
38+
2439
class ConfigParamStore;
2540

2641
/// This provides unified access to the parameters specified in the workflow
@@ -63,6 +78,8 @@ class ConfigParamRegistry
6378
return mStore->store().get<std::string>(key);
6479
} else if constexpr (std::is_same_v<T, std::string_view>) {
6580
return std::string_view{mStore->store().get<std::string>(key)};
81+
} else if constexpr (is_base_of_template<std::vector, T>::value) {
82+
return extractVector<typename T::value_type>(mStore->store().get_child(key));
6683
} else if constexpr (std::is_same_v<T, boost::property_tree::ptree>) {
6784
return mStore->store().get_child(key);
6885
} else if constexpr (std::is_constructible_v<T, boost::property_tree::ptree>) {

Framework/Core/include/Framework/ConfigParamStore.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ class ConfigParamStore
3737
boost::property_tree::ptree& store() { return *mStore; };
3838
boost::property_tree::ptree& provenanceTree() { return *mProvenance; };
3939

40+
/// Get the specs
41+
std::vector<ConfigParamSpec> const& specs() const
42+
{
43+
return mSpecs;
44+
}
45+
4046
/// Activate the next store
4147
void activate();
4248

Framework/Core/include/Framework/ConfigParamsHelper.h

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@
1818
#include <string>
1919
#include <type_traits>
2020

21-
namespace o2
22-
{
23-
namespace framework
21+
namespace o2::framework
2422
{
2523

2624
using options_description = boost::program_options::options_description;
@@ -101,22 +99,40 @@ struct ConfigParamsHelper {
10199
{
102100
const char* name = spec.name.c_str();
103101
const char* help = spec.help.c_str();
104-
using Type = typename variant_type<V>::type;
105-
using BoostType = typename std::conditional<V == VariantType::String, std::string, Type>::type;
106-
auto value = boost::program_options::value<BoostType>();
107-
if (spec.defaultValue.type() != VariantType::Empty) {
108-
// set the default value if provided in the config spec
109-
value = value->default_value(spec.defaultValue.get<Type>());
110-
}
111-
if (V == VariantType::Bool) {
112-
// for bool values we also support the zero_token option to make
113-
// the option usable as a single switch
114-
value = value->zero_tokens();
102+
103+
if constexpr (V == VariantType::Int ||
104+
V == VariantType::Int64 ||
105+
V == VariantType::Float ||
106+
V == VariantType::Double ||
107+
V == VariantType::Bool) {
108+
using Type = typename variant_type<V>::type;
109+
using BoostType = typename std::conditional<V == VariantType::String, std::string, Type>::type;
110+
auto value = boost::program_options::value<BoostType>();
111+
value = value->default_value(spec.defaultValue.get<BoostType>());
112+
if constexpr (V == VariantType::Bool) {
113+
// for bool values we also support the zero_token option to make
114+
// the option usable as a single switch
115+
value = value->zero_tokens();
116+
}
117+
options.add_options()(name, value, help);
118+
} else if constexpr (V == VariantType::ArrayInt ||
119+
V == VariantType::ArrayFloat ||
120+
V == VariantType::ArrayDouble ||
121+
V == VariantType::ArrayBool) {
122+
auto value = boost::program_options::value<std::string>();
123+
value = value->default_value(spec.defaultValue.asString());
124+
if constexpr (V != VariantType::String) {
125+
value = value->multitoken();
126+
}
127+
options.add_options()(name, value, help);
128+
} else {
129+
using Type = typename variant_type<V>::type;
130+
using BoostType = typename std::conditional<V == VariantType::String, std::string, Type>::type;
131+
auto value = boost::program_options::value<BoostType>();
132+
options.add_options()(name, value, help);
115133
}
116-
options.add_options()(name, value, help);
117134
}
118135
};
119136

120-
} // namespace framework
121-
} // namespace o2
137+
} // namespace o2::framework
122138
#endif // FRAMEWORK_CONFIGPARAMSHELPER_H

Framework/Core/include/Framework/Variant.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,50 @@ DECLARE_VARIANT_TRAIT(long int, Int64);
5353
DECLARE_VARIANT_TRAIT(long long int, Int64);
5454
DECLARE_VARIANT_TRAIT(float, Float);
5555
DECLARE_VARIANT_TRAIT(double, Double);
56+
DECLARE_VARIANT_TRAIT(bool, Bool);
57+
5658
DECLARE_VARIANT_TRAIT(const char*, String);
5759
DECLARE_VARIANT_TRAIT(char*, String);
5860
DECLARE_VARIANT_TRAIT(char* const, String);
5961
DECLARE_VARIANT_TRAIT(const char* const, String);
6062
DECLARE_VARIANT_TRAIT(std::string_view, String);
6163
DECLARE_VARIANT_TRAIT(std::string, String);
62-
DECLARE_VARIANT_TRAIT(bool, Bool);
64+
6365
DECLARE_VARIANT_TRAIT(int*, ArrayInt);
6466
DECLARE_VARIANT_TRAIT(float*, ArrayFloat);
6567
DECLARE_VARIANT_TRAIT(double*, ArrayDouble);
6668
DECLARE_VARIANT_TRAIT(bool*, ArrayBool);
6769

70+
DECLARE_VARIANT_TRAIT(std::vector<int>, ArrayInt);
71+
DECLARE_VARIANT_TRAIT(std::vector<float>, ArrayFloat);
72+
DECLARE_VARIANT_TRAIT(std::vector<double>, ArrayDouble);
73+
DECLARE_VARIANT_TRAIT(std::vector<bool>, ArrayBool);
74+
75+
template <typename T>
76+
struct variant_array_symbol {
77+
constexpr static char symbol = 'u';
78+
};
79+
80+
template <>
81+
struct variant_array_symbol<int> {
82+
constexpr static char symbol = 'i';
83+
};
84+
85+
template <>
86+
struct variant_array_symbol<float> {
87+
constexpr static char symbol = 'f';
88+
};
89+
90+
template <>
91+
struct variant_array_symbol<double> {
92+
constexpr static char symbol = 'd';
93+
};
94+
95+
template <>
96+
struct variant_array_symbol<bool> {
97+
constexpr static char symbol = 'b';
98+
};
99+
68100
template <typename T>
69101
inline constexpr VariantType variant_trait_v = variant_trait<T>::value;
70102

@@ -84,6 +116,7 @@ DECLARE_VARIANT_TYPE(float, Float);
84116
DECLARE_VARIANT_TYPE(double, Double);
85117
DECLARE_VARIANT_TYPE(const char*, String);
86118
DECLARE_VARIANT_TYPE(bool, Bool);
119+
87120
DECLARE_VARIANT_TYPE(int*, ArrayInt);
88121
DECLARE_VARIANT_TYPE(float*, ArrayFloat);
89122
DECLARE_VARIANT_TYPE(double*, ArrayDouble);
@@ -293,6 +326,7 @@ class Variant
293326

294327
VariantType type() const { return mType; }
295328
size_t size() const { return mSize; }
329+
std::string asString() const;
296330

297331
private:
298332
friend std::ostream& operator<<(std::ostream& oss, Variant const& val);

Framework/Core/src/AnalysisManagers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ struct OptionManager<Configurable<T, IP>> {
360360
static bool appendOption(std::vector<ConfigParamSpec>& options, Configurable<T, IP>& what)
361361
{
362362
if constexpr (variant_trait_v<typename std::decay<T>::type> != VariantType::Unknown) {
363-
options.emplace_back(ConfigParamSpec{what.name, variant_trait_v<typename std::decay<T>::type>, what.value, {what.help}});
363+
options.emplace_back(ConfigParamSpec{what.name, variant_trait_v<std::decay_t<T>>, what.value, {what.help}});
364364
} else {
365365
auto specs = RootConfigParamHelpers::asConfigParamSpecs<T>(what.name, what.value);
366366
options.insert(options.end(), specs.begin(), specs.end());

Framework/Core/src/BoostOptionsRetriever.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ void BoostOptionsRetriever::update(std::vector<ConfigParamSpec> const& specs,
6868
case VariantType::ArrayFloat:
6969
case VariantType::ArrayDouble:
7070
case VariantType::ArrayBool:
71+
options = options(name, bpo::value<std::string>()->multitoken()->default_value(spec.defaultValue.asString(), help));
72+
break;
7173
case VariantType::Unknown:
7274
case VariantType::Empty:
7375
break;

Framework/Core/src/ConfigParamsHelper.cxx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ void ConfigParamsHelper::populateBoostProgramOptions(
3535
if (vetos.find_nothrow(spec.name, false)) {
3636
continue;
3737
}
38-
const char* name = spec.name.c_str();
39-
const char* help = spec.help.c_str();
4038

4139
switch (spec.type) {
4240
// FIXME: Should we handle int and size_t diffently?
@@ -60,9 +58,17 @@ void ConfigParamsHelper::populateBoostProgramOptions(
6058
addConfigSpecOption<VariantType::Bool>(spec, options);
6159
break;
6260
case VariantType::ArrayInt:
61+
addConfigSpecOption<VariantType::ArrayInt>(spec, options);
62+
break;
6363
case VariantType::ArrayFloat:
64+
addConfigSpecOption<VariantType::ArrayFloat>(spec, options);
65+
break;
6466
case VariantType::ArrayDouble:
67+
addConfigSpecOption<VariantType::ArrayDouble>(spec, options);
68+
break;
6569
case VariantType::ArrayBool:
70+
addConfigSpecOption<VariantType::ArrayBool>(spec, options);
71+
break;
6672
case VariantType::Unknown:
6773
case VariantType::Empty:
6874
break;

Framework/Core/src/DataProcessingDevice.cxx

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include <unordered_map>
5656
#include <uv.h>
5757
#include <execinfo.h>
58+
#include <sstream>
5859

5960
using namespace o2::framework;
6061
using Key = o2::monitoring::tags::Key;
@@ -175,6 +176,27 @@ void on_socket_polled(uv_poll_t* poller, int status, int events)
175176
// We do nothing, all the logic for now stays in DataProcessingDevice::doRun()
176177
}
177178

179+
namespace
180+
{
181+
template <typename T>
182+
std::string arrayPrinter(boost::property_tree::ptree const& tree)
183+
{
184+
std::stringstream ss;
185+
int size = tree.size();
186+
int count = 0;
187+
ss << variant_array_symbol<T>::symbol << "[";
188+
for (auto& element : tree) {
189+
ss << element.second.get_value<T>();
190+
if (count < size - 1) {
191+
ss << ",";
192+
}
193+
++count;
194+
}
195+
ss << "]";
196+
return ss.str();
197+
}
198+
} // namespace
199+
178200
/// This takes care of initialising the device from its specification. In
179201
/// particular it needs to:
180202
///
@@ -219,14 +241,13 @@ void DataProcessingDevice::Init()
219241
} else {
220242
retrievers.emplace_back(std::make_unique<FairOptionsRetriever>(GetConfig()));
221243
}
222-
auto configStore = std::move(std::make_unique<ConfigParamStore>(mSpec.options, std::move(retrievers)));
244+
auto configStore = std::make_unique<ConfigParamStore>(mSpec.options, std::move(retrievers));
223245
configStore->preload();
224246
configStore->activate();
225247
using boost::property_tree::ptree;
226248

227249
/// Dump the configuration so that we can get it from the driver.
228250
for (auto& entry : configStore->store()) {
229-
LOG(INFO) << "[CONFIG] " << entry.first << "=" << configStore->store().get<std::string>(entry.first) << " 1 " << configStore->provenance(entry.first.c_str());
230251
PropertyTreeHelpers::WalkerFunction printer = [&configStore, topLevel = entry.first](ptree const& parent, ptree::path_type childPath, ptree const& child) {
231252
// FIXME: not clear why we get invoked for the root entry
232253
// and twice for each node. It nevertheless works
@@ -236,8 +257,32 @@ void DataProcessingDevice::Init()
236257
LOG(INFO) << "[CONFIG] " << topLevel << "." << childPath.dump() << "=" << child.data() << " 1 " << configStore->provenance(topLevel.c_str());
237258
}
238259
};
239-
PropertyTreeHelpers::traverse(entry.second, printer);
260+
261+
auto spec = std::find_if(configStore->specs().begin(), configStore->specs().end(), [&](auto& x) { return x.name == entry.first; });
262+
if (spec != configStore->specs().end()) {
263+
switch (spec->type) {
264+
case VariantType::ArrayInt:
265+
LOG(INFO) << "[CONFIG] " << entry.first << "=" << arrayPrinter<int>(entry.second) << " 1 " << configStore->provenance(entry.first.c_str());
266+
break;
267+
case VariantType::ArrayFloat:
268+
LOG(INFO) << "[CONFIG] " << entry.first << "=" << arrayPrinter<float>(entry.second) << " 1 " << configStore->provenance(entry.first.c_str());
269+
break;
270+
case VariantType::ArrayDouble:
271+
LOG(INFO) << "[CONFIG] " << entry.first << "=" << arrayPrinter<double>(entry.second) << " 1 " << configStore->provenance(entry.first.c_str());
272+
break;
273+
case VariantType::ArrayBool:
274+
LOG(INFO) << "[CONFIG] " << entry.first << "=" << arrayPrinter<bool>(entry.second) << " 1 " << configStore->provenance(entry.first.c_str());
275+
break;
276+
default:
277+
LOG(INFO) << "[CONFIG] " << entry.first << "=" << configStore->store().get<std::string>(entry.first) << " 1 " << configStore->provenance(entry.first.c_str());
278+
PropertyTreeHelpers::traverse(entry.second, printer);
279+
}
280+
} else {
281+
LOG(INFO) << "[CONFIG] " << entry.first << "=" << configStore->store().get<std::string>(entry.first) << " 1 " << configStore->provenance(entry.first.c_str());
282+
PropertyTreeHelpers::traverse(entry.second, printer);
283+
}
240284
}
285+
241286
mConfigRegistry = std::make_unique<ConfigParamRegistry>(std::move(configStore));
242287

243288
mExpirationHandlers.clear();

Framework/Core/src/DeviceConfigInfo.cxx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,9 @@
1010

1111
#include "Framework/DeviceConfigInfo.h"
1212
#include "Framework/DeviceInfo.h"
13-
#include <cassert>
14-
#include <cinttypes>
1513
#include <cstdlib>
16-
17-
#include <algorithm>
1814
#include <regex>
1915
#include <string_view>
20-
#include <tuple>
21-
#include <iostream>
2216

2317
namespace o2::framework
2418
{
@@ -67,10 +61,26 @@ bool DeviceConfigHelper::processConfig(ParsedConfigMatch& match,
6761
match.beginProvenance == nullptr || match.endProvenance == nullptr) {
6862
return false;
6963
}
70-
info.currentConfig.put(std::string(match.beginKey, match.endKey - match.beginKey),
71-
std::string(match.beginValue, match.endValue - match.beginValue));
72-
info.currentProvenance.put(std::string(match.beginKey, match.endKey - match.beginKey),
73-
std::string(match.beginProvenance, match.endProvenance - match.beginProvenance));
64+
auto keyString = std::string(match.beginKey, match.endKey - match.beginKey);
65+
auto valueString = std::string(match.beginValue, match.endValue - match.beginValue);
66+
auto provenanceString = std::string(match.beginProvenance, match.endProvenance - match.beginProvenance);
67+
std::regex fmatch(R"([ifdb]\[.*\])", std::regex_constants::ECMAScript);
68+
std::regex nmatch(R"((?:(?!=,)|(?!=\[))[+-]?\d+\.?\d*(?:[eE][+-]?\d+)?(?=,|\]))", std::regex_constants::ECMAScript);
69+
auto end = std::sregex_iterator();
70+
auto fmt = std::sregex_iterator(valueString.begin(), valueString.end(), fmatch);
71+
if (fmt != end) {
72+
boost::property_tree::ptree branch;
73+
auto values = std::sregex_iterator(valueString.begin(), valueString.end(), nmatch);
74+
for (auto v = values; v != end; ++v) {
75+
boost::property_tree::ptree leaf;
76+
leaf.put("", v->str());
77+
branch.push_back(std::make_pair("", leaf));
78+
}
79+
info.currentConfig.put_child(keyString, branch);
80+
} else {
81+
info.currentConfig.put(keyString, valueString);
82+
}
83+
info.currentProvenance.put(keyString, provenanceString);
7484
return true;
7585
}
7686

0 commit comments

Comments
 (0)