Skip to content

Handle CAF making when Pandora runs after the NuGraph2 filter#616

Open
rtriozzi wants to merge 13 commits into
developfrom
feature/llena_CAFMaker_PandoraAfterNuGraph
Open

Handle CAF making when Pandora runs after the NuGraph2 filter#616
rtriozzi wants to merge 13 commits into
developfrom
feature/llena_CAFMaker_PandoraAfterNuGraph

Conversation

@rtriozzi

@rtriozzi rtriozzi commented Dec 5, 2025

Copy link
Copy Markdown
Contributor

This PR adds a mode governed by the UsePandoraAfterNuGraph FHiCL flag to handle NuGraph2 variables in the CAF maker, when using a second-pass Pandora after filtering noise with NuGraph2, based on work by summer intern Leonardo Lena.

This PR also provides code to fill new NuGraph2 slice-level variables in CAF files.

Relevant information about the NuGraph2 chain is provided in icaruscode PR #868.


Associated PRs


Review

Tagging for review @acampani and @PetrilloAtWork as reconstruction and infrastructure experts. Thanks a lot!


Description

Please provide a detailed description of the changes this pull request introduces. If available, also link to a docdb link where the issue/change have been presented on/discussed.

  • Have you added a label? (bug/enhancement/physics etc.)
  • Have you assigned at least 1 reviewer?
  • [] Is this PR related to an open issue / project?
  • Does this PR affect CAF data format? If so, please assign a CAF maintainer as additional reviewer.
  • Does this PR require merging another PR in a different repository (such as sbnanobj/sbnobj etc.)? If so, please link it in the description.
  • Are you submitting this PR on behalf of someone else who made the code changes? If so, please mention them in the description.

@cerati cerati left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, overall it looks great -- especially removing the need for the hit mapping makes things much simpler.

The two things I would suggest to change are:

  1. Avoid erasing elements from vectors. I think it should be much easier to simply add a check that the element is non-null in the Fill*NuGraph method. Or is there another reason for erasing the elements with null nugraph score?
  2. There is no need to get the NuGraph slices from the event if then we just use slices (when UsePandoraAfterNuGraph=true)

@kjplows kjplows moved this to Open pull requests in SBN software development Dec 14, 2025
@kjplows kjplows moved this from Open pull requests to Partially reviewed in SBN software development Dec 14, 2025
@rtriozzi

Copy link
Copy Markdown
Contributor Author

I have addressed Giuseppe’s comments (with which I agree). I also added more code to fill some new NuGraph2 CAF variables we developed. I opened the corresponding sbnanaobj PR #183.

@kjplows

kjplows commented Jan 15, 2026

Copy link
Copy Markdown
Contributor

Thanks! @cerati do the changes look good to you?

Comment thread sbncode/CAFMaker/FillReco.cxx Outdated
@cerati

cerati commented Jan 15, 2026

Copy link
Copy Markdown
Contributor

Looks great! I only left a single comment above

@cerati cerati left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for addressing my comments!

@kjplows

kjplows commented Feb 11, 2026

Copy link
Copy Markdown
Contributor

@PetrilloAtWork sorry to add more to your plate, just bumping this 🙂 -- could you take a look please? Thanks!

@kjplows kjplows moved this from Todo to In Progress in PR archaeology Feb 11, 2026
@kjplows

kjplows commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

@PetrilloAtWork , @acampani -- could you please take a look at this? Thanks.

@rtriozzi rtriozzi force-pushed the feature/llena_CAFMaker_PandoraAfterNuGraph branch from 3017213 to 6aa4a4c Compare March 16, 2026 21:26
Comment thread sbncode/CAFMaker/CAFMaker_module.cc
Comment thread sbncode/CAFMaker/CAFMakerParams.h
@sparshitadey

Copy link
Copy Markdown

Hi!
Small addition to fix ng_filt_pass_frac (currently always 1.0 in the NuGraph workflow):
In the workflow, slcHits comes from hits that already passed the filter by construction, so ng_filt_pass_frac computed from ngFilterResult is trivially 1.0.

The fix is to compute it directly from collection sizes - see commit 363b5120 on my branch. Gives mean ~0.81, varying event to event, consistent with Stage 1 filter retention (and the printouts). Happy to open a separate PR if preferred!

@PetrilloAtWork PetrilloAtWork 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.

My usual burst of comments.
There is at least one which must be addressed, about uninitialised variables.

nuGraphSlices = slices;
} else {
nuGraphSlices = evt.getProduct<std::vector<art::Ptr<recob::Slice>>>(fParams.NuGraphSlicesLabel().label() + pandora_tag_suffix);
}

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.

I don't understand this logic.
If fParams.UsePandoraAfterNuGraph() is true, nugraphSlices will be the same as slices (so that case could easily live outside the loop); in the other case, nuGraphSlices is overwritten with the content of each tag until the last one, hence holding only slices from the data product with the last tag.
I suspect what was meant to add slices, something like

      if (!fParams.UsePandoraAfterNuGraph()) {
        auto const& moreSlices = evt.getProduct<std::vector<art::Ptr<recob::Slice>>>(fParams.NuGraphSlicesLabel().label() + pandora_tag_suffix);
        nuGraphSlices.insert(nuGraphSlices.end(), moreSlices.begin(), moreSlices.end());
      }

}
fmPFPartHits.push_back(pfphits);
std::vector<art::Ptr<recob::Hit>> pfphits;
std::vector<art::Ptr<recob::Cluster>> pfclusters = fmPFPClusters.at(ipf);

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.

Avoid copies:

Suggested change
std::vector<art::Ptr<recob::Cluster>> pfclusters = fmPFPClusters.at(ipf);
std::vector<art::Ptr<recob::Cluster>> const& pfclusters = fmPFPClusters.at(ipf);

