/* dxl.q: Open Data Explorer interface $Id: dxl.q,v 1.5 2004/04/14 08:40:25 agraef Exp $ */ /* This file is part of the Q programming system. The Q programming system is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. The Q programming system is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* DXL connection handles. ***************************************************/ /* Multiple instances of the DX server can be run at at the same time, which makes it possible to execute several different visualization programs simultaneously in a single Q script. The handles to open server connections are represented using the DXLHandle type. */ public extern type DXLHandle; /* Starting and exiting the DX server. ***************************************/ /* dxl_start: Create a new connection to the DX server, by running the given shell command (usually something like "dx -image" or "dx -exonly"). Returns a handle to the new connection (unless an error occurs, in which case the function fails). */ public extern dxl_start SH_CMD; /* dxl_close: Close the server connection given by the handle H. After this, the connection is inaccessible. This function is carried out automatically when a DXLHandle object ceases to exist. The dxl_exit function is like dxl_close, but also terminates the server immediately. */ public extern dxl_close H, dxl_exit H; /* Loading and executing programs. *******************************************/ /* Operations for loading and executing visual programs, macros and scripts. Note that macros and scripts are only understood when the server runs in "executive only" (rather than "user interface") mode. This mode can be accessed by invoking the server with the -exonly option. */ /* dxl_load, dxl_load_macro, dxl_load_script, dxl_load_config: Load the specified visual program, or DX macro/script/configuration file (executive mode only) into the server specified by the connection handle H. Filenames are relative to the directory in which the server was invoked. */ public extern dxl_load H NAME, dxl_load_macro H NAME, dxl_load_script H NAME, dxl_load_config H NAME; /* dxl: Send a single script command to the server (executive mode only). */ public extern dxl H CMD; /* dxl_begin_macro, dxl_end_macro: Send a macro definition to the server running in executive mode. The body of the macro is sent in between using the dxl operation (see above). */ public extern dxl_begin_macro H HEADER, dxl_end_macro H; /* dxl_exec_once, dxl_exec_on_change: Start execution of the main macro. Two execution modes are available, "execute-once" and "execute-on-change". The latter automatically reexecutes the DX program as soon as inputs change. */ public extern dxl_exec_once H, dxl_exec_on_change H; /* Same for arbitrary macros (executive mode only). These also take a list of string values specifying the parameters to be passed to the macro. */ public extern dxl_exec_once_named H NAME ARGS, dxl_exec_on_change_named H NAME ARGS; /* dxl_end_exec, dxl_end_exec_on_change: Stop program execution and execute-on-change mode. Note that the latter does *not* stop program execution immediately, it only disables execute-on-change mode and hence keeps the program from reexecuting on a change after it has terminated. */ public extern dxl_end_exec H, dxl_end_exec_on_change H; /* dxl_seq_ctl: Send a command (of the DXLSeqCmd enumeration type) to the sequencer. This allows you to control an animation from a Q script; see the DX user manual for an explanation of the sequencer. */ public type DXLSeqCmd = const seq_loop_off, seq_loop_on, seq_palindrome_off, seq_palindrome_on, seq_play_backward, seq_play_forward, seq_step, seq_stop; public extern dxl_seq_ctl H CMD; /* The following operations are for UI mode only. ***********************/ /* dxl_render_mode: Set the rendering mode (0 = software, 1 = hardware rendering) for the window with the given title. */ public extern dxl_render_mode H TITLE MODE; /* dxl_reset: Resets the DX server (flushes the server's cache). This is necessary, in particular, to make the server pick up new data when the input file has been overwritten. */ public extern dxl_reset H; /* Status queries. ***********************************************************/ /* dxl_ready: Check that the connection to the server is up and running. When given a server handle, this operation never fails and always returns a truth value. */ public extern dxl_ready H; /* dxl_busy: Check whether the server is currently executing a program. */ public extern dxl_busy H; /* dxl_wait: Wait until the server has finished executing the current program. */ public extern dxl_wait H; /* dxl_check: Check whether a result (output value or error message, see the dxl_read operation below) is ready to be processed. */ public extern dxl_check H; /* Communication with the server. ********************************************/ /* These functions allow you to feed input variables into DLXInput modules in the program executing on the server, and to retrieve output values (results in DLXOutput modules) and error messages as they are generated by the program. All values are encoded as strings in DX syntax. */ /* dxl_input: Send a DXLInput variable value to the server. */ public extern dxl_input H NAME VALUE; /* dxl_output: Declare a DXLOutput variable to be monitored. The value will be sent back to the Q script and can be retrieved using dxl_read as soon as it becomes available during execution of the DX program. */ public extern dxl_output H NAME; /* dxl_read: Retrieves results from the server; if necessary, keeps polling until a result is available. Sends back either an output value in the format of a (NAME,VALUE) pair, or an error term of the form `dxl_error MSG' (you can define the dxl_error function as appropriate for your application, e.g., you might define it to print and error message). Note that dxl_read is a blocking operation; if necessary, you can check beforehand whether a result is ready to be processed with the dxl_check function, see above. */ public dxl_error MSG; public extern dxl_read H; /* Data file generation. *****************************************************/ /* The dxl_file function helps to create simple kinds of DX input files consisting of positions, connections and an arbitrary number of data components. The data components can be position- or connection-dependent. The components are specified using the Positions, Connections and Data types defined below. See the IBM Visualization Data Explorer User's Guide, Appendix B.2, for a closer description of the various structures. */ /* dxl_file NAME POS CONN DATA: creates a DX data file. Parameters: NAME string specifying the name of the data file to be created POS positions component (see Positions type below) CONN connections component (see Connections type below) DATA single data component (see Data type below), or a tuple of different data components The returned result is just the name of the data file, as specified in the NAME parameter. */ public dxl_file NAME POS CONN DATA; /* Note that in the following data structures all points and vectors are encoded as lists, not tuples. */ /* Positions type: regular_positions COUNTS ORIG DELTAS: specifies a regular grid. Parameters: COUNTS = [N1,N2,...] specifies the dimensions of the grid ORIG = [X1,X2,...] specifies the origin (#COUNTS-dimensional vector) DELTAS = [D1,D2,...] specifies the displacement vectors for each dimension, each of dimension #COUNTS. Note: All parameters must be lists of the same size. positions DIM DATA: specifies an irregular grid. Parameters: DIM specifies the dimension of the grid DATA the coordinate list Note: The grid points are encoded as a flat coordinate list in row-major order [X11, X12, ..., X21, X22, ...], i.e., the column index varies fastest). */ public type Positions = const regular_positions COUNTS ORIG DELTAS, positions DIM DATA; /* Connections type: regular_connections COUNTS ELEM_TYPE: specifies regular connections. Parameters: COUNTS = [N1,N2,...] specifies the grid dimensions ELEM_TYPE a string specifying the connection type ("triangles", "quads", "cubes", "tetrahedra", etc.) connections DIM ELEM_TYPE DATA: specifies irregular connections. Parameters: DIM specifies the dimension of the grid ELEM_TYPE string specifying the connection type (null value for default) DATA a list of integers, the position indices Note: Again, DATA is a flat list whose items are grouped into sublists of size DIM. Here, each entry of the list is a zero-based integer index referring to the corresponding grid point. */ public type Connections = const regular_connections COUNTS ELEM_TYPE, connections DIM ELEM_TYPE DATA; /* Data type: data NAME DEP TYPE DIMS DATA: specifies the data values. Parameters: NAME string specifying the name of the data component (use "data" for the default data component of a field) DEP string specifying the component the data depends on ("positions", "connections"), or null value if no dependency TYPE string specifying the type of the data ("int", "float", "string", etc.); make sure that your actual data matches the specification DIMS dimensions of the data ([] for scalar values, [N1] for N1-dimensional vectors, [N1,N2] for N1 x N2 matrices, etc.) DATA the data values, encoded as a flat list Note: DX internally stores a string array as a char matrix, and higher- order arrays of strings are not permitted. Therefore, if TYPE="string", DATA must be a string list, and the DIMS argument must be of the form [L], where L is the size of the largest string + 1. */ public type Data = const data NAME DEP TYPE DIMS DATA; /* implementation of the dxl_file function */ private write_positions, write_connections, write_data, write_field; dxl_file NAME:String POS:Positions CONN:Connections DATA:Data = write_positions F POS || write_connections F CONN || write_data F (3,DATA) || write_field F POS CONN [(3,DATA)] || NAME where F:File = fopen NAME "w"; dxl_file NAME:String POS:Positions CONN:Connections DATA:Tuple = write_positions F POS || write_connections F CONN || do (write_data F) DATA_LIST || write_field F POS CONN DATA_LIST || NAME where F:File = fopen NAME "w", DATA_LIST = zip [3..#DATA+2] (list DATA); /* private helper functions */ private write_delta, write_array; write_positions F (regular_positions COUNTS ORIG DELTAS) = fprintf F "\n# positions\nobject 1 class gridpositions counts" () || do (fprintf F " %s") (map str COUNTS) || fprintf F "\norigin" () || do (fprintf F " %s" . str) ORIG || do (write_delta F) DELTAS || fprintf F "\n" () if not null COUNTS; = () otherwise; write_delta F DELTA = fprintf F "\ndelta" () || do (fprintf F " %s") (map str DELTA); write_positions F (positions DIM DATA) = fprintf F "\n# positions" () || write_array F 1 "float" [DIM] DATA || fprintf F "\n" () if (DIM>0) and then not null DATA; = () otherwise; write_connections F (regular_connections COUNTS ELEM_TYPE) = fprintf F "\n# connections\nobject 2 class gridconnections counts" () || do (fprintf F " %s") (map str COUNTS) || ifelse (null ELEM_TYPE) () (fprintf F "\nattribute \"element type\" string %s" (str ELEM_TYPE)) || fprintf F "\nattribute \"ref\" string \"positions\"\n" () if not null COUNTS; = () otherwise; write_connections F (connections DIM ELEM_TYPE DATA) = fprintf F "\n# connections" () || write_array F 2 "int" [DIM] DATA || ifelse (null ELEM_TYPE) () (fprintf F "\nattribute \"element type\" string %s" (str ELEM_TYPE)) || fprintf F "\nattribute \"ref\" string \"positions\"\n" () if (DIM>0) and then not null DATA; = () otherwise; write_data F (K, data NAME DEP TYPE DIMS DATA) = fprintf F "\n# %s" NAME || write_array F K TYPE DIMS DATA || ifelse (null DEP) (fprintf F "\n" ()) (fprintf F "\nattribute \"dep\" string %s\n" (str DEP)) if not null DATA; = () otherwise; private empty_positions POS, empty_connections CONN, write_data_descr, regstr; write_field F POS CONN DATA_LIST = fprintf F "\n# field\nobject \"%s positions %s connections\" class field" (regstr POS, regstr CONN) || ifelse (empty_positions POS) () (fprintf F "\ncomponent \"positions\" value 1" ()) || ifelse (empty_connections CONN) () (fprintf F "\ncomponent \"connections\" value 2" ()) || do (write_data_descr F) DATA_LIST || fprintf F "\nend\n" (); empty_positions (regular_positions COUNTS ORIG DELTAS) = null COUNTS; empty_positions (positions DIM DATA) = (DIM<=0) or else null DATA; empty_connections (regular_connections COUNTS ELEM_TYPE) = null COUNTS; empty_connections (connections DIM ELEM_TYPE DATA) = (DIM<=0) or else null DATA; regstr (regular_positions _ _ _) = "regular"; regstr (regular_connections _ _) = "regular"; regstr _ = "irreg" otherwise; private empty_data DATA; write_data_descr F (K, DATA) = ifelse (empty_data DATA) () (fprintf F "\ncomponent %s value %d" (str NAME, K)) where data NAME _ _ _ _ = DATA; empty_data (data NAME DEP TYPE DIMS DATA) = null DATA; private write_elems, write_elem, shape; write_array F K "string" DIMS DATA = fprintf F "\nobject %d class array type string rank %d%s items %d data follows" (K, #DIMS, shape DIMS, #DATA) || write_elems F 0 1 DATA; write_array F K TYPE DIMS DATA = fprintf F "\nobject %d class array type %s rank %d%s items %d data follows" (K, TYPE, #DIMS, shape DIMS, #DATA div N) || write_elems F 0 N DATA where N = prd DIMS; write_elems F I N Xs = write_elem F I N X1 || write_elems F ((I+1) mod N) N X1s where [X1|X1s] = Xs; = () otherwise; write_elem F I N X = fprintf F "\n%s" (str X) if I = 0; = fprintf F " %s" (str X) otherwise; shape [] = ""; shape DIMS = " shape " ++ join " " (map str DIMS);