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:
The C++ part of Tree parameter. Note that the SpecTcl Programming Reference chapter will include full reference material on the classes that make up Tree Parameter
The old Tree Parameter GUI (tree parameter classic?), and how to use it. The tree parameter classic GUI is still available for peopel who are used to it.
The C++ part of Tree parameter provides the following:
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.
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.
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:
Creating a CTreeParameter
object defines a SpecTcl parameter just
as if the parameter command
were used.
Parameter ids are dynamically allocated so you don't have to keep track of them.
CTreeParameter objects include
optional information about how to best histogram them.
CTreeParameter objects
can be dynamically reboud to different
CEvent objecs so that
they can be re-used from event to event.
The mechanics of the binding/re-binding
described above are handled transparently by
having all
CTreeParameter objects
bound to the same CEvent
(though not to the same element of the
CEvent
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;
} MyEvent;
// Having created the struct we must make an instance
// that constructs the appropriate objects:
MyEvent event = {
*(new CTreeParameterArray("event.raw", "channels", 10, 0)),
*(new CTreeParameter("event.sum", "arbitrary"))
};

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

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);
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++;
nWords--;
param++;
}
if (event.raw[0].isValid() && event.raw[1].isValid()) {
event.sum = event.raw[0] + event.raw[1];
}
return kfTRUE; // kfFALSE would abort pipeline.
}


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.

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.

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:
CTreeVariableWhich makes it easier to bind a Tcl variable to a floating point like object.
CTreeVariableArrayWhich 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 {
CTreeVariable& w1;
CTreeVariable& w2;
CTreeVariableArray& unused;
} MyParameters;
// Similarly, having declared the structure, we must define
// it and construct its elements
MyParameters vars = {
*(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))
};


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.

unused
that looks like an array that maps to several
Tcl variables.


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:
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{ 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,
CBufferDecoder& rDecoder) { if (event.raw[0].isValid() && event.raw[1].isValid()) {
float normalization = vars.w1 + vars.w2; if (normalization != 0.0) { event.sum = (event.raw[0]*vars.w1 + event.raw[1]*vars.w2)/normalization;
} else { event.sum = 0.0;
} } return kfTRUE;
}

CAddFirst2

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.

event.raw[] array, we need to
ensure that they have been assigned values by
earlier pipeline stages.



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:
How to start the classic tree parameter GUI
How to use the classic tree parameter GUI to create spectra.
How to save and restore tree parameter configuration files.
How to set the values of tree variables
How to change the definitions of tree parameters.
How to create compound gates.
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 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:
The upper right hand box of the GUI Spectra tab contains and buttons that load and save the analysis configuration respectively. The checkbutton specifies that the GUI should write a failsafe.tcl file when changes to the configuration are made. The 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 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 is actually a drop down cascading menu. Click on it and navigate the parameter hierarchy until you can click on 00 under event.raw:
Ensure that the correct axis limits appear in the boxes to the right of the parameter name and, when satisfied, click to create the new spectrum.
Setting Tree Variables. To view/edit tree variable values, you must first select the tab. This brings up a page that looks like this:
Use the radiobutton set along the left side of this page to select a slot. In this case, the 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 button loads the value from the program data overriding any uncommitted changes you may have made. The 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 tab. This displays the following 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 to set the new values or to reload the current values.
Clicking the 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 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:
The lower bulk of the window contains a list of the existing gates. Using the mouse you can select one or more gates. The deletes the gates you have selected with the mouse, while 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 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 button clears that text field.
When you are happy with your new gate definition, you can click the button to create the gate. Back on the page, you can select a spectrum and use the drop down to selecct gate to apply to that spectrum.
| [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. |