Skip to content

Commit 6321af7

Browse files
committed
Ability to create configurable param from a given external struct
This commit provides the new feature of being able to create configurable param instances from a given external C++ struct. For example, a C++ struct `struct A { double x; }` can be used to define a correspondig configurable parameter via ``` class MyConfigParamA : o2::conf::ConfigurableParamPromoter<MyConfigParamA, A> {} ``` This allows to: - have "template" structs to create multiple params of the same structure - separate data from configkey functionality - extract data copies from underlying configurable parameters The application thereof is demonstrated for GeneratorPythia8Param. A unit test is added to check the new functionality.
1 parent c7c9f54 commit 6321af7

File tree

9 files changed

+278
-68
lines changed

9 files changed

+278
-68
lines changed

Common/Utils/include/CommonUtils/ConfigurableParam.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -321,17 +321,19 @@ class ConfigurableParam
321321
} // end namespace o2
322322

323323
// a helper macro for boilerplate code in parameter classes
324-
#define O2ParamDef(classname, key) \
325-
public: \
326-
classname(TRootIOCtor*) {} \
327-
classname(classname const&) = delete; \
328-
\
329-
private: \
330-
static constexpr char const* const sKey = key; \
331-
static classname sInstance; \
332-
classname() = default; \
333-
template <typename T> \
334-
friend class o2::conf::ConfigurableParamHelper;
324+
#define O2ParamDef(classname, key) \
325+
public: \
326+
classname(TRootIOCtor*) {} \
327+
classname(classname const&) = delete; \
328+
\
329+
private: \
330+
static constexpr char const* const sKey = key; \
331+
static classname sInstance; \
332+
classname() = default; \
333+
template <typename T> \
334+
friend class o2::conf::ConfigurableParamHelper; \
335+
template <typename T, typename P> \
336+
friend class o2::conf::ConfigurableParamPromoter;
335337

336338
// a helper macro to implement necessary symbols in source
337339
#define O2ParamImpl(classname) classname classname::sInstance;

Common/Utils/include/CommonUtils/ConfigurableParamHelper.h

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,18 @@ class _ParamHelper
4545
{
4646
private:
4747
static std::vector<ParamDataMember>* getDataMembersImpl(std::string const& mainkey, TClass* cl, void*,
48-
std::map<std::string, ConfigurableParam::EParamProvenance> const* provmap);
48+
std::map<std::string, ConfigurableParam::EParamProvenance> const* provmap, size_t virtualoffset);
4949

5050
static void fillKeyValuesImpl(std::string const& mainkey, TClass* cl, void*, boost::property_tree::ptree*,
5151
std::map<std::string, std::pair<std::type_info const&, void*>>*,
52-
EnumRegistry*);
52+
EnumRegistry*, size_t offset);
5353

5454
static void printWarning(std::type_info const&);
5555

5656
static void assignmentImpl(std::string const& mainkey, TClass* cl, void* to, void* from,
57-
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap);
57+
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap, size_t offset);
5858
static void syncCCDBandRegistry(std::string const& mainkey, TClass* cl, void* to, void* from,
59-
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap);
59+
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap, size_t offset);
6060

6161
static void outputMembersImpl(std::ostream& out, std::string const& mainkey, std::vector<ParamDataMember> const* members, bool showProv, bool useLogger);
6262
static void printMembersImpl(std::string const& mainkey, std::vector<ParamDataMember> const* members, bool showProv, bool useLogger);
@@ -65,6 +65,9 @@ class _ParamHelper
6565

6666
template <typename P>
6767
friend class ConfigurableParamHelper;
68+
69+
template <typename Base, typename P>
70+
friend class ConfigurableParamPromoter;
6871
};
6972

7073
// ----------------------------------------------------------------
@@ -140,7 +143,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
140143
return nullptr;
141144
}
142145

143-
return _ParamHelper::getDataMembersImpl(getName(), cl, (void*)this, sValueProvenanceMap);
146+
return _ParamHelper::getDataMembersImpl(getName(), cl, (void*)this, sValueProvenanceMap, 0);
144147
}
145148

146149
// ----------------------------------------------------------------
@@ -153,7 +156,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
153156
_ParamHelper::printWarning(typeid(P));
154157
return;
155158
}
156-
_ParamHelper::fillKeyValuesImpl(getName(), cl, (void*)this, tree, sKeyToStorageMap, sEnumRegistry);
159+
_ParamHelper::fillKeyValuesImpl(getName(), cl, (void*)this, tree, sKeyToStorageMap, sEnumRegistry, 0);
157160
}
158161

