(Generic Reconstruction Of VERtices)

The person currently responsible for the Grover package is: Dmitri Emeliyanov. Please send all correspondence to him.

Click here for the latest version of the manual (refers to Grover v2.01 in ARTE-03-08-r7).

Primary Vertex Reconstruction by Grover, Tracking meeting, March 27th 2002.

The New Primary Vertex Finder in Grover.

The documentation below is historical. Please use the postscript manual above.


Grover is a package for vertexing at HERA-B which tries to merge two different tools - VT and Rover. VT was written by Thomas Lohse before HERA-B was built and before the DST data structure was fixed. It is a series of stand-alone FORTRAN routines and is rather complete. A FORTRAN Arte interface was written a few years ago, but the structure of the Arte tables and Arte itself has changed rather a lot. In particular, most users are now using C++. Rover is a C++ package, started by Thomas Perschke and developed by Ivan Kisel and others, which, at the time Grover was conceived, contained a primary finder, a basic two-track secondary fit and a graphical display. It was integrated with Arte from the start.

Grover is an attempt to allow the ordinary user to use both packages in a transparent way from their usevnt() function. I have tried to make it as general as possible so that the package can be extended a lot. It should be considered as under test for the moment!

VT can now be tuned on real and MC data. numbers such as chi-squared cuts in the package which were PARAMETERs have now been turned into 'cuts' which can be set inside Grover. The immediate aim is to allow everybody to tune VT and compare its performance with Rover's, and to allow the authors to extend Rover at their leisure without interfering with or slowing down the vertexing effort as a whole.

The following sections describe the structure very briefly. If you'd rather, you can just download the tarball below and read the README file. It should be fairly obvious what's happening. When you need to change things read this page completely and refer to the header file grover.hh for complete specifications of the classes and functions.


There are four classes defined in Grover: The first three have a corresponding container - GroverParticleList, GroverWireList, GroverVertexList. These are just typedef'ed to a STL vector for the moment, although that might change if it proves inadequate for you, the user. The containers provide the usual functionality, including random-access iterators. For more STL info see here (courtesy of SGI).

The documentation in the header file Grover.hh is more complete

A GroverParticle corresponds roughly to a RSEG entry, with additional data and, of course, internal functionality, such as propagating the beginning of the track to a plane in z, swapping it between Global and Local VDS coordinates, finding the chi-squared distance to another GroverParticle, GroverWire or GroverVertex, etc. It can be constructed from RSEGs, RTRAs, other GroverParticles, etc. It can even be constructed from vertices or MC tracks to provide more flexibility. It also possesses a type specifying what kind of object it was made from, and a pointer to that object. In this way information is not lost. It also possesses various numbers and flags that can be set and read by the user.

A GroverWire can be constructed from a GTAR entry and also has some functionality - coordinate transformations, for example. It also has numbers and flags for the user's convenience - number of primaries associated to this wire, etc.

A GroverVertex is also designed to be rather flexible and can be constructed from RVER entries, GroverParticleLists, etc. It possesses a GroverParticleList which can be manipulated both by the user and internally. The particles in the list can be fitted as as a primary or secondary using one of the member functions (only one exists at the moment - the geometrical primary vertex fitting routine vertex.RPGeoFit implemented in Rover1.05).

A GroverCuts object is basically a struct. It is constructed with all the default values of VT and Rover already set, but they can be changed by the user.

The contents of all Grover objects can be dumped to stdout using GroverObject.Dump().

(*) Mavens please note: the classes are by no means bullet-proof, and encapsulation is only partial. You can do lots of nonsensical things to a Grover class and make it break without too much effort. Vertexing is physics and the classes are there to make life easier. If you switch your brain off you will get in a mess :-)

