7.4. Introduction to treeparameter

The Tree parameter package was initially designed by Daniel Bazin. It was adopted into SpecTcl formally starting with Version 3.0. When it was adopted the C++ segment of the package was redesigned and re-written. The Tcl segment of the package was redesigned and re-written to create the Folder Gui starting with Spectcl version 3.1

The C++ part of Tree parameter provides a structured view of the parameter array. The Tcl part provides a very nice Grahpical User interface through which you can do most of the typical SpecTcl jobs.

This section will describe:

7.4.1. The C++ Part of Tree Parameter

The C++ part of Tree parameter provides the following:

  1. The rEvent CEvent object is a flat array. While this is fine for small analysis cases, it is much more convenient to use a hierarhcical data structure such as a set of nested C structs. for more complex experiments, composed of multiple detector systems.

    The Tree parameter defines two classes; CTreeParameter that acts like a float but modifies and fetches its value from an element of the rEvent array, and CTreeParameterArray which acts like a fixed sized array, that fetches and sets contiguous elements in the rEvent array.

  2. It is often useful for parameters to provide hints about the limits and resolutions that should be used for axis of histograms. The CTreeParameter and CTreeParameterArray objects allow that.

  3. Often, SpecTcl event processors use Tcl variables to parameterize their computations. Tree Parameter provides the classes CTreeVariable and CTreeVariableArray which provide float like variables that map to the values of Tcl variables, and, in the case of CTreeVariableArray map to sets of Tcl variables (not elements of Tcl arrays).

    The Tree variable classes can then be organized in structs in any way that makes sense to your application.

The tree parameter classes. The tree parameter classes, CTreeParameter and CTreeParameterArray provide a way to produce float-like variables that, when assigned to set the value of an CEvent element and, when read from, fetch the value of that element. CTreeParameter provides a single variable, while CTreeParameterArray provides an array like variable (a variable that can be indexed).

I'm going to start the discussion with CTreeParameter, follow up with an introduction to CTreeParameterArray and finally, conclude with a simple SpecTcl sample that uses these classes. Using these classes requires that you


#include <TreeParameter.h>
                    

CTreeParameter objects are facade objects to a single element of a CEvent array. They are pretty much indistiguishable from a float in computation. CTreeParameter objects also do the following:

The CTreeParameterArray looks to C++ software like an array of CTreeParameter objects, in the sense that it supports indexing. CTreeParameterArray objects form parameter names for their CTreeParameter constituents using a base name to which is appended .number where number is a set of consecutive numbers. By default number starts from zero, however some constructors allow you to specify a starting value for number.

Let's look at an example of the use of these two classes from the sample MySpecTclApp.cpp that is provided with the SpecTcl skeleton. Using CTreeParameter and CTreeParameterArray is a matter of creating a structure of objects of these classes and then referring to them in your event processor classes.

Here is the code in MySpecTclApp.cpp that creates a simple tree parameter structure:

Example 7-19. Creating Tree Parameter Structures.


typedef
struct  {
  CTreeParameterArray&  raw;
  CTreeParameter&       sum;          (1)
} MyEvent;

// Having created the struct we must make an instance
// that constructs the appropriate objects:


MyEvent event = {
  *(new CTreeParameterArray("event.raw", "channels",  10, 0)),  (2)
  *(new CTreeParameter("event.sum", "arbitrary"))
};
                        
(1)
This statement defines a struct that contains references to tree parameters. Since static struct initializers do bit by bit copies and not copy construction, we must hold references to existing objects rather than actual objects.

The structure is going to contain an array named raw and a single parameter named sum

(2)
Since copy construction is not done to initialize static structs, I have initialized the event struct by initializing its references to dynamically allocated objects. Another perfectly good alternative is to use a constructor for the struct that explicitly constructs its members, or even class that holds these objects as member data.

Tree parameter objects have quite a few member functions. These are described in detail in SpecTcl Programming Reference below. For the most part all you need to know is that tree parameter objects can be assigned to as if they were ordinary float variables, and that the isValid member returns true if the tree parameter has been assigned to this event.

Let's conclude this discussion of the CTreeParameter class by annotating an example of an event processor that references the tree parameter objects created in the previous example:

Example 7-20. Tree parameters in event processors