159162
// ----------------------------------------------------------------
@@ -167,7 +170,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
167170
file->GetObject(getName().c_str(), readback);
168171
if (readback != nullptr) {
169172
_ParamHelper::assignmentImpl(getName(), TClass::GetClass(typeid(P)), (void*)this, (void*)readback,
170-
sValueProvenanceMap);
173+
sValueProvenanceMap, 0);
171174
delete readback;
172175
}
173176
setRegisterMode(true);
@@ -185,7 +188,146 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
185188
//
186189
setRegisterMode(false);
187190
_ParamHelper::syncCCDBandRegistry(getName(), TClass::GetClass(typeid(P)), (void*)this, (void*)externalobj,
188-
sValueProvenanceMap);
191+
sValueProvenanceMap, 0);
192+
setRegisterMode(true);
193+
}
194+
195+
// ----------------------------------------------------------------
196+
197+
void serializeTo(TFile* file) const final
198+
{
199+
file->WriteObjectAny((void*)this, TClass::GetClass(typeid(P)), getName().c_str());
200+
}
201+
};
202+
203+
// Promotes a simple struct Base to a configurable parameter class
204+
// Aka implements all interfaces for a ConfigurableParam P, which shares or
205+
// takes the fields from a Base struct
206+
template <typename P, typename Base>
207+
class ConfigurableParamPromoter : public Base, virtual public ConfigurableParam
208+
{
209+
public:
210+
using ConfigurableParam::ConfigurableParam;
211+
212+
static const P& Instance()
213+
{
214+
return P::sInstance;
215+
}
216+
217+
// extracts a copy of the underlying data struct
218+
Base detach() const
219+
{
220+
static_assert(std::copyable<Base>, "Base type must be copyable.");
221+
return static_cast<Base>(*this);
222+
}
223+
224+
// ----------------------------------------------------------------
225+
std::string getName() const final
226+
{
227+
return P::sKey;
228+
}
229+
230+
// ----------------------------------------------------------------
231+
// get the provenace of the member with given key
232+
EParamProvenance getMemberProvenance(const std::string& key) const final
233+
{
234+
return getProvenance(getName() + '.' + key);
235+
}
236+
237+
// ----------------------------------------------------------------
238+
239+
// one of the key methods, using introspection to print itself
240+
void printKeyValues(bool showProv = true, bool useLogger = false) const final
241+
{
242+
if (!isInitialized()) {
243+
initialize();
244+
}
245+
auto members = getDataMembers();
246+
_ParamHelper::printMembersImpl(getName(), members, showProv, useLogger);
247+
}
248+
249+
//
250+
size_t getHash() const final
251+
{
252+
return _ParamHelper::getHashImpl(getName(), getDataMembers());
253+
}
254+
255+
// ----------------------------------------------------------------
256+
257+
void output(std::ostream& out) const final
258+
{
259+
auto members = getDataMembers();
260+
_ParamHelper::outputMembersImpl(out, getName(), members, true, false);
261+
}
262+
263+
// ----------------------------------------------------------------
264+
265+
// Grab the list of ConfigurableParam data members
266+
// Returns a nullptr if the TClass of the P template class cannot be created.
267+
std::vector<ParamDataMember>* getDataMembers() const
268+
{
269+
// just a helper line to make sure P::sInstance is looked-up
270+
// and that compiler complains about missing static sInstance of type P
271+
// volatile void* ptr = (void*)&P::sInstance;
272+
// static assert on type of sInstance:
273+
static_assert(std::is_same<decltype(P::sInstance), P>::value,
274+
"static instance must of same type as class");
275+
276+
// obtain the TClass for the Base type and delegate further
277+
auto cl = TClass::GetClass(typeid(Base));
278+
if (!cl) {
279+
_ParamHelper::printWarning(typeid(Base));
280+
return nullptr;
281+
}
282+
283+
// we need to put an offset of 8 bytes since internally this is using data members of the Base class
284+
// which doesn't account for the virtual table of P
285+
return _ParamHelper::getDataMembersImpl(getName(), cl, (void*)this, sValueProvenanceMap, 8);
286+
}
287+
288+
// ----------------------------------------------------------------
289+
290+
// fills the data structures with the initial default values
291+
void putKeyValues(boost::property_tree::ptree* tree) final
292+
{
293+
auto cl = TClass::GetClass(typeid(Base));
294+
if (!cl) {
295+
_ParamHelper::printWarning(typeid(Base));
296+
return;
297+
}
298+
_ParamHelper::fillKeyValuesImpl(getName(), cl, (void*)this, tree, sKeyToStorageMap, sEnumRegistry, 8);
299+
}
300+
301+
// ----------------------------------------------------------------
302+
303+
void initFrom(TFile* file) final
304+
{
305+
// switch off auto registering since the readback object is
306+
// only a "temporary" singleton
307+
setRegisterMode(false);
308+
P* readback = nullptr;
309+
file->GetObject(getName().c_str(), readback);
310+
if (readback != nullptr) {
311+
_ParamHelper::assignmentImpl(getName(), TClass::GetClass(typeid(Base)), (void*)this, (void*)readback,
312+
sValueProvenanceMap, 8);
313+
delete readback;
314+
}
315+
setRegisterMode(true);
316+
}
317+
318+
// ----------------------------------------------------------------
319+
320+
void syncCCDBandRegistry(void* externalobj) final
321+
{
322+
// We may be getting an external copy from CCDB which is passed as externalobj.
323+
// The task of this function is to
324+
// a) update the internal registry with fields coming from CCDB
325+
// but only if keys have not been modified via RT == command line / ini file
326+
// b) update the external object with with fields having RT provenance
327+
//
328+
setRegisterMode(false);
329+
_ParamHelper::syncCCDBandRegistry(getName(), TClass::GetClass(typeid(Base)), (void*)this, (void*)externalobj,
330+
sValueProvenanceMap, 8);
189331
setRegisterMode(true);
190332
}
191333

Common/Utils/src/ConfigurableParamHelper.cxx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,19 @@ std::string asString(TDataMember const& dm, char* pointer)
182182
// potentially other cases to be added here
183183

184184
LOG(error) << "COULD NOT REPRESENT AS STRING";
185-
return nullptr;
185+
return std::string();
186186
}
187187

188188
// ----------------------------------------------------------------------
189189

190190
std::vector<ParamDataMember>* _ParamHelper::getDataMembersImpl(std::string const& mainkey, TClass* cl, void* obj,
191-
std::map<std::string, ConfigurableParam::EParamProvenance> const* provmap)
191+
std::map<std::string, ConfigurableParam::EParamProvenance> const* provmap, size_t globaloffset)
192192
{
193193
std::vector<ParamDataMember>* members = new std::vector<ParamDataMember>;
194194

195-
auto toDataMember = [&members, obj, mainkey, provmap](const TDataMember* dm, int index, int size) {
195+
auto toDataMember = [&members, obj, mainkey, provmap, globaloffset](const TDataMember* dm, int index, int size) {
196196
auto TS = getSizeOfUnderlyingType(*dm);
197-
char* pointer = ((char*)obj) + dm->GetOffset() + index * TS;
197+
char* pointer = ((char*)obj) + dm->GetOffset() + index * TS + globaloffset;
198198
const std::string name = getName(dm, index, size);
199199
auto value = asString(*dm, pointer);
200200

@@ -280,14 +280,14 @@ std::type_info const& nameToTypeInfo(const char* tname, TDataType const* dt)
280280

281281
void _ParamHelper::fillKeyValuesImpl(std::string const& mainkey, TClass* cl, void* obj, boost::property_tree::ptree* tree,
282282
std::map<std::string, std::pair<std::type_info const&, void*>>* keytostoragemap,
283-
EnumRegistry* enumRegistry)
283+
EnumRegistry* enumRegistry, size_t globaloffset)
284284
{
285285
boost::property_tree::ptree localtree;
286-
auto fillMap = [obj, &mainkey, &localtree, &keytostoragemap, &enumRegistry](const TDataMember* dm, int index, int size) {
286+
auto fillMap = [obj, &mainkey, &localtree, &keytostoragemap, &enumRegistry, globaloffset](const TDataMember* dm, int index, int size) {
287287
const auto name = getName(dm, index, size);
288288
auto dt = dm->GetDataType();
289289
auto TS = getSizeOfUnderlyingType(*dm);
290-
char* pointer = ((char*)obj) + dm->GetOffset() + index * TS;
290+
char* pointer = ((char*)obj) + dm->GetOffset() + index * TS + globaloffset;
291291
localtree.put(name, asString(*dm, pointer));
292292

293293
auto key = mainkey + "." + name;
@@ -355,14 +355,14 @@ bool isMemblockDifferent(char const* block1, char const* block2, int sizeinbytes
355355
// ----------------------------------------------------------------------
356356

357357
void _ParamHelper::assignmentImpl(std::string const& mainkey, TClass* cl, void* to, void* from,
358-
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap)
358+
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap, size_t globaloffset)
359359
{
360-
auto assignifchanged = [to, from, &mainkey, provmap](const TDataMember* dm, int index, int size) {
360+
auto assignifchanged = [to, from, &mainkey, provmap, globaloffset](const TDataMember* dm, int index, int size) {
361361
const auto name = getName(dm, index, size);
362362
auto dt = dm->GetDataType();
363363
auto TS = getSizeOfUnderlyingType(*dm);
364-
char* pointerto = ((char*)to) + dm->GetOffset() + index * TS;
365-
char* pointerfrom = ((char*)from) + dm->GetOffset() + index * TS;
364+
char* pointerto = ((char*)to) + dm->GetOffset() + index * TS + globaloffset;
365+
char* pointerfrom = ((char*)from) + dm->GetOffset() + index * TS + globaloffset;
366366

367367
// lambda to update the provenance
368368
auto updateProv = [&mainkey, name, provmap]() {
@@ -402,14 +402,14 @@ void _ParamHelper::assignmentImpl(std::string const& mainkey, TClass* cl, void*
402402
// ----------------------------------------------------------------------
403403

404404
void _ParamHelper::syncCCDBandRegistry(const std::string& mainkey, TClass* cl, void* to, void* from,
405-
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap)
405+
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap, size_t globaloffset)
406406
{
407-
auto sync = [to, from, &mainkey, provmap](const TDataMember* dm, int index, int size) {
407+
auto sync = [to, from, &mainkey, provmap, globaloffset](const TDataMember* dm, int index, int size) {
408408
const auto name = getName(dm, index, size);
409409
auto dt = dm->GetDataType();
410410
auto TS = getSizeOfUnderlyingType(*dm);
411-
char* pointerto = ((char*)to) + dm->GetOffset() + index * TS;
412-
char* pointerfrom = ((char*)from) + dm->GetOffset() + index * TS;
411+
char* pointerto = ((char*)to) + dm->GetOffset() + index * TS + globaloffset;
412+
char* pointerfrom = ((char*)from) + dm->GetOffset() + index * TS + globaloffset;
413413

414414
// check current provenance
415415
auto key = mainkey + "." + name;

Generators/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,15 @@ if(doBuildSimulation)
129129
COMPONENT_NAME Generator
130130
LABELS generator
131131
PUBLIC_LINK_LIBRARIES O2::Generators)
132+
133+
o2_add_test(GeneratorPythia8Param NAME test_Generator_test_GeneratorPythia8Param
134+
SOURCES test/test_GeneratorPythia8Param.cxx
135+
COMPONENT_NAME Generator
136+
LABELS generator
137+
PUBLIC_LINK_LIBRARIES O2::Generators)
132138
endif()
133139

140+
134141
o2_add_test_root_macro(share/external/tgenerator.C
135142
PUBLIC_LINK_LIBRARIES O2::Generators
136143
LABELS generators)

Generators/include/Generators/GeneratorPythia8Param.h

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,21 @@ namespace eventgen
2424
{
2525

2626
/**
27-
** a parameter class/struct to keep the settings of
28-
** the Pythia8 event generator and
29-
** allow the user to modify them
27+
** a parameter class/struct to configure the settings of
28+
** the GeneratorPythia8 event generator
3029
**/
31-
32-
struct GeneratorPythia8Param : public o2::conf::ConfigurableParamHelper<GeneratorPythia8Param> {
30+
struct Pythia8GenConfig {
3331
std::string config = "";
3432
std::string hooksFileName = "";
3533
std::string hooksFuncName = "";
3634
bool includePartonEvent = false; // whether to keep the event before hadronization
3735
std::string particleFilter = ""; // user particle filter
3836
int verbose = 0; // verbose control (if > 0 may show more info messages about what is going on)
39-
O2ParamDef(GeneratorPythia8Param, "GeneratorPythia8");
4037
};
4138

42-
struct Pythia8GenConfig {
43-
std::string config = "";
44-
std::string hooksFileName = "";
45-
std::string hooksFuncName = "";
46-
bool includePartonEvent = false; // whether to keep the event before hadronization
47-
std::string particleFilter = ""; // user particle filter
48-
int verbose = 0; // verbose control (if > 0 may show more info messages about what is going on)
39+
// construct a configurable param singleton out of the Pythia8GenConfig struct
40+
struct GeneratorPythia8Param : public o2::conf::ConfigurableParamPromoter<GeneratorPythia8Param, Pythia8GenConfig> {
41+
O2ParamDef(GeneratorPythia8Param, "GeneratorPythia8");
4942
};
5043

5144
} // end namespace eventgen

0 commit comments

Comments
 (0)