Back to home page

EIC code displayed by LXR

 
 

    


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 ![EcalEndcapNIslandClusters energy](EcalEndcapNIslandClusters_energy.png)
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.