From 95ea00fa8dc3d96f5a1c02e6b07a7ca10a98f061 Mon Sep 17 00:00:00 2001 From: tmadlener Date: Thu, 27 Jun 2024 10:36:29 +0200 Subject: [PATCH 1/5] Make the Vertex point to its decay particles Instead of to the incoming praticle --- edm4hep.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/edm4hep.yaml b/edm4hep.yaml index e6d2f0eeb..3e175c2df 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -541,8 +541,8 @@ datatypes: - int32_t algorithmType // type code for the algorithm that has been used to create the vertex VectorMembers: - float parameters // additional parameters related to this vertex - OneToOneRelations: - - edm4hep::ReconstructedParticle associatedParticle // reconstructed particle associated to this vertex + OneToManyRelations: + - edm4hep::ReconstructedParticle particles // particles that have been used to form this vertex, aka the decay particles emerging from this vertex ExtraCode: includes: "#include \n #include \n" From 1f9e2f06f84e88ce4e6644f04827aee05e4bef55 Mon Sep 17 00:00:00 2001 From: tmadlener Date: Thu, 27 Jun 2024 10:37:01 +0200 Subject: [PATCH 2/5] Rename the vertex relation of the ReconstructedParticle --- edm4hep.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edm4hep.yaml b/edm4hep.yaml index 3e175c2df..34a358e39 100644 --- a/edm4hep.yaml +++ b/edm4hep.yaml @@ -588,7 +588,7 @@ datatypes: - float goodnessOfPID // overall goodness of the PID on a scale of [0;1] - edm4hep::CovMatrix4f covMatrix // covariance matrix of the reconstructed particle 4vector OneToOneRelations: - - edm4hep::Vertex startVertex // start vertex associated to this particle + - edm4hep::Vertex decayVertex // decay vertex for the particle (if it is a composite particle) OneToManyRelations: - edm4hep::Cluster clusters // clusters that have been used for this particle - edm4hep::Track tracks // tracks that have been used for this particle From 2b638eb6e57060c7f4e22b075ef1bb7b6650b515 Mon Sep 17 00:00:00 2001 From: tmadlener Date: Fri, 5 Jul 2024 14:29:36 +0200 Subject: [PATCH 3/5] Add partial documentation on intended usage and design --- doc/VertexRecoParticleRecos.md | 178 +++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 doc/VertexRecoParticleRecos.md diff --git a/doc/VertexRecoParticleRecos.md b/doc/VertexRecoParticleRecos.md new file mode 100644 index 000000000..3c44c0f7c --- /dev/null +++ b/doc/VertexRecoParticleRecos.md @@ -0,0 +1,178 @@ +# The relations and associations between `Vertex` and `ReconstructedParticle` + +The `Vertex` and the `ReconstructedParticle` have relations that can in +principle form a loop: +- The `Vertex` has a `OneToManyRelation` to `particles` +- The `ReconstructedParticle` has a `OneToOneRelation` to a `startVertex` +- The `RecoParticleVertexAssociation` is an association that links both + +Since this has the potential for some confusion this document gives a brief +overview of the main design principles for EDM4hep and also shows the intended +way of using all of these. Additionally, this is one of the places where EDM4hep +is conceptually different than LCIO. Hence, we will also show how the two +concepts map to each other. + +## Design principles + +The major design principle was *make it possible to create each collection in +separate steps **without having to mutate collections once they have been +created***. The latter part is the most important one, as it is imposed by +EDM4hep's mutability concept. As a consequence, filling the relation information +should follow these main guidelines +- the decay particles that form a `Vertex` should be added to the `particles`. + Hence, a `Vertex` can always be queried for those +- a `ReconstructedParticle` that decayed at a given `Vertex` should point to + this `Vertex` via the `decayVertex`. It is then always possible to get the + decay produces via `getDecayVertex().getParticles()`. +- in order to allow navigation from a decay particle to the vertex it originated + from a `RecoParticleVertexAssociation` should be created. If no such + navigation is necessary, creating these associations can also be omitted. + +## Using `Vertex` and (high level) `ReconstructeParticle` objects + +The following examples show a few use cases and how to achieve them. We assume +that the following variables are defined externally somehow +- `particle` is a `edm4hep::ReconstructeParticle`. This denotes a decaying particle +- `startVtxAssocs` is a `edm4hep::RecoParticleVertexAssociationCollection` +- `reco` is a `edm4hep::ReconstructedParticle`. This denotes a decay particle, + i.e. it was used as an input to vertexing. + +### Getting all decay particles from a `ReconstructedParticle` + +```cpp +const auto vtx = particle.getDecayVertex() +const auto decayParticles = vtx.getParticles(); +``` + +### Getting the start vertex for a decay particle + +This is a small helper function that encapsulates the main functionality + +```cpp +std::optional getStartVertex(edm4hep::ReconstructedParticle p, + const edm4hep::RecoParticleVertexAssociationCollection& assocs) { + for (const auto assoc : assocs) { + if (assoc.getRec() == rec) { + return assoc.getVertex(); + } + } + return std::nullopt; +} +``` + +## Creating `Vertex` and (high level) `ReconstructedParticle` objects + +In the following examples we will assume, that we have a list of +`ReconstructedParticle`s that we want to use in vertexing. We will produce the +following outputs +- a `Vertex` collection, containing all the vertices that we could find. +- a `ReconstructedParticle` collection, that represent the particles that + decayed at these vertices. Each of them will have exactly one `decayVertex` + attached to them. +- a `RecoParticleVertexAssociation` collection that links each of the input + `ReconstructedParticle`s back to the `Vertex` from which they emerged. + +All of the steps will use function stubs whereever necessary and will mainly +focus on setting the relations / associations. + +### 1. Creating vertices + +The main point here is to attach the decay particles to the `particles` field of +each `Vertex`. In this example we will assume that that is not already done by +the `magicVertexing` function; mainly to make this part very explicit. + +```cpp +// This is a possible signature that works in the example below +std::vector> +magicVertexing(const edm4hep::ReconstructedParticleCollection&); + +edm4hep::VertexCollection createVertices(const edm4hep::ReconstructedParticleCollection& particles) { + auto vertices = edm4hep::VertexCollection{}; + + // magicVertexing returns + for (const auto& [vtx, decayParticles] : magicVertexing(particles)) { + for (const auto p : decayParticles) { + vtx.addToParticles(p); + } + vertices.push_back(vtx); + } + + return vertices; +} +``` + +### 2. Creating high level reconstruction particles + +This is the most simplest implementation possible. It simply sums up all four +vectors of the decay particles and sets that into the newly created particles. +Again, this is mainly done for illustration purposes, as the important part is +the relation setting. + +```cpp +// This is a possible signature for that works in the example below +edm4hep::LorentzVectorM sumFourMomenta(const podio::RelationRange&); + +edm4hep::ReconstructedParticleCollection createVertexRecos(const edm4hep::VertexCollection& vertices) { + auto recos = edm4hep::ReconstructedParticleCollection{}; + for (const auto vtx : vertices) { + auto reco = recos.create(); + reco.setDecayVertex(vtx); + + auto fourMom = sumFourMomenta(vtx.getParticles()); + reco.setMass(fourMom.M()); + reco.setMomentum(fourMom.X(), fourMom.Y(), fourMom.Z()); + } + + return recos; +} +``` + +### 3. Creating start vertex associations + +This is a potentially optional step, depending on whether it is necessary to +allow for easier navigation from the particles back to their start vertices. + +```cpp +edm4hep::RecoParticleVertexAssociationCollection(const edm4hep::VertexCollection& vertices) { + auto startVtxAssocs = edm4hep::RecoParticleVertexAssociationCollection{}; + for (const auto vtx : vertices) { + for (const auto particle : vtx.getParticles()) { + auto assoc = startVtxAssocs.create(); + assoc.setVertex(vtx); + assoc.setRec(particle); + } + } + return startVtxAssocs; +} +``` + + +## EDM4hep vs LCIO + +### The concept in LCIO + +In LCIO the `Vertex` and `ReconstructedParticle` have similar but slightly +different relations (we will express them in podio/EDM4hep terminology here): +- a `Vertex` has a `OneToOneRelation` to an `associatedParticle` +- a `ReconstructeParticle` has a `OneToOneRelation` to a `startVertex` +- there is a similar association (`LCRelation`) between `Vertex` and + `ReconstructedParticle` as in EDM4hep + +The intended way to fill these in LCIO is +- a `Vertex` points back to the particle that decayed via the + `associatedParticle` +- the `associateParticle` has the decay products in its `particles` relation +- each of the decay particles points back to the `Vertex` via the `startVertex` + relation. + +The main issue with this format is, that it's impossible to fill this +information in the EDM4hep mutability model without either +- doing the reconstruction of all particles, the vertexing and the high level + reconstruction in one step +- or cloning collections of objects several times in order to be able to fill + all the information consistently + +### In LCIO I do this, how do I do it in EDM4hep? + +- [ ] TODO + From 0c7a5cb5c6654c73eb5d2cd7ee4a4933621a2101 Mon Sep 17 00:00:00 2001 From: tmadlener Date: Fri, 5 Jul 2024 15:34:44 +0200 Subject: [PATCH 4/5] Add more documentation and first LCIO - EDM4hep comparisons --- doc/VertexRecoParticleRecos.md | 113 +++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 6 deletions(-) diff --git a/doc/VertexRecoParticleRecos.md b/doc/VertexRecoParticleRecos.md index 3c44c0f7c..c02c3dc91 100644 --- a/doc/VertexRecoParticleRecos.md +++ b/doc/VertexRecoParticleRecos.md @@ -27,6 +27,9 @@ should follow these main guidelines - in order to allow navigation from a decay particle to the vertex it originated from a `RecoParticleVertexAssociation` should be created. If no such navigation is necessary, creating these associations can also be omitted. +- in order to allow for an easy navigation from the `Vertex` to the high level + `ReconstructedParticle` a `RecoParticleVertexAssociation` should be created if + necessary. ## Using `Vertex` and (high level) `ReconstructeParticle` objects @@ -37,6 +40,10 @@ that the following variables are defined externally somehow - `reco` is a `edm4hep::ReconstructedParticle`. This denotes a decay particle, i.e. it was used as an input to vertexing. +A few concrete examples are shown now, a few more can be found +[below](#in-lcio-i-do-this-how-do-i-do-it-in-edm4hep) where a few more details +about the differences between LCIO and EDM4hep can be found. + ### Getting all decay particles from a `ReconstructedParticle` ```cpp @@ -75,7 +82,7 @@ following outputs All of the steps will use function stubs whereever necessary and will mainly focus on setting the relations / associations. -### 1. Creating vertices +### Creating vertices The main point here is to attach the decay particles to the `particles` field of each `Vertex`. In this example we will assume that that is not already done by @@ -101,7 +108,7 @@ edm4hep::VertexCollection createVertices(const edm4hep::ReconstructedParticleCol } ``` -### 2. Creating high level reconstruction particles +### Creating high level reconstruction particles This is the most simplest implementation possible. It simply sums up all four vectors of the decay particles and sets that into the newly created particles. @@ -127,13 +134,33 @@ edm4hep::ReconstructedParticleCollection createVertexRecos(const edm4hep::Vertex } ``` -### 3. Creating start vertex associations +#### Creating associations from `Vertex` to high level `ReconstructedParticle` + +This is a potentially optional step that makes it possible to more easily access +the `ReconstructedParticle` that decayed at a `Vertex` + +```cpp +edm4hep::RecoParticleVertexAssociationCollection +createVtxParticleAssociations(const edm4hep::ReconstructedParticleCollection& particles) { + auto vtxPartAssocs = edm4hep::RecoParticleVertexAssociationCollection{}; + for (const auto p : particles) { + auto assoc = vtxPartAssocs.create(); + assoc.setRec(p); + assoc.setVertex(p.getDecayVertex()); + } + + return vtxPartAssocs; +} +``` + +### Creating start vertex associations This is a potentially optional step, depending on whether it is necessary to allow for easier navigation from the particles back to their start vertices. ```cpp -edm4hep::RecoParticleVertexAssociationCollection(const edm4hep::VertexCollection& vertices) { +edm4hep::RecoParticleVertexAssociationCollection +createStartVtxAssociations(const edm4hep::VertexCollection& vertices) { auto startVtxAssocs = edm4hep::RecoParticleVertexAssociationCollection{}; for (const auto vtx : vertices) { for (const auto particle : vtx.getParticles()) { @@ -146,7 +173,6 @@ edm4hep::RecoParticleVertexAssociationCollection(const edm4hep::VertexCollection } ``` - ## EDM4hep vs LCIO ### The concept in LCIO @@ -171,8 +197,83 @@ information in the EDM4hep mutability model without either reconstruction in one step - or cloning collections of objects several times in order to be able to fill all the information consistently + +In many cases the `Vertex` and `ReconstructedParticle` collection containing the +high level particle are created in one step in LCIO to circumvent parts of these +limitations. ### In LCIO I do this, how do I do it in EDM4hep? -- [ ] TODO +#### Get the decay products from a `Vertex` + +This case is rather similar between the two datamodels. There is effectively +just one additional step involved for LCIO. + + + + + + + + + +
LCIOEDM4hep
+ +```cpp +const auto& dps = vtx->getAssociatedParticle()->getParticles(); +``` + +`dps` will be a `std::vector`. + + + +```cpp +const auto dps = vtx.getParticles(); +``` + +`dps` will be a `podio::RelationRange`. + +
+ +#### Get the particle associated to a `Vertex` + +In this case there is a conceptual difference that requires to switch approaches +a bit. The example below assumes that you are looping over all vertices to +figure out the associated `ReconstructedParticle`. The main difference in this +case is that in EDM4hep the iteration does not go over a `Vertex` collection, +but rather a `RecoParticleVertexAssociation` collection. + + + + + + + + + +
LCIOEDM4hep
+ +```cpp +const auto vtxColl = event->getCollection("vertices"); + +for (size_t i = 0; i < vtxColl->getNumberOfElements(); ++i) { + const auto vtx = dynamic_cast(vtxColl->getElementAt(i)); + const auto reco = vtx->getAssociatedParticle(); + // .. do something with reco and vtx +} +``` + + + +```cpp +const auto& assocColl = + event.get("vtx_particle_associations"); + +for (const auto assoc : assocColl) { + const auto vtx = assoc.getVertex(); + const auto reco = assoc.getRec(); + // .. do something with reco and vtx +} +``` +
From 022e75e85c80d196b0ff54c33bbe0765afe7e33c Mon Sep 17 00:00:00 2001 From: tmadlener Date: Fri, 19 Jul 2024 16:58:40 +0200 Subject: [PATCH 5/5] Fix whitespace for pre-commit --- doc/VertexRecoParticleRecos.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/VertexRecoParticleRecos.md b/doc/VertexRecoParticleRecos.md index c02c3dc91..567435e25 100644 --- a/doc/VertexRecoParticleRecos.md +++ b/doc/VertexRecoParticleRecos.md @@ -56,7 +56,7 @@ const auto decayParticles = vtx.getParticles(); This is a small helper function that encapsulates the main functionality ```cpp -std::optional getStartVertex(edm4hep::ReconstructedParticle p, +std::optional getStartVertex(edm4hep::ReconstructedParticle p, const edm4hep::RecoParticleVertexAssociationCollection& assocs) { for (const auto assoc : assocs) { if (assoc.getRec() == rec) { @@ -148,7 +148,7 @@ createVtxParticleAssociations(const edm4hep::ReconstructedParticleCollection& pa assoc.setRec(p); assoc.setVertex(p.getDecayVertex()); } - + return vtxPartAssocs; } ``` @@ -159,7 +159,7 @@ This is a potentially optional step, depending on whether it is necessary to allow for easier navigation from the particles back to their start vertices. ```cpp -edm4hep::RecoParticleVertexAssociationCollection +edm4hep::RecoParticleVertexAssociationCollection createStartVtxAssociations(const edm4hep::VertexCollection& vertices) { auto startVtxAssocs = edm4hep::RecoParticleVertexAssociationCollection{}; for (const auto vtx : vertices) { @@ -197,14 +197,14 @@ information in the EDM4hep mutability model without either reconstruction in one step - or cloning collections of objects several times in order to be able to fill all the information consistently - + In many cases the `Vertex` and `ReconstructedParticle` collection containing the high level particle are created in one step in LCIO to circumvent parts of these limitations. ### In LCIO I do this, how do I do it in EDM4hep? -#### Get the decay products from a `Vertex` +#### Get the decay products from a `Vertex` This case is rather similar between the two datamodels. There is effectively just one additional step involved for LCIO.