Back to home page

EIC code displayed by LXR

 
 

    


Warning, /tutorial-jana2/_episodes/03-end-user-plugin.md is written in an unsupported language. File is not indexed.

0001 ---
0002 title: "Creating a plugin to make custom histograms/trees"
0003 teaching: 15
0004 exercises: 20
0005 questions:
0006 - "Why should a I make a custom plugin?"
0007 - "How do I create a custom plugin?"
0008 objectives:
0009 - "Understand when one should make a plugin and when they should just use a ROOT macro."
0010 - "Understand how to create a new, stand-alone plugin with your own custom histograms."
0011 keypoints:
0012 - "Plugins can be used to generate custom histograms by attaching directly to the reconstruction process."
0013 - "Plugins can be used for monitoring or custom analysis."
0014 ---
0015 > Note: The following episode presents a somewhat outdated view, and some commands may not function.
0016 > If you are only interested in analyzing already-reconstructed data, then there is no requirement
0017 > to use a plugin as described below; the output ROOT file works too.
0018 {: .callout}
0019 
0020 Plugins are the basic building blocks when it comes to analyzing data.  They request objects and perform actions, such as making histograms, or writing out certain objects to files.  When your plugin requests objects (e.g. clusters) the factory responsible for the requested object is loaded and run (We will dive into factories in the next exciting episode of how to use JANA).  When running EICrecon you will configure it to use some number of plugins (each potentially with their own set of configuration parameters). Now, let us begin constructing a new plugin.
0021 
0022 To do this we will use the eicmkplugin.py script that comes with EICrecon.  This utility should be your "go-to" for jumpstarting your work with EICrecon/JANA when it comes to data. To put eicmkplugin.py in your path, you can do the following:
0023 ~~~
0024 source EICrecon/bin/eicrecon-this.sh
0025 ~~~
0026 
0027 The eickmkplugin script can be called simply by typing: "eicmkplugin.py" followed by the name of the plugin. Let's begin by calling: 
0028 ~~~
0029 eicmkplugin.py  myFirstPlugin 
0030 ~~~
0031 
0032 You should now have terminal output that looks like this:
0033 ~~~
0034 Writing myFirstPlugin/CMakeLists.txt ...
0035 Writing myFirstPlugin/myFirstPluginProcessor.h ...
0036 Writing myFirstPlugin/myFirstPluginProcessor.cc ...
0037 
0038 Created plugin myFirstPlugin.
0039 Build with:
0040 
0041   cmake -S myFirstPlugin -B myFirstPlugin/build
0042   cmake --build myFirstPlugin/build --target install
0043 ~~~
0044 There should now exist a new folder labeled "myPlugin". That directory contains 2 files: a CMakelists.txt file (needed for compiling our new plugin) and the source code for the plugin itself. 
0045 
0046 Inside the source code for your plugin is a fairly simple class.  The private data members should contain the necessary variables to successfully run your plugin;  this will likely include any histograms, canvases, fits or other accoutrement. The public section contains the required Constructor, Init, Process, and Finish functions.  In init we get the application, as well as initialize any variables or histograms, etc.  The Process function typically gets objects from the event and does something with them (e.g. fill the histogram of cluster energy). And finally Finish is called where we clean up and do final things before ending the run of our plugin.
0047 
0048 Before we compile our plugins we need to tell JANA about where the plugins will be found.  Start by setting your EICrecon_MY environment variable to a directory where you have write permission. The build instructions will install the plugin to that directory. When eicrecon is run, it will also look for plugins in the $EICrecon_MY directory and the EICrecon build you are using. This step is easy to overlook but necessary for the plugin to be found once compiled. Let's do this now before we forget:
0049 
0050 ~~~
0051 mkdir EICrecon_MY
0052 export EICrecon_MY=${PWD}/EICrecon_MY
0053 ~~~
0054  
0055 To compile your plugin, let's follow the guidance given and type:
0056 ~~~
0057 cmake -S myFirstPlugin -B myFirstPlugin/build
0058 cmake --build myFirstPlugin/build --target install
0059 ~~~
0060 
0061 You can test plugin installed and can load correctly by runnign eicrecon with it: 
0062 ~~~
0063 eicrecon -Pplugins=myFirstPlugin,JTest -Pjana:nevents=10
0064 ~~~
0065 
0066 The second plugin, JTest, just supplies dummy events, ensuring your plugin is properly compiled and found. To generate your first histograms, let's edit the myFirstPluginProcessor.cc and myFirstPluginProcessor.h files (located in the myFirstPlugin directory). Start by modifying myFirstPluginProcessor.h.  In the end it should look similar to the one below: 
0067 
0068 ```c++
0069 #include <JANA/JEventProcessorSequentialRoot.h>
0070 #include <TH2D.h>
0071 #include <TFile.h>
0072 
0073 #include <edm4hep/SimCalorimeterHit.h>
0074 
0075 class myFirstPluginProcessor: public JEventProcessorSequentialRoot {
0076 private:
0077 
0078     // Data objects we will need from JANA e.g.
0079     PrefetchT<edm4hep::SimCalorimeterHit> rawhits   = {this, "EcalBarrelHits"};
0080 
0081     // Declare histogram and tree pointers here. e.g.
0082     TH1D* hEraw = nullptr;
0083 
0084 public:
0085     myFirstPluginProcessor() { SetTypeName(NAME_OF_THIS); }
0086     
0087     void InitWithGlobalRootLock() override;
0088     void ProcessSequential(const std::shared_ptr<const JEvent>& event) override;
0089     void FinishWithGlobalRootLock() override;
0090 };
0091 ```
0092 Next, edit the myFirstPluginProcessor.cc file to the following:
0093 ```c++
0094 #include "myFirstPluginProcessor.h"
0095 #include <services/rootfile/RootFile_service.h>
0096 
0097 // The following just makes this a JANA plugin
0098 extern "C" {
0099     void InitPlugin(JApplication *app) {
0100         InitJANAPlugin(app);
0101         app->Add(new myFirstPluginProcessor);
0102     }
0103 }
0104 
0105 //-------------------------------------------
0106 // InitWithGlobalRootLock
0107 //-------------------------------------------
0108 void myFirstPluginProcessor::InitWithGlobalRootLock(){
0109 
0110     // This ensures the histograms created here show up in the same root file as
0111     // other plugins attached to the process. Place them in dedicated directory
0112     // to avoid name conflicts.
0113     auto rootfile_svc = GetApplication()->GetService<RootFile_service>();
0114     auto rootfile = rootfile_svc->GetHistFile();
0115     rootfile->mkdir("myFirstPlugin")->cd();
0116 
0117     hEraw  = new TH1D("Eraw",  "BEMC hit energy (raw)",  100, 0, 0.075);
0118 }
0119 
0120 //-------------------------------------------
0121 // ProcessSequential
0122 //-------------------------------------------
0123 void myFirstPluginProcessor::ProcessSequential(const std::shared_ptr<const JEvent>& event) {
0124 
0125      for( auto hit : rawhits() ) hEraw->Fill(  hit->getEnergy() );
0126 }
0127 
0128 //-------------------------------------------
0129 // FinishWithGlobalRootLock
0130 //-------------------------------------------
0131 void myFirstPluginProcessor::FinishWithGlobalRootLock() {
0132 
0133     // Do any final calculations here.
0134 }
0135 ```
0136 Before we continue, stop for a moment and remember that plugins are compiled objects.  Thus it is imperative we rebuild our plugin after making any changes.  To do this, we can simply run the same commands we used to build the plugin in the first place:
0137 
0138 ~~~
0139 cmake -S myFirstPlugin -B myFirstPlugin/build
0140 cmake --build myFirstPlugin/build --target install
0141 ~~~
0142 
0143 You can test the plugin using the following simulated data file:
0144 
0145 ~~~bash
0146 wget https://eicaidata.s3.amazonaws.com/2022-09-26_ncdis10x100_minq2-1_200ev.edm4hep.root
0147 eicrecon -Pplugins=myFirstPlugin 2022-09-26_ncdis10x100_minq2-1_200ev.edm4hep.root
0148 ~~~
0149 
0150 You should now have a root file, eicrecon.root, with a single directory: "myFirstPlugin" containing the resulting hEraw histogram.
0151 
0152 
0153 _____________________________________________________________________________________________________________
0154 
0155 As exercises try (make sure you rebuild everytime you change your plugin):
0156 
0157 1) Plot the X,Y positions of all the hits.  
0158 
0159 2) Repeat only for hits with energy greater than 0.005 GeV.  
0160 
0161 3) Try to plot similar histograms from the EcalEndcapN.
0162 
0163 Feel free to play around with other objects and their properties (hint: when you ran eicrecon, you should have seen a list of all the objects that were available to you.  You can also see this list by typing: eicrecon -Pplugins=myFirstPlugin -Pjana:nevents=0)
0164 
0165 Note: very shortly you will be adding a factory.  After you do come back to this plugin and access your newly created objects
0166 
0167 
0168 {% include links.md %}
0169