Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PandoraLArRecoNDBranchFiller #76

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Conversation

jback08
Copy link
Member

@jback08 jback08 commented Aug 22, 2024

Created the PandoraLArRecoNDBranchFiller class to store the reconstruction information from Pandora's LArRecoND package (used for the DUNE ND). It requires a ROOT file created by the HierarchyAnalysisAlgorithm, which uses Pandora's Hierarchy Tools.

The filled reco branches are rec.nd.lar.pandora.tracks and .rec.nd.lar.pandora.showers. No distinction is made (yet) between tracks and showers, and so the same 3D-cluster Particle Flow Objects (PFOs) are used for both. Here is the list of reco variables used:

  1. Start position = cluster vertex point or the first hit position if no vertex is available
  2. End position = cluster end position
  3. Energy = charge Q
  4. Length = primary principal axis length
  5. Quality = number of 3D hits.

Any changes needed here can be done mostly in the LArRecoND package, since the CAF just retrieves the output stored by Pandora's hierarchy algorithm.

The MC truth matching uses Pandora's Hierarchy Tools and not TruthMatcher. Pandora requires all MC particles to have a unique ID (even if they originate from different neutrinos), and so the following offsets are applied to the original (ndlar-flow) MC Ids:

  1. nuId = orig_nuId + 10^8
  2. mcId = orig_mcId + nuIndex * 10^6

where nuIndex = 0 to N-1 for an event with N neutrinos, and the orig_mcId number range restarts from zero for each neutrino. This ensures all IDs are unique, for up to 100 neutrino interactions per event, each containing up to 10^6 hits.

These ID offsets are reversed when the Pandora CAF truth information is filled using the best reco-MC match achieved with Hierarchy Tools, and so the mcId's should then have values consistent with the equivalent input ndlar-flow files. The filled truth information corresponds to:

  1. truth.ixn = orig_nuId
  2. truth.part = orig_mcId (best match)
  3. truth.type = primary, secondary or other
  4. truthOverlap = completeness (best match)

H5 input files are first converted to ROOT using h5_to_root_ndlarflow.py before they are used by LArRecoND & Pandora, which in turn creates the hierarchy analysis output file that can be used to make the equivalent CAFs.

For the trigger, the event run numbers are propagated using those originally from the input ndar_flow ROOT files. Also, the start time is currently set using the ts_start variable, but this needs to be updated (in LArRecoND) to use the correct time and units.

Also updated ndcaf_setup.sh and build.sh to use a consistent environment.

@noeroy noeroy self-assigned this Aug 22, 2024
@noeroy
Copy link
Contributor

noeroy commented Aug 22, 2024

I think that the truth part of it could be an issue, as the truth branches are shared by all reconstructions.

The particles are uniquely identified with two ids, one that identifies the interaction inside a given spill: vertex_id in the flow files, and one that is uniquely identifying for a given interaction which is the Geant4 trajectory id, I believe it is traj_id in the flow files. Those IDs are shared within MLReco and MINERvA so that truth particles are matched to the same id. Would it be possible to have a match between orig_nuId and vertex_id and between orig_mcId and traj_id?

@jback08
Copy link
Member Author

jback08 commented Oct 3, 2024

I think this is ready for review now. We have added the unix_ts variable to set the trigger time, and we are using the same MC Id variables as the other reco methods.

@noeroy noeroy self-requested a review October 7, 2024 16:17
const int traj_id = mcId - nuIndex*m_maxMCId;

caf::TrueParticleID trueID;
trueID.ixn = vertex_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

Tracks and shower truth.ixn are not directly the vertex_id, but the position of the neutrino interaction associated to that vertex_id in the truth interaction stack.

I think you can have access to it by doing:

