Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to create configurable param from a given external struct #13733

Merged
merged 1 commit into from
Nov 26, 2024
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
24 changes: 13 additions & 11 deletions Common/Utils/include/CommonUtils/ConfigurableParam.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,17 +321,19 @@ class ConfigurableParam
} // end namespace o2

// a helper macro for boilerplate code in parameter classes
#define O2ParamDef(classname, key) \
public: \
classname(TRootIOCtor*) {} \
classname(classname const&) = delete; \
\
private: \
static constexpr char const* const sKey = key; \
static classname sInstance; \
classname() = default; \
template <typename T> \
friend class o2::conf::ConfigurableParamHelper;
#define O2ParamDef(classname, key) \
public: \
classname(TRootIOCtor*) {} \
classname(classname const&) = delete; \
\
private: \
static constexpr char const* const sKey = key; \
static classname sInstance; \
classname() = default; \
template <typename T> \
friend class o2::conf::ConfigurableParamHelper; \
template <typename T, typename P> \
friend class o2::conf::ConfigurableParamPromoter;

// a helper macro to implement necessary symbols in source
#define O2ParamImpl(classname) classname classname::sInstance;
Expand Down
158 changes: 150 additions & 8 deletions Common/Utils/include/CommonUtils/ConfigurableParamHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ class _ParamHelper
{
private:
static std::vector<ParamDataMember>* getDataMembersImpl(std::string const& mainkey, TClass* cl, void*,
std::map<std::string, ConfigurableParam::EParamProvenance> const* provmap);
std::map<std::string, ConfigurableParam::EParamProvenance> const* provmap, size_t virtualoffset);

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

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

static void assignmentImpl(std::string const& mainkey, TClass* cl, void* to, void* from,
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap);
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap, size_t offset);
static void syncCCDBandRegistry(std::string const& mainkey, TClass* cl, void* to, void* from,
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap);
std::map<std::string, ConfigurableParam::EParamProvenance>* provmap, size_t offset);

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

template <typename P>
friend class ConfigurableParamHelper;

template <typename Base, typename P>
friend class ConfigurableParamPromoter;
};

// ----------------------------------------------------------------
Expand Down Expand Up @@ -140,7 +143,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
return nullptr;
}

return _ParamHelper::getDataMembersImpl(getName(), cl, (void*)this, sValueProvenanceMap);
return _ParamHelper::getDataMembersImpl(getName(), cl, (void*)this, sValueProvenanceMap, 0);
}

// ----------------------------------------------------------------
Expand All @@ -153,7 +156,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
_ParamHelper::printWarning(typeid(P));
return;
}
_ParamHelper::fillKeyValuesImpl(getName(), cl, (void*)this, tree, sKeyToStorageMap, sEnumRegistry);
_ParamHelper::fillKeyValuesImpl(getName(), cl, (void*)this, tree, sKeyToStorageMap, sEnumRegistry, 0);
}

// ----------------------------------------------------------------
Expand All @@ -167,7 +170,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
file->GetObject(getName().c_str(), readback);
if (readback != nullptr) {
_ParamHelper::assignmentImpl(getName(), TClass::GetClass(typeid(P)), (void*)this, (void*)readback,
sValueProvenanceMap);
sValueProvenanceMap, 0);
delete readback;
}
setRegisterMode(true);
Expand All @@ -185,7 +188,146 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
//
setRegisterMode(false);
_ParamHelper::syncCCDBandRegistry(getName(), TClass::GetClass(typeid(P)), (void*)this, (void*)externalobj,
sValueProvenanceMap);
sValueProvenanceMap, 0);
setRegisterMode(true);
}

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

void serializeTo(TFile* file) const final
{
file->WriteObjectAny((void*)this, TClass::GetClass(typeid(P)), getName().c_str());
}
};

