Skip to content

Commit acbc6a8

Browse files
committed
Add README for ConfigurableParam + minor refactoring/cleanup
* a MarkDown README * fix typos * make singleton const/readonly access * in consequence, use HallParam as `struct` which should much more friendly to use/access.
1 parent 1573020 commit acbc6a8

File tree

5 files changed

+128
-29
lines changed

5 files changed

+128
-29
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Configurable Parameters
2+
3+
This is a short README for configurable parameters as offered by
4+
the ConfigurableParameter class.
5+
6+
# Introduction
7+
8+
The ConfigurableParameter class implements the demand
9+
* to have simple variables (under a compound namespace) be declared as 'knobs'
10+
of an algorithm in order to be able to change/configure their value without recompilation.
11+
* to have such declared variables be automatically registered in a parameter database or manager instance.
12+
* to be able to configure/change the parameter values in a textual way (for instance from the command line)
13+
* to provide automatic serialization / deserialization techniques (to text files or binary blobs) -- for instance to load from CCDB or to pass along parameter snapshots to other processing stages.
14+
* to keep track of who changes parameters (provenance tracking).
15+
16+
# Example / HowTo:
17+
18+
Imagine some algorithms `algorithmA` depends on 2 parameters `p1` and `p2` which you want to be able to configure.
19+
20+
You would do two steps:
21+
1. Declare a parameter class listing the parameters and their default values.
22+
```c++
23+
struct ParamA : ConfigurableParamHelper<ParamA> {
24+
int p1 = 10;
25+
double p2 = 1.23;
26+
// boilerplate stuff + make parameters known under key "A"
27+
O2ParamDef(ParamA, "A");
28+
};
29+
2. Access and use the parameters in the code.
30+
```c++
31+
void algorithmA() {
32+
// get the parameter singleton object
33+
auto& pa = ParamA::Instance();
34+
// access the variables in your code
35+
doSomething(pa.p1, pa.p2);
36+
}
37+
```
38+
39+
Thereafter, the parameter `ParamA` is automatically registered in a parameter registry and can be read/influenced/serialized through this. The main influencing functions are implemented as static functions on the `ConfigurableParam` class. For example, the following things will be possible:
40+
* get a value by string key, addressing a specific parameter:
41+
```
42+
auto p = ConfigurableParam::getValue<double>("A.p2");
43+
```
44+
where the string keys are composed of a primary key and the variable name of the parameter.
45+
* set/modify a value by a key string
46+
```
47+
ConfigurableParam::setValue<double>("A.p2", 10);
48+
```
49+
where the string keys are composed of a primary key and the variable name of the parameter.
50+
Side note: This API allows to influence values from a string, for instance obtained from command line:
51+
```
52+
ConfigurableParam::fromString("A.p2=10,OtherParam.a=-1.");
53+
```
54+
The system will complain if a non-existing string key is used.
55+
56+
* serialize the configuration to a ROOT snapshot or to formats such as JSON or INI
57+
```
58+
ConfigurableParam::toINI(filename);
59+
ConfigurableParam::toJSON(filename); // JSON repr. of param registry
60+
ConfigurableParam::toCCDB(filename); // CCDB snapshot of param registry
61+
```
62+
* retrieve parameters from CCDB snapshot
63+
```
64+
ConfigurableParam::fromCCDB(filename);
65+
```
66+
* **Provenance tracking**: The system can keep track of the origin of values. Typically, few stages of modification can be done:
67+
- default initialization of parameters from code (CODE)
68+
- initialization/overwritting from a (CCDB) snapshot file
69+
- overriding by user during runtime (RT)
70+
71+
The registry can keep track of who supplied the current (decisive) value for each parameter: CODE, CCDB or RT. If a parameter is not changed it keeps the state of the previous stage.
72+
73+
# Further technical details
74+
75+
* Parameter classes are **read-only** singleton classes/structs. As long as the user follows the pattern to inherit from `ConfigurableParamHelper<T>` and to use the macro `O2ParamDef()` everything is implemented automatically.
76+
* We use the `ROOT C++` introspection facility to map the class layout to a textual configuration. Hence ROOT dictionaries are needed for parameter classes.
77+
* BOOST property trees are used for the mapping to JSON/INI files but this is an internal detail and might change in future.
78+
79+
# Limitations
80+
81+
* Parameter classes may only contain simple members! Currently the following types are supported
82+
* simple pods (for example `double x; char y;`)
83+
* simple char strings (`char *`)
84+
* fixed size arrays of pods using the ROOT way to serialize:
85+
```c++
86+
static constexpr int N=3; //!
87+
double array[N] = {1, 2, 3}; //[N] -- note the [N] after //!!
88+
```
89+
* array parameters need to be addressed textual with an index operator:
90+
```
91+
ConfigurableParam::fromString("ParamA.array[2]=10");
92+
```
93+
It is planned to offer more flexible ways to set arrays (see below).
94+
* there is currently no support for pointer types or objects. Parameter classes may not be nested.
95+
* At the moment serialization works on the whole paramter registry (on the whole set of parameters). Everything is written to the same file or snapshot.
96+
97+
# Wish list / planned improvements
98+
99+
* Offer a more flexible way to set array types (to represent them in strings), for example
100+
```c++
101+
ConfigurableParam::fromString("ParamA.array = {5, 6, 7}");
102+
```
103+
* Offer a better more flexible way to read from CCDB.
104+
* read from complete snapshots (give single file name) **or** read from different files reciding in paths corresponding to key/namespace.
105+
* Of a more flexible way to serialize, for example allowing to output configuration to different files.
106+
* Be able to change the configuration from a text file (next to current possibility from command line)
107+
* support for few important stl containers (std::array, std::vector)
108+
* a better way to define stages (CODE, CCDB, RT) and to transition between them; potentially more allowed stages
109+
* take away more boilerplate: Automatic creation of dictionaries for parameter classes.

Common/SimConfig/include/SimConfig/ConfigurableParam.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace conf
2727
{
2828
// Base class for a configurable parameter.
2929
//
30-
// A configurable parameter is a simple class, defining
30+
// A configurable parameter (ConfigurableParameter) is a simple class, defining
3131
// a few (pod) properties/members which are registered
3232
// in a global (boost) property tree / structure.
3333
//
@@ -36,7 +36,7 @@ namespace conf
3636
// format via ROOT introspection and boost property trees and
3737
// the possibility to readably save the configuration
3838
// *) Serialization/Deserialization into ROOT binary blobs (for the purpose
39-
// of writing/retrieving parameters from CCDB)
39+
// of writing/retrieving parameters from CCDB and to pass parameters along the processing chain)
4040
// *) Automatic integration of sub-classes into a common configuration
4141
// *) Be able to query properties from high level interfaces (just knowing
4242
// *) Be able to set properties from high-level interfaces (and modifying the underlying
@@ -95,16 +95,18 @@ class ConfigurableParam
9595
return names[(int)p];
9696
}
9797

98-
//
99-
virtual std::string getName() const = 0; // print the name of the configurable Parameter
98+
// get the name of the configurable Parameter
99+
virtual std::string getName() const = 0;
100100

101101
// print the current keys and values to screen (optionally with provenance information)
102102
virtual void printKeyValues(bool showprov = true) const = 0;
103103

104104
static void printAllRegisteredParamNames();
105105
static void printAllKeyValuePairs();
106106

107+
// writes a human readable JSON file of all parameters
107108
static void writeJSON(std::string filename);
109+
// writes a human readable INI file of all parameters
108110
static void writeINI(std::string filename);
109111

110112
// can be used instead of using API on concrete child classes
@@ -143,17 +145,13 @@ class ConfigurableParam
143145
}
144146
}
145147

148+
// initializes the parameter database
146149
static void initialize();
147150

151+
// create CCDB snapsnot
148152
static void toCCDB(std::string filename);
153+
// load from (CCDB) snapshot
149154
static void fromCCDB(std::string filename);
150-
virtual void serializeTo(TFile*) const = 0;
151-
virtual void initFrom(TFile*) = 0;
152-
153-
// allows to provide a file from which to update
154-
// (certain) key-values
155-
// propagates changes down to each registered configuration
156-
static void updateFromFile(std::string filename);
157155

158156
// allows to provide a string of key-values from which to update
159157
// (certain) key-values
@@ -174,6 +172,8 @@ class ConfigurableParam
174172

175173
// fill property tree with the key-values from the sub-classes
176174
virtual void putKeyValues(boost::property_tree::ptree*) = 0;
175+
virtual void serializeTo(TFile*) const = 0;
176+
virtual void initFrom(TFile*) = 0;
177177

178178
// static map keeping, for each configuration key, its memory location and type
179179
// (internal use to easily sync updates, this is ok since parameter classes are singletons)

Common/SimConfig/include/SimConfig/ConfigurableParamHelper.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ConfigurableParamHelper : virtual public ConfigurableParam
5050
{
5151
public:
5252
using ConfigurableParam::ConfigurableParam;
53-
static P& Instance()
53+
static const P& Instance()
5454
{
5555
return P::sInstance;
5656
}

Detectors/Passive/include/DetectorsPassive/HallSimParam.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,22 @@
1313

1414
#include "SimConfig/ConfigurableParam.h"
1515
#include "SimConfig/ConfigurableParamHelper.h"
16-
#include <array>
1716

1817
namespace o2
1918
{
2019
namespace passive
2120
{
2221

23-
class HallSimParam : public o2::conf::ConfigurableParamHelper<HallSimParam>
24-
{
25-
public:
26-
float getCUTGAM() const { return mCUTGAM; }
27-
float getCUTELE() const { return mCUTELE; }
28-
float getCUTNEU() const { return mCUTNEU; }
29-
float getCUTHAD() const { return mCUTHAD; }
30-
31-
private:
22+
struct HallSimParam : public o2::conf::ConfigurableParamHelper<HallSimParam> {
3223
float mCUTGAM = 1.e00;
3324
float mCUTELE = 1.e00;
3425
float mCUTNEU = 1.e-1;
3526
float mCUTHAD = 1.e-3;
36-
static constexpr int N = 3;
37-
int mPos[N] = { 1, 0, -2 }; //[N]
3827

3928
// boilerplate stuff + make principal key "HallSim"
4029
O2ParamDef(HallSimParam, "HallSim");
4130
};
31+
4232
} // namespace passive
4333
} // namespace o2
4434

Detectors/Passive/src/Hall.cxx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,11 @@ void Hall::SetSpecialPhysicsCuts()
112112
auto& matmgr = MaterialManager::Instance();
113113

114114
// \note ported from AliRoot. People responsible for the HALL implementation must judge and modify cuts if required.
115-
auto& hallparam = HallSimParam::Instance();
116-
const auto cutgam = hallparam.getCUTGAM();
117-
const auto cutele = hallparam.getCUTELE();
118-
const auto cutneu = hallparam.getCUTNEU();
119-
const auto cuthad = hallparam.getCUTHAD();
115+
auto& hp = HallSimParam::Instance();
116+
const auto cutgam = hp.mCUTGAM;
117+
const auto cutele = hp.mCUTELE;
118+
const auto cutneu = hp.mCUTNEU;
119+
const auto cuthad = hp.mCUTHAD;
120120

121121
matmgr.SpecialCuts(
122122
"HALL", kSTST_C2,

0 commit comments

Comments
 (0)