|
The ZPD DAQ
Introduction
This page describes the exact data format for the ZPD data in the DAQ TC.
It also explains how one can access those data and how the FEX is producing
it. The entire ZPD DAQ system has been designed to allow data format changes.
Details on the ZPD raw data format and on the DAQ TC data format are encapsulated
(hiden) in few classes of the L1DctOnline package. Coupled with a versioning
system for the ZPD section TC, this system gives great flexibility to change
raw data or TC data formats. Examples on how to change these formats
are provided.
|
L1DBltZpdModuleTC and L1DBltZpdParasiteModuleTC
The L1DBltZpdModuleTC has a TC identity of 0xf90bf. The L1DBltZpdParasiteModuleTC
has a TC identity of 0xf91bf. They both contain up to one L1DBltPtdSectionTC
for BLT data and 8 L1DZpdSectionTC
for ZPD data. They both derive from L1DBltZpdModuleTCBase.
L1DZpdSectionTC
The L1DZpdSectionTC contains data produced by 1 ZPD. It has
a TC primary identity of 0xf90be. Its secondary identity is used as
a version number. There are 5 versions.
- This version contains section header
+ input mask
+ fitted tracks
(without phi info) and decisions
.
- This version contains section header
+ fitted tracks
(without phi info) and decisions
.
- This version contains only the section
header
.
- This version contains section header
+ fitted tracks and decisions. There is
an extra 4 bytes of garbage after the fitted tracks data when the
number of tracks is either 6 or 10
.
- This version contains section header
+ input mask
+ fitted tracks and decisions. There is
an extra 4 bytes of garbage after the fitted tracks data when the
number of tracks is either 6 or 10
.
- This version contains section header
+ fitted tracks and decisions
.
- This version contains section header
+ input mask
+ fitted tracks and decisions
.
ZPD Section Header
The ZPD section header is always the first word in a
L1DZpdSectionTC
. It corresponds partially to the first word send
by the ZPD
. Some bits of that original word are zeroed, some other are replaced
by a different information.
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
check bit
|
DAQ format
(bit swapped)
|
0
|
Frame bits
(bit swapped)
|
0
|
DCH sector
|
Dataflow L1 Accept data
|
The check bit should always be set to 1. If it is 0, the data
are surely corrupted. If it is 1, the data may be good.
L1DZpdSectionInputTC
The L1DZpdSectionInputTC contains a L1DZpdInputMaskTickData
for each recorded tick. It has a TC identity of 0xf90bd. If present,
it is located right after the section header
. The L1DZpdInputMaskTickData has a TC identity of 0xf90bc. It is
however not a TC. It is made of five 32-bit words which are the exact
copy of the 153 input mask bit + padding send by the
ZPD
.
Fitted tracks and decisions
At the end of the L1DZpdSectionTC
, there are the data produced by the ZPD, namely, the fitted tracks
and the GLT decision. If for a given clock tick, there are no valid tracks
and if the GLT decision is zero, there is no saved data for that clock
tick. The following tables show the data format for one tick of data for
a number of tracks in that tick equal to :
[0 but non zero GLT decision
(weird case)][1
][2
][3
][4
][5
][6
][7
][8
][9
][10
][11
][12
]
The tables show the format for L1DZpdSectionTC
version 4 and 5. The format for version 1 and 2 can be obtained by removing
phi and cell info but keeping data 32-bit aligned.
0 track
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
unused
|
GLT decision word
|
0
|
Number of fitted tracks
|
Clock tick (0 to 7)
|
1 track
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
unused
|
Phi track A
|
cell track A
|
GLT decision word
|
0
|
Number of fitted tracks
|
Clock tick (0 to 7)
|
fitted track A
|
2 tracks
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Phi track B
|
cell track B
|
Phi track A
|
cell track A
|
GLT decision word
|
0
|
Number of fitted tracks
|
Clock tick (0 to 7)
|
fitted track A
|
fitted track B
|
3 tracks
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Phi track B
|
cell track B
|
Phi track A
|
cell track A
|
GLT decision word
|
0
|
Number of fitted tracks
|
Clock tick (0 to 7)
|
fitted track A
|
fitted track B
|
fitted track C
|
unused
|
Phi track C
|
cell track C
|
4 tracks
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Phi track B
|
cell track B
|
Phi track A
|
cell track A
|
GLT decision word
|
0
|
Number of fitted tracks
|
Clock tick (0 to 7)
|
fitted track A
|
fitted track B
|
fitted track C
|
fitted track D
|
unused
|
Phi track C
|
cell track C
|
Phi track D
|
cell track D
|
5 tracks
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Phi track B
|
cell track B
|
Phi track A
|
cell track A
|
GLT decision word
|
0
|
Number of fitted tracks
|
Clock tick (0 to 7)
|
fitted track A
|
fitted track B
|
fitted track C
|
fitted track D
|
fitted track E
|
unused
|
Phi track C
|
cell track C
|
Phi track D
|
cell track D
|
Phi track E
|
cell track E
|
6 tracks
7 tracks
8 tracks
9 tracks
10 tracks
11 tracks
12 tracks
ZPD track
1f
|
1e
|
1d
|
1c
|
1b
|
1a
|
19
|
18
|
17
|
16
|
15
|
14
|
13
|
12
|
11
|
10
|
f
|
e
|
d
|
c
|
b
|
a
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
tandip
|
curvature
|
engine number
|
zo error
|
z0
|
Accessing ZPD data in a TC
The access to the ZPD data are done through a collection of
abstract C++ interfaces. The ZPD data are inside a
L1DZpdSectionTC
and are accessed with a L1DAbsZpdSectionTCAccessor
.A given accessor is able to access data for one version of the
L1DZpdSectionTC
. The accessors are implemented in the L1DctOnline package. When the ZPD
DAQ data format changed during the summer 2003, the support for the TC version
1 and 2 has been reduced. The folowing table indicates which tags of L1DctOnline
can support what as a function of the TC version.
L1DZpdSectionTC
version number
|
support up to L1DctOnline gg-030820
|
support from L1DctOnline
gg-030822 to gg-030926
|
support starting with L1DctOnline
gg-030926c
|
1
|
full suport
|
support only access
to header and input mask
|
support only access
to header and input mask
|
2
|
full support
|
support only access
to header
|
support only access
to header
|
3
|
full support
|
full support
|
full support
|
4
|
not supported
|
full support with few cases with bad decoding
|
full support
|
5
|
not supported
|
full support with few cases with bad decoding
|
full support
|
6
|
not supported
|
not supported
|
full support
|
7
|
not supported
|
not supported
|
full support
|
The L1DctOnline tags between gg-030820 and gg-030822 and between gg-030926 and gg-030926c are transition tags
(and should not be used).
L1DZpdModuleTCIterator
This class knows how to extract L1DZpdSectionTC
from a L1DBltZpdModuleTCBase
. It also knows which accessor can handle which version of the
L1DZpdSectionTC
. Once created with a L1DBltZpdModuleTCBase
, L1DZpdModuleTCIterator offers 2 functions :
Since the L1DAbsZpdSectionTCAccessor
knows which L1DZpdSectionTC
it is accessing, you can have many
L1DAbsZpdSectionTCAccessor
at the same time. Clients who need to access ZPD data doesn't need to know
anything about the version of the L1DZpdSectionTC
they access.
L1DAbsZpdSectionTCAccessor
L1DAbsZpdSectionTCAccessor is the central part to access data corresponding
to one ZPD board. Its interface provides means to access each element of
the ZPD DAQ data. Access to the section header
are provided through the methods :
- d_ULong section() : returns the DCH sector (0 to
7)
- d_ULong synchBit() : returns the frame bits value.
- d_ULong dataFormat() : returns the DAQ format.
- d_Boolean headerOK() : checks that the
header check bit
is ON.
For the rest of the ZPD data, L1DAbsZpdSectionTCAccessor provides references
to iterators :
Each iterator has the ability to abort the program in case it is not used
properly. One can turn on and off that possibility for all the iterators
of a L1DAbsZpdSectionTCAccessor with the methods :
- void enableCrashOnIteratorMisuse()
- void disableCrashOnIteratorMisuse()
iterators
Iterators are
All iterators have the ability to abort the program in case they are not
used properly. One can turn on and off that possibility by calling the iterator's
methods:
- void enableCrashOnMisuse()
- void disableCrashOnMisuse()
The next() method iterates on the element. To access
the first element, one has to call next() once, to access the second element,
one has to call next() twice,...
Depending on the iterator, next returns either a boolean or a pointer.
At the end of the iteration, it returns either false or a null pointer.
The typical code to loop on these iterators is : while ( iterator.next()
) {...}
L1DAbsZpdInputMaskTickIterator
next()
returns a pointer to a const L1DZpdInputMaskTickData.
The other method is :
- d_ULong currentTick() : gives the clock tick (0 to
7) of the data currently accessed.
L1DAbsZpdDecisionTickIterator
next()
returns a boolean.
The other methods are :
- d_ULong decision() : the GLT decision
- d_ULong tick()
: the current clock tick
L1DAbsZpdTrackIterator
next()
returns a boolean.
The other methods are for accessing the data of the current track:
- d_ULong z0()
- d_ULong errZ0()
- d_ULong curvature()
- d_ULong tanLambda()
- SeedLayer seedLayer() SeedLayer = seven(numeric
value 1) or ten(numeric value 0)
- DchSector dchSide() DchSector
= first(numeric value 2) or second(numeric value 3)
- SeedIndex seedIndex() SeedIndex
(aka order) = zero(numeric value 0), one(numeric value 1) or two(numeric
value 2)
- d_ULong tick()
- d_ULong cellPhi()
- d_ULong cellLoc()
Filling the TC: the Feature EXtraction
L1Accept odfAction
The L1Accept odfAction knows very little about both the
L1DZpdSectionTC
and the raw DAQ format
send by the ZPD. This may sound surprising, let's have a closer look. The
L1Accept odfAction is a template class. It is templated on a
L1DZpdElementIterator
which knows about raw data format
and L1DZpdSectionTC
data format.
At each L1Accept, the L1Accept odfAction will create either a
L1DBltZpdModuleTC
or a L1DZBltZpdParasiteModuleTC
. It will also retrieve the odfElement containing the ZPD
raw data
and give it to its L1DZpdElementIterator.
Then, it loops on the odfElements. By using the map, the L1Accept odfAction
knows if the odfElement has been produced by a BLT or a ZPD. If it is BLT
data, it creates a L1DBltPtdSectionTC which does the BLT FEX during its creation.
If it is ZPD data, it uses the map and the
L1DZpdElementIterator
to create a L1DZpdSectionTC
with the correct version number
and section header
. It also checks for frame bit errors and assert a FEX_ERROR in case there
is one. The L1Accept odfAction has also the ability to ship a full FEXed TC
for only a fraction of the events and ship a L1DZpdSectionTC
of version 3
for the rest of the events. If the full FEX should be done, the L1Accept
will first load the entire odfElement in the processor data cache using address
pipelining which nearly doubles the speed at which the data are loaded in
the cache. Once the odfElement is loaded, it delegates the details of
the FEX to its L1DZpdElementIterator
.
So, the L1Accept odfAction knows only how to create a
L1DZpdSectionTC
and it knows only the header (the first 4 bytes) of the ZPD raw data. The
data format details are handled by the L1DZpdElementIterator
. But what ensures that the L1Accept is using the correct
L1DZpdElementIterator
? This is the configuration odfAction which knows which data format and
how many ticks of data will be shipped by the ZPD. The configuration odfAction
is able to create the correct L1Accept odfAction, the one with the correct
L1DZpdElementIterator
.
L1DZpdElementIterator
This is the class to access the ZPD raw data
. its derivatives L1DZpdElementOutputAccessor
and L1DZpdElementFullAccessor
do the ZPD FEX. L1DZpdElementIterator provides the following methods:
- L1DZpdElementIterator(unsigned ntick=8): constructor.
It precises the number of ticks that are shipped out by the ZPD. This same
kind of constructor is requested for all derivatives.
- void setElement(L1DZpdElementHeader* el): set the
odfElement. L1DZpdElementHeader is a derivative of odfElement which contains
the 32 bits of the raw ZPD data header word. ZPD
raw DAQ
data always starts by a L1DZPdElementHeader.
- void next(): go to the next L1DZpdElementHeader.
- d_Boolean end(): are we at the end
of the odfElement list?
- const L1DZpdElementHeader* element(): access to the
L1DZpdElementHeader (needed to create the L1DZpdSectionTC
)
- const L1DBltNewElement* bltElement(): conversion to
a BLT odfElement for BLT FEX.
- odfTypeIdSecondary_t secId(): Returns the
version of the L1DZpdSectionTC
this Iterator produces. L1DZpdLEmentIterator produces
L1DZpdSection version 3.
This function should be overloaded by derivatives.
- void doZpdFex(L1DZpdSectionTC
*): Does nothing for this class. Should be overloaded by derivatives.
L1DZpdElementOutputAccessor
This class extracts from the ZPD raw data
, the GLT decision and the fitted tracks. It derives from
L1DZpdElementIterator
. This is a templated class. Its template argument named decoderDriverTickData
is used to access the cellloc and phi information of the ZPD tracks for a
given tick. The requirements on decoderDriver are the following:
- if p is a pointer to decoderDriverTickData for a given tick, then p+1
points to the next tick.
- it implements a 'const L1DZpdTrackPhiTickData& trackPhi()' methods
where L1DZpdTrackPhiTickData is a class that describes one clock tick worth
of ZPD track phi and cellloc information
.
There is 2 classes that fulfill decoderDriverTickData requirements: L1DZpdTrackPhiTickData
itself when the ZPD does not send input mask data and L1DZpdDecoderDriverTickData
when ZPD sends input mask data.
During doZpdFex, this output accessor loops on the clock tick both for the
Decision Module tick data and for the Decoder Driver tick data. For each tick,
it loops on ZPD tracks
and copy those which are valid (their error is smaller than 15.) in the
L1DZpdSectionTC
. It memorizes, the engine number and counts the number of copied tracks.
After this track loop, it stores in the L1DZpdSectionTC
, the GLT decision, the number of good tracks and
the phi information of the 2 first tracks
. Finally, if there is more than 2 copied tracks, it adds their corresponding
phi informations
after the track data.
L1DZpdElementFullAccessor
This class extracts from the ZPD raw data
both the track information and the input mask information. It derives from
L1DZpdElementOutputAccessor<L1DZpdDecoderDriverTickData>.
During doZpdFex, it first creates a L1DZpdSectionInputTC
after the section header
and copy all L1DZpdInputMaskTickData
into it. It then calls the L1DZpdElementOutputAccessor
doZpdFex
method to append the track data after the
L1DZpdSectionInputTC
.
Why is it so easy to change data formats.
The details of both the raw ZPD DAQ
data and of the L1DZpdSectionTC
are encapsulated (hiden) behind interfaces. The offline world sees
L1DZpdSectionTC
through a polymorphic interface defined by
L1DAbsZpdSectionTCAccessor
and related classes. As an example, the TC to digi doesn't know anything
about the TC format. For the ROM side, virtual function calls take too much
time for the FEX. In that case the abstraction is implemented through template
arguments in templated classes. Those template arguments are the
L1DZpdElementIterator
and derivatives. As an illustration, you can change the
ZPD raw DAQ format
and the L1DZpdSectionTC
data format wiothout changing nor the ZPD L1Accept action neither
the ZPD configure action.
Both L1DAbsZpdSectionTCAccessor
and L1DZpdElementIterator
are in the L1DctOnline package. One might object to this choice. L1DctOnline
is a dual use package and the number of classes in it should be kept as low
as possible. The L1DAbsZpdSectionTCAccessor
is a pure offline concept and could be put in L1DctOep while the
L1DZpdElementIterator
is a pure dataflow concept and can be put in L1DctOdf. The above argument
is right, however, it makes plain sense to have in the same package the classes
that create the data structure and the classes that read the same data structure.
When a change in the data format occurs, both the creators and the accessors
need to be changed, they are a unit of release which is what a package is.
In the following, we will see examples on how to change
the DAQ raw data format
and how to change the TC data format
.
A new raw DAQ format
There is a significant amount of padding
to keep ZPD data 4 bytes aligned. In a clock tick of data, there is the
GLT decision (1 byte data + 3 bytes padding). After it, there is the 12 tracks,
each of it is made of 1 byte for the curvature, 1 byte for tandip, 1 byte
for z0, half a byte for the error on z0 and half a byte of padding.
In total, for each clock tick, there is 3+12*0.5=9 bytes of padding. For 8
clock ticks, this represents 72 bytes of zeros which is quite important.
It is possible to send the same amount of information, with less padding
and still have data 4 bytes aligned. Rather than sending track information
track by track, we can send information measurement by measurement. The new
format would be: the GLT decision (1 byte + 1 byte of padding) followed by
the z0 errors(6 bytes) then the 12 curvatures (12 bytes) then the 12 tandip
(12 bytes), then the 12 z0(12 bytes). With this data format, there is only
1 byte of padding per clock tick. For 8 clock ticks, it reduces the raw DAQ
size by 64 bytes.
If such a change occurs, the ZPD FEX needs to be changed. The TC format
however doesn't. In such a case, one would need to change the doZpdFex method
of L1DZpdElementOutputAccessor
so that it rebuilds tracks
. An algorithm to build ZPD tracks
from the above raw data format can be:
loop on each engine and for each engine number and for each engine, do:
- extract z0 and z0 error
- if z0 error is not 15, extract curvature and tandip and combine the
4 elements in a ZPD track
The idea behind the above algorithm is that there is 2 integer
modules in the powerPC processor and extracting one byte from 2 different
integers might be done in parallel. I don't know, if the above FEX would be
faster than the current one but you are welcome to study it.
This example shows that changing the ZPD raw DAQ data format implies to
change classes in L1DctOnline. You don't need to touch L1DctOdf for that.
You might want not to change the raw format but to add one (for example
ZPD DAQ format 3 which is not currently used). For that you would need to
create an equivalent of L1ZpdElementOuputAccessor
for your new data format and you would need to change a couple of files
in L1DctOdf. More precisely, you need to change the following 2 files:
- L1DctBltZpdConfigure.cc where you should add the creation of the correct
L1Accept odfAction
for the case of ZPD DAQ format 3.
- L1DctOdfTemplates.cc where you should add an explicit declaration of
your new L1Accept odfAction
(this is because the L1Accept odfAction
is a template classes and that the vxworks compiler doesn't understand
templates).
A new TC format
Let's suppose that after some time, you notice that you don't need so many
bits for the track information. Lets say that it would be enough to have 6
bits for tandip, curvature and z0. Then the curvature, z0, z0 error, tandip,
phi and cellloc of a track can fit in a 32-bit word. The ZPD can't do it for
you due to its design but the FEX can do it. The new TC format could then
replace the ZPD track
data format and store the engine information as a bit mask with the
GLT decision
.
To perform this change, you need to change the ZPD FEX as described above.
In that case, you need also to change the TC version number given by the secID()
method both for L1DZpdElementOutputAccessor
and L1DZpdElementFullAccessor.
The L1DZpdSectionTC version numbers
are defined in L1DZpdSectionTCVersion.hh. You need also to provide the
new accessors
for the new format and to update the first() method of the
L1DZpdModuleTCIterator
class so that it knows about the new version.
And that's all.
Again changes are limited to the L1DctOnline package.
Numbers
A few key numbers on the ZPD data size.
|
|
tracks+input mask
|
tracks only
|
|
|
header part
|
4
|
4
|
4
|
|
input mask per tick (for 8 ticks)
|
20 (160)
|
0 (0)
|
0 (0)
|
|
track data per tick (for 8 ticks)
|
64 (512)
|
64 (512)
|
56 (448)
|
|
switch garbage
|
4
|
4
|
4
|
|
total for 1 tick (for 8 ticks)
|
92 (680)
|
72 (520)
|
64 (456)
|
|
total for 8 boards for 1 tick (for 8 ticks)
|
736 (5440)
|
576 (4160)
|
512 (3648)
|
|
ZPD section TC size for
|
version 3
|
version 4
|
version 5
|
|
header
|
16
|
16
|
16
|
|
input mask header
|
0
|
0
|
12
|
|
input mask per tick (for 8 ticks)
|
0 (0)
|
0 (0)
|
20 (160)
|
|
tracks per tick (for 8 ticks)
|
0 (0)
|
variable 0 to 64 (0 to 512)
|
variable 0 to 64 (0 to 512)
|
|
total for 1 tick (for 8 ticks)
|
16 (16)
|
variable 16 to 80 (16 to 528)
|
variable 48 to 112 (188 to 700)
|
|
total for 8 boards for one tick (for 8 ticks)
|
128 (128)
|
variable 128 to 640 (128 to 4224)
|
variable 384 to 896 (1504 to 5600)
|
The variability for the section TC size is due to the number of good tracks
that may be stored. In the above table, the min number is for an event with
no tracks in any ZPD and the max number is for an event with 12 tracks in
each ZPD. This latter case is very unlikely. To the final total, there is
the need to add 12 bytes for the module TC header and some bytes for the BLT
data.
To try to get some estimation of the TC size, let's redo the computation
in the hypothesis that the mean occupancy is as follows:
1/4 of the tick data have no track, 1/4 have 1 track, 1/4 have 2 tracks
and 1/4 have 3 tracks. The mean track output per tick per board is then 10
bytes. With such an hypothesis, the above table gives:
|
ZPD section TC size for
|
version 3
|
version 4
|
version 5
|
|
header
|
16
|
16
|
16
|
|
input mask header
|
0
|
0
|
12
|
|
input mask per tick (for 8 ticks)
|
0 (0)
|
0 (0)
|
20 (160)
|
|
tracks per tick (for 8 ticks)
|
0 (0)
|
10 (80)
|
10 (80)
|
|
total for 1 tick (for 8 ticks)
|
16 (16)
|
26 (96)
|
58 (268)
|
|
total for 8 boards for one tick (for 8 ticks)
|
128 (128)
|
208 (768)
|
464 (2144)
|
Time of execution for the FEX: before including the phi information for the tracks, the FEX would have run in roughly 80 microseconds for 8 ZPDs. The phi information increases both the data volume and the amount of operations to perform. However, I wouldn't expect the total time to be above 100 microseconds for 8 ZPD shipping 8 cklock ticks of data but this has to be confirmed by real data taking. If the time of the FEX is too big, one can either reduce the number of ticks or perform the FEX for a smaller fraction of the events.
useful link
The ZPD DAQ raw data is described in this
document
.
Gérald Grenier
University of Iowa
|