Accessing Tcl Variables from within SpecTcl code |
SpecTcl Home General Information User Guide Programmer's Guide Obtaining and Installing
In many other histogramming systems, programs provide for a set of arbitrary user parameters. These may be floating point or integer parameters or what have you. Usually these are presented to the user as an array of integers, floats booleans or whatever. This makes keeping track of things like the usage of these array elements a burden on the experimenter. SpecTcl's approach is different.
Since SpecTcl contains an embedded Tcl/Tk interpreter, and since this interpreter allows you to create named variables and arrays, we take a different approach. Instead of creating artificial arrays of integers and reals which you have to keep track of, we reccomend instead creating Tcl variables and accessing them directly from within your code.
To do this you must:
Create tcl variables and give them initial values. | |
Bind these tcl variables to C/C++ variables in your unpacker. |
The remaining parts of this page will assume that you are trying to produce a calibrated parameter where the calibration is a simple linear function of one of the raw parameters.
Sample code will be given to show how this can be implemented.
The Tcl set command is used to create a variable and assign it a value. The form of this command is:
set variablename value
SpecTcl has two initialization phases. The first, runs SpecTclInit.tcl at startup time, prior to hooking together the analysis system. The second, SpecTclRC.tcl is run after all initialization is complete. Typically, the binding between Tcl and program variables will be done in the Unpacker's OnAttach() member function. It is therefore a good idea to at least create these variables and give them initial default values in a user SpecTclInit.tcl (located in the user's home directory). This ensures that the Tcl variable exists at OnAttach() time. In our example the following lines would be added to the ~/SpecTclInit.tcl file:
set slope 1.0 ;# Initialize to 1-1 calibration. set crossover 0.0 ;# so m = 1.0, b = 0.0
Top
The class CTCLVariable is an interface to TCL variables. The key member functions you will need are:
Name/Type | Arguments | Description |
CTCLVariable | (CTCLInterpreter*
pInterp, std::string rsVariable, Bool_t fTracing ) |
Constructor. The
parameters are as follows:
|
int Link | (void* pVariable, int Type) |
Links the TCL
Variable to a program variable. When Tcl does a set for
that variable, your variable is modifed. When Tcl
substitutes for the variable, the value of your variable
is consulted. If successful, the return value is TCL_OK.
The parameters are:
|
void Unlink | () | Remove the current variable linkage. |
The modifications requires will all take place within UserCode.cpp They involve:
Adding member variables m_dSlope and m_dCrossover to the unpacker class, along with appropriate CTCLVariable member functions as well. | |
Connecing m_dSlope and m_dCrossover to the the Tcl varaibles named "slope" and "crossover" respectively.in OnAttach() | |
Using the member variables in computation of a calibrated pseudo parameter in operator() |
The complete, modified UserCode.cpp is available here.
Four member variables will be added. One for each of the C/C++ variables and one for each of the corresponding Tcl/Tk variables:
#include <TCLVariable.h> #include <Globals.h> #include <assert.h> ... class CTestUnpacker : public CEventUnpacker { private: // Member variables. DFloat_t m_dSlope; // Calibration slope. DFloat_t m_dCCrossover // Calibration zero crossing. CTCLVariable* m_pSlope; // Pointer to TCL Variable for slope. CTCLVariabel* m_pCrossover; // Pointer to TCL Variable for crossover. public: CTestUnpacker() : // Constructor must be done this way because m_pSlope(0), // The TCL interpreter is not yet up at the time m_pCrossover(0) // of construction. {} ~CTestUnpacker() { // Delete the CTCL Variable at destruction time. if(m_pSlope) m_pSlope->Unlink(); if(m_pCrossover) m_pCrossover->Unlink(); delete m_pSlope; delete m_pCrossover; } UInt_t operator()(const Address_t pEvent, CEvent& rEvent, CAnalyzer& rAnalyzer, CBufferDecoder& rDecoder); virtual void OnAttach(CAnalyzer& rAnalyzer); virtual void OnDetach(CAnalyzer& rAnalyzer); };
The text below shows the modified version of OnAttach.
void CTestUnpacker::OnAttach(CAnalyzer& rAnalyzer) { CEventUnpacker::OnAttach(rAnalyzer); // Create the TCL variable objects: m_pSlope = new CTCLVariable(gpInterpreter, std::string("slope"), kfFALSE); m_pCrossover = new CTCLVariable(gpInterpreter, std::string("crossover"), kfFALSE); // Now link these variables to our variables Any failure results in a // crash of the program. assert(m_pSlope->Link((void*)&m_dSlope, TCL_LINK_DOUBLE) == TCL_OK); assert(m_pCrossover->Link((void*)&m_dCrossover, TCL_LINK_DOUBLE) == TCL_OK); }
This member contains the unpacking code. We assume that the parameter with id 1 will be calibrated into an element of the rEvent array indexed by pIdx:
... DFloat_t calib = (DFloat_t)rEvent[1]; // Compute calibrated var. calib = calib*m_dSlope + m_dCrossover; rEvent[pIdx] = (Int_t)(calib + 0.5); // Round it into integer. ...
SpecTcl Home General Information User Guide Programmer's Guide Obtaining and Installing
Last Modified: October 28, 2003 by: fox@nscl.msu.edu
© Copyright NSCL 1999, All rights reserved