std::vector<art::Ptr<recob::Cluster>> pfclusters = fmPFPClusters.at(ipf);
art::FindManyP<recob::Hit> fmCluHits = FindManyPStrict<recob::Hit>(pfclusters, evt, fParams.PFParticleLabel() + slice_tag_suff);
for (size_t icl=0; icl<fmCluHits.size();icl++) {
for (auto hit : fmCluHits.at(icl)) {

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.

Avoid copies:

Suggested change
for (auto hit : fmCluHits.at(icl)) {
for (auto const& hit : fmCluHits.at(icl)) {

Comment on lines +2058 to +2059
art::FindOneP<anab::FeatureVector<1>> findOneFilter(slcHits, evt, fParams.NuGraphFilterLabel().label() + slice_tag_suff + ":" + fParams.NuGraphFilterLabel().instance());
art::FindOneP<anab::FeatureVector<5>> findOneSemantic(slcHits, evt, fParams.NuGraphSemanticLabel().label() + slice_tag_suff + ":" + fParams.NuGraphSemanticLabel().instance());

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.

It's hard to see whether the labels are the same. Define the tag first:

Suggested change
art::FindOneP<anab::FeatureVector<1>> findOneFilter(slcHits, evt, fParams.NuGraphFilterLabel().label() + slice_tag_suff + ":" + fParams.NuGraphFilterLabel().instance());
art::FindOneP<anab::FeatureVector<5>> findOneSemantic(slcHits, evt, fParams.NuGraphSemanticLabel().label() + slice_tag_suff + ":" + fParams.NuGraphSemanticLabel().instance());
art::InputTag const filtTag{
fParams.NuGraphFilterLabel().label() + slice_tag_suff,
fParams.NuGraphFilterLabel().instance()
};
art::FindOneP<anab::FeatureVector<1>> findOneFilter(slcHits, filtTag);
art::FindOneP<anab::FeatureVector<5>> findOneSemantic(slcHits, filtTag);

float vtx_wire[3];
float vtx_tick[3];

if (vertex != NULL) {

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 kind of garbage is going to end into the tree if the vertex is null? The arrays need to be initialised somehow.
This is a request, as we don't want uninitialised values to end into the trees as it compromises tree comparisons.
Also, NULL is C, and we need to keep a façade here.

Suggested change
if (vertex != NULL) {
if (vertex) {

@rtriozzi rtriozzi Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

going through the comments right now! about this: every slice has to have a vertex, sort of by definition in Pandora (e.g., even if the reconstruction is sure that the slice is a cosmic, the vertex will just be the highest-y hit)

I think there are also protections for failed vertexing (which should be very rare: we really just need a hit to define a vertex...) within Pandora, so that we always get something when we grab the vertex in the CAF maker...

anyway, I agree it's bad practice from the CAF maker stand point (+ the NULL check was therefore strange), I'll fix this! thanks!

std::max_element(semVec.begin(), semVec.end())
);

// `MIP` hits

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.

This sequence may be better served with a switch block.

Comment on lines +675 to +681
slice.ng_plane[plane].mip_hits = nMIPHits;
slice.ng_plane[plane].hip_hits = nHIPHits;
slice.ng_plane[plane].shr_hits = nShrHits;
slice.ng_plane[plane].mhl_hits = nMhlHits;
slice.ng_plane[plane].dif_hits = nDifHits;
slice.ng_plane[plane].ng_vtx_hip_hits = nVtxHIPHits;
slice.ng_plane[plane].unclustered_shr_hits = nUnclusteredShrHits;

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.

Suggested change
slice.ng_plane[plane].mip_hits = nMIPHits;
slice.ng_plane[plane].hip_hits = nHIPHits;
slice.ng_plane[plane].shr_hits = nShrHits;
slice.ng_plane[plane].mhl_hits = nMhlHits;
slice.ng_plane[plane].dif_hits = nDifHits;
slice.ng_plane[plane].ng_vtx_hip_hits = nVtxHIPHits;
slice.ng_plane[plane].unclustered_shr_hits = nUnclusteredShrHits;
auto& hitInfo = slice.ng_plane[plane];
hitInfo.mip_hits = nMIPHits;
hitInfo.hip_hits = nHIPHits;
hitInfo.shr_hits = nShrHits;
hitInfo.mhl_hits = nMhlHits;
hitInfo.dif_hits = nDifHits;
hitInfo.ng_vtx_hip_hits = nVtxHIPHits;
hitInfo.unclustered_shr_hits = nUnclusteredShrHits;

size_t sem_label = std::distance(ng2semscores.begin(), std::max_element(ng2semscores.begin(), ng2semscores.end()));//arg_max(ng2semscores);
ng2sempfpcounts[sem_label]++;
}
if (ngFilterResult.at(pos).isNull()) 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.

Indentation seems off.

Comment on lines +1131 to +1132
std::vector<float> ng2semscores;
for (size_t i=0;i<scores->size();i++) ng2semscores.push_back(scores->at(i));

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.

Suggested change
std::vector<float> ng2semscores;
for (size_t i=0;i<scores->size();i++) ng2semscores.push_back(scores->at(i));
std::vector<float> ng2semscores{ scores.begin(), scores.end() };

const std::vector<art::Ptr<anab::FeatureVector<1>>> &ngFilterResult,
const std::vector<art::Ptr<anab::FeatureVector<5>>> &ngSemanticResult,
const std::vector<art::Ptr<recob::Hit>> &pfpHits,
const float filter_cut,

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.

Fix the indentation.

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

Labels

enhancement New feature or request

Projects

Status: In Progress
Status: Partially reviewed

Development

Successfully merging this pull request may close these issues.

7 participants