xvs is a visualization tool for analyzing, among other things, the output of time-dependent PDEs in one spatial dimension (or time dependent cuts of higher-d solutions).
As with other OpenGL applications, xvs is designed to take full advantage of the prodigious hardware of modern PC graphics cards, so it must be used at the console of one of the lnx machines (or on any Linux machine with a decent graphics card to which you have access---talk to the instructor for installation help).
xvs clients, on the other hand, are applications which send the data that the server visualizes. In this tutorial, we will discuss the xvs server, and two clients:
You start the xvs server on your graphics console by invoking xvs with no command-line arguments at a shell prompt:
lnx1% xvsAssuming that your path is set correctly, and that you are on a graphics console, the following GUI should pop up in the upper-right hand corner of your screen.
NOTE: From time to time, xvs will output diagnostic messages to standard error, so it is recommended that you run it in a separate shell so that you will be able to see these messages.
The server is now running, but has not accepted any data; we could discuss the various buttons and pull downs on the GUI, but those should be reasonably self-explanatory once you play around with the GUI a bit. Instead, we will send some data to the server using the sdftoxvs command.
You should now download the .sdf file wave101.sdf, preferably to a location within your home directory.
Following the download, if you obtain detailed information on the file using ls -l, you should see something like this:
% ls -l wave101.sdf -rw-r--r-- 1 matt choptuik 173114 Nov 1 09:39 wave101.sdf
As mentioned above, xvs uses a client/server model of operation. As is typical of networked applications, the server and the client need not be executing on the same machine. Thus, in general, clients need to specify the machine on which the server is being run. In xvs this specification occurs via the setting of an environment variable, XVSHOST.
You should now check the setting of this envrionment variable in your own shell
% printenv XVSHOST lnx1.physics.ubc.caOn the lnx machines, XVSHOST is by default set via
setenv XVSHOST `hostname`(see /etc/csh.cshrc) whenever a new tcsh starts up. So long as you are sending data from the same machine on which you are visualizing that data, this is the way things should be set up.
With a properly set XVSHOST variable, we are ready to send data to xvs using sdftoxvs. Although sdftoxvs has quite a few options, the following simple type of invocation will suffice in most cases:
% sdftoxvs wave101.sdf
If all is well, after the completion of the sdftoxvs
command, the xvs GUI will look like this:
Although many of the functions of the xvs server can be controlled via the keyboard and mouse, there is an additional component to the GUI---the control panel---whose visibility can be toggled by mouse-clicking (any button) on the Control item of xvs's toolbar, located at the top of the GUI.
After clicking on Control you should see the
xvs operation is based on the concept of an active window. A specific xvs window is made active in one of the following ways:
In other words, the active window is the window which has input focus---input focus follows the mouse when the control panel is closed, and is attached to a window by left-clicking in that window when the control panel is open.
In both cases, the active window is bordered in green, whereas non-active windows have red borders.
In the context of the current example, xvs is displaying only a single window. One of the ways that we can generate another data window is to invoke a function ("applicator") on the wave101 data set. Before we do this, let us close the control window by clicking on the control window's kill button (the x in the upper left-hand corner, or the equivalent, depending on which display manager you are running). Once the control window has been closed, position the mouse in the wave101 window, then click and hold the right mouse button to bring up a pop-up menu. Select the apply xy submenu, and then highlight the dy/dx entry of that sub-menu and release the mouse button.
The GUI should now look like this:
xvs can display a maximum of 25 windows, as in THIS IMAGE If you perform an operation that would require the opening of a 26th window, xvs will tell you that it is unable to do so via a message in the status area (the rectangular box near the top of the GUI).
Continuing, whenever xvs is displaying more than a single window, any particular window can be made to occupy the entire GUI ("brought to the foreground") by making the window active, then depressing the SPACE key. This key sequence is a toggle; if SPACE is depressed while the active window is in the foreground, the multi-window display will be restored.
Individual windows may be killed (closed) either through the kill window pull-down sub-menu (activated via the RIGHT MOUSE button while in the active window), or via the keystroke command SHIFT-Q.
The xvs server itself can be shut-down using the Exit selection under the File entry on the main toolbar, or by clicking on the kill icon of the xvs window. In both cases, you will be prompted to verify that you really do want to exit the application.
You may now want to spend some time reading about the following topics:
Refer to the section below for information on how to interface xvs
with your application programs.
In a typical application, data sent to xvs will be generated by some Fortran/C/C++ program that solves some set of partial differential equations in one space variable and time.
From the application point of view, the xvs API (Application Program Interface) is a single routine, which historically, has been called vsxynt. However, as a convenience, the name xvs itself can now be used as an alias for vsxynt, and we shall use this alias in the following.
Depending on which particular implementation of the API is linked to during generation of the application executable (i.e. which library), data can either be sent:
The xvs subroutine has the following prototype:
subroutine xvs(name,time,x,y,nx) character*(*) name ! dataset name real*8 time ! dataset time (scalar) integer nx ! length of dataset real*8 x(nx), y(nx) ! x, y values of dataset (vectors)and has a typical usage best illustrated by example. Here, then, is a sample Fortran program that uses xvs calls to output data representing the propagation of a 1-dimensional "wave"---actually a Gaussian pulse. (The program and associated makefile is also available on-line in /d/lnx1/home/phys410/xvs, and is, in fact, the program that generated wave101.sdf used above).
c=========================================================== c xvswave: Generates time-series of profiles of c left-moving "wave" (f(t+x) = constant) and outputs c profiles via 'xvs' interface. c=========================================================== program xvswave implicit none integer i4arg integer maxn parameter ( maxn = 10 000 ) real*8 f real*8 x(maxn), y(maxn) integer i, j, n, nx, & nt real*8 h, t, dt n = i4arg(1,-1) if( n .lt. 1 .or. n .gt. maxn ) goto 900 nx = n nt = n h = 1.0d0 / (nx - 1) x(1) = 0.0d0 do j = 1 , nx - 1 x(j+1) = x(j) + h end do t = 0.0d0 dt = 1.0d0 / (nt - 1) do i = 1 , nt do j = 1 , nx c----------------------------------------------------------- c Define y(x,t) c----------------------------------------------------------- y(j) = f(mod((x(j) + t),1.0d0)) end do c----------------------------------------------------------- c Output data via 'xvs' interface. c----------------------------------------------------------- call xvs('wave',t,x,y,nx) t = t + dt end do stop 900 continue write(0,*) 'usage: xvswaveIn the above code, the xvs subroutine is called at every iteration of the do i = 1 , nt loop; i.e. at every time-step of the mock simulation of the solution of a partial differential equation in t and x.
' stop end c=========================================================== c Gaussian function. c=========================================================== double precision function f(x) implicit none real*8 x f = exp(-((x-0.5d0)/0.1d0)**2) return end
The first argument to xvs is a character string (more generally, it can be a character variable) that names the dataset being output, and that will be used in the creation of the name of the .sdf file in which the dataset will be stored. In the current example, and as will normally be the case, the same name---wave in this instance---is used to label the dataset for all time steps. The first time that xvs is called with a given name, the interface automatically opens a file which will generally have a name composed of the string passed to xvs with an .sdf extension---in this case wave.sdf. The data associated with that first call is then stored in the file, and subsequent calls to xvs with wave as the first argument will cause the corresponding data to be appended to the file.
Within a given program, if calls are made to xvs with different strings supplied as the first argument, then a corresponding number of distinct .sdf files will be created. For example, a program with a code structure such as
do it = 1 , nt . . . call xvs('v',t,x,v,nx) call xvs('w',t,x,w,nx) call xvs('dw/dx',t,x,dwdx,nx) . . . end dowill result in the creation of separate files u.sdf, w.sdf, dwdx.sdf. Note that the xvs interface will generally ignore non-alphanumeric characters (underscore is considered alphanumeric) in the creation of a file name from its string-valued first argument. Thus, in the above example, call xvs('dw/dx',...) creates the file dwdx.sdf.
Continuing with our discussion of the xvs calling sequence, the second argument to xvs is a real*8 scalar specifying the time associated with the dataset, the third and fourth arguments are real*8 vectors containing the x and y values, respectively, which define the dataset, and the fifth and final argument is an integer specifying the length of the dataset (i.e. the length of the x and y vectors).
Here is a Makefile for the above program:
.IGNORE: ############################################################ # NOTE: This Makefile assumes that the environment # variable LIBXVS has been set prior to invocation. ############################################################ F77_COMPILE = $(F77) $(F77FLAGS) $(F77CFLAGS) F77_LOAD = $(F77) $(F77FLAGS) $(F77LFLAGS) .f.o: $(F77_COMPILE) $*.f EXECUTABLES = xvswave all: $(EXECUTABLES) xvswave: xvswave.o $(F77_LOAD) xvswave.o -lp410f $(LIBXVS) -o xvswave clean: rm *.o rm *.sdf rm $(EXECUTABLES)Here is a sample build and invocation of the program (xvswave 101) that results in the creation of a file wave.sdf.
lnx1% pwd; ls /d/lnx1/home/phys410/xvs Makefile xvswave.f lnx1% make pgf77 -g -Msecond_underscore -c xvswave.f pgf77 -g -Msecond_underscore -L/usr/local/PGI/lib xvswave.o -lp410f -lsvs -lbbhutil -lsv -o xvswave Linking: lnx1% xvswave 101 lnx1% ls -lt *sdf -rw-r--r-- 1 phys410 phys410 172811 Nov 1 18:04 wave.sdfNote that in building the application, several libraries (-lsvs -lbbhutil -lsv) must be linked in. The Makefile assumes that these are specified in the LIBXVS environment variable, as should be the case, by default, on your lnx accounts.
The data stored in the file wave.sdf may now be sent to the xvs server using the previously discussed sdftoxvs command:
lnx1% sdftoxvs wave.sdf
lnx1% xvs put <name> <time>Here <name> is the name of the xvs window to which the data is to be directed, and <time> is the time to be associated with the dataset. The program then reads xi, yi pairs from standard input until EOF is detected, at which point it transmits the data to the server.
lnx1% xvs put squares 0.0 0.0 0.0 1.0 1.0 2.0 4.0 3.0 9.0 4.0 16.0 Ctrl-D
Example 2: File data contains two columns of data defining xi and yi values respectively:
lnx1% xvs put data 0.0 < data