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 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.