Bool_t
CFixedEventUnpacker::operator()(const Address_t pEvent,
				CEvent&         rEvent,
				CAnalyzer&      rAnalyzer,
				CBufferDecoder& rDecoder)
{

  // This sample unpacker unpacks a fixed length event which is
  // preceded by a word count.
  //
  TranslatorPointer<UShort_t> p(*(rDecoder.getBufferTranslator()), pEvent);
  CTclAnalyzer&      rAna((CTclAnalyzer&)rAnalyzer);  (1)
  UShort_t  nWords = *p++;
  Int_t     i      = 1;

  // At least one member of the pipeline must tell the analyzer how
  // many bytes were in the raw event so it knows where to find the
  // next event.

  rAna.SetEventSize(nWords*sizeof(UShort_t)); // Set event size.

  nWords--;			// The word count is self inclusive.
  int param = 0;		// No more than 10 parameters.

  while(nWords && (param < 10)) {		// Put parameters in the event starting at 1.
    event.raw[param] = *p++;                                (2)
    nWords--;
    param++;
  }
  
    if (event.raw[0].isValid() && event.raw[1].isValid()) { (3)
        event.sum = event.raw[0] + event.raw[1];                    (4)
    }
  
  return kfTRUE;		// kfFALSE would abort pipeline.
}
                        
(1)
This code is just the boilerplate that every event processor needs whether it is using tree parameters or not.
(2)
This line references an element of a CTreeParameterArray object. Note that tree parameter array objects can be indexed, and their elements can be assigned to just as if they were ordinary float values.
(3)
While in this simple example, prior to performing computations on parameters you should check to be sure they have been assigned to (unless the flow of your program makes it clear they must have been). In this line, the isValid method is invoked on the fist two elements of event.sum to ensure they have been assigned to prior to used on the right hand side of an assignment.

