Introduction: CUMULVS is a middle ware library for the extraction of data from distributed applications. It provides a global view of distributed data and a protocol for coordinating data extraction and parameter steering in a running, distributed application. There are two parts to this software library. One part is used to instrument an application. The routines in this part are imbedded in an application and are used to identify which arrays and arameters are to be viewed or steered and how the data is distributed. This part of the library is fairly well documented in the CUMULVS distribution documents. The other part of the library is used to construct VIEWER programs which communicate with an application and are "where the data goes" when it is extracted from the running application. This part of the library is... well not really documented very well at all. I have, over the course of several months and through my good fortune of being personal friends with the developers, become familiar enough with the viewer portion of the library to attempt to write this guide to constructing cumulvs viewers. For further information one can consult the source code, or several viewer examples included in the examples subdirectory of the CUMULVS distribution.;
STVattach - Attach to application. This command is used to attach a viewer to an application. It has two arguments. The first is the application name and the second is the returned set of field names associated with this application. The field names are available from the STV_VIEWER data structure (as are all the other data) and this command need not return the field list, however I thought it was convenient to do it here reather than provide another command to collect the field list. The field list is a tcl list and can be accessed as such.
The example above shows the use of STVattach. The foreach loop just shows how to access the field list. In the vtk slicer example the field list is used to make a radio button selection dialog.example: set appname spoot_app; # set the application name STVattach $appname fieldlist; # attach and retrieve the field list foreach i $fields { puts $i; # spit out the field names } STVselectfield - "Select a field". The STVslectfield command is used to select a field for viewing. Selecting the field just marks the selected flags in the appropriate data structure. This is part of constructing a view field group which then must be explicitly requested. A view field group may contain several fields each of which is selected by calling STVselectfield. STVselectfield clears any previous selections.
example:The above example shows how to select some fields. It is given here that the field names are known and hard coded into the field variable. A call to STVselectfield clears all previously selected fields. The command returns the name of the last field found or "field not found" if it cant find any of the names you request.set field "density pressure"; # some field I made up STVselectfield $field; # mark the field STVaddvfg - Make a view field group request. This call makes the view field group request. Once this call is made you are ready to receive frames. It takes no arguments but returns an integer field group id. This fgid is used later to identify a particular vfg in a collection of vfgs. For example one might want to change a vis region on a particular view field group out of several possible groups. STVaddvfg allocates memory for this particular group. Other functions are provided to access this memory.
example:Not much to this example. Once the fields are "selected" in the data structure they are requested by the STVaddvfg call.
set fgid [STVaddvfg]
STVdelvfg - If you can add 'em you gotta be able to delete 'em too. STVdelvfg also whacks any memory associated with this group. It also sends a halt message to the application to tell it to stop sending data.
example:Again, not much to say. This is a good example of why we want to keep track of field group ids. Remember that the memory associated with this vfg is gone so dont try to ref it.
STVdelvfg $fgid; # fgid contains the field group id of this vfg
STVreceiveframe - This command does the actual receiving of the data and is called after calling the other setup routines defined above. This command checks to see if the viewer is connected and it is ok to receive a frame of data. The latter condition is only met if there is memory for the data to be received into. The command takes no arguments but returns the field group id of the vfg it receives if a complete frame is received. Otherwise it returns a StatusIncomplete or BadFrame. It is a nonblocking call at this time.
example:This example shows how to receive a frame of data. The above commands are imbedded into a loop. The STVreceiveframe call sends an xon to the application as required. It is assumed that "render" knows what to do in the instance of each result.
set result [STVreceiveframe]; #receive it
if { $result != StatusIncomplete } {
render $result; #rendering procedure
}STVsetvisregion - This routine is used to reset the visualization region bounds. Calling this routine reallocates the memory for the view field group. The pointer to the data will change and should be treated as volitile.
example:The arguments to STVsetvisregion are the field group id, fgid, and the lower and upper bounds of the visualization region in each coordinate direction.set xlb 1
set ylb 1
set zlb 1
set xub 10
set yub 10
set zub 1
eval "STVsetvisregion $fgid $xlb $xub $ylb $yub $zlb $zub"STVsetviscell - This routine sets the stride size in each of the coordinate directions. It also reallocates the memory for the view field group with the same results as for the setvisregion call. Be carefull how you use the pointer to the data.
example:Similar to the vis region call this call takes a group id and the cell sizes in each of the coordinate directions. Again be carefull how you use the data.set xcell 1
set ycell 2
set zcell 3
eval "STVsetviscell $fgid $xcell $ycell $zcell"
//# Copyright (C) 1995 Board of Trustees of the University of Illinois
//#
//# This software, both binary and source, is copyrighted by The
//# Board of Trustees of the University of Illinois. Ownership
//# remains with the University. You should have received a copy
//# of a licensing agreement with this software. See the file
//# "COPYRIGHT", or contact the University at this address:
//#
//# Visualization & Virtual Environments
//# National Center for Supercomputing Applications
//# University of Illinois
//# 405 North Mathews Ave.
//# Urbana, IL 61801
/*
c declarations for stvTcl package
*/
#include "Stvtcl.h"
int Stvtcl_Init(Tcl_Interp *interp)
{
/* Initialize some cumulvs global stuff.. */
STVTCL_VIEWER = (STV_VIEWER) NULL;
STVTCL_VFG = (STV_VIEW_FIELD_GROUP) NULL;
STVTCL_AVFG = (STV_VIEW_FIELD_GROUP) NULL;
STVTCL_CURRENT_VFG = (STV_VIEW_FIELD_GROUP) NULL;
STVTCL_VF = (STV_VIEW_FIELD) NULL;
STVTCL_F = (STV_FIELDPTR) NULL;
stv_init_region(STVTCL_VISREGION);
stv_init_cell(STVTCL_VISCELL);
STVTCL_RESTART = stvFalse;
STVTCL_freq = 1;
STVTCL_no_sync = 0;
/* stv_setopt(stvOptNull, stvOptVerbose, stvTrue); */
/* enrole in pvm and get tid */
stv_myid(&STVTCL_MYTID);
if(STVTCL_MYTID < 0 )
{
return(TCL_ERROR);
}
/* create some commands */
Tcl_CreateCommand(interp,"STVattach",attach_to_app, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVselectfield",select_view_field, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVsetvisregion",set_vis_region, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVsetviscell",set_vis_cell, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVsetvisfreq",set_vis_freq, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVaddvfg",add_view_field_group, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVdelvfg",del_view_field_group, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVreceiveframe",receive_frame, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
Tcl_CreateCommand(interp,"STVsteering",steer, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
return(TCL_OK);
}
/* command definitions */
int steer(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
STV_VIEW_PARAM VP;
STV_PARAMPTR P;
double dval;
int newsteer;
int changed;
int nsteer;
int rcount;
int count;
int cc;
int i;
char *varValue;
/* Initialize Steered Param Count */
newsteer = 0;
nsteer = 0;
VP = STVTCL_VIEWER->vparams;
rcount = 0;
count = 0;
while ( VP != NULL )
{
if ( VP->token == stvSteerNot )
{
printf( "\t%s\n", VP->param->name );
varValue = Tcl_SetVar(interp,argv[1],VP->param->name,TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
count++;
}
else
rcount++;
VP = VP->next;
}
interp->result = varValue;
return(TCL_OK);
}
int receive_frame(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int cc;
if(STVTCL_CONNECTED && !STVTCL_RESTART) {
if( STVTCL_GET_FRAME == stvTrue)
cc = stv_viewer_receive_frame( &STVTCL_VFG, STVTCL_VIEWER, &STVTCL_RESTART,stvFalse );
else
cc = stvStatusIncomplete;
if( cc == stvStatusOk || cc == stvStatusBadFrame ) {
stv_viewer_send_XON( STVTCL_VFG, STVTCL_VIEWER );
if(cc == stvStatusBadFrame)
interp->result = "BadFrame";
else
sprintf(interp->result,"%d",STVTCL_VFG->fgid);
} else
interp->result = "StatusIncomplete";
}
return(TCL_OK);
}
int del_view_field_group(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
int fgid;
STV_VIEW_FIELD_GROUP avfg;
Tcl_GetInt(interp,argv[1],&fgid);
avfg = stv_get_view_field_group_id(STVTCL_VIEWER->vfglist,STVTCL_VIEWER->nvfgs,fgid);
if( avfg != NULL) {
stv_viewer_send_FieldHaltGroup(avfg,STVTCL_VIEWER); // Send the field halt group
stv_viewer_release_field(&avfg,STVTCL_VIEWER); // Release this view field group
return(stvStatusOk);
}
}
int add_view_field_group(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
STVTCL_AVFG = stv_viewer_request_field(STVTCL_VIEWER,STVTCL_VISREGION,STVTCL_VISCELL,STVTCL_freq,STVTCL_no_sync,&STVTCL_RESTART);
if(STVTCL_AVFG != NULL) {
if( allocate_vfg_memory(STVTCL_AVFG) != stvFalse) {
STVTCL_GET_FRAME = stvTrue;
sprintf(interp->result,"%d",STVTCL_AVFG->fgid);
} else {
STVTCL_GET_FRAME = stvFalse;
}
} else {
STVTCL_GET_FRAME = stvFalse;
interp->result = "bad vfg request";
return(TCL_OK);
}
return(TCL_OK);
}
int
allocate_vfg_memory(STV_VIEW_FIELD_GROUP avfg)
{
int state,i,nfields;
/* allocate memory for the vfg */
if(avfg != NULL) {
nfields = avfg->nvfields;
for(i=0;ivfglist,STVTCL_VIEWER->nvfgs,fgid);
stv_viewer_set_VisRegion( avfg, STVTCL_VIEWER,STVTCL_VISREGION, STVTCL_VISCELL );
nfields = avfg->nvfields;
for(i=0;ivfglist,STVTCL_VIEWER->nvfgs,fgid);
stv_viewer_set_VisRegion( avfg, STVTCL_VIEWER,STVTCL_VISREGION, STVTCL_VISCELL );
nfields = avfg->nvfields;
for(i=0;ivfglist,STVTCL_VIEWER->nvfgs,fgid);
stv_viewer_set_VisFrequency( avfg, STVTCL_VIEWER, STVTCL_freq );
return(TCL_OK);
}
int select_view_field(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
/* select a number of fields by flipping the appropriate switches in the
view field strucure. The actual view field request is made elsewhere.
*/
int nfields;
int i;
stv_clear_view_field_select(STVTCL_VIEWER); /* clear the current selections */
nfields = argc - 1;
STVTCL_VF = (STV_VIEW_FIELD) NULL;
for(i=1;i<=nfields;i++) { /* find the view field pointer by name */
STVTCL_VF = stv_get_view_field_name(argv[i],STVTCL_VIEWER->vfields,STVTCL_VIEWER->nvfields);
if(STVTCL_VF != (STV_VIEW_FIELD) NULL) {
STVTCL_VF->selected = stvTrue;
STVTCL_VF->view_type = stvFloat;
}
}
if(STVTCL_VF != NULL) {
interp->result = STVTCL_VF->field->name; /* return the name of the last field found */
} else
interp->result = "field not found";
return(TCL_OK);
}
int attach_to_app(ClientData clientdata, Tcl_Interp *interp, int argc, char *argv[])
{
char *varValue;
if(STVTCL_CONNECTED) {
if ( STVTCL_AVFG != NULL )
stv_viewer_send_FieldHaltAll(STVTCL_AVFG,STVTCL_VIEWER);
STVTCL_CONNECTED = stvFalse;
}
STVTCL_INITIALIZED = (stv_viewer_init(&STVTCL_VIEWER,STVTCL_MYTID,argv[1],stvFalse) == stvStatusOk);
if(STVTCL_INITIALIZED) {
/* get the field list and pass it back to the application.
the command should be used like this: STVattach appname fieldlist, where fieldlist is the
tcl variable that will contain the list of fields.
*/
STVTCL_F = STVTCL_VIEWER->fields;
while(STVTCL_F != NULL) {
varValue = Tcl_SetVar(interp,argv[2],STVTCL_F->name,TCL_LIST_ELEMENT|TCL_APPEND_VALUE);
STVTCL_F = STVTCL_F->next;
if(varValue == NULL) {
return(TCL_ERROR);
}
}
STVTCL_CONNECTED = stvTrue;
interp->result = "CONNECTED";
} else {
STVTCL_CONNECTED = stvFalse;
interp->result = "FAILED";
}
return(TCL_OK);
}