HOWTO Access Geometry Information from JANA/DANA
Contents
Overview
Geometry information used for physics analysis and simulation in Hall-D is maintained in a set of XML files that conform the HDDS format (a variant of ATLAS' AGDD). These same XML files can be read by JANA based reconstruction programs. The current plan is to keep the core geometry information in the XML files, but to have perturbations due to misalignments etc. kept in the calibration database. At this point in time (April 2008) however, we are still at least 5 years out from data taking so the details of that can be worked out later.
The JANA framework provides a mechanism by which to read in XML files using the xerces parser and probe it for values using an xpath-like syntax (described below). The DGeometry class implemented in DANA adds a more user friendly layer to getting at some of the more commonly accessed information such as the z-locations of the FDC wire planes.
For the most part, reconstruction authors are expected to use the convenience methods of the DGeometry class to access geometry information and use the Get(string xpath,...) methods only for the more obscure values. This will be the most likely place to implement calibration constants to modify values from the XML.
Setting up you environment
In order to access the XML files, JANA must know where they are at. The location may be system dependent so the JANA_GEOMTERY_URL is used to specify the topmost XML file. This should be set to a string that starts with xmlfile:// and then has the full path to and including the main_HDDS.xml file.
Example: setenv JANA_GEOMTERY_URL xmlfile:///Users/davidl/HallD/builds/latest/src/programs/Simulation/hdds/main_HDDS.xml
Reading the Geometry With jgeomread
JANA (>=0.4.1) comes with a command-line utility called jgeomread that can used to probe the XML tree specified in the JANA_GEOMETRY_URL environment variable. Running it with no arguments gives a usage statement:
fwing-dhcp13:~>jgeomread Usage: jgeomread [options] xpath Print the contents of a JANA geometry source (e.g. a file) to the screen. Options: -h Print this message -q Quiet mode. Print only the values separated by newlines. -L List all xpaths -a Include attributes for all nodes when listing xpaths -b Include attributes for only the last node when listing xpaths(default) -c Don't include any attributes listing xpaths -t type Set data type (float, int, ...) Example: (note this relies on the structure of the backend) jgeomread '//hdds:element[@name="Antimony"]/@a'
A list of the xpaths available in the current tree can be obtained using the -L switch.
This is probably the easiest way to get a valid xpath command for a specific
attribute. Use of the -a option will likely be needed with significant editing of the
returned xpath.
The jgeomread program can also be used to extract values and test xpaths from the command line. Running the example given in the usage statement above yields:
fwing-dhcp13:~>jgeomread '//hdds:element[@name="Antimony"]/@a' Values for "//hdds:element[@name="Antimony"]/@a" for run 100 -------------------- a 121.75
Modifying the Geometry
Most of the documentation on modifying the geometry is currently contained in the HDDS schema file. This can be found in the repository at https://halldsvn.jlab.org/repos/trunk/src/programs/Simulation/hdds/HDDS-1_0.xsd
or, if you don't have an account on the JLab CUE you can try here.
There is also a brief mention in the Getting Started with GlueX Software HOWTO.
Accessing data from within a DANA program
Data are accessed in DANA through the DGeometry class. A pointer to a DGeometry object can be obtained from the DApplication class. A pointer to the DApplication object can be obtained from the JEventLoop class. A pointer to a JEventLoop object is passed into a factory's init method. (Gee whiz that sounds worse than I thought it would). Here is a code snippet of how a pointer to the appropriate DGeometry object from within the brun method of a factory:
jerror_t MyFactory::brun(JEventLoop *loop, int runnumber) { DGeometry *dgeom = NULL; DApplication *dapp = dynamic_cast<DApplication*>(loop->GetJApplication()); if(dapp) dgeom = dapp->GetDGeometry(runnumber); if(dgeom){ // do something with dgeom pointer } }
Convenience Methods
Most needs for accessing the geometry should be addressed through the "convenience" methods of DGeometry. If a factory author needs information that does not appear to be accessible through one of these methods then they are encouraged to add a method to DGeometry. This will:
- Make the code in the factories easier to read
- Provide a convenient place to apply calibrations
- Make it easier for someone else who may need to access the same information later on
A current list of convenience methods is given below. Note that at the time of this writing, not all of these have been implemented.
bool GetFDCZ(vector<double> &z_wires); ///< z-locations for each of the FDC wire planes in cm bool GetFDCStereo(vector<double> &stereo_angles); ///< stereo angles of each of the FDC wire layers bool GetFDCRmin(vector<double> &rmin_packages); ///< beam hole size for each FDC package in cm bool GetFDCRmax(double &rmax_active_fdc); ///< outer radius of FDC active area in cm bool GetCDCOption(string &cdc_option); ///< get the centralDC_option-X string bool GetCDCCenterZ(double &cdc_center_z); ///< z-location of center of CDC wires in cm bool GetCDCAxialLength(double &cdc_axial_length); ///< length of CDC axial wires in cm bool GetCDCStereo(vector<double> &cdc_stereo); ///< stereo angle for each CDC layer in degrees bool GetCDCRmid(vector<double> &cdc_rmid); ///< Distance of the center of CDC wire from beamline for each layer in cm bool GetCDCNwires(vector<int> &cdc_nwires); ///< Number of wires for each CDC layer bool GetBCALRmin(double &bcal_rmin); ///< minimum distance of BCAL module from beam line bool GetBCALNmodules(unsigned int &bcal_nmodules); ///< Number of BCAL modules bool GetBCALCenterZ(double &bcal_center_z); ///< z-location of center of BCAL module in cm bool GetBCALLength(double &bcal_length); ///< length of BCAL module in cm bool GetBCALDepth(double &bcal_depth); ///< depth (or height) of BCAL module in cm bool GetFCALZ(double &z_fcal); ///< z-location of front face of FCAL in cm bool GetTOFZ(vector<double> &z_tof); ///< z-location of front face of each of TOF in cm bool GetTargetZ(double &z_target); ///< z-location og center of target bool GetTargetLength(double &target_length); ///< z-location of center of target
Inconvenient Methods
Authors of the convenience methods or those addressing special cases where adding a new method to DGeometry is not appropriate may extract values from the XML using an xpath-like syntax. The DGeometry class has several Get(string xpath, ...) methods that essentially provide 3 ways to get data:
- Get a single attribute's value
- Get a single attribute's value, but split it up into multiple values using a delimiter (e.g. for attributes like X_Y_Z="1 2 3")
- Get a list of all attributes and their values for a single node
The methods themselves have the form:
bool Get(string xpath, string &sval); bool Get(string xpath, map<string, string> &svals); template<class T> bool Get(string xpath, T &val); template<class T> bool Get(string xpath, vector<T> &vals, string delimiter=" "); template<class T> bool Get(string xpath, map<string,T> &vals);
The last 3 Get(string xpath, ...) methods are templated so that the values can be automatically converted from strings (from the native XML) into things like doubles and ints. The conversions are done using stringstream and so are limited to those types stringstream supports. Similar to JANA's Get mechanism, the variable type passed into the Get"" call determines what type of data is returned.
The two methods that pass in STL map references each return a full list of attributes and values for a single node.
The methods that pass in string reference or a type T reference each return the value for a single attribute.
Finally, the method that gets a reference to an STL vector passed in will take a single attribute and split it into multiple values, each of which is added to the vector. This last one is for cases where a single attribute may contain multiple values. For example:
X_Y_Z="1 2 3"
The format for the xpath string used for specifying which attribute or node is desired is described in the following section.
xpath syntax
The xpath syntax implemented in JANA is very limited compared to the full specification. The general features are as follows:
- Nodes are separated by forward slashes "/"
- Two forward slashes at the beginning of the xpath indicate to match any path that ends in what follows
- Attributes are specified by an "@" prepended to the name
- If an attribute contains an "=" then it indicates that the attribute must have a specific value which is specified immediately after the "="
- Attributes that are associated with a specific node are enclosed in square brackets "[" and "]" immediately after the node name
- An attribute that is NOT associated with a node (i.e. appears between two forward slashes without any square brackets) indicates it is the desired return value
Example 1:
Consider the following XML
<A> <B type="3"></B> </A>
If we want to extract the value of type in node B, then we could use:
/A/B/@type
Example 2:
Consider the following XML:
<A> <B type="3" id="1"></B> <B type="4" id="2"></B> </A>
Suppose we want to find the type in node B, but only for when id is "2":
/A/B[@id="2"]/@type
Example 3:
Consider the following XML:
<A> <B type="3"> <C id="1"></C> </B> <B type="4"> <C id="2"></C> </B> </A>
Suppose here, we want to to find the type of B, but only when it contains a sub-node of type C whose id attribute is "2":
/A/B/@type/C[@id="2"]
Example 4: (a realistic one)
Suppose one wants to extract the "radlen" attribute of Oxygen which is defined in the XML snippet below:
<materials version="3.0" date="2006-11-22" author="R.T. Jones" specification="v1.0" > <element name="Oxygen" symbol="O" z="8" a="15.9995"> <real name="density" value="0.00133" unit="g/cm^3" /> <real name="radlen" value="34.24" unit="g/cm^2" /> <real name="collen" value="63.2" unit="g/cm^2" /> <real name="abslen" value="91.0" unit="g/cm^2" /> <real name="dedx" value="1.801" unit="MeV/g/cm^2" /> </element> </materials>
An xpath specifying this value is:
//materials/element[@name='Oxygen']/real[@name='radlen']/@value
While this xpath may not be too difficult to understand, it may not be entirely obvious how to form it "from scratch". For this, you can have jgeomread guide you on how to form the xpath. You do this by having the program list all xpaths and grep out the one(s) of interest using a combination of keywords. In this case "Oxygen" and "radlen" which I know from looking at the XML.
fwing-dhcp13:~>jgeomread -L -a | grep "Oxygen" | grep "radlen" /HDDS[@specification='v1.0' and @xmlns='http://www.gluex.org/hdds' and @xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' and @xsi:schemaLocation='http://www.gluex.org/hdds HDDS-1_0.xsd']/Material_s/materials[@author='R.T. Jones' and @date='2006-11-22' and @specification='v1.0' and @version='3.0']/element[@a='15.9995' and @name='Oxygen' and @symbol='O' and @z='8']/real[@name='radlen' and @unit='g/cm^2' and @value='34.24'] /HDDS[@specification='v1.0' and @xmlns='http://www.gluex.org/hdds' and @xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' and @xsi:schemaLocation='http://www.gluex.org/hdds HDDS-1_0.xsd']/Material_s/materials[@author='R.T. Jones' and @date='2006-11-22' and @specification='v1.0' and @version='3.0']/element[@a='15.9995' and @name='LiqOxygen' and @symbol='LO' and @z='8']/real[@name='radlen' and @unit='g/cm^2' and @value='34.24']
The two (long) lines returned are for Oxygen and LiqOxygen the latter of which we are not interested in right now.
The first part of the line of interest above just specifies the HDDS node which everything falls under. That can be cut out completely and replaced by 2 forward slashes at the beginning of the line. In fact, the Materials_s node can also be dropped since the rest of the xpath is unique in the tree. This cuts us down to this:
//materials[@author='R.T. Jones' and @date='2006-11-22' and @specification='v1.0' and @version='3.0']/element[@a='15.9995' and @name='Oxygen' and @symbol='O' and @z='8']/real[@name='radlen' and @unit='g/cm^2' and @value='34.24']
The attributes of the materials tag are not needed here and can be dropped. Only one attribute of the element tag is needed to specify the appropriate one. In this case, the name attribute should be kept. Now we have:
//materials/element[@name='Oxygen']/real[@name='radlen' and @unit='g/cm^2' and @value='34.24']
The attribute we actually want is the value attribute of the real tag. We specify this by moving the "@value" specifier (without its value) to another section immediately following the real node like this:
//materials/element[@name='Oxygen']/real[@name='radlen' and @unit='g/cm^2']/@value
The "/@" pair of characters signifies that this is not really a new node, but rather an attribute specification for the node immediately preceding this one.
Finally, we might consider removing the unit qualifier just to make things prettier. One could choose to leave it of course just to guarantee that the units are correct. We remove it for the purposes of this example to leave the final xpath expression:
//materials/element[@name='Oxygen']/real[@name='radlen']/@value
This can now be tested with jgeomread:
fwing-dhcp13:~>jgeomread "//materials/element[@name='Oxygen']/real[@name='radlen']/@value" Values for "//materials/element[@name='Oxygen']/real[@name='radlen']/@value" for run 100 -------------------- value 34.24
Getting Help
If you have trouble accessing the geometry information or would like to report a bug please contact:
David Lawrence at davidl@jlab.org