Warning, /tutorial-reconstruction-algorithms/episodes/06-working-with-podio.md is written in an unsupported language. File is not indexed.
0001 ---
0002 title: "Working with PODIO"
0003 teaching: 5
0004 exercises: 1
0005 ---
0006
0007 ::::::::::::::::::::::::::::::::::::::::::::: questions
0008
0009 - What is PODIO and why does the EIC data model use it?
0010 - How do I create and fill PODIO collections, and what is a subset collection?
0011
0012 :::::::::::::::::::::::::::::::::::::::::::::
0013
0014 ::::::::::::::::::::::::::::::::::::::::::::: objectives
0015
0016 - Gain familiarity working with PODIO collections.
0017 - Understand PODIO subset collections.
0018
0019 :::::::::::::::::::::::::::::::::::::::::::::
0020
0021 ## Introduction to PODIO
0022
0023 Our data model is in a library/namespace/repository called `edm4eic`, and it is built on top of `edm4hep`, a data model designed to capture commonalities across HEP experiments. `edm4eic` is implemented using PODIO, which is a toolkit for generating the data model classes from a specification written in YAML. Here is a very simple example of a PODIO specification:
0024
0025 ```yaml
0026 options :
0027 # should getters / setters be prefixed with get / set?
0028 getSyntax: False
0029 # should POD members be exposed with getters/setters in classes that have them as members?
0030 exposePODMembers: True
0031 includeSubfolder: True
0032
0033 datatypes :
0034 ExampleHit :
0035 Description : "Hit"
0036 Author : "B. Hegner"
0037 Members:
0038 - unsigned long long cellID // cellID
0039 - double x // x-coordinate
0040 - double y // y-coordinate
0041 - double z // z-coordinate
0042 - double energy // measured energy deposit
0043
0044 ExampleCluster :
0045 Description : "Cluster"
0046 Author : "N. Brei"
0047 Members:
0048 - double energy // cluster energy
0049 OneToManyRelations:
0050 - ExampleHit Hits // hits contained in the cluster
0051 - ExampleCluster Clusters // sub clusters used to create this cluster
0052 ```
0053
0054 PODIO will then generate for us the following classes:
0055 ```
0056 DatamodelDefinition.h ExampleCluster.h ExampleClusterCollection.h ExampleClusterCollectionData.h ExampleClusterData.h ExampleClusterObj.h ExampleHit.h ExampleHitCollection.h ExampleHitCollectionData.h ExampleHitData.h ExampleHitObj.h MutableExampleHit.h MutableExampleCluster.h
0057 ```
0058
0059 As you can see, PODIO has a lot of moving pieces. Why?
0060
0061 1. PODIO adds a separate layer for managing memory in a way which is more consistent with Python and other garbage-collected languages. The user only has to work with values, no explicit allocations or deletions.
0062 2. PODIO separates the data's memory layout from its accessors
0063 3. PODIO enforces immutability directly in the object model
0064 4. PODIO has sophisticated (though fragile!) mechanisms for tracking object references
0065
0066 These design principles in principle should eliminate entire classes of bugs. However, there are still subtleties when using PODIO that can lead to leaks, crashes, or corrupted references. Luckily, the correct usage pattern is quite simple, as we will discuss next.
0067
0068
0069 ## Working with PODIO objects, collections, and subset collections:
0070
0071
0072 ```c++
0073 auto hits = std::make_unique<ExampleHitCollection>();
0074
0075 hits->push_back(ExampleHit(22, 0.0, 0.0, 0.0, 0.001));
0076
0077 MutableExampleHit hit;
0078 hit.x(0.0);
0079 hit.energy(0.001);
0080 // ...
0081 hits->push_back(hit);
0082
0083 MutableExampleCluster cluster;
0084 cluster.addHits(hit);
0085
0086 // Safety tip: Add object to a collection BEFORE creating an association to it
0087
0088 auto clusters = std::make_unique<ExampleClusterCollection>();
0089 clusters->push_back(cluster);
0090
0091 auto subset_clusters = std::make_unique<ExampleClusterCollection>();
0092 subset_clusters->setSubsetCollection(true);
0093 subset_clusters->push_back(cluster);
0094
0095 // Safety tip: Every PODIO object is owned by exactly one collection.
0096 // If you want to put the object in other collections, those collections need to
0097 // be designated as "subset collections", which means that they don't own their contents.
0098 ```
0099
0100
0101 Note that when you write a factory, its inputs will be `const ExampleHitCollection*`, which are *immutable*.
0102 Its output is held by a `PodioOutput<ExampleHit>` member; calling `m_output()` returns a `std::unique_ptr<ExampleHitCollection>&` that the factory can mutate, and `m_output().get()` gives a raw mutable pointer that you can hand to your algorithm's `process()` method. After `Process()` returns, JOmniFactory transfers ownership of that collection to JANA2, which adds it to a podio `Frame`. From that point on, the collection is immutable and owned by the `Frame`.
0103
0104 JANA2 will create and destroy `Frame`s internally.
0105
0106
0107 ::::::::::::::::::::::::::::::::::::::::::::: challenge
0108
0109 ## Exercise
0110
0111 - Have your algorithm produce some (fake) output data!
0112
0113 ::::::::::::::: solution
0114
0115 In your algorithm's `process()`, create mutable objects, set some field values, and `push_back`
0116 them onto the output collection (or, for an electron finder, mark the output as a subset collection
0117 with `setSubsetCollection()` and push existing input objects onto it). Running EICrecon and
0118 inspecting the output collection should now show your fabricated entries.
0119
0120 :::::::::::::::
0121
0122 :::::::::::::::::::::::::::::::::::::::::::::
0123
0124 ::::::::::::::::::::::::::::::::::::::::::::: keypoints
0125
0126 - `edm4eic` (on top of `edm4hep`) is generated by PODIO from a YAML specification.
0127 - PODIO manages memory, separates layout from accessors, and enforces immutability, but object references are fragile.
0128 - Every PODIO object is owned by exactly one collection; use a *subset collection* (`setSubsetCollection()`) to reference objects owned elsewhere.
0129 - Factory inputs are immutable `const *`; the output collection becomes immutable once JANA2 moves it into a `Frame`.
0130
0131 :::::::::::::::::::::::::::::::::::::::::::::