Skip to content

Adding DLShowerMatching algorithms - #288

Open
imawby wants to merge 4 commits into
PandoraPFAOrg:masterfrom
imawby:feature/DLShowerMatching
Open

Adding DLShowerMatching algorithms#288
imawby wants to merge 4 commits into
PandoraPFAOrg:masterfrom
imawby:feature/DLShowerMatching

Conversation

@imawby

@imawby imawby commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Hello again,

This PR introduces the DLShowerMatching. The DLShowerMatching is called the DLMultiViewMatchingAlgorithm (it's not actually specific to showers). The algorithm works as follows:

  1. Topological information is used to identify pairs of clusters (each in a different view) which may belong to the same pfo. These matches are stored in the 'navigation maps' which record the associated cluster pairs.
  2. Connected groups of clusters are identified by following the identified cluster navigations (akin to the Pandora matching Tensor/Matrix logic)
  3. The cluster similarity network (trained on all U/V/W clusters) is ran on each connected group.
  4. The navigations are revised, and those that have low similarity scores are removed.
  5. The connected groups are once again found, and for each group several tools are ran in order to extract the pfos.

These tools are:

  • DLThreeViewClearShowersTool: Forms pfos from 1:1:1 matches
  • DLThreeViewMergeAndCreateShowersTool: forms pfos from N:N:N matches. This tool will form a pfo from the cluster triplet that has the highest number of hits (and in which each cluster pair has an above threshold similarity score). Remaining clusters can be merged into the pfo if the similarity score with the cluster in their view exceeds some threshold.
  • DLTwoViewClearShowersTool: two view equivalent of DLThreeViewClearShowersTool
  • DLTwoViewMergeAndCreateShowersTool: two view equivalent of DLThreeViewMergeAndCreateShowersTool

Okay so, there is a spicy element to the PR - the LArCaloHit updates. I think we need to read in more information about the geometry into pandora. I 100% agree that this is not the best way to do it. Ideally we'd want to pass in a mapping between wires->overlapping wire range for each wire, in each plane, in each daughter volume. But I don't see how that's possible with the current SDK. I am very happy to discuss other approaches.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new deep-learning-driven multi-view cluster matching workflow (DLMultiViewMatchingAlgorithm) and supporting “clear”/“merge-and-create” tools to build 3D shower-like PFOS from connected multi-view cluster groups. It also extends geometry/hit metadata to support wire-overlap logic and hit feature extraction for model inference/training.

Changes:

  • Introduces DLMultiViewMatchingAlgorithm plus 2-view/3-view matching tools to create PFOS from connected cluster groups using learned similarity scores.
  • Adds LArDLShowerHelper for per-hit feature calculation used in matching/training.
  • Extends LArCaloHit and geometry helpers to provide plane/wire/intersection metadata and detector drift-gap boundaries needed by the new matching logic; wires new sources into build/registration.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLTwoViewMergeAndCreateShowersTool.h Declares 2-view ambiguous-group merging/seed selection tool.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLTwoViewMergeAndCreateShowersTool.cc Implements 2-view ambiguous-group seed selection and merging logic.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLTwoViewClearShowersTool.h Declares 2-view clear (0:1:1 etc.) PFO creation tool.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLTwoViewClearShowersTool.cc Implements 2-view clear-group PFO creation.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLThreeViewMergeAndCreateShowersTool.h Declares 3-view ambiguous-group merging/seed selection tool.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLThreeViewMergeAndCreateShowersTool.cc Implements 3-view ambiguous-group seed selection and merging logic.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLThreeViewClearShowersTool.h Declares 3-view clear (1:1:1) PFO creation tool.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLThreeViewClearShowersTool.cc Implements 3-view clear-group PFO creation.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLMultiViewMatchingAlgorithm.h Declares the main multi-view matching algorithm, data structures, and tool interface.
larpandoradlcontent/LArThreeDReco/LArShowerMatching/DLMultiViewMatchingAlgorithm.cc Implements navigation building, overlap logic, model inference/training output, and tool execution loop.
larpandoradlcontent/LArHelpers/LArDLShowerHelper.h Declares hit-feature helper used by DL shower matching/growing.
larpandoradlcontent/LArHelpers/LArDLShowerHelper.cc Implements hit feature extraction (relative coords, gap distance, energy, etc.).
larpandoradlcontent/LArDLContent.cc Registers the new algorithm and tools with the DL content factory.
larpandoracontent/LArObjects/LArCaloHit.h Extends hit parameters/object and IO with plane/wire/intersection ranges needed for overlap logic.
larpandoracontent/LArHelpers/LArGeometryHelper.h Adds API to expose detector drift-gap x boundaries.
larpandoracontent/LArHelpers/LArGeometryHelper.cc Implements drift-gap x boundary extraction from geometry gap list.
cmake/LArDLContent_sources.cmake Adds new sources to the DL content build.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread larpandoradlcontent/LArHelpers/LArDLShowerHelper.cc
Comment thread larpandoradlcontent/LArHelpers/LArDLShowerHelper.cc Outdated
Comment thread larpandoracontent/LArHelpers/LArGeometryHelper.cc Outdated
if (m_version > 3)
{
PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, xmlFileWriter.WriteVariable("Plane", pLArCaloHit->GetPlane()));
PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, xmlFileWriter.WriteVariable("WireId", pLArCaloHit->GetWireId()));

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore

@AndyChappell AndyChappell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly trivial comments, a few more substantive, and one in need of more serious discussion (LArCaloHit extension).

Comment thread larpandoracontent/LArHelpers/LArGeometryHelper.cc Outdated
Comment thread larpandoracontent/LArHelpers/LArGeometryHelper.cc Outdated
Comment on lines +32 to +39
pandora::InputUInt m_plane; ///< The plane id
pandora::InputUInt m_wireId; ///< The wire id (only unique to daughter volume)
pandora::InputUInt m_plane1; ///< The first projection plane id
pandora::InputUInt m_minIntersectWire1; ///< The id of the first (lowest wire id) intersecting wire (in proj plane 1)
pandora::InputUInt m_maxIntersectWire1; ///< The id of the last (highest wire id) intersecting wire (in proj plane 1)
pandora::InputUInt m_plane2; ///< The second projection plane id
pandora::InputUInt m_minIntersectWire2; ///< The id of the first (lowest wire id) intersecting wire (in proj plane 2)
pandora::InputUInt m_maxIntersectWire2; ///< The id of the last (highest wire id) intersecting wire (in proj plane 2)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can discuss timing and milestone requirements etc, but, I think in reality, we would want the wireId (and somewhat (also time tick would be useful, but obviously not directly relevant to this work), but everything else belongs in a new geometry object that should keep track of these geometry- rather than hit-relative quantities, given that this is a lot of overhead on hits for quantities that aren't unique to the hit (and you know the knock on effects this has on persistency, pending an overhaul of that). I agree, this would require an SDK update - but I think we should do that.

That said, from this point forward, I'll review the code under the assumption this is all fine.

*
* @return the plane id
*/
unsigned int GetPlane() const;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partly a note to myself - why do we need plane id, given we already have HitType?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think we've spoken about this, but just for completeness it's due to the wrapping of wires in DUNE HD FD - so U&V pandora view wires (on opposite sides of the APA) correspond to the same plane

unsigned int GetWireId() const;

/**
* @brief Get the first projection plane id

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What constitutes the "first" plane in this context?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just one of the 'other' views. There's some ordering to this though. So if your wire is U then 1st and 2nd are V & W respectively, V -> W(1)U(2), W -> U(1)V(2).

But this will change to use the new geom functionality.

Comment thread larpandoradlcontent/LArDLContent.cc Outdated
Comment thread larpandoradlcontent/LArDLContent.cc Outdated

@AndyChappell AndyChappell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor (though possibly substantive) follow up points.

}
const double dist(x - xGap);
if (std::abs(dist) < distToXGap)
distToXGap = dist;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this not risk signing a negative value to distToXGap, which would then fail all subsequent comparisons?

Comment on lines +228 to +231
const LArCaloHit *const pLArHit1(dynamic_cast<const LArCaloHit *>(pCaloHit1));

if (!pLArHit1)
continue;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was just a point of ordering. You check for LArCaloHit dynamic cast before you know if you're going to use this hit (if you don't, it's a redundant op and check).

@AndyChappell AndyChappell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Latest changes look good. I won't tag it as approved yet because the SDK geometry updates, but in terms of the algorithm as presented, this one is ready.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants