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).


Available xvs documentation

  1. Curent usage/help message (TEXT)
  2. Getting started (this document)
  3. Generating data to send to xvs
  4. Sending data to xvs using xvs itself
  5. The Control Panel
  6. Pull Down Menus
  7. Pocket Guide (HTML)

Getting Started

xvs uses a client/server model. The xvs server is a GUI-based application whose principal purpose is to visualize and manipulate data generated from the finite-difference solution of partial differential equations in one space variable and time, i.e. data of the form y(xj,tn) where xj and tn are discrete spatial and temporal coordinates respectively.

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:

  1. sdftoxvs, which sends files in .sdf form to the server.
  2. xvs itself, which, when used with command-line arguments, communicates to the server.

You start the xvs server on your graphics console by invoking xvs with no command-line arguments at a shell prompt:

lnx1% xvs
Assuming 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
On 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 following window:

The control panel has several tabs (Ops, View, File, etc.) which you can select, and that are described in more detail HERE

xvs operation is based on the concept of an active window. A specific xvs window is made active in one of the following ways:

  1. If the control panel is closed, by moving the mouse so that the cursor is within that window.
  2. If the control panel is open, by clicking the LEFT mouse button while the cursor is in the window which is to be activated.

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:

Note that the selection of the apply xy sub-menu item created a new window named wave101' (the prime denotes differentiation) whose contents are a (numerical) first spatial derivative of the contents of the wave101 data set.

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:

Using the sample data loaded into xvs, experimentation with some of the features described therein (particularly the Ops section of the control menu documentation) should quickly give you a basic facility with the server.

Refer to the section below for information on how to interface xvs with your application programs.

Generating data to send to xvs

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:

  1. Directly to the xvs server.
  2. To .sdf files. The contents of these files can subsequently be sent to xvs using the sdftoxvs utility.
At this point, we will consider only the second mechanism.

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     xvswave: Generates time-series of profiles of
c     left-moving "wave" (f(t+x) = constant) and outputs
c     profiles via 'xvs' interface.
      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           Define y(x,t)
            y(j) = f(mod((x(j) + t),1.0d0))
         end do
c        Output data via 'xvs' interface.
         call xvs('wave',t,x,y,nx)
         t = t + dt
      end do
900   continue
         write(0,*) 'usage: xvswave '
c     Gaussian function.
      double precision function f(x)
         implicit      none
         real*8        x
         f = exp(-((x-0.5d0)/0.1d0)**2)
In 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.

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 do
will 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:

# 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)
        $(F77_COMPILE) $*.f
xvswave: xvswave.o
        $(F77_LOAD) xvswave.o -lp410f $(LIBXVS) -o xvswave
        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
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

lnx1% xvswave 101

lnx1% ls -lt *sdf
-rw-r--r--    1 phys410  phys410    172811 Nov  1 18:04 wave.sdf 
Note 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

Sending data to xvs using xvs itself

It is also possible to send data in ASCII form to xvs, a single dataset at a time, using the "client-side" facilities of the program---this is done using a command-line invocation of the following form:
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.

Example 1:

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

Example 2: File data contains two columns of data defining xi and yi values respectively:

lnx1% xvs put data 0.0 < data