Difference between revisions of "Module Writing Tutorial"

From Mu2eWiki
Jump to navigation Jump to search
Line 38: Line 38:
  
 
=== Exercise 2: Adding module configuration (Hello, Fhicl Validation!) ===
 
=== Exercise 2: Adding module configuration (Hello, Fhicl Validation!) ===
* Add a configuration parameter to the module
+
In this exercise, we will add some module configuration parameters that can be set in fcl
 +
 
 
<ol style="list-style-type:lower-alpha">
 
<ol style="list-style-type:lower-alpha">
 
  <li>Copy last exercise's .cc file and create a new file</li>
 
  <li>Copy last exercise's .cc file and create a new file</li>
Line 68: Line 69:
 
   </ol>
 
   </ol>
 
This is why fhicl validation is nice. We can catch errors in the module configurations before we waste time running the module. Some modules use an old format for module configuration, which does not catch such errors. These will be slowly converted but all new modules should use fhicl validation.
 
This is why fhicl validation is nice. We can catch errors in the module configurations before we waste time running the module. Some modules use an old format for module configuration, which does not catch such errors. These will be slowly converted but all new modules should use fhicl validation.
  <li>We can add a default value for the parameter at the end of its declaration:</li>
+
  <li>We can add parameter with a default value by adding this value to end of the parameter declaration:</li>
 
  <nowiki>fhicl::Atom<int> defaultNumber{Name("number"), Comment("This module will print this number"), 100};</nowiki>
 
  <nowiki>fhicl::Atom<int> defaultNumber{Name("number"), Comment("This module will print this number"), 100};</nowiki>
  <li>Recompile and play with the fcl configuration again</li>
+
  <li>Add some code to write this parameter out, recompile and play with the fcl configuration again. Note that it is often best to have default values defined in fcl prolog(?)</li>
  <li>Add an optional parameter</li>
+
<li>We can also add an optional parameter:</li>
 +
<nowiki>fhicl::OptionalAtom<int> optionalNumber{Name("optionalNumber"), Comment("This module will print this number but it is optional")};</nowiki>
 +
However, we can't initialise this in the initialiser list. Instead we have to check that the parameter exists:
 +
<nowiki>if (_conf.optionalNumber(_optionalNumber)) {
 +
  std::cout << "My _optionalNumber is..." << _optionalNumber << std::endl;
 +
}</nowiki>
 
  <li>(Optional): add some more parameters (try floats, strings etc.)</li>
 
  <li>(Optional): add some more parameters (try floats, strings etc.)</li>
 
</ol>
 
</ol>
  
 
=== Exercise 3: Reading in a mu2e data product (Hello, Mu2e Data Product!) ===
 
=== Exercise 3: Reading in a mu2e data product (Hello, Mu2e Data Product!) ===
* Find a mu2e data product in an event
+
In this exercise, we will be reading the results of the track fit and printing their times to the screen.
 +
 
 +
<ol style="list-style-type:lower-alpha">
 +
<li>Let's get a minimal working example set up:</li>
 +