If you use uninitialized tree parameters (or elements of rEvent for that matter in expressions as r-values, [1] will throw an exception if they have not first been assigned values. This prevents you from computing on uninitialized values.

(4)
This line shows assignment to a CTreeParameter object from the sum of two elements of a CTreeParameterArray object. The intent of this line is to demonstrate that objects of both the CTreeParameter and CTreeParameterArray classes can be treated as if they are essentially float variables.

The tree variable classes. One advantage that falls out of using Tcl as the command language for SpecTcl is the support for using Tcl to set variables that the C++ analysis software uses to steer the event by event analysis. Application graphical user interface elements can easily be added to control the values of these variables (e.g. checkboxes for logical flags or sliders (Tk scale widgets) for numerical values, and listboxes or spinboxes for enumerated types.

The reference material, C++ encapsulation of a Tcl API subset, provides a mechanism for C++ code to access Tcl variables; the CTCLVaraible class. The treeparameter package layers on top of that code two classes:

CTreeVariable

Which makes it easier to bind a Tcl variable to a floating point like object.

CTreeVariableArray

Which binds a related set of Tcl variables to an array like object.

Programming SpecTcl provides reference material on both of these classes. You should review that material carefully when you start to program with these classes.

In this introductory treatment, I'm going to show how to statically declare a set of tree variables and a tree variable array so that their names match how they are referenced by the C++ code in a struct. I'm then going to show you how to use these objects to produce a weighted sum of parameters where the weights can be dynamically adjusted by setting the values of the Tcl variables these objects represent.

To put tree variables in a struct you must first describe the layout of the struct, and then create a variable that contains that struct. The code below shows how this can be done statically at initialization time.

Example 7-21. Creating tree variables


typedef
struct {                          (1)
CTreeVariable&  w1;         (2)
CTreeVariable&  w2;
CTreeVariableArray& unused;  (3)
} MyParameters;                    (4)

// Similarly, having declared the structure, we must define
// it and construct its elements

MyParameters vars = {              (5)
   *(new CTreeVariable("vars.w1", 1.0,  "arb/chan")),
   *(new CTreeVariable("vars.w2", 1.0, "arb/chan")),
   *(new CTreeVariableArray("vars.unused", 0.0, "furl/fort", 10, 0))
};
                    
(1)
This struct declaration starts the definition of a new type MyParameters that will hold tree variables. Just as a class definition does not actually create anything, a struct declaration or typedef only creates a shape that defines what a variable of that type could look like.
(2)
This line indicates that struct MyParameters will have an element named w1 that is a tree parameter. Only when we create the a variable will we be able to determine which Tcl variable this field will be bound to.
(3)
This line indicates that struct MyParameters will have an element named unused that looks like an array that maps to several Tcl variables.
(4)
Again a reminder that this declaration of a struct does not actually create anything but a shape that a variable may hold.
(5)
This line and the next four creat a variable vars that is of type MyParameters. The w1 field will be bound to the tcl variable vars.w1, The w2 field to vars.w2 and the unused field will act like an array whose element are bound to vars.unused.00, vars.unused.01 ... vars.unused.09.

The Tcl variables can be set in any way from the Tcl code. source the following small script into SpecTcl via the SpecTclRC.tcl initialization script, we'll have a small GUI that lets us set the values of the vars.w1 and vars.w2 variables to be anything in the range 0.0 through 2.0 in steps of 0.1 by adjusting a pair of sliders.

Example 7-22. Gui to set the weights of the sum


toplevel .vars
label .vars.l1 -text "vars.w1"
label .vars.l2 -text "vars.w2"

scale .vars.w1 -from 0.0 -to 2.0 -showvalue 1 \
               -variable vars.w1 -resolution 0.1
scale .vars.w2 -from 0.0 -to 2.0 -showvalue 1 \
               -variable vars.w2 -resolution 0.1

grid .vars.l1 .vars.l2
grid .vars.w1 .vars.w2

                    

This results in a GUI that looks like the one shown below:

Figure 7-22. Sample weight setting GUI

Both the foler and classic GUI's also provide simple methods for viewing and setting the values of tree variables.

We can use the weights set by this GUI by referencing vars.w1 and vars.w2 as if they were any other C/C++ variable. The event processor below will do this to create a weighted sum of the first two parameters in the event.sum tree parameter. The sum is normallized to the sum of the two variables. If that sum is 0, the result is 0.

Example 7-23. Computing a weighted sum using treevariables and tree parameters.


class CAddFirst2 : public CEventProcessor                  (1)
{
public:
  virtual Bool_t operator()(const Address_t pEvent,
			    CEvent&         rEvent,
			    CAnalyzer&      rAnalyzer,
			    CBufferDecoder& rDecoder);

};

Bool_t
CAddFirst2::operator()(const Address_t pEvent,
		       CEvent&         rEvent,
		       CAnalyzer&      rAnalyzer,        (2)
		       CBufferDecoder& rDecoder)
{
  if (event.raw[0].isValid() && event.raw[1].isValid()) { (3)
    float normalization = vars.w1 + vars.w2;
    if (normalization != 0.0) {                                  
      event.sum = (event.raw[0]*vars.w1 +
                   event.raw[1]*vars.w2)/normalization;      (4)
    } 
    else {
      event.sum = 0.0;                                       (5)
    }
  }

  return kfTRUE;                                              (6)
}


                    
(1)
Defines the class event processor class CAddFirst2
(2)
Begins the implementation of the operator() member function. that function is invoked for each event. In this case, we will only be referencing parameters that have been unpacked from the raw event by earlier stages of the event pipeline.
(3)
Before computing using the first to elements of the event.raw[] array, we need to ensure that they have been assigned values by earlier pipeline stages.
(4)
If the sum of the weights is non zero, the weighted sum is produced and normalized by the sum of the weights.
(5)
If the sum of the weights is zero, we set the result to zero.
(6)
As for all event processors, we need to return a Bool_t that, when true, allows SpecTcl to continue processing event pipeline elements.

7.4.2. The classic Tree Parameter GUI

The original tree parameter software, written by Daniel Bazin, included a GUI. This GUI is known (in this manual) as the classic tree parameter GUI. You may also hear it referred to as the multicolored GUI. When you see screen shots, the reason for this will be clear.

While the folder GUI displays SpecTcl's objects as a tree of folders that you can open or close to get the level of detail you want, the classic Tree Parameter Gui presents these objects as tables that can be filter by glob pattern. A glob pattern is a string of characters that can contain any of the wild card matching characters and substrings supported by the bash command shell when matching files.

While the folder GUI presents all object types in a single tree, the classic Tree Parameter GUI uses a tabbed notebook paradigm to separate these objects by type.

In this section I'm going to explain:

Throughout we will see that the classic GUI makes use of cascading menus to represent the hierarchical structure of parameter names that the folder GUI uses nested folders to represent. A cascading menu is a menu that has items that, when selected or lingered over, will pull up a submenu.

To start the classic Tree parameter GUI; edit your SpecTclRC.tcl file. Locate the line that reads:


source $SpecTclHome/Script/newGui.tcl
                    
and change it to read:

 source $SpecTclHome/Script/SpecTclGui.tcl
                    
When SpecTcl starts up it will ask you if you'd like to try the new GUI. Click No to continue with the classic tree parameter GUI.

The figure below shows a screen shot of the initial presentation of the classic tree parameter GUI:

Figure 7-23. Tree parameter classic GUI

The upper right hand box of the GUI Spectra tab contains Load and Save buttons that load and save the analysis configuration respectively. The failsafe checkbutton specifies that the GUI should write a failsafe.tcl file when changes to the configuration are made. The cumulate button indicates that configuration loads should be cumulative. That is the existing configuration is not erased prior to loading a new configuration.

Creating a spectrum. Now let's make a new spectrum with the classical tree parameter GUI. In the upper left cyan colored box, select the spectrum type (in our example we will be creating a 1-d spectrum), check the 1-d radio button. Next enter the new spectrum name in the box below the spectrum type box (manilla colored). We'll enter event.raw.00.

In the box below the spectrum name box, the Parameter is actually a drop down cascading menu. Click on it and navigate the parameter hierarchy until you can click on 00 under event.raw:

Figure 7-24. Selecting the parameter

Ensure that the correct axis limits appear in the boxes to the right of the parameter name and, when satisfied, click Create/Replace to create the new spectrum.

Setting Tree Variables. To view/edit tree variable values, you must first select the Variables tab. This brings up a page that looks like this:

Figure 7-25. The variable setting page

Use the radiobutton set along the left side of this page to select a slot. In this case, the Variable column title is a drop down cascade menu. Use it to select vars.w1. Note that row of the table is filled in with the name, value and units of that tree variable. The Load button loads the value from the program data overriding any uncommitted changes you may have made. The Set commits that row's value and units to the named Tree variable.

Editing Parameter Definitions. The classic tree parameter GUI allows you to edit the definitions of tree parameters. This is done by selecting the Parameters tab. This displays the following page:

Figure 7-26. Classic Tree Parameter GUI Parameter editing page

The Parameter title is a drop down cascading menu that allows you to navigate the parameter tree and select a parameter to place in the line of the table selected by the radiobutton at the left of the page.

Having loaded a parameter, you can modify its suggested range, and units. You can then click Set to set the new values or Load to reload the current values.

Clicking the ChangeSpecra button allows you to change the axis definitions of any spectra that depend on that parameter to match the new definitions you made.

Creating, editing or "deleting" gates. The Gates tab brings up a primitive gate editor page. Using this page, you can create new gates, edit existing gates, and "delete" existing gates [2]

This user interface is shown below:

Figure 7-27. Classic tree parameter gate editor

The lower bulk of the window contains a list of the existing gates. Using the mouse you can select one or more gates. The Delete Selected deletes the gates you have selected with the mouse, while Delete All deletes all gates.

The top, light yellow section is used to create or modify gates. The left most entry is for a gate name. You can type in a gate name of double click a gate in the green list to load its definition into the editor.

The right most yellow button is a drop down menu that allows you to specify the gate type. The contents of the right hand text entry field depend on the gate type. The Gate Select text, once more is a drop down cascading menu that lets you select a gate to append to the dependency list for this gate. The Clear Dependency button clears that text field.

When you are happy with your new gate definition, you can click the Create/Replace button to create the gate. Back on the Spectra page, you can select a spectrum and use the Gate drop down to selecct gate to apply to that spectrum.

Notes

[1]

An r-value is a variable used in a context where it must supply a value to an expression. C/C++ also define an r-value as an entity that is appearing on the left side of an assignment (that is an entity that is being assigned a value). The terms come from left hand and right hand side of assignments.

[2]

SpecTcl never actually deletes gates. The gate "delete" operation changes the gate type to F which is a gate that is never true.