caf::SRTrueInteraction & srTrueInt = truthMatch->GetTrueInteraction(sr, vertex_id, false); // Gets the true interaction in the stack
int srTrueIntIdx = std::distance(sr.mc.nu.begin(),
                                           std::find_if(sr.mc.nu.begin(),
                                                        sr.mc.nu.end(),
                                                        [&srTrueInt](const caf::SRTrueInteraction& ixn) {return ixn.id == srTrueInt.id;})); // Get the position of the truth interaction

Copy link
Contributor

Choose a reason for hiding this comment

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

Also I see that particles that are not "primaries" have a mcNuId == 0 so that makes the truth matching tricky for them.

Copy link
Contributor

Choose a reason for hiding this comment

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

And finally, I'm not sure the vertex_id has the same definition as in the other part of the chain production chain.

For instance, in entry 2 of the Pandora MiniRun6 file 1, you have a particle with mcNuId==100100016, hence vertex_id = 100016 while vertex_id has for definition 1E6 * TaggedRunId + EdepSimEventId so should be >1e6 for the file 1. in that case the equivalent runID in the other files is 10000016.

Furthermore, rock muons vertex_id are expected to be at the 1e15 order, but I don't see any big number in that file.

Copy link
Member Author

Choose a reason for hiding this comment

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

The mcNuId is truncated in the H5-to-ROOT script to go up to 10^6 here. This affects all vertex_id numbers, including rock muons.

We store eventID and run numbers, where eventID normally goes from 0 to N (with some numbers skipped), but it looks like run is always set to zero. We don't use TaggedRunId. Is eventID = EdepSimEventId? For an event with N neutrinos, what are the typical values of TaggedRunId and EdepSimEventId?

Copy link
Contributor

Choose a reason for hiding this comment

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

So vertex_id is defined here. That's the one in Flow hence the one used in Pandora if I'm not mistaken.
The way I understand the code you sent me, it seems that it takes the 1st digit of the vertex ID, the last 5 digits and bunch them together. I'm not sure how you can recover the initial definition vertex_id from that.

For current Minirun files, for instance run 15, TaggedRunId varies between 15*10 and 16*10 for the neutrino events and 15*10+1e9 - 16*10 1e9 for rock muons. So basically the run_number *10 annd (run_number +1) *10, and same +1e9 for rock muons. The ratio 10 TaggedRunId per file is not set in stone though.

For EdepSimEventId, for a MiniRun file, it can go up to 30 000 in what I've seen, but I wouldn't say it's an absolute limit.

} else {
trueID.type = caf::TrueParticleID::kSecondary;
}
trueID.part = traj_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

Tracks and showers truth.part are not directly the traj_id.
Is that a unique ID created inside Pandora or the original Trajectory id from Edepsim/G4?

if it's the latest, then that variable can be retrieved the following way:


caf::SRTrueParticle & srTruePart = isPrimary? truthMatch->GetTrueParticle(sr, srTrueInt, traj_id, true, false)
                                                    : truthMatch->GetTrueParticle(sr, srTrueInt, traj_id, false, true);
//If it's a primary, the particle is already stored in the particle stack so we just want to retrieve it, if it's not we might want to create a new particle if it wasn't created originally. 
if (truePartID.type == caf::TrueParticleID::kPrimary) truePartID.part = traj_id; //We could be a bit smarter like what's done for the MLNDLArRecoBranchFiller but that works
else 
{
    truePartID.part = std::distance(srTrueInt.sec.begin(), std::find_if(srTrueInt.sec.begin(), srTrueInt.sec.end(), [traj_id](const caf::SRTrueParticle& part) { return part.G4ID == traj_id; })); // we just filled it so it should be fine
}

That way you also make sure that the truth matcher algorithm save the particle of interest if that was not done before.

const int traj_id = mcId - nuIndex*m_maxMCId;

caf::TrueParticleID trueID;
trueID.ixn = vertex_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as for tracks

} else {
trueID.type = caf::TrueParticleID::kSecondary;
}
trueID.part = traj_id;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same Comment as for tracks

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.

2 participants