// Promotes a simple struct Base to a configurable parameter class
// Aka implements all interfaces for a ConfigurableParam P, which shares or
// takes the fields from a Base struct
template <typename P, typename Base>
class ConfigurableParamPromoter : public Base, virtual public ConfigurableParam
{
public:
using ConfigurableParam::ConfigurableParam;

static const P& Instance()
{
return P::sInstance;
}

// extracts a copy of the underlying data struct
Base detach() const
{
static_assert(std::copyable<Base>, "Base type must be copyable.");
return static_cast<Base>(*this);
}

// ----------------------------------------------------------------
std::string getName() const final
{
return P::sKey;
}

// ----------------------------------------------------------------
// get the provenace of the member with given key
EParamProvenance getMemberProvenance(const std::string& key) const final
{
return getProvenance(getName() + '.' + key);
}

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

// one of the key methods, using introspection to print itself
void printKeyValues(bool showProv = true, bool useLogger = false) const final
{
if (!isInitialized()) {
initialize();
}
auto members = getDataMembers();
_ParamHelper::printMembersImpl(getName(), members, showProv, useLogger);
}

//
size_t getHash() const final
{
return _ParamHelper::getHashImpl(getName(), getDataMembers());
}

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

void output(std::ostream& out) const final
{
auto members = getDataMembers();
_ParamHelper::outputMembersImpl(out, getName(), members, true, false);
}

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

// Grab the list of ConfigurableParam data members
// Returns a nullptr if the TClass of the P template class cannot be created.
std::vector<ParamDataMember>* getDataMembers() const
{
// just a helper line to make sure P::sInstance is looked-up
// and that compiler complains about missing static sInstance of type P
// volatile void* ptr = (void*)&P::sInstance;
// static assert on type of sInstance:
static_assert(std::is_same<decltype(P::sInstance), P>::value,
"static instance must of same type as class");

// obtain the TClass for the Base type and delegate further
auto cl = TClass::GetClass(typeid(Base));
if (!cl) {
_ParamHelper::printWarning(typeid(Base));
return nullptr;
}

// we need to put an offset of 8 bytes since internally this is using data members of the Base class
// which doesn't account for the virtual table of P
return _ParamHelper::getDataMembersImpl(getName(), cl, (void*)this, sValueProvenanceMap, 8);
}

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

// fills the data structures with the initial default values
void putKeyValues(boost::property_tree::ptree* tree) final
{
auto cl = TClass::GetClass(typeid(Base));
if (!cl) {
_ParamHelper::printWarning(typeid(Base));
return;
}
_ParamHelper::fillKeyValuesImpl(getName(), cl, (void*)this, tree, sKeyToStorageMap, sEnumRegistry, 8);
}

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

void initFrom(TFile* file) final
{
// switch off auto registering since the readback object is
// only a "temporary" singleton
setRegisterMode(false);
P* readback = nullptr;
file->GetObject(getName().c_str(), readback);
if (readback != nullptr) {
_ParamHelper::assignmentImpl(getName(), TClass::GetClass(typeid(Base)), (void*)this, (void*)readback,
sValueProvenanceMap, 8);
delete readback;
}
setRegisterMode(true);
}

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

void syncCCDBandRegistry(void* externalobj) final
{
// We may be getting an external copy from CCDB which is passed as externalobj.
// The task of this function is to
// a) update the internal registry with fields coming from CCDB
// but only if keys have not been modified via RT == command line / ini file
// b) update the external object with with fields having RT provenance
//
setRegisterMode(false);
_ParamHelper::syncCCDBandRegistry(getName(), TClass::GetClass(typeid(Base)), (void*)this, (void*)externalobj,
sValueProvenanceMap, 8);
setRegisterMode(true);
}

Expand Down
30 changes: 15 additions & 15 deletions Common/Utils/src/ConfigurableParamHelper.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,19 @@ std::string asString(TDataMember const& dm, char* pointer)
// potentially other cases to be added here

LOG(error) << "COULD NOT REPRESENT AS STRING";
return nullptr;
return std::string();
}

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

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

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

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

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

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

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

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

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

// check current provenance
auto key = mainkey + "." + name;
Expand Down
7 changes: 7 additions & 0 deletions Generators/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,15 @@ if(doBuildSimulation)
COMPONENT_NAME Generator
LABELS generator
PUBLIC_LINK_LIBRARIES O2::Generators)

o2_add_test(GeneratorPythia8Param NAME test_Generator_test_GeneratorPythia8Param
SOURCES test/test_GeneratorPythia8Param.cxx
COMPONENT_NAME Generator
LABELS generator
PUBLIC_LINK_LIBRARIES O2::Generators)
endif()


o2_add_test_root_macro(share/external/tgenerator.C
PUBLIC_LINK_LIBRARIES O2::Generators
LABELS generators)
Expand Down
19 changes: 6 additions & 13 deletions Generators/include/Generators/GeneratorPythia8Param.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,21 @@ namespace eventgen
{

/**
** a parameter class/struct to keep the settings of
** the Pythia8 event generator and
** allow the user to modify them
** a parameter class/struct to configure the settings of
** the GeneratorPythia8 event generator
**/

struct GeneratorPythia8Param : public o2::conf::ConfigurableParamHelper<GeneratorPythia8Param> {
struct Pythia8GenConfig {
std::string config = "";
std::string hooksFileName = "";
std::string hooksFuncName = "";
bool includePartonEvent = false; // whether to keep the event before hadronization
std::string particleFilter = ""; // user particle filter
int verbose = 0; // verbose control (if > 0 may show more info messages about what is going on)
O2ParamDef(GeneratorPythia8Param, "GeneratorPythia8");
};

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

} // end namespace eventgen
Expand Down
Loading
Loading