<ol style="list-style-type:lower-roman">
 +
  <li>Copy the first exercise's .cc file to create a new module</li>
 +
  <li>Add a fhicl parameter of type <code>art::InputTag</code> and a simple print statement that prints the parameter</li>
 +
  <li>Copy a previous fcl file and edit it so that runs your new module and uses the new parameter (at the moment, it doesn't matter what the value of this parameter is).</li>
 +
  <li>Compile, run and make sure everything works as you expect</li>
 +
</ol>
 +
<li>Now we want to read in an art file. For the time being, we will do nothing with it.</li>
 +
<ol style="list-style-type:lower-roman">
 +
  <li>in the <code>source</code> block of your fcl file, change <code>EmptyEvent</code> to <code>RootInput</code></li>
 +
  <li>run your fcl file with this option added on the command line <code>-S filelists/mcs.mu2e.CeEndpoint-mix-cat.MDC2018h.1-file.lst</code> to make sure everything works</li>
 +
</ol>
 +
<li>Now let's actually do something with a Mu2e data product. We will be looking at tracks (class <code>KalSeed</code>) from the downstream e-minus fit. Set the value of your fcl parameter to <code>KFFDeM</code> and then make the following changes in your module's <code>analyze()</code> functione</li>
 +
<ol style="list-style-type:lower-roman">
 +
  <li><code>#include</code> the file RecoDataProducts/inc/KalSeed.hh</li>
 +
  <li>get a valid handle to the <code>KalSeedCollection</code> from the event:</li>
 +
<nowiki>const auto& kalSeedCollectionHandle = event.getValidHandle<KalSeedCollection>(_input);</nowiki>
 +
  <li>get the <code>KalSeedCollection</code> itself</li>
 +
<nowiki>const auto& kalSeedCollection = *kalSeedCollectionHandle;</nowiki>
 +
  <li>loop through and print the t0 of each <code>KalSeed</code> (you can look in $MU2E_BASE_RELEASE/RecoDataProducts/inc/KalSeed.hh to work out why we need two <code>.t0()</code>)</li>
 +
<nowiki>for (const auto& i_kalSeed : kalSeedCollection) {
 +
  std::cout << "t0 = " << i_kalSeed.t0().t0() << " ns" << std::endl;
 +
}</nowiki>
 +
</ol>
 +
<li>(Optional): try to print the times of a different KalSeedCollection (e.g. KFFDmuM)</li>
 +
<li>(Optional): try to print some other values from the KalSeed (e.g. momentum (which can be found in KalSegment))</li>
 +
<li>(Optional): try to read a different type of Mu2e data product (you can find the list of data products in an event with <code>mu2e -c Print/fcl/dumpDataProducts.fcl -S filelist -n 1)</code>
 +
</ol>
  
 
=== Exercise 4: Filling a histogram (Hello, Histogram!) ===
 
=== Exercise 4: Filling a histogram (Hello, Histogram!) ===
* Create and fill a histogram from a data product
+
In this exercise, we will plot a histogram of the times that we were printing out to the screen in Exercise 3.
  
=== Exercise 5: ===
+
<ol style="list-style-type:lower-alpha">
 +
<li>To start, you can either copy or edit the module from exercise 3:</li>
 +
<ol style="list-style-type:lower-roman">
 +
</ol>
 +
</ol>
 +
 
 +
=== Exercise 5: Creating a subset of a data product (Hello, Cool Data Products!) ===
 
* Create a subset of a data product and add it to the event
 
* Create a subset of a data product and add it to the event
 +
 +
=== Exercise 6: Creating a new data product (Hello, My Data Product!) ===
 
* Create a new data product, fill it, and add it to the event
 
* Create a new data product, fill it, and add it to the event
 +
 +
=== Exercise 7: Creating and using a pointer to a data product (Hello, Art Ptrs!) ===
 
* Create and use a persistent pointer (Ptr) to a data product
 
* Create and use a persistent pointer (Ptr) to a data product
 +
 +
=== Exercise 8: Creating and using an assn between two data products (Hello, Art Assns!) ===
 
* Create an association between 2 data products
 
* Create an association between 2 data products
  
 
== Reference Materials ==
 
== Reference Materials ==
 
* art workbook
 
* art workbook

Revision as of 18:16, 31 May 2019

Tutorial Session Goal

This tutorial will show how to write an art module for Mu2e. It will explain how to structure the code, define runtime parameters, produce histograms and/or TTrees, and consume and produce data products.

Session Prerequisites and Advance Preparation

This tutorial requires the user to:

Session Introduction

Mu2e uses the art framework to organize our event processing code. The art framework processes events through a configurable sequential set of modules, called a path. Modules expects certain inputs, and optionally produces certain outputs. Modules have a standard interface for interacting with the art framework, giving the user access to data at run/subrun/event transitions. Modules have a standard library for defining configuration parameters that can be changed at runtime.

In this tutorial you will learn how to create an art module from a basic template, and perform basic data operations in that module. You will learn how to configure your module in code and fcl, and how to produce various kinds of output.

Disclaimer! In this tutorial we will be copying old modules to create new modules. In general, this is not a greate idea because we can end up copying errorful code. If yuo do this in the real world make sure you trust the code you're copying!

Basic Exercises

Exercise 1: Running a simple module (Hello, Tutorial!)

In this exercise, we will run a simple module that will print a welcoming message.

  1. First create a Satelite release in the ModuleWriting tutorial
  2. > cd $TUTORIAL_BASE/ModuleWriting > /cvmfs/mu2e.opensciencegrid.org/Offline/v7_4_0/SLF6/prof/Offline/bin/createSatelliteRelease --directory . > source setup.sh
  3. This first module has already been written for you so we can compile straight away
  4. > scons -j4
  5. And run
  6. mu2e -c fcl/HelloEx01.fcl This will write "Hello, world" and the full event id for the first 3 events.

Exercise 2: Adding module configuration (Hello, Fhicl Validation!)

In this exercise, we will add some module configuration parameters that can be set in fcl

  1. Copy last exercise's .cc file and create a new file
  2. > cp src/HelloTutorial_module.cc src/HelloFhiclValidation_module.cc
  3. Open the new file in your favourite text editor and make the following changes
    1. find and replace "HelloTutorial" with "HelloFhiclValidation"
    2. in the Config struct, below the using commands add the following:
    3. fhicl::Atom<int> number{Name("number"), Comment("This module will print this number")};
    4. add a private member variable to the class:
    5. int _number;
    6. add to the constructor initialisation list:
    7. _number(conf().number())
    8. add a second std::cout command to print the number e.g.
    9. std::cout << "My number is..." << _number << std::endl;
  4. Recompile with scons -j4 and fix any compilation errors
  5. Now create a copy of the fcl file, open it and make the following changes:
    1. find and replace "HelloTutorial" with "HelloFhiclValidation"
    2. add the new fhicl parameter to the module configuation and assign it a value
  6. Run mu2e with the new fcl file
  7. Try doing the following and note the errors you see:
    1. run without the new parameter in the fcl file
    2. run with a typo in the parameter name
    3. run with the value of the parameter as a float and a string

    This is why fhicl validation is nice. We can catch errors in the module configurations before we waste time running the module. Some modules use an old format for module configuration, which does not catch such errors. These will be slowly converted but all new modules should use fhicl validation.

  8. We can add parameter with a default value by adding this value to end of the parameter declaration:
  9. fhicl::Atom<int> defaultNumber{Name("number"), Comment("This module will print this number"), 100};
  10. Add some code to write this parameter out, recompile and play with the fcl configuration again. Note that it is often best to have default values defined in fcl prolog(?)
  11. We can also add an optional parameter:
  12. fhicl::OptionalAtom<int> optionalNumber{Name("optionalNumber"), Comment("This module will print this number but it is optional")}; However, we can't initialise this in the initialiser list. Instead we have to check that the parameter exists: if (_conf.optionalNumber(_optionalNumber)) { std::cout << "My _optionalNumber is..." << _optionalNumber << std::endl; }
  13. (Optional): add some more parameters (try floats, strings etc.)

Exercise 3: Reading in a mu2e data product (Hello, Mu2e Data Product!)

In this exercise, we will be reading the results of the track fit and printing their times to the screen.

  1. Let's get a minimal working example set up:
    1. Copy the first exercise's .cc file to create a new module
    2. Add a fhicl parameter of type art::InputTag and a simple print statement that prints the parameter
    3. Copy a previous fcl file and edit it so that runs your new module and uses the new parameter (at the moment, it doesn't matter what the value of this parameter is).
    4. Compile, run and make sure everything works as you expect
  2. Now we want to read in an art file. For the time being, we will do nothing with it.
    1. in the source block of your fcl file, change EmptyEvent to RootInput
    2. run your fcl file with this option added on the command line -S filelists/mcs.mu2e.CeEndpoint-mix-cat.MDC2018h.1-file.lst to make sure everything works
  3. Now let's actually do something with a Mu2e data product. We will be looking at tracks (class KalSeed) from the downstream e-minus fit. Set the value of your fcl parameter to KFFDeM and then make the following changes in your module's analyze() functione
    1. #include the file RecoDataProducts/inc/KalSeed.hh
    2. get a valid handle to the KalSeedCollection from the event:
    3. const auto& kalSeedCollectionHandle = event.getValidHandle<KalSeedCollection>(_input);
    4. get the KalSeedCollection itself
    5. const auto& kalSeedCollection = *kalSeedCollectionHandle;
    6. loop through and print the t0 of each KalSeed (you can look in $MU2E_BASE_RELEASE/RecoDataProducts/inc/KalSeed.hh to work out why we need two .t0())
    7. for (const auto& i_kalSeed : kalSeedCollection) { std::cout << "t0 = " << i_kalSeed.t0().t0() << " ns" << std::endl; }
  4. (Optional): try to print the times of a different KalSeedCollection (e.g. KFFDmuM)
  5. (Optional): try to print some other values from the KalSeed (e.g. momentum (which can be found in KalSegment))
  6. (Optional): try to read a different type of Mu2e data product (you can find the list of data products in an event with mu2e -c Print/fcl/dumpDataProducts.fcl -S filelist -n 1)

Exercise 4: Filling a histogram (Hello, Histogram!)

In this exercise, we will plot a histogram of the times that we were printing out to the screen in Exercise 3.

  1. To start, you can either copy or edit the module from exercise 3:

Exercise 5: Creating a subset of a data product (Hello, Cool Data Products!)

  • Create a subset of a data product and add it to the event

Exercise 6: Creating a new data product (Hello, My Data Product!)

  • Create a new data product, fill it, and add it to the event

Exercise 7: Creating and using a pointer to a data product (Hello, Art Ptrs!)

  • Create and use a persistent pointer (Ptr) to a data product

Exercise 8: Creating and using an assn between two data products (Hello, Art Assns!)

  • Create an association between 2 data products

Reference Materials

  • art workbook