The NAIA data model#
The NAIA data model is vaguely inspired by gbatch. The first thing needed to access data is to create a NAIAChain
object
// ...
#include "Chain/NAIAChain.h"
int main(int argc, char const *argv[]) {
NAIA::NAIAChain chain;
chain.Add("somefile.root");
chain.SetupBranches();
}
the chain.SetupBranches()
is mandatory (with some work it could be made automatic with the instantiation of a chain,
but this might come in a future release) and takes care of setting up the whole “read-on-demand” mechanism.
Looping#
The chain contains all the events in the added runs, looping over events is particularly easy:
for (NAIA::Event& event : chain){
// your analysis here :)
}
If you’re uncomfortable with range-based for loops you can still do it the old fashioned way
unsigned long long nEntries = chain.GetEntries());
for (unsigned long long iEv = 0; iEv < nEntries; iEv++) {
NAIA::Event &event = chain.GetEvent(iEv);
// your analysis here :)
}
NAIA root-files contain two more TTree
with additional data for the analysis.
The RTIInfo
tree#
The data about the ISS position, its orientation, and physical quantities connected to them, as well as some time-averaged data about the run itself are usually retrieved in AMS analysis from the RTI (Real Time Information) database. This database stores data with a time granularity of one second, and it can be accessed using the gbatch library.
Since we try to get rid of any dependency on gbatch during the analysis the entire RTI database is converted to a TTree
that is stored
alongside the main event TTree
in the NAIA root-files. This tree has only one branch, which contains objects of the RTIInfo
class, one for each second of the current run.
When looping over the events you can get the RTIInfo
object for the current event by calling
NAIA::RTIInfo &rti_info = chain.GetEventRTIInfo();
In some cases you might not want to loop over all the events, but still perform analysis on the RTI data standalone. In such cases you can directly retrieve the RTI tree from the NAIA file and loop over each second.
TChain* rti_chain = chain.GetRTITree();
NAIA::RTIInfo* rti_info = new NAIA::RTIInfo();
rti_chain->SetBranchAddress("RTIInfo", &rti_info);
for(unsigned long long isec=0; isec < rti_chain->GetEntries(); ++isec){
rti_chain->GetEntry(isec);
// your analysis here :)
}
The FileInfo
tree#
In a similar fashion we also store some useful information about the original AMSRoot file that from which the current NAIA file was derived.
This information is stored in the FileInfo TTree
, which usually has only a single entry for each NAIA root-file. Having this data in a
TTree
allows us to chain multiple NAIA root-files and still be able to retrieve the FileInfo data for the current run we’re processing.
This tree has one branch, which contains objects of the FileInfo
class
and, if the NAIA root-file is a Montecarlo file, an additional branch containing objects of the
MCFileInfo
class.
When looping over the events you can get both objects for the current event by calling
NAIA::FileInfo &file_info = chain.GetEventFileInfo();
NAIA::MCFileInfo &mcfile_info = chain.GetEventMCFileInfo();
Also in this case you can directly retrieve the FileInfo tree from the NAIA file and loop over each entry.
TChain* file_chain = chain.GetFileInfoTree();
NAIA::FileInfo* file_info = new NAIA::FileInfo();
NAIA::MCFileInfo* mcfile_info = new NAIA::MCFileInfo();
file_chain->SetBranchAddress("FileInfo", &file_info);
if(chain.IsMC()){
file_chain->SetBranchAddress("MCFileInfo", &mcfile_info);
}
for(unsigned long long i=0; i < file_chain->GetEntries(); ++i){
file_chain->GetEntry(i);
// do stuff with file_info
if(chain.IsMC()){
// do stuff with mcfile_info
}
}
Containers#
The main structure for holding data in the NAIA data model is the Container. Each container is associated to
a single branch in the main TTree
and allows for reading the corresponding branch data only when first
accessed.
This means that if you never use a particular container in your analysis, you’ll never read the corresponding data from file
Note
i.e.: TBranch::GetEntry
will never be called unless actually needed
Warning
In order for this to work in NAIA we overload the ->
operator to hide this “read-on-demand” behavior. It is
required that you always use ->
to access the data members and methods of a container.
Example:
// Get the inner tracker charge from the "trTrackBase" container
auto innerCharge = event.trTrackBase->Charge[NAIA::TrTrack::ChargeRecoType::YJ];
// ^^
// this is very important :)
Variable types and structure#
Most variables in AMS analysis are computed for several different variants, which usually refer to different
possible reconstructions of the same quantity. To mantain the data format as light as possible, and not
write to disk non-existing data, variables in NAIA are often implemented as associative containers
(e.g: std::map
).
If that is the case, then there is always a enum
describing all the available variants for a given variable.
If you want to make sure that a given variant exists you can use the ContainsKeys
function.
This function takes a container and one or more keys and will check recursively that those keys exist in the container structure.
if (NAIA::ContainsKeys(event.tofBase->Charge, NAIA::Tof::ChargeType::Upper))
tof_charge = event.tofBase->Charge[NAIA::Tof::ChargeType::Upper];
because it is not guaranteed that, for example, a particular reconstruction succeeded, or that there is a hit on a given layer.
Note
The KeyExists
function is completely replaced by ContainsKeys
. It is still available for backward-compatibility but it is now deprecated
and will be removed in a future release. A warning message will be printed (at most 10 times), advising to switch to ContainsKeys
.
As an example, what before would have been achieved with
if (KeyExists(layer, LayerCharge) && KeyExists(NAIA::Track::ChargeRecoType::YJ, LayerCharge.at(layer)) &&
KeyExists(TrTrack::Side::X, LayerCharge.at(layer).at(NAIA::Track::ChargeRecoType::YJ)))
is now done by
if (ContainsKeys(LayerCharge, layer, NAIA::Track::ChargeRecoType::YJ, TrTrack::Side::X))
Note
Not all variables are stored in associative containers, when we know that all possible variants of a variable will be present
we use a std::vector
instead.
In NAIA there are several variable archetype defined, so that it is clear which enum
to use and what kind of variable
variant is available. The archetypes in the NAIA data model are:
LayerVariable
: one number for each layer (applies to Tracker, Tof, TRD, …).Uses the layer number
(0, ..., N-1)
for accesstemplate<class T> using LayerVariable = std::map< unsigned int, T >
Example:
unsigned int layer = 4; // layer 5 if (NAIA::ContainsKeys(event.trTrackPlus->TrackFeetDistance, layer)) track_distance_to_feet_l5 = event.trTrackPlus->TrackFeetDistance[layer];
EcalEnergyVariable
: one number for each energy reconstruction type.Uses the
Ecal::EnergyRecoType
enum for accesstemplate<class T> using EcalEnergyVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.ecalBase->Energy, NAIA::Ecal::EnergyType::EnergyD)) ecal_energy_D = event.ecalBase->Energy[NAIA::Ecal::EnergyType::EnergyD];
EcalLikelihoodVariable
: one number for each likelihood type.Uses the
Ecal::LikelihoodType
enum for accesstemplate<class T> using EcalLikelihoodVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.ecalPlus->Likelihood, NAIA::Ecal::Likelihood::Integral)) ecal_likelihood = event.ecalPlus->Likelihood[NAIA::Ecal::Likelihood::Integral];
EcalBDTVariable
: one number for each BDT type.Uses the
Ecal::BDTType
enum for accesstemplate<class T> using EcalBDTVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.ecalBase->BDT, NAIA::Ecal::BDTType::v7std)) bdt = event.ecalBase->BDT[NAIA::Ecal::BDTType::v7std];
RichBetaVariable
: one number for each RICH beta reconstruction type.Uses the
Rich::BetaType
enum for accesstemplate<class T> using RichBetaVariable = std::map< Rich::BetaType, T >
Example:
if (NAIA::ContainsKeys(event.richBase->GetBeta(), NAIA::Rich::BetaType::CIEMAT)) rich_beta = event.richBase->GetBeta()[NAIA::Rich::BetaType::CIEMAT];
TofChargeVariable
: one number for each kind of Tof charge.Uses the
Tof::ChargeType
enum for accesstemplate<class T> using TofChargeVariable = std::map< Tof::ChargeType, T >
Example:
if (NAIA::ContainsKeys(event.tofBase->Charge, NAIA::Tof::ChargeType::Upper)) tof_charge = event.tofBase->Charge[NAIA::Tof::ChargeType::Upper];
TofBetaVariable
: one number for each Tof beta reconstruction type.Uses the
Tof::BetaType
enum for accesstemplate<class T> using TofBetaVariable = std::map< Tof::BetaType, T >
Example:
if (NAIA::ContainsKeys(event.tofBase->Beta, NAIA::Tof::BetaType::BetaH)) tof_beta = event.tofBase->Beta[NAIA::Tof::BetaType::BetaH];
TofClusterTypeVariable
: one number for each Tof cluster type.Uses the
Tof::BetaClusterType
enum for accesstemplate<class T> using TofClusterTypeVariable = std::map< Tof::BetaClusterType, T >
Example:
unsigned int layer = 0; if (NAIA::ContainsKeys(event.tofPlus->Nclusters, layer, NAIA::Tof::BetaClusterType::OnTime)) ontime_clusters = event.tofPlus->NClusters[layer][NAIA::Tof::BetaClusterType::OnTime];
TrdChargeVariable
: one number for each TRD charge reconstruction type.Uses the
TrdK::ChargeType
enum for accesstemplate<class T> using TrdChargeVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.trdKBase->Charge, NAIA::TrdK::ChargeType::Total)) trd_charge = event.trdKBase->Charge[NAIA::TrdK::ChargeType::Total];
TrdLikelihoodVariable
: one number for each TRD likelihood type.Uses the
TrdK::LikelihoodType
enum for accesstemplate<class T> using TrdLikelihoodVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.trdKBase->Likelihood, NAIA::TrdK::LikelihoodType::Electron)) trd_like_e = event.trdKBase->Likelihood[NAIA::TrdK::LikelihoodType::Electron];
TrdLikelihoodRVariable
: one number for each TRD likelihood ratio type.Uses the
TrdK::LikelihoodRType
enum for accesstemplate<class T> using TrdLikelihoodRVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.trdKBase->LikelihoodRatio, NAIA::TrdK::LikelihoodRType::ep)) trd_likeratio_ep = event.trdKBase->LikelihoodRatio[NAIA::TrdK::LikelihoodRType::ep];
TrdOnTrackVariable
: one number for on-track / off-track TRD hits.Uses the
TrdK::QualType
enum for accesstemplate<class T> using TrdOnTrackVariable = std::vector< T >
Example:
if (NAIA::ContainsKeys(event.trdKBase->NHits, NAIA::TrdK::QualType::OffTrack)) offtrack_hits = event.trdKBase->NHits[NAIA::TrdK::QualType::OffTrack];
TrackChargeVariable
: one number for each Tracker charge reconstruction type.Uses the
TrTrack::ChargeRecoType
enum for accesstemplate<class T> using TrackChargeVariable = std::map< TrTrack::ChargeRecoType, T >
Example:
if (NAIA::ContainsKeys(event.trTrackBase->InnerCharge, NAIA::TrTrack::ChargeRecoType::YJ)) trtrack_charge_inner = event.trtrackBase->InnerCharge[NAIA::TrTrack::ChargeRecoType::YJ];
TrackFitVariable
: one number for each track fitting type, and for each track span type.Uses the
TrTrack::Fit
andTrTrack::Span
enums for accesstemplate<class T> using TrackFitVariable = std::map< TrTrack::Fit, std::map< TrTrack::Span, T >>
Note
For this kind of variable you can use
TrTrackBase::FitIDEsists(TrTrack::Fit fit, TrTrack::Span span)
to check if a given fit+span combination existsExample:
if (event.trTrackBase->FitIDExists(NAIA::TrTrack::Fit::Kalman, NAIA::TrTrack::Span::InnerL1)) trtrack_rigidity_innerL1 = event.trtrackBase->Rigidity[NAIA::TrTrack::Fit::Kalman][NAIA::TrTrack::Span::InnerL1];
TrackFitOnlyVariable
: one number for each Track fit type.Uses the
TrTrack::Fit
enum for accesstemplate<class T> using TrackFitOnlyVariable = std::map< TrTrack::Fit, T >
Example:
unsigned int layer = 1; // exclude layer 2 if (NAIA::ContainsKeys(event.trTrackPlus->PartialRigidity, layer, NAIA::TrTrack::Fit::Choutko)) ontime_clusters = event.trTrackPlus->PartialRigidity[layer][NAIA::TrTrack::Fit::Choutko];
TrackSideVariable
: one number for each Tracker side.Uses the
TrTrack::Side
enum for accesstemplate<class T> using TrackSideVariable = std::map< TrTrack::Side, T >
Example:
if (NAIA::ContainsKeys(event.trTrackBase->TrTrackHitPos, layer, NAIA::TrTrack::Side::X)) ontime_clusters = event.trTrackBase->TrTrackHitPos[layer][NAIA::TrTrack::Side::X];
TrackFitPosVariable
: one number for each fixed z-position in the Tracker.Uses the
TrTrack::FitPositionHeight
enum for accesstemplate<class T> using TrackFitPosVariable = std::map< TrTrack::FitPositionHeight, T >
Example:
auto fit = NAIA::TrTrack::Fit::Kalman; auto span = NAIA::TrTrack::Span::InnerL1; if (NAIA::ContainsKeys(event.trtrackBase->TrTrackFitPos, NAIA::FitPositionHeight::TofLayer0)){ if (event.trTrackBase->FitIDExists(fit, span)){ trtrack_position_at_upper_tof_x = event.trtrackBase->TrTrackFitPos[NAIA::FitPositionHeight::TofLayer0][fit][span][NAIA::TrTrack::Side::X]; } }
TrackDistanceVariable
: one number for each distance-from-the-track type.Uses the
TrTrack::DistanceFromTrack
enum for accesstemplate<class T> using TrackDistanceVariable = std::map< TrTrack::DistanceFromTrack, T >
Example:
unsigned int layer = 1; // layer 2 if (NAIA::ContainsKeys(event.trTrackPlus->NClusters, layer, NAIA::TrTrack::DistanceFromTrack::Onecm, TrTrack::Side::X)) track_clusters_within_onecm_x = event.trTrackPlus->NClusters[layer][NAIA::TrTrack::DistanceFromTrack::Onecm][TrTrack::Side::X];
HitChargeVariable
: same asTrackChargeVariable
Please refer to the doxygen documentation for all the details.