Warning, /EICrecon/docs/howto/add_factory.md is written in an unsupported language. File is not indexed.
0001 # Notice
0002
0003 **This section of the tutorial is outdated due to switch from `JFactory` to `JOmniFactory`. Refer to a [tutorial on reconstruction algorithms](https://eic.github.io/tutorial-reconstruction-algorithms/) for up-to-date information.**
0004
0005 # Adding a reconstruction algorithm to EICrecon
0006
0007 In JANA, algorithms are kept in `JFactory` classes. These are the classes that
0008 interact with the JANA framework to match requests for certain objects or
0009 collections with the algorithm that produces them.
0010
0011
0012 ## Creating a new factory
0013 For this example, we will create a factory that takes reconstructed
0014 `edm4eic::ProtoCluster` objects from the collection `EcalEndcapNIslandProtoClusters`
0015 and will create objects of type `edm4eic::Cluster` with collection name
0016 `EcalEndcapNIslandClusters`.
0017
0018 To start with, create a file in the `EICrecon` source tree called:
0019 ~~~
0020 src/detectors/EEMC/Cluster_factory_EcalEndcapNIslandClusters.h
0021 ~~~
0022 Edit the file to have these contents:
0023
0024 ```cpp
0025 #pragma once
0026
0027 #include <cmath>
0028
0029 #include <JANA/JEvent.h>
0030 #include <JANA/JFactoryT.h>
0031 #include <edm4eic/ClusterCollection.h>
0032 #include <edm4eic/ProtoClusterCollection.h>
0033
0034 class Cluster_factory_EcalEndcapNIslandClusters : public JFactoryT<edm4eic::Cluster> {
0035 public:
0036 //------------------------------------------
0037 // Constructor
0038 Cluster_factory_EcalEndcapNIslandClusters(){
0039 SetTag("EcalEndcapNIslandClusters");
0040 }
0041
0042 //------------------------------------------
0043 // Init
0044 void Init() override{
0045 auto m_app = GetApplication();
0046
0047 // This is an example of how to declare a configuration parameter that
0048 // can be set at run time. e.g. with -PEEMC:EcalEndcapNIslandClusters:scaleFactor=0.97
0049 m_scaleFactor =0.98;
0050 m_app->SetDefaultParameter("EEMC:EcalEndcapNIslandClusters:scaleFactor", m_scaleFactor, "Energy scale factor");
0051 }
0052
0053 //------------------------------------------
0054 // Process
0055 void Process(const std::shared_ptr<const JEvent> &event) override{
0056
0057 // Grab inputs
0058 const auto &protoclusters = *static_cast<const edm4eic::ProtoClusterCollection*>(event->GetCollectionBase("EcalEndcapNIslandProtoClusters"));
0059
0060 // Loop over protoclusters and turn each into a cluster
0061 std::vector<edm4eic::Cluster*> outputClusters;
0062 for( auto proto : protoclusters ) {
0063
0064 // Fill cumulative values by looping over all hits in proto cluster
0065 float energy = 0;
0066 double energyError_squared = 0.0;
0067 float time = 1.0E8;
0068 float timeError;
0069 edm4hep::Vector3f position;
0070 double sum_weights = 0.0;
0071 for( uint32_t ihit=0; ihit<proto.hits_size() ; ihit++){
0072 auto const &hit = proto.getHits(ihit);
0073 auto weight = proto.getWeights(ihit);
0074 energy += hit.getEnergy();
0075 energyError_squared += std::pow(hit.getEnergyError(), 2.0);
0076 if( hit.getTime() < time ){
0077 time = hit.getTime(); // use earliest time
0078 timeError = hit.getTimeError(); // use error of earliest time
0079 }
0080 auto &p = hit.getPosition();
0081 position.x += p.x*weight;
0082 position.y += p.y*weight;
0083 position.z += p.z*weight;
0084 sum_weights += weight;
0085 }
0086
0087 // Normalize position
0088 position.x /= sum_weights;
0089 position.y /= sum_weights;
0090 position.z /= sum_weights;
0091
0092 // Create a cluster object from values accumulated from hits above
0093 auto cluster = new edm4eic::Cluster(
0094 0, // type (?))
0095 energy * m_scaleFactor,
0096 sqrt(energyError_squared),
0097 time,
0098 timeError,
0099 proto.hits_size(),
0100 position,
0101
0102 // Not sure how to calculate these last few
0103 edm4eic::Cov3f(), // positionError,
0104 0.0, // intrinsicTheta,
0105 0.0, // intrinsicPhi,
0106 edm4eic::Cov2f() // intrinsicDirectionError
0107 );
0108
0109 outputClusters.push_back( cluster );
0110 }
0111
0112 // Hand ownership of algorithm objects over to JANA
0113 Set(outputClusters);
0114 }
0115
0116 private:
0117 float m_scaleFactor;
0118 };
0119 ```
0120
0121 For the above algorithm to be available in JANA to other factories or plugins,
0122 you will need to add a `JFactoryGeneratorT` object for it. Do this by editing
0123 the file named for the source directory in which it resides. In this example,
0124 because the above file will live in _src/detectors/EEMC_, edit the file
0125 __src/detectors/EEMC/EEMC.cc_. It should look something like the following where
0126 the last `include` line and the last _app->Add(...)_ line have been added to
0127 declare the new factory.
0128
0129 ```cpp
0130 // Copyright 2022, David Lawrence
0131 // Subject to the terms in the LICENSE file found in the top-level directory.
0132 //
0133 //
0134
0135 #include <JANA/JApplication.h>
0136 #include <JANA/JFactoryGenerator.h>
0137
0138
0139 #include "RawCalorimeterHit_factory_EcalEndcapNRawHits.h"
0140 #include "CalorimeterHit_factory_EcalEndcapNRecHits.h"
0141 #include "ProtoCluster_factory_EcalEndcapNTruthProtoClusters.h"
0142 #include "ProtoCluster_factory_EcalEndcapNIslandProtoClusters.h"
0143 #include "Cluster_factory_EcalEndcapNClusters.h"
0144 #include "Cluster_factory_EcalEndcapNMergedClusters.h"
0145 #include "Cluster_factory_EcalEndcapNIslandClusters.h"
0146
0147 extern "C" {
0148 void InitPlugin(JApplication *m_app) {
0149 InitJANAPlugin(m_app);
0150 m_app->Add(new JFactoryGeneratorT<RawCalorimeterHit_factory_EcalEndcapNRawHits>());
0151 m_app->Add(new JFactoryGeneratorT<CalorimeterHit_factory_EcalEndcapNRecHits>());
0152 m_app->Add(new JFactoryGeneratorT<ProtoCluster_factory_EcalEndcapNTruthProtoClusters>());
0153 m_app->Add(new JFactoryGeneratorT<ProtoCluster_factory_EcalEndcapNIslandProtoClusters>());
0154 m_app->Add(new JFactoryGeneratorT<Cluster_factory_EcalEndcapNClusters>());
0155 m_app->Add(new JFactoryGeneratorT<Cluster_factory_EcalEndcapNMergedClusters>());
0156 m_app->Add(new JFactoryGeneratorT<Cluster_factory_EcalEndcapNIslandClusters>());
0157 }
0158 }
0159 ```
0160
0161 ## Testing the new factory
0162
0163 Please follow the instructions on [creating a user plugin](HowTo_make_plugin.md)
0164 to get a working plugin. Then add these lines in the inidacted places:
0165
0166 ```cpp
0167 // Place this at the top of the processor header file (e.g. DaveTestProcessor.h)
0168 #include <edm4eic/Cluster.h>
0169
0170 // Place this in the body of the class definition of the processor header file
0171 TH1D* hRecClusterEnergy = nullptr;
0172
0173 // Place this in the InitWithGlobalRootLock() method in the processor implementation
0174 // file (e.g. DaveTestProcessor.cc)
0175 hRecClusterEnergy = new TH1D("hRecClusterEnergy", "EcalEndcapNIslandClusters energy (MeV)", 250, 0.0, 400.0);
0176
0177 // Place this in the ProcessSequential method of the same file
0178 const auto &clusters = *static_cast<const edm4eic::ClusterCollection*>(event->GetCollectionBase("EcalEndcapNIslandClusters"));
0179 for (auto cluster : clusters) hRecClusterEnergy->Fill(cluster.getEnergy() / dd4hep::MeV);
0180 ```
0181
0182 Run some events through and have a look at the result. Here is what this looks like
0183 for the file:
0184 [https://eicaidata.s3.amazonaws.com/2022-09-04_pgun_e-_podio-0.15_edm4hep-0.6_0-30GeV_alldir_1k.edm4hep.root]()
0185
0186 ![EcalEndcapNIslandClusters energy](EcalEndcapNIslandClusters_energy.png)
0187
0188 ## Generic algorithms
0189 For EPIC, we have as a goal to use generic algorithms that are framework unaware.
0190 Thus, for these algorithms the _JFactory_ classes will serve as a layer to JANA
0191 for these generic algorithm classes.
0192
0193 At this point in time, the generic algorithms that `EICrecon` uses are being kept in the
0194 `EICrecon` repository. Work is ongoing in a separate repository that is
0195 planned to host these in the future, but that is being deferred until after the
0196 initial simulation campaign.
0197
0198 To see an example of how a generic algorithm is being implemented, look at these
0199 files:
0200
0201
0202 [src/detectors/EEMC/RawCalorimeterHit_factory_EcalEndcapNRawHits.h]()<br/>
0203 [src/algorithms/calorimetry/CalorimeterHitDigi.h]()<br/>
0204 [src/algorithms/calorimetry/CalorimeterHitDigi.cc]()<br/>
0205
0206
0207 Using generic algorithms requires additional classes and so makes things
0208 slightly more complex. However, the generic algorithms can be recycled
0209 for use in multiple detector systems which adds some simplification.