KaliVeda
Toolkit for HIC analysis
|
The base class for the description of the kinematics of all particles in KaliVeda is KVParticle. It implements all kinematical manipulations necessary for obtaining angles, kinetic energies, transverse energies etc. etc., defining and changing relativistic reference frames.
Unless otherwise stated,
KVParticle is derived from TLorentzVector - a particle is basically a Lorentz 4-vector with added attributes (mass!). This means that all particles and kinematics are relativistic in KaliVeda.
Particle kinematical properties can be defined either using one of the constructors :
or with the usual 'Set' methods:
Particles are created with a given kinetic energy and direction (or momentum) Particle kinematics in different frames can be accessed with several methods provided by KVParticle, all using the KVFrameTransform class which represents one of the allowed kinematical transformations:
This method can be used to access the kinematics of any particle in a different frame to the one in which its kinematics were defined
Example: inspect kinematics of particle
Particle kinematics can be permanently modified using this method:
Example: change kinematics of particle
Rather than changing the reference frame of the particle, you can define and use several different reference frames while keeping the original kinematics as the default. Each frame can be used independently, and new frames can be defined based on any of the existing frames:
Example:
Note that the same frame can be defined directly from the original particle by using a combined boost-then-rotation transform:
part.SetFrame("rotated_moving_frame", KVFrameTransform({0,0,5},rot));Utility class for kinematical transformations of KVParticle class.Definition KVFrameTransform.h:61
Note that the frame "rotated_moving_frame"
is directly accessible even if it is defined in two steps as a rotation of the "moving_frame"
.
The total number of defined frames (including the default frame) is given by KVParticle::GetNumberOfDefinedFrames(). Calling KVParticle::Print() will show all reference frames defined for the particle:
Indentation indicates the relationships between frames: "rotated_moving_frame"
is a child frame of "moving_frame"
. The first line is the default kinematics, which by default has no name (a name can be set using KVParticle::SetFrameName()).
The current default kinematics can always be accessed using KVParticle::GetCurrentDefaultKinematics(): this method returns the default kinematical frame for the particle when accessed from any kinematical frame:
Let us consider a particle for which the different reference frames in the previous paragraph have been defined. For an example, imagine that the default kinematics are that of particle with rest mass 939 MeV moving with a momentum of 250 MeV/c at an angle of \(45^o\) to the +ve z-direction:
Now if we want to change the default kinematical frame for this particle:
The relationships between frames are preserved, i.e. if we present the frames as graphs:
with "lab" as default frame:
with "rotated_moving_frame" as default frame:
If you call KVParticle::SetFrame() several times with the same frame name [note that frame names are case insensitive], the existing reference frame will be updated to use the new transformation, which will be applied to the kinematics of the particle in the 'parent' frame used to define the frame. Any frames which were defined based on the frame will be updated too.
Example: for the previous particle & frame definitions, after resetting the default kinematics:
Note that in this case, the "rotated_moving_frame" is updated automatically to take account of the new velocity of "moving_frame".
However, if you change the kinematics of the particle in its original (default) frame, you have to update the kinematics in all defined frames by hand, it does not occur automatically:
Atomic nuclei are described by the KVNucleus class. Nuclei can be initialised using \(Z\), \(Z\) and \(A\), or the symbol for the element (eventually with an isotopic mass):
When no isotope mass is specified for an element \(Z\), the mass number \(A\) is calculated according to some formula:
\(Z\) and \(A\) can also be specified in separate steps:
Many informations on the known properties of atomic nuclei are included in the toolkit:
This will print out:
Although not part of or accessible from a KVNucleus object, the KVLevelScheme class includes information on nuclear levels and excited states for nuclei. To use it:
The '+', '-' and '=' operators have been redefined for the KVNucleus class. One can therefore perform "nuclear arithmetic":
Example:
which produces the following output:
The \(Z\), \(A\), momentum vector and excitation energy of 'c' are calculated from the appropriate conservation laws. The mass excesses of the 3 nuclei are obviously taken into consideration. Therefore if 'a' and 'b' are projectile and target, 'c' is the compound nucleus after fusion, with its \(Z\), \(A\), recoil velocity and excitation energy.
In order to perform calorimetry (calculation of source characteristics from daughter nuclei) one need only sum all nuclei associated with the source. The resulting nucleus is the source nucleus with its Z, A, momentum and excitation energy.
The subtraction operator allows to perform energy balance for a binary splitting of a nucleus. Example:
In this case, the resulting nucleus 'd' should be identical to 'a' in the first example. One could also imagine
where 'alpha' is a KVNucleus alpha-particle, for which we specify the momentum after emission. The resulting nucleus 'e' is the residue of the fusion compound after evaporation of an alpha particle.
The operators '+=' and '-=' also exist. 'a+=b' means 'a = a + b' etc.
The main business of KaliVeda is the analysis of multi-body events produced in heavy-ion reactions, therefore it is no surprise that a central role is played by container classes for collections of nuclei, known as events. In fact there are three main event classes:
Each of these classes inherits from the abstract base class KVEvent which can be used as an argument for general functions which can manipulate any type of event:
Events are built up by successive calls to the KVEvent::AddParticle() method, which adds a particle object to the event corresponding to the event's defined particle type, and returns a pointer to the new particle:
A small subtlety of this (virtual) method is that, when the event is accessed through a base pointer or reference, the pointer returned by KVEvent::AddParticle() is also a base pointer (to a KVParticle), although the added particle is of course always of the correct type for the event:
We also provide the KVEvent::AddNucleus() method, which does exactly the same thing as KVEvent::AddParticle(), except that it always returns a pointer to KVNucleus, as long as the particles contained in the event derive from KVNucleus (otherwise it returns nullptr
):
Once added to an event, a particle cannot be removed from the event; however, all particles can be removed (deleted) in order to build a new event with method Clear():
The number of particles in any event (the size of the container) is called the multiplicity of the event, and is given by the method KVEvent::GetMult():
The multiplicity can also be restricted to consider only nuclei which are considered "OK" for analysis (this usually concerns only reconstructed events) or counting only nuclei belonging to a previously defined "group":
All nuclei in an event belong to the event and are destroyed by the KVEvent destructor when it goes out of scope.
Therefore a KVEvent cannot be used to store references to nuclei in another KVEvent object, for example if one wants to handle a subset of the nuclei in the event. This is why the iterators presented below allow to iterate only over selected subsets (groups) of particles if required.
If you really need to store a list of references to some nuclei in an event, you can use an STL container, TCollection or KVSeqCollection collection class to store the nuclei's pointers, as long as the collection does not try to delete the objects when it goes out of scope (e.g. don't use KVList which owns its objects by default).
You can if you wish copy all or part of an event, as long as you understand that the nuclei in the copy will be new independent objects; they will not change if you change the original event after the copy (there may also be unwanted side-effects, especially for KVReconstructedNucleus particles).
Making a complete copy of an event (included the associated list of parameters) can be done like this:
Although it is difficult/unwise to separate events into subevents, on the other hand it is possible to merge several event fragments into one single event:
WARNING after merging, the subevents in the list will be empty and useless. Do not try to use them after merging!
Events i.e. KVEvent-derived objects can be written in a branch of a TTree in order to store them in a ROOT file. This is the format used for all event-based data handled (or generated) by KaliVeda.
Here is a complete example of how to write events in a TTree on disk:
Reading back the events written in the branch of a TTree can be done as follows:
There are several different ways to loop over all (or part of) the nuclei in an event and do something useful (for analysis) with them.
Note that the same result can be achieved thus:
As for the KVEvent::AddParticle() method (see above), the type of pointer returned by KVEvent::GetParticle() changes if the event is accessed through a base pointer or reference: in this case a base KVParticle pointer or reference is returned. If the particles in the event are derived from KVNucleus, KVEvent::GetNucleus() can be used in cases where a pointer to KVNucleus is sufficient. If more specific child class methods are accessed for the nuclei in the event, casting is required:
In a simple indexed loop, if the iteration is to be restricted to only "OK" particles, or only those belonging to a previously-defined group, the loop must still be carried out over the full event (i.e. using KVEvent::GetMult() with no arguments), and the test performed for each particle:
Note that each of these iterations can be replaced by:
The KVEvent::GetNextParticle() and KVEvent::GetNextNucleus() methods can be used to easily loop over nuclei in an event (the former returns a pointer of the type of the particles in the event - unless the event is accessed through a base KVEvent pointer or reference, in which case a KVParticle pointer is returned - , the latter a KVNucleus pointer):
This method is deprecated as it uses a shared internal iterator which makes it impossible to perform a nested loop using two such iterations; some methods such as KVEvent::GetMult() may also use the same internal iterator, therefore using any of those inside a loop using KVEvent::GetNextParticle() will have unexpected results!
As for the KVEvent::GetParticle() method (see above), the type of pointer returned by KVEvent::GetNextParticle() changes if the event is accessed through a base pointer or reference: in this case a base KVParticle pointer or reference is returned. Therefore if specific child class methods are accessed for the nuclei in the event, care must be taken:
With the KVEvent::GetNextParticle()/KVEvent::GetNextNucleus() methods, it is easy to restrict the loop to only nuclei which are "OK" or only those belonging to a previously defined group:
Again, the name of the group or the "OK" status argument are case insensitive.
STL containers such as std::vector can be iterated over using the std::vector::iterator class:
KVEvent containers can be iterated over in an analogous fashion:
Dereferencing the iterator (i.e. the result of *it
) gives a reference to the type of nucleus contained in the event: in this case, a reference to a KVReconstructedNucleus. The following table resumes the different event classes & associated iterators and underlying nucleus types:
Event class | Iterator class | Type of nucleus |
---|---|---|
KVNucleusEvent | KVNucleusEvent::Iterator | KVNucleus |
KVSimEvent | KVSimEvent::Iterator | KVSimNucleus |
KVReconstructedEvent | KVReconstructedEvent::Iterator | KVReconstructedNucleus |
The iterator returned by KVReconstructedEvent::begin() in the previous example will include all nuclei of the event in the loop: this Iterator is of type KVReconstructedEvent::Iterator::Type::All. Iterating over only a selection of particles can be achieved using the KVTemplateParticleCondition class, which is just a wrapper for a lambda function used to select each particle according to user-defined criteria:
To iterate over a selected subgroup of particles can therefore be carried out as in the following example:
Note that the type of the particle pointer argument in the lambda function must match the type of particles in the event.
Alternatively, you can call the ConditionalIterator() method of the event:
In order to simplify the use of such iterators, and especially when events are accessed through a KVEvent base pointer or reference (see below), we provide wrapper classes and aliases for an easier interface:
The following table resumes all types, wrappers and aliases for the three main event classes:
Event class | Iterator type | Wrapper | Alias |
---|---|---|---|
KVNucleusEvent | KVNucleusEvent::Iterator::Type::All | KVNucleusEvent::EventIterator | EventIterator |
KVNucleusEvent::Iterator::Type::OK | KVNucleusEvent::EventOKIterator | EventOKIterator | |
KVNucleusEvent::Iterator::Type::Group | KVNucleusEvent::EventGroupIterator | EventGroupIterator | |
KVReconstructedEvent | KVReconstructedEvent::Iterator::Type::All | KVReconstructedEvent::EventIterator | ReconEventIterator |
KVReconstructedEvent::Iterator::Type::OK | KVReconstructedEvent::EventOKIterator | ReconEventOKIterator | |
KVReconstructedEvent::Iterator::Type::Group | KVReconstructedEvent::EventGroupIterator | ReconEventGroupIterator | |
KVSimEvent | KVSimEvent::Iterator::Type::All | KVSimEvent::EventIterator | SimEventIterator |
KVSimEvent::Iterator::Type::OK | KVSimEvent::EventOKIterator | SimEventOKIterator | |
KVSimEvent::Iterator::Type::Group | KVSimEvent::EventGroupIterator | SimEventGroupIterator |
The Group
and OK
variants are specialized versions for selecting all particles belonging to a named group, or all particles which are "OK".
Just as STL containers can be iterated over using a range-based for
loop,
the same facility is also available for event classes, thanks to the iterator classes and wrappers presented above:
Note the use of an automatic reference type for nuc
: this is recommended to avoid copying of underlying nucleus objects, which may have unfortunate side-effects in certain cases (KVReconstructedNucleus).
Range-based for loops limited to subsets of selected particles can also be easily implemented thanks to the wrappers introduced above:
Often, for example in analysis classes, the event to be analysed (=iterated over) is accessed through a pointer or reference of base type KVEvent, for example via the KVEventSelector::GetEvent() method. The STL-type iterators which allow to perform the range-based for loops presented above are not defined for KVEvent, only in daughter classes inheriting from the templated class KVTemplateEvent. In such a case we do not necessarily know in advance what is the actual type of the event (and hence of the contained nuclei). However, the wrapper classes presented above require only a base pointer or reference (KVEvent* or KVEvent&), and so still can be used:
The choice of wrapper to use depends on the type of nucleus reference which is required in the loop, which in turn depends on the methods applied to each nucleus in the code: if only those methods which are defined for KVNucleus are required, an EventIterator wrapper (which returns KVNucleus& references) can be used; if methods specific to KVSimNucleus are used, a SimEventIterator wrapper should be used; etc. The following table resumes the different options:
It should be noted that these iterator wrappers are not 'type-safe': at compile time, there is no way of knowing if the event whose pointer or reference is supplied to the wrapper at run time will contain nuclei of the class corresponding to the wrapper (note that it is perfectly OK for the nuclei in the event to be of a class which inherits from the wrapper nucleus type). Consider the following example:
The KVSimEvent contains KVSimNucleus nuclei; using the ReconEventIterator wrapper with a base reference to this event, we attempt to use a method with these nuclei which is only defined for KVReconstructedNucleus nuclei. This would have disastrous consequences (segmentation violation). To avoid this, a warning will be printed if the wrapper does not correspond to the type of nuclei in the event, and no iteration will be performed: in the previous case, this will give:
You can define and use several different reference frames for the particles in an event. Each frame can be used independently, and new frames can be defined based on any of the existing frames:
Example:
Note that the same frame can be defined directly from the original frame of all particles in the event by using a combined boost-then-rotation transform:
Note that the frame "rotated_moving_frame"
is directly accessible even if it is defined in two steps as a rotation of the "moving_frame"
.
Let us consider an event for which the different reference frames in the previous paragraph have been defined. Calling method KVEvent::Print() will show all reference frames defined for each particle:
Indentation indicates the relationships between frames: "rotated_moving_frame"
is a child frame of "moving_frame"
. The first line is the default kinematics. As yet it has no name, but if we want we can set a name for the default kinematics of each particle in the event:
Now if we want to change the default kinematical frame for the event by using KVEvent::ChangeDefaultFrame():
Note that the name of the default kinematics is stored as a parameter "frameName"
and can be retrieved with method KVEvent::GetFrameName(). Note also how the relationships between frames are preserved, i.e. if we present the frames as graphs:
with "lab" as default frame:
with "rotated_moving_frame" as default frame: