Warning, /tutorial-reconstruction-algorithms/_episodes/04-parameterizing-a-factory.md is written in an unsupported language. File is not indexed.
0001 ---
0002 title: "Parameterizing a factory"
0003 teaching: 5
0004 exercises: 0
0005 objectives:
0006 - "Learn how to set parameters on a factory"
0007 - "Learn how to override factories via a generator"
0008 - "Learn how to override factories via the command line"
0009 - "Learn how to access services from a factory"
0010 ---
0011
0012 ## Setting parameters on a factory
0013
0014 Parameters are also handled using registered members. JOmniFactory provides a `Parameter` class template which can hold its own value, but in EICrecon we prefer to use Config structs. Thus JOmniFactory provides `ParameterRef`, which stores a reference into the Config object.
0015
0016 ```c++
0017 ParameterRef<double> m_samplingFraction {this, "samplingFraction", config().sampFrac};
0018 ParameterRef<std::string> m_energyWeight {this, "energyWeight", config().energyWeight};
0019 ```
0020
0021 Parameters are fetched immediately before `Init()` is called, so you may access them from any of the callbacks like so:
0022
0023 ```c++
0024 void Process(int64_t run_number, uint64_t event_number) {
0025 logger()->debug( "Event {}: samplingFraction = {}", event_number, m_samplingFraction() );
0026 }
0027
0028 ```
0029 Because we are using ParameterRefs, we can also access the field the ref points to directly:
0030 ```c++
0031 void Process(int64_t run_number, uint64_t event_number) {
0032 logger()->debug( "Event {}: samplingFraction = {}", event_number, config().sampFrac );
0033 }
0034 ```
0035
0036 ## Config objects
0037
0038 We create a plain-old struct to hold our parameters. For now this config struct can live in the same header file as our factory, although eventually it should belong with the algorithm instead.
0039
0040 ```c++
0041 struct ReconstructedElectrons_config {
0042 double threshold = 0.9;
0043 int bucket_count = 4;
0044 // ...
0045 }
0046 ```
0047
0048 By passing it in to the JOmniFactory base class, we can make it automatically available via the `config()` method.
0049
0050 ```c++
0051 class ReconstructedElectrons_factory : public JOmniFactory<ReconstructedElectrons_factory, ElectronReconstructionConfig> {
0052 ...
0053 }
0054 ```
0055
0056
0057 ## Overriding parameters via a generator
0058
0059 If you use a Config object for your parameters, you can pass it in directly to the factory generator:
0060
0061 ```c++
0062 app->Add(new JOmniFactoryGeneratorT<BasicTestAlg>(
0063 "FunTest", {"MyHits"}, {"MyClusters"},
0064 {
0065 .threshold = 6.1,
0066 .bucket_count = 22
0067 },
0068 app));
0069 ```
0070
0071 ## Overriding parameters via the command line
0072
0073 We can override parameters on the command line like so:
0074
0075 ```bash
0076 eicrecon -PFunTest:threshold=12.0 in.root
0077 ```
0078
0079
0080 ## Accessing services from a factory
0081
0082 Services are singletons that provide access to resources such as loggers, geometry, magnetic field maps, etc. Services need to be thread-safe because they are shared by different threads. The most relevant service right now is `DD4hep_service`. You obtain a service using a registered member like this:
0083
0084 ```c++
0085 Service<DD4hep_service> m_geoSvc {this};
0086 ```
0087
0088 Oftentimes we want to retrieve a resource from a Service and refresh it whenever the run number changes. OmniFactory provides `Resource` for this purpose.
0089
0090 > Exercise:
0091 > - Give your factory a Config struct
0092 > - Give your Config struct some parameters
0093 > - Experiment with overriding parameter values in the generator and on the command line.
0094 {: .challenge}