Visualizing Scalar Fields
ElVis is a visualization system created for the
OverviewThe Element Visualizer (ElVis) is an integrated visualization system designed specifically for high-order finite element solutions. It supports:
- Extensible Architecture: To support data originating from arbitrary simulation systems, ElVis' visualization algorithms are decoubled from the data representation. This allows the visualization algorithms to be updated independent of the underlying data, and also allows for new high-order systems to be added to ElVis with minimal effort.
- Accurate Visualization: ElVis avoids introducing error into the final image by operating on the high-order data directly. The algorithms used by ElVis are based on the knowledge that the data is produced by a high-order finite element simulation, and is able to make use of the smoothness properties of the field on the interior of each element, while respecting the breaks in continuity that may occur at element boundaries.
- Interactive Performance: Using the high-order data directly entails significanltly higher computational costs when compared to approaches designed to view high-order data using linear primitives. ElVis uses the parallel processing capabilities of recent Graphics Processing Units (GPU) to provide interactive visualizations on desktop computers.
- NVIDIA GPU with compute capability 2.0 or greater.
- Operating System: Windows 7 (32 or 64 bit), OpenSuse and Mac OSX.
- Supported compilers include Visual C++ on Windows, CUDA supported gcc and g++ on Linux and OS X.
Third Party SoftwareThe following third party software is required to build and run ElVis.
CMakeCMake is used to generated the project files required to build ElVis (Makefiles on Linux and OS X, Visual Studio solutions on Windows). ElVis requires version 2.8 or later, which can be obtained here (linux distributions often have cmake available through their package managers).
Once installed, the path to the binaries should be added to the PATH environment variable.
QtWe use the Qt framework for ElVis' graphical user interface. ElVis can be used with a binary distribution or with a version built from source. Once Qt is installed, it is helpful, but not required, to set the QTDIR environment variable to the location at which Qt has been installed. For example, if Qt has been installed in /usr/local/Trolltech/Qt-4.7, then the environment variable should be set to
QTDIR=/usr/local/Trolltech/Qt-4.7and to add QTDIR/bin to the PATH (and to the LD_LIBRARY_PATH on Linux).
ElVis has been tested with Qt 4.7, which can be obtained here.
OptiXOptiX is the GPU-based ray-tracing engine that ElVis uses for all of its visualizations. The installers can be found here.
ElVis requires OptiX 2.1.1 or later, although we have found that performance is better using 2.5 or later.
After OptiX is installed, ElVis configuration can be done faster if the enivornment variable OptiX_INSTALL_DIR is set to the directory where OptiX is installed.
Note for OSX Users: Currently ElVis on OSX only supports OptiX 3.0. Earlier versions of OptiX can be found under the "Previous Releases" section on the OptiX download page here.
CudaElVis requires a minimum of CUDA 4.2. The version of Cuda that is required is based on the version of OptiX that is used. See the OptiX release notes to determine which Cuda version can be used. CUDA installers can be found here.
Note for Ubuntu users: When installing CUDA do not install the NVIDIA Accelerated Graphics Driver that comes with CUDA because it is not compatible with all versions of Ubuntu. You must use the NVIDIA Graphics Driver that is specific to your version of Ubuntu.
Note for OSX users: Currently ElVis on OSX only supports CUDA 5.0, which can be found on the CUDA Toolkit Archive page here.
Compiling ElVisElVis has only been tested with out of source builds, so all instructions that follow assume that your chosen build directly is not in the ElVis source directory.
Run CMake as normal, choosing whatever build directory you like, and ELVis/src as the source directory. If you have used the default directories for CUDA, OptiX and Qt and the respecitive PATH variables are set you should not have to change any CMake settings. If CMake is unable to find any of the following variables, this is how they should be set.
|QT_QMAKE_EXECUTABLE||On many Linux systems, and if QTDIR is set, Qt will automatically be found by CMake. If it is not, set this variable to the full path to the qmake executable.|
|OptiX_INSTALL_DIR||The root path to your OptiX installation. Once this variable is set, running configure again will automatically set the corresponding OptiX variables (OptiX_INCLUDE, optix_LIBRARY, and optixu_LIBRARY).|
|CUDA_SAMPLE_DIR||Within the CUDA root installation directory there is a samples directory.|
|CUDA_TOOLKIT_ROOT_DIR||This is the directory that houses your nvcc executable.|
|GL_LIBRARY||The second path in this variable (separated by ;) should be equal to the path in the OPENGL_glu_LIBRARY variable. If it instead contains "NOT-FOUND", then set it to the OPENGL_glu_LIBRARY path.|
CMake attempts to determine your video card's compute capability automatically. If your compute capability cannot be automatically determined, CMake requires you to check the correct box that corresponds to your card's compute capability (see image below). If your compute capability is not listed then choose the closest compute capability that is listed.
Setting The Compute Capability
ElVis OptionsElVis provides several options to indicate which modules are built and features are available in the CMake configuration file.
|ELVIS_ENABLE_DATA_CONVERTER||Enables the ElVis Data Conversion module, which converts existing high-order data into the Nektar++ data format. Requires Nektar++ 3.1 or greater. This module is only required to convert models to the Nektar++ format, and does not need to be built if runtime extensions are used.|
|ELVIS_ENABLE_FUNCTION_PROJECTION_MODULE||A reference implementation of a data conversion extension. This module projects a function onto the Nektar++ modified basis.|
|ELVIS_ENABLE_JACOBI_EXTENSION||Enables a reference extension which uses Jacobi polynomials as the basis function for each element type.|
|ELVIS_ENABLE_NEKTAR++_EXTENSION||Enables the Nektar++ extension. Requires Nektar++ 3.1 or greater.|
|ELVIS_ENABLE_NEKTAR_EXTENSION||Not yet implemented.|
|ELVIS_ENABLE_PRINTF||The presence of print statments in device code, even when they are not executed, increases compile and run time of the OptiX and Cuda kernels. This option allows all ELVIS_PRINTF statements to be turned off globally.|
|ELVIS_ENABLE_ProjectX_EXTENSION||Reference implementation based on ProjectX. This extension requires the ELVIS_USE_DOUBLE_PRECISION flag be set.
|ELVIS_USE_DOUBLE_PRECISION||Selects whether to use float or double for floating point computations.|
Once ElVis is built, the regression tests can be executed to verify that the code compiled correctly. To execute the regression tests, go to the build directory and enter the following:
Linux: > ctest
Windows: % ctest -C Release
This will create a series of visualizations and compare them with the expected image.
Setting UpElVis requires that the GPU used for the Cuda and OptiX kernels must be the same GPU connected to the display. The first step is to determine what number has been assigned to your GPU by the OS. Once that is determined, you then set the environment variable CUDA_VISIBLE_DEVICES=, where X is the number assigned to your GPU as determined below.
- Open the Control Panel then the NVIDIA Control Panel.
- Go to the Set up multiple displays option to see which GPUs are connected to your monitors.
- Click on System Information (lower left corner) to see which number has been assigned to the GPU connected to the monitor on which you will use ElVis.
- Set the environment variable CUDA_VISIBLE_DEVICES=, where X is the number from the system information dialog. Note that the environment variable starts at 0, while the system information starts at 1, so you must subtract 1 from the number obtained from the system information dialog.
Loading ExtensionsAfter starting ElVis, a screen similar to the following will be visible:
The first step is to load an extension. This is done via the plugin menu. Select Plugins->Load Plugin
Extensions are implemented as shared libraries (.dll on Windows, .so on Linux). To load an extension, select the shared libarary corresponding to the desired exension.
Once selected, extensions will be automatically loaded when ElVis starts in the future.
Visualizing Cut PlanesFor this example, we'll be using the Jacobi extension, which is a sample implementation of a runtime extension that ships with ElVis.
Load the file bulletH1P3.dat, located in the volumes directory of the ElVis distribution. After loading the model, a bounding box representing the spatial extent of the volume is shown in the visualization window.
|Click and Drag Left Mouse Button||Rotate around current look at point|
|Click and Drag Middle Mouse Button||Pan|
|Click and Drag Right Mouse Button||Zoom in and out|
|Mouse Wheel||Zoom in and out|
To create a cut-plane, select the Sources menu then click "Create Cut Plane". This creates a cut plane that cuts through the center of the dataset.
ElVis can be extended with two different types of extensions. In the following sections, we describe each type of extension and discuss their pros and cons.
Model Conversion Extensions
A conversion extension is used to convert a finite element volume to the Nektar++ format used internally by ElVis. This type of extension is most appropriate for volumes that have the following properties:
All elements are represented by hexahedra, tetrahedra, prisms, or square-based pyramids.
The field is represented by a polynomial.
If the volume contains elements of different types than those listed above, a conversion exetension may still be created, but the elements must be converted into one of the four element types indicated above. If the field is not represented by a polynomial, then the converted volume will contain error. In this case, we recommend that a runtime extension be used.
The model conversion extension's relys on the Nektar++ extension for all runtime processing. Since the Nektar++ extension only currently supports hexahedra, model conversion extensions only support hexahedra as well. Additional functionality is currently being added to the Nektar++ extensions to support the remaining element types.
Runtime extensions give ElVis the ability to access a simulation's native data, rather than first converting it to the Nektar++ format. It does this through a collection of high-level OptiX and Cuda functions that must be implemented in your extension.
Runtime extensions are implemented as shared libraries that are loaded by ElVis at runtime. Each runtime extension consists of three components, described in further detail below.
- C++ Interface. This interface is responsible for interfacing with the ElVis gui and handling the movement of model data from main memory to the GPU.
- OptiX Interface. This component is responsible for providing methods to sample a field on the GPU in OptiX.
- Cuda Interface. This component is responsible for providing methods to sample a filed on the GPU in Cuda.
The OptiX and Cuda interfaces are both written in Cuda. Cuda does not support linking of pre-compiled object files, so ElVis uses a different methods to provide customized behavior for each extension.
Creating Runtime Extensions
In this section, we will create a fully-functional runtime extension to illustrate the necessary steps and code. This section, we assume that there is an ElVis source distribution. We will refer to the location of the source distribution with the variable $ELVIS. Therefore, the source files are located at $ELVIS/src, the build is at $ELVIS/Build, and the ElVis distribution is at $ELVIS/build/dist. To simplilfy the initial extension development steps, we have included a runtime extension template at $ELVIS/src/ElVis/Extensions/RuntimeExtensionTemplate. This template will enable the creation of a simple runtime extension that can be loaded into ElVis (although it will have no functionality). The code that is located in this directory is not able to be compiled directly; rather, CMake must first be used to generate the runtime extension code, customized with your extension's name.
These steps generate the source code for the new runtime extension, which is located at $BUILD_BASE/$RUNTIME_EXTENSION_NAME (which we will refer to as $EXTENSION_BASE). The folders $BUILD_BASE/Build and $BUILD_BASE/CMakeFiles are not necessary and can be deleted, as well as the files $BUILD_BASE/CMakeCache.txt, $BUILD_BASE/cmake_install.cmake, and $BUILD_BASE/Makefile.
The C++ interface is responsible for loading high-order data from disk and tranferring it to the GPU for visualization. It is also responsible for handling user interaction and populating the ElVis gui. This is primarily accomplished through concrete subclasses of ElVis::Model. Each extension is required to have a model-specific version of this class available.
When an extension is initially loaded, ElVis looks for the following three methods, which must exist at the global namespace, have C linkage, and be visible outside the shared library. On Linux/OS X, these methods will be visible by default. On Windows, however, they are not, and must be explicitly exported (see ElVis/Extensions/JacobiExtension/Declspec.h for an example). These methods provide the initial interface to the extension.
const char* GetPluginName();
Each plugin must provide a name that is used in the ElVis gui to differentiate it from the other loaded plugins. There are no restrictions on the name.
const char* GetVolumeFileFilter();
Returns a file name filter for use by the Qt QFileDialog class to open volume. The format of the string is " (*.)". For example, "Jacobi Volumes (*.dat)".
ElVis::Model* LoadModel(const char* path);
Loads the model from the given location and returns a pointer to a new Model object representing it. ElVis will take control of this pointer and handle cleanup.
The runtime extension template provides default implementations of LoadModel and GetPluginName that are unlikely to need modification. The implementation of GetVolumeFileFilter, however, will need to be modified to correspond to the extension used by the model.
The next step is to fill in the implementation of the model class (located in $EXTENSION_BASE/Model.h and $EXTENSION_BASE/Model.cpp). For this sample extension, we will build a model that can visualize a simple high-order system that consists of axis-aligned hexahedra.
The file format we will use is a binary format with the following structure:
sizeof(int) : Number of Vertices
sizeof(double) * 3 * Number of Vertices : Vertex Array
sizeof(int) : Number of faces
sizeof(int) * 4 * Number of faces : For each face, an index into the vertex array for each of the face's vertices
sizeof(int) : Number of hexahedra
sizeof(int) * Number of hexahedra : For each hex, an index into the face array for each of the hexahedra's faces.
sizeof(int) : Number of coefficients
sizeof(double) * Number of coefficients : Coefficient array.
sizeof(int) * 3 * Number of hexahedra : Modes
In this example, there is a single scalar field associated with the volume. This example uses a modal basis. This is not a restriction imposed by ElVis and is simply the example used. Volumes using a nodal basis can be used as well.
Loading a volume from disk is performd in the
LoadModel method. The default behavior of this method is to call the
SampleRuntimeExtensionModel constructor that takes a single parameter (the location of the volume on disk). So the first step is to populate this constructor with the appropriate code to perform this task.
Several of the Model class' virtual functions are reporting functions that inform ElVis about the model.
For some volumes, the behavior of the field around some surface is of interest, and the surface coincides with element faces. This often occurs at the boundary between the elements and some geometry of interest. For 3D volumes, ElVis supports the collection of element faces into groups called Boundary Surfaces. Boundary surfaces can be rendered using color maps and contours.
The OptiX interface can be found in ElVis/Core/ElVisOptiX.cu. Each of the methods in the interface section must be implemented by the extension in a filed called ExtensionOptiXInterface.cu.
The Cuda interface can be found in ElVis/Core/ElVisCuda.cu. Each of the methods in the interface section must be implemented by the extension in a filed called ExtensionCudaInterface.cu.