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

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

@ceraticerati 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)

@kjplowskjplows moved this to Open pull requests in SBN software developmentDec 14, 2025
@kjplowskjplows moved this from Open pull requests to Partially reviewed in SBN software developmentDec 14, 2025
@rtriozzi

Copy link
Copy Markdown
ContributorAuthor

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

Copy link
Copy Markdown
Contributor

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

Comment threadsbncode/CAFMaker/FillReco.cxx Outdated
@cerati

Copy link
Copy Markdown
Contributor

Looks great! I only left a single comment above

@ceraticerati 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

Copy link
Copy Markdown
Contributor

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

@kjplowskjplows moved this from Todo to In Progress in PR archaeologyFeb 11, 2026
@kjplows

Copy link
Copy Markdown
Contributor

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

@rtriozzi
rtriozziforce-pushed the feature/llena_CAFMaker_PandoraAfterNuGraph branch from 3017213 to 6aa4a4cCompareMarch 16, 2026 21:26
Comment threadsbncode/CAFMaker/CAFMaker_module.cc
Comment threadsbncode/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!

@PetrilloAtWorkPetrilloAtWork 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()) {
autoconst& 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 (autoconst& 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) {

@rtriozzirtriozziJul 9, 2026

Copy link
Copy Markdown
ContributorAuthor

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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or request

Projects

Status: In Progress
Status: Partially reviewed

Development

Successfully merging this pull request may close these issues.

7 participants

@rtriozzi@kjplows@cerati@sparshitadey@PetrilloAtWork@acampani@leonardo-lena