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 Add these lines in your plugin:
0164
0165 ```cpp
0166 // Place this at the top of the processor header file (e.g. DaveTestProcessor.h)
0167 #include <edm4eic/Cluster.h>
0168
0169 // Place this in the body of the class definition of the processor header file
0170 TH1D* hRecClusterEnergy = nullptr;
0171
0172 // Place this in the InitWithGlobalRootLock() method in the processor implementation
0173 // file (e.g. DaveTestProcessor.cc)
0174 hRecClusterEnergy = new TH1D("hRecClusterEnergy", "EcalEndcapNIslandClusters energy (MeV)", 250, 0.0, 400.0);
0175
0176 // Place this in the ProcessSequential method of the same file
0177 const auto &clusters = *static_cast<const edm4eic::ClusterCollection*>(event->GetCollectionBase("EcalEndcapNIslandClusters"));
0178 for (auto cluster : clusters) hRecClusterEnergy->Fill(cluster.getEnergy() / dd4hep::MeV);
0179 ```
0180
0181 Run some events through and have a look at the result. Here is what this looks like
0182 for the file:
0183 [https://eicaidata.s3.amazonaws.com/2022-09-04_pgun_e-_podio-0.15_edm4hep-0.6_0-30GeV_alldir_1k.edm4hep.root]()
0184
0185 
0186
0187 ## Generic algorithms
0188 For EPIC, we have as a goal to use generic algorithms that are framework unaware.
0189 Thus, for these algorithms the _JFactory_ classes will serve as a layer to JANA
0190 for these generic algorithm classes.
0191
0192 At this point in time, the generic algorithms that `EICrecon` uses are being kept in the
0193 `EICrecon` repository. Work is ongoing in a separate repository that is
0194 planned to host these in the future, but that is being deferred until after the
0195 initial simulation campaign.
0196
0197 To see an example of how a generic algorithm is being implemented, look at these
0198 files:
0199
0200
0201 [src/detectors/EEMC/RawCalorimeterHit_factory_EcalEndcapNRawHits.h]()<br/>
0202 [src/algorithms/calorimetry/CalorimeterHitDigi.h]()<br/>
0203 [src/algorithms/calorimetry/CalorimeterHitDigi.cc]()<br/>
0204
0205
0206 Using generic algorithms requires additional classes and so makes things
0207 slightly more complex. However, the generic algorithms can be recycled
0208 for use in multiple detector systems which adds some simplification.