More Detail


  • Constructors: There is a default constructor, which is not very useful. Better are GroverParticle fred(ArtePointer jim(0)) and the RTRA equivalent which initialise the track parameters and coordinate system flags correctly and set up the pointer to the parent RSEG/RTRA and type flag.
  • Data Structure: The object contains the track parameters (x,y,z,ax,ay) and their triangular covariance matrix at each of four points. Two are fixed during construction - the start and end of the parent object (e.g. RTRA entry). The other two are moveable using the member functions PropagateXXXTo() described below. The momentum and inverse momentum (plus errors) are also stored, as are the mass (and its error), charge and total number of hits in the Vertex Detector. Also stored are an index integer, a 'used in primary' integer and a couple of floats for weights. There is also a 'parent type' flag which tells you what kind of object its parent was, and a set of pointers of appropriate type to allow you to always follow a trail back to the DST or Clue object. All of these things are gettable and settable. Remember that not all of them are meaningful at all times. For example, you can't expect the mass to be set if you constructed from an RSEG object.
  • Member Functions: There are member functions for finding the spatial and chi-2 distances to other objects of type GroverParticle, GroverWire or GroverVertex, which take the pointer to that object as an argument. There are member functions to swap all the track parameters between coordinate systems. The covariances are not changed for the moment. This is probably not such a problem since the rotations involved are small. There are two member functions PropagateBeginTo(z) and PropagateEndTo(z) which use the internally defined start and end points of the particle and propagate the track upstream or downstream, respectively, to a plane in z. The Begin and End points accessed with BeginX(), EndSlopeY() etc. refer to these virtual points. The covariance matrices are also adjusted. If you want to rediscover the original points of the parent object (e.g. RTRA entry) you can find the original z with OriginalBeginZ() or OriginalEndZ() and then project to this plane. There is a Dump() function to get a quick look at what's inside the object.


  • Constructors: The default is a 250um thick vertical wire at 0,0,0 in global coordinates with number -1. The constructor for a GTAR entry is the only one anybody would want to use, I suspect.
  • Data Structure: Pretty much the same as GTAR. There are flags for horizontal and vertical, and three integers to label the wire with number of particles, number of primaries and number of secondaries. They are set by the user and may be garbage!
  • Member Functions: The wire can be swapped between coordinate systems and there is also a Dump() and a full set of getters and setters.


  • Constructors:Only one, which sets the members to their default values.
  • Data Structure: An open c-style struct. Just a bunch of integers and floats.
  • Member Functions: Dump()


  • Constructors:The standard way to construct a vertex is from a GroverParticle or GroverParticleList. It can also be constructed from an RVER entry, whereupon the internal particle list (see below) is also filled correctly from RTRA using the relations on the DST. The coordinate system is set to be the same as the particle, or last on the list of particles, from which the vertex was constructed. There is also a shortcut vertex(x,y,z) where by default x,y,z are in local VDS coordinates.
  • Data Structure: The vertex position and momentum are stored. The covariance matrix is a 6x6 triangular matrix. The first six elements are the spatial covariances. It has not been decided which three parameters to use for the momentum - {ax,ay,p} or {px,py,pz}. VT uses the former. The Rover routines are all geometric so far, so the question remains open for a few days until the VT interface is running. There is an index integer and a couple of chi-squares which can be set by the user or a major routine such as a GroverPrimaries. The main data structures are two GroverParticleLists called particles and trashcan which are publically accessible. This makes the class less robust and people should not add or remove particles unless absolutely necessary. This is dealt with below
  • Member Functions: It would be unwise to allow all possible fitting procedures to become member functions of the class, although conceptually that is where they belong. In practice it could get very slow and messy to deal with multiple GroverVertexLists if each GroverVertex in them contained lots of matrices corresponding to the internal data structures of each routine. In general it is better to keep such routines as separate functions which operate on a GroverVertex, or list thereof. This keeps the class small and efficient. Very useful and/or general procedures - such as momentum or covariance estimation as starting points for fits - can be added, of course. One or two are already there. EstimateCov(z) projects all the tracks in particles to a plane in z and estimates a diagonal covariance matrix according to the scatter of the tracks in that plane. EstimateMomentum() uses a method similar to VT's to estimate the momentum of a vertex, taking into account all the covariance matrices of the tracks. Now to the internal particle lists. Imagine I have a constrained fitting routine. First I use Add(gp) or Add(gpl) (where gp and gpl are pointers to a GroverParticle or GroverParticleList, respectively. This copies the particle(s) onto the internal particles list. The author of the fit might do the following: 0) Clear the trashcan. 1) Do an unconstrained fit to see if all the particles are compatible with the constraint. 2) use the standard member functions of an STL vector to remove from the particles list any which are not compatible and add them to the trashcan list. 3) Perform the fit again with the constraint, and update the parameters of the particles in the particles list. 4) Write the chi-2 of the fit into the appropriate variable in the vertex, and the contribution of each track to the chi-2 into the appropriate place in the GroverParticles. Aafter this procedure the user can see the results of the fit, but also get access to the particles which were excluded. In general, the author of a fit program will clear() the trashcan before starting, so the particles there are lost unless the user accesses them immediately after the fit. The lists are publically accessible, so the user can do nonsensical things like wiping the particles list clean and asking for a momentum estimate for a vertex with zero particles. This is the price we have to pay for flexibility. The general user should not have to alter either particles or trashcan. The Add() function can be used to prepare a vertex candidate for fitting, and then pass it to a carefully thought out fitting routine which does its own book-keeping. In principle we could have one or more Remove() functions. For example, "Remove all particles in the list with less than seven hits in the VDS'. This might be feasible for certain common cases, but I think in general it's better and safer to construct a new vertex and fill it with the tracks you are interested in, then pass it to a general routine like a J/psi finder. Mail me if you have any feelings on this. Finally there are routines for swapping between coordinate systems. The covariances are not changed. All the particles in both lists are also transformed, to save you having to do it by hand.
  • STL vector commands: Elements in a list fred can be accessed with an iterator:
    for (GroverVertexList::iterator j = fred.begin(); j!=fred.end(); ++j)
       p = j->Momentum();
    // OR if fred is a pointer to a GroverVertexList
    for (GroverVertexList::iterator j = fred->begin(); j!=fred->end(); ++j)
       p = j->Momentum();
    or via indexed access (index starts at 0, i.e C-style, not Fortran style!):
    p = fred[i].Momentum();
    // OR if fred is a pointer to a GroverVertexList
    p = (*fred)[i].Momentum();
    The lists behave as stacks. e.g. to get the momentum of the last on the stack and then remove it, do something like:
    p = fred.back().Momentum();
    You can also do fred.push_back(vtx) (where vtx is a GroverVertex) to add a vertex to the stack. You can have multiple iterators operating on the same list, and you can even add and remove particles in the middle of a list, although this is should be done extremely carefully in Grover as the indexing will get mixed up and any iterators pointing to vertices after the one removed or added will be invalid and could cause a segmentation fault if dereferenced.

    Utility Routines

    A few utility routines already exist. GroverFillFromRSEG and GroverFillFromRTRA fill a GroverParticleList from the Arte banks, as does GroverFillLikeRover. This latter routine fills the track list in the same way as Rover 1.0x, that is, using one RTRA for each RSEG (when one or more exists) and all remaining RSEGs. This routine will change quickly as the tracking situation improves. GroverFillFromGTAR fills a GroverWireList from GTAR. GroverAddToRVER writes a GroverVertexList into the RVER table and updates the relations to RTRA. GroverFillVTInputs fills the common blocks necessary for running VT with the GroverWireList, GroverParticleList and GroverCuts specified by the user. See the header file for a complete list of prototypes, and the corresponding source code for comments and explanation. If you are still none the wiser, send me an email!

    Primary Vertex Finding

    Primary Vertex finding can be done with VT or Rover. Both are called in the same way. Lists of wires, particles and cuts are passed as inputs and a list of vertices is returned as output. If the appropriate flag in the passed GroverCuts is set, a graphical display is started when GroverPrimaries or GroverVTPrimaries is called. The simplest way is simply to call GroverEvent(0). See the README file in the tarball below.

    Secondary Vertex Finding

    Very primitive at the moment. Use it if you like, but I make no claims for it. The situation is expected to improve rapidly in the next three weeks, so update the tarball regularly and look here for documentation. The secondary finder at the moment uses only VDS RSEGs, so you should specify TrackChoice = 2 in the cut file. The algorithm looks for secondaries consisting of the two tracks identified online as the J/psi electrons, and tries to add anything else which is not already in the primaries. It's added to RVER if reasonably separated from the nearest primary.

    Sven Schaller
    Last modified: Mon Jul 8 16:24:24 MEST 2002