NA60 Note 2003-
February 7, 2003
The NA60 Monitoring Framework (Version 1.000)
IST, Lisbon, Portugal
In this note all the components of the NA60 Monitoring Framework are presented
and explained in detail. This includes the monitoring framework proper, designed
exclusively for online purposes, and the offline portion, designed to monitor data
files. This last part was integrated in NA60ROOT to open the DATE files with
The NA60 Monitoring Framework was conceived due to the very similar
requirements that all of the (many) monitoring programs used in the experiment
have. Instead of repeating the same code over and over again, to do very similar
things, OOP (Object Oriented Programming) was used with C++ to create
reusable modules containing the behaviour common to all programs. After this
initial stage, other modules were added to be used for features belonging to a
certain subclass of monitoring programs.
As the NA60 experiment uses DATE for data acquisition, the online and offline
(DATE files) data have the same format, making it easy for the monitoring
programs to read either one of them in the exact same way. The NA60 Offline
Program, however, has to read the data files to do its analysis. After a few
modifications, the NA60 Monitoring Framework code was used in NA60ROOT to
do exactly that.
ROOT is used for all the graphics, including histograms. That makes it easy to
analyse the data via the standard ROOT fitting routines without needing to write
the code for that ourselves. ROOT is also used for mouse input and GUI
(Graphical User Interface) routines.
Throughout this note, it is assumed that the reader is familiar with C++ and
OOP concepts, as well as some of the terms associated to DATE.
2. Class Organisation
The main classes in the framework are NaMonitor, NaDateDecoder and
NaSource. NaMonitor deals with the common behaviour we expect from all
monitoring programs. NaDateDecoder is a base class for a classes that read
DATE files and decodes the raw data in the file into something more
understandable (such as columns and rows for the pixel telescope), which are
called digits. Finally, NaSource is a base class for all data sources programs
might want to read from.
A general monitoring program will define a class deriving from NaMonitor to
monitor the data; another one that derives from NaDateDecoder to not only
decode the data it receives but also to actually fetch it from the stream; and a
digit class to contain the decoded data that will be passed from the decoder to
the monitor class. The only prerequisite for the digit class is that it must derive
from the ROOT class TObject and have a dictionary (in the ROOT sense of the
word). This is necessary since objects of this digit class will be stored in a class
deriving from the ROOT container TClonesArray. This also means that all of the
digits must belong to the same class.
NaMonitor deals with common functions that aren't particular to any of the
monitoring programs. In general, such a program will want to look at the next
event, know if we are supposed to integrate over several events, reset the display,
etc. This class handles all these operations generically, not needing to know what
the program outputs to the screen, or the kind of data it receives. All of the
application specific functionality is contained in virtual functions, delegating the
responsibility to child classes.
The actual GUI is handled by another class, NaMonitorGui. This links the
buttons and text boxes to functions in NaMonitor, such as the ones that start or
stop acquiring data. The graphical refresh after the selected number of events is
also handled by a separate class, NaMonitorRefresh.
Each time NaMonitor fetches new data, it calls its member function
HandleNextDigits. After fetching the decoded digits, this function first extracts
event header information so it can show the event number, run number and
burst number. It uses the virtual function DigitsHandler to update the
application dependent data structures, and the virtual functions UpdateDisplay
and ResetDisplay to correctly manage the graphical output according to the
Decoded digits are returned by a NaDateDecoder member object which is
passed to the NaMonitor constructor. This means that to use a NaMonitor, you
must specify where it gets its data from via a NaDateDecoder object. Digits are
then obtained by calling the public method GetDigits on this object.
Monitoring programs are divided into 2 classes: those that show multiple
screens of data (NaTabMon), and those that show only one (NaCanvasMon). The
multiple screen programs use tabs so that the user can select which screen he or
she wants to see. This needs some extra code, not only for the tabs, but also
because updating all of them at once could be slow. To solve this problem,
bookkeeping is done so as to only update screens that have changed and that
have been selected. All of the current monitoring programs derive from one of
these 2 classes.
This class is responsible for decoding the raw data and transforming it into
digits. It calls the virtual function DecodeDigits to do the application specific
decoding, and returns an array of digits (of the class NaDigitsArray) when a
client calls its public method GetDigits.
NaDateDecoder derives from NaDateReader, which is a class for reading
DATE streams, which can be online data or DATE files. The standard way for
doing this is via the library distributed with DATE (either libmonitor.a or
libmonitorstdalone.a) with C and FORTRAN functions to access the events in
the stream. This library also allows the client code to specify a monitoring policy
(please consult the DATE manual), amongst other options. Unfortunately, the
DATE library only allows the client code to open one DATE stream at a time.
There is an OOP library that allows for multiple data sources, but it only works
with ROOT version 2.23 or under. To allow us to work with more recent versions
of ROOT, a custom class for reading DATE files and fetching the desired events
was written. The DATE library is still used to read online streams, however.
The reason why we need NaDateReader to be able to read from more than one
DATE file at once is twofold: first, because the events from one run are split into
several files due to the existence of more than one GDC; and second, because in
the offline analysis we need information from a file that is after the event we are
analysing. In the latter case, we need to open the same file twice.
NaDateReader deals with getting the relevant information from a data file.
There are many layers of information, with correspondent headers and trailers.
As all of the NA60 readout programs use the generic readlist to read out the
front-end electronics (please consult chapter 7 of the DATE manual), the data for
a single detector is separated into equipments. A detector may have several copies
of a particular equipment type, and so there are also equipment ID numbers.
Specifying which portions of data we are interested in (defined by the triplet
<detector ID, equipment type, equipment ID>) by setting the protected member
variable fEqParams in derived classes, it is then easy to process the information
in an event sequentially (as we would want to do in a monitoring program) by
redefining the virtual function RawDataHandler. This function is called
automatically by EventHandler, which can be used for handling one specific
event or for looping over all events in the stream, where it is called by the method
The member variable fEqParams is an array of NaEqParams objects, each one
being a triplet of the kind mentioned above. This is basically a list of the
equipments we want to read from the DATE stream. The class that actually uses
that information to return a pointer to the requested data is NaDateEvent, which
encapsulates the structure used by DATE to store experimental data.
NaDateEvent encapsulates a DATE event, keeping track of whether or not it is
a GDC event or an LDC subevent, the error code for when it was created and
other details. Its most used public method is GetEqData, which uses the
NaEqParams information passed to it to return a pointer to a NaEqData object.
With this object, one has access to the raw data (via a pointer to unsigned chars),
as well as other variables such as the DATE event header. Since some NA60 runs
include different detectors than others, NaDateEvent can also check the
existence of data from a certain detector via its public method
As mentioned before, some offline uses of these classes require NaDateReader
to read from more than one file at once. Online monitoring, on the other hand,
reads only from one stream at a time. Since the general behaviour does not
change, only one interface is used to access the events from the source(s),
defined by NaSource. An array of sources has extra management associated to it,
since we cannot guarantee an equal distribution of events among the sources in
the array. By specifying a common interface for getting the next event
(CreateNextEvent), we leave that kind of bookkeeping to NaSourceArray, which
is a class that derives from NaSource, and thus has to implement its interface.
NaDateReader is created by specifying a source of data via a string. If this
string happens to be a number, it considers it to be a run number, looks for all
GDC files (should they exist) in directories contained in a configuration file, and
initialises a source array with all GDC files found. Each of these sources in the
array will be NaDateFileSource objects. As most runs distribute events across
several files for one GDC to avoid huge data files, once a file ends these sources
look for the next file in the sequence and carry on fetching events as if it were in
the same file.
There is also an ad-hoc data source class called NaStripSource. During the
October 2001 run, the readout for the MST telescope had not yet been integrated
in the general DAQ. This lead to the creation of pure binary files with the strips
data that did not conform to the DATE standard. To avoid a completely different
way of monitoring this data, NaStripSource dealt with the MST data dependent
functionality without changing the rest of the monitoring framework. The other
classes can then request an event in exactly the same manner, using the same
interface. NaStripSource objects are instantiated depending on the file
extension. Any file that isn't a .raw file is treated as being an MST file, since
those do not have a fixed extension and the NA60 DATE files do.
In any of these cases, however, the specific NaSource object is instantiated via
the virtual constructor CreateDataSource in NaDataSource.
3. Program Examples
Below are screenshots from 2 of the programs used in the actual NA60
experiment. Both of these use the monitoring framework described in this note.
In Fig. 1 we can see the 2 Beamscope planes, each represented by a colour
coded 2D histogram. The “hotter” the colour, the higher the value in that
histogram bin. This allows us to see where (if at all) the beam is hitting the
detector, and try to steer it into the centre.
To get a rotated histogram like the ones below, a 3D drawing option was used,
and the histogram was rotated in the C++ code to face the user. We also had a
problem with the 2 axes demonstrating the size of the sensor. In our first try they
were drawn on the histogram’s coordinates and were rotated as well.
The Pixel Telescope monitoring program is shown in Fig. 2. Due to
simultaneous development of the framework and this monitoring program, it
does not derive from NaCanvasMon but derives instead directly from NaMonitor.
At the time it was developed there wasn’t any NaCanvasMon to derive from. This
can be seen due to the fact that this monitoring program does not have the Run
Number, Burst Number and Event Number labels found on Fig. 1, and has its
own labels to show that, and other information.
Each of the pixel chips in the plane shown below is, as was the case in Fig. 1,
represented by a colour coded 2D histogram. This screenshot was obtained by
integrating over several events, as just one event has relatively few hits to show.
Fig 1. Beamscope monitoring program for steering the beam
Fig 2. Pixel Telescope Monitoring Program
I would like to thank the ROOT team and mailing list for support on how to use
their framework, and P. Rosinský for his suggestions to solve some of the
ROOT 3.01 Manual
DATE 2.7 Manuals