Ntuples for AMS-Italy Analysis
Status of the framework and tools
# STATUS
# TOOLS
NAIA is just a data model and framework for AMS analysis. We can think of it as the foundational layer, but there is room for creating useful tools to further the data analysis experience.
We currently have in the works:
# TOOLS
NSL: A common selection library
This project aims at providing a set of commonly used selections that:
Manual available at: https://nsl-readthedocs.readthedocs.io/en/latest/index.html
# TOOLS
A story as old as time
//Trigger selection
if( (PhysBPatt & triggerPatt) == 0 ) continue; //Any non-prescaled trigger
//Inner Tracker selection
if( trtrackc->InnerCharge[chargeRecoType] < ITrTrackCharge_low || trtrackc->InnerCharge[chargeRecoType] > ITrTrackCharge_high ) continue;
if( trtrackc->TrChiSqY[TrTrackCont::Span::InnerOnly] > 10 ) continue;
if( trtrackc->InnerChargeRMS[chargeRecoType]/trtrackc->InnerCharge[chargeRecoType] > TrackChargeRMS ) continue;
if( !trtrackc->CheckInnerPattern() ) continue;
if( !option.CompareTo("") || option.Contains("PG") ){
if( trtrackc->NGoodCluster < 3 ) continue;
}
if( !option.CompareTo("qi") ){
if( trtrackc->GetNHitsInnerY() < 5 ) continue;
}
//Upper ToF selection
if( betahc->Beta < Beta_thr ) continue;
if(Charge < 9){
if( !betahc->TofGoodPathL[0] && !betahc->TofGoodPathL[1] ) continue;
}
if( betahc->UTofCharge < UTofCharge_lthr || betahc->UTofCharge > UTofCharge_hthr ) continue;
//L1 selection
if( !trtrackc->SpanType[TrTrackCont::Span::InnerL1] ) continue;
if (trtrackc->TrChiSqY[TrTrackCont::Span::InnerL1] > 10) continue;
if( trtrackc->GetL1NormRes() > 10 ) continue;
# TOOLS
A story as old as time:
The first item can be summarized as:
We are only interested in a precise subset of events, and we filter out events we don’t care about by asking simple yes/no questions about the value of some variables.
The whole library is designed around this concept
# TOOLS
In short, a selection is just a yes/no question about variables in an event.
Whenever you instantiate a NSL::Selection
object you can always query wether a NAIA::Event
passes that selection
NSL::Selection my_selection = get_some_selection();
// ...
for (NAIA::Event &ev : chain) {
if (my_selection(event)){
// do stuff...
}
}
things can still get out of hands pretty soon
if (my_selection_1(event) && my_selection_2(event) && /* ... */ my_selection_N(event)) {
# TOOLS
Another main point of this library is allowing to define the whole selection logic ahead of time before the event loop, so that in the event loop you can focus on what you actually do with the events you select, rather than how you select them.
namespace ns = NSL::Selections;
auto triggerSel = ns::Trigger::HasPhysicsTrigger();
auto innerTrackerSel =
ns::InnerTracker::HitPattern() &&
ns::Track::ChiSquareLessThan(10.0f, NAIA::TrTrack::Side::Y, NAIA::TrTrack::Fit::GBL, NAIA::TrTrack::Span::InnerOnly);
for (NAIA::Event &ev : chain) {
if (!triggerSel(event))
continue;
if (!innerTrackerSel(event))
continue;
// fill histos or whatever :)
}
A full list of already defined selections is available here
# TOOLS
In some cases it might be useful to perform some check between the evaluation of two or more selections, maybe you want to print some value to the screen, fill some histogram, check if some precondition is satisfied, etc…
# TOOLS
In some cases it might be useful to perform some check between the evaluation of two or more selections, maybe you want to print some value to the screen, fill some histogram, check if some precondition is satisfied, etc…
But if you defined you entire Selection sequence in one go there is no way of inserting code between one check and the next one. On the other hand, keeping all selections separated only to be able to fill a histogram in between kinda defeats the purpose of the whole design of this library.
# TOOLS
In some cases it might be useful to perform some check between the evaluation of two or more selections, maybe you want to print some value to the screen, fill some histogram, check if some precondition is satisfied, etc…
But if you defined you entire Selection sequence in one go there is no way of inserting code between one check and the next one. On the other hand, keeping all selections separated only to be able to fill a histogram in between kinda defeats the purpose of the whole design of this library.
For this exact application NSL allows to define for each selection a “hook”, which is a snippet of code that can be run before or after the evaluation of the selection. The former case is named a “pre-hook”, while the latter is called a “post-hook” and can be selectively run when the check succeeds, fails or in both cases.
# TOOLS
The way you attach a hook to a Selection is by calling AddPreHook
or AddPostHook
// NSL namespace omitted for clarity
auto my_selection_chain = MySelection1(...).AddPreHook([](NAIA::Event &ev){ /* your hook code here */ }) &&
MySelection2(...).AddPostHook([](NAIA::Event &ev){ /* ... */ }, PostHookCondition::OnSuccess) &&
/* All your selections ... */;
# TOOLS
The way you attach a hook to a Selection is by calling AddPreHook
or AddPostHook
// NSL namespace omitted for clarity
auto my_selection_chain = MySelection1(...).AddPreHook([](NAIA::Event &ev){ /* your hook code here */ }) &&
MySelection2(...).AddPostHook([](NAIA::Event &ev){ /* ... */ }, PostHookCondition::OnSuccess) &&
/* All your selections ... */;
A hook is represented in code by any kind of function that takes a NAIA::Event &
and returns void
. Also, for post-hooks the PostHookCondition
enum controls when the hook is actually executed. In the last example we added a “pre-hook” to MySelection1
which will always be executed before the selection is checked, and a “post-hook” to MySelection2
which will only be executed when the selection is passed.
# TOOLS
// create a chain and add a rootfile to it
NAIA::NAIAChain chain;
chain.Add("some_root_file.root");
// define your selections
auto my_selections = NSL::Trigger::HasPhysicsTrigger() &&
NSL::Tof::BetaInRange(0.3, 1.5, NAIA::Tof::BetaType::BetaH);
// create a histogram for the charge distribution plot
TH1D charge_distribution{"charge", ";Q;Counts", 100, 0, 15};
// create the action that fills the charge histogram
// NOTE: since NSL requires that hooks take an event and return void, we need to use lambda capture-by-reference to
// have the histogram available inside our hook function
auto fill_charge_distribution = [&charge_distribution](NAIA::Event &ev){
charge_distribution.Fill(ev.trTrackBase->InnerCharge[NAIA::TrTrack::ChargeRecoType::YJ]);
};
// add our function to our selectinos as a post-hook, to be run when the selections pass
my_selections.AddPostHook(fill_charge_distribution, NSL::PostHookCondition::OnSuccess);
// loop over the events and evaluate the selection(s).
for (NAIA::Event &event : chain){
if (!my_selections(event)){
continue;
}
}
charge_distribution.Draw();
#