Viewer

VisIt's viewer is the central state manager and is responsible for communicating with all other components and drawing graphics. The viewer can be embedded in other applications (See Using the viewer in a Qt application), enabling them to use VisIt for plotting. Parts of the viewer are also used in the Libsim runtime library, which enables in situ data analysis and plotting in simulation codes.

Sources

The sources for Visit's viewer are located in trunk/src/viewer in the VisIt source tree. The viewer directory contains the following subdirectories:

  • core - The "core" parts of the viewer without any GUI components or connections to objects that enable the viewer to talk to other VisIt components
  • main - The parts of the viewer that give it GUI components and the ability to talk to other VisIt components. The main viewer application is located here.
  • proxy - Contains the viewer proxy object which lets client programs such as the GUI and CLI launch and control the viewer.
  • rpc - Contains the viewer "rpc" or commands that control the viewer. This directory also contains the ViewerMethods object, which provides methods that encode their arguments in the viewer rpc object.

Design

The top object in the Viewer is the VisItViewer object, which provides a minimal API to calling applications and contains the bulk of the important viewer objects, including the main ViewerSubject object. The VisItViewer object is instantiated from a minimal Qt application which creates the Qt application and then calls the Qt event loop. The VisItViewer object continues to initialize itself during the first iterations of the event loop and then responds to user inputs from the VisIt clients and from the viewer GUI, which is mainly composed of the visualization windows.

Most objects in the viewer inherit from the ViewerBase base class. ViewerBase provides useful functions for gaining access to the main objects in the viewer. The main viewer objects are instantiated via a factory class that returns different objects based on where the viewer code is being called. For instance, then the viewer code is used in Libsim, the factory class returns different objects than when the viewer code is called in the viewer program itself. This design makes it easy to reuse parts of the viewer in other contexts.

ViewerInternalArchitecture.png

Important objects accessible via ViewerBase

The ViewerBase base class enables all derived classes in the viewer to gain access to important singleton objects. The ViewerBase class contains static methods that return many of the important objects in the viewer, which are in turn created via a factory class within the static Get methods. This approach was taken to allow different factory classes to be used in order to create objects for the viewer, which lets the program behavior be altered depending on the nature of the created classes. For example, one viewer factory creates action handler objects for the various viewer commands. In the "full" graphical version of the viewer, a different factory class is used that also creates GUI objects for a subset of the viewer action classes. Most of the important objects in the viewer have a corresponding Get method in the ViewerBase class.

  • The current exceptions are: ViewerQueryManager and ViewerWindowManager. These just need to be adapted to the newer Get method style of coding, which followed a 2014 refactor of the viewer.

Since most of the important top level objects have a "Get" method and since all objects inherit ViewerBase, objects can be obtained by calling the appropriate "Get" method:

if(GetViewerProperties()->GetNowin())
{
    std::cout << "We're using offscreen rendering." << std::endl;
}

ViewerFactory

The ViewerFactory class is a factory class for creating various other classes used in the viewer. ViewerFactory is used to create ViewerWindows, VisWindows, action managers, interfaces to the file server and engine managers, plugin managers, and various GUI objects. In the viewercore library, the default version of ViewerFactory will create an action manager with no GUI handlers and it will create offscreen windows. In the viewer, a different ViewerFactory class will create an action manager with GUI support and it will create on-screen capable windows.

Most developers will not have a need to interact directly with the ViewerFactory.

ViewerState

ViewerState is a class that contains the set of state objects that can be communicated between the VisIt clients and the viewer. This includes objects that encode the viewer method calls, the plot list and other global state, and plot and operator attributes. The various state objects are included in ViewerState to simplify the addition of new state objects to the viewer. The ViewerState class is used in the viewer itself and in the ViewerProxy class which is used to control the viewer from client codes such as the GUI. The ViewerState class provides "Get" methods to obtain pointers to the various state objects that VisIt exposes. The state objects can be used in Subject/Observer code.

ViewerMethods

ViewerMethods is a class that is used to tell VisIt to do an operation. The class provides a lot of methods and encodes the method calls into the ViewerRPC state object with ViewerState. This prevents clients from needing to know how to modify ViewerRPC to tell the viewer to do an operation. The ViewerMethods class is exposed from the ViewerProxy, enabling clients such as the GUI and CLI to control the viewer. The ViewerMethods object is exposed inside the viewer itself, because sometimes it is convenient just to queue up commands that will run later when the code returns to the event loop.

ViewerMessaging

The ViewerMessaging class handles messaging within the viewer. There are 2 main types of messaging used internally: notifications to the user, and internal command messages.

Notifications to the user include all error, warning, and status messages. Part of the notification mechanism also includes support for creating information windows for certain rare instances when the viewer wants to alert the user to something important. Since the ViewerMessaging class is created from the ViewerFactory, there is a GUI version of it that can create Qt-based information dialogs.

Internal command messages are objects that describe actions that are posted to the event loop for later execution. An example of this is sometimes down in the viewer, we want to cause the window to re-execute its plots in response to some action. It might not be appropriate to handle that action right away but an internal command object can be created and be scheduled for execution later when the viewer returns to the Qt event loop. This mechanism is far cleaner than the old mechanism that it replaced where the viewer would append string-based commands containing arguments and pointers to important objects.

ViewerPlotFactory

VisIt plots are based on plugins and part of a plugin is its "plugin information". The plugin information provides metadata about the plugin such as its name and version but in the case of the viewer, the plugin information provides some behavior as well. The plugin information behavior lets the plugin change some aspects of how it behaves when instantiated in the viewer. All plots inside of the viewer are wrapped by a generic ViewerPlot object which contains the plot's plugin-appropriate state objects, and also the results of the plot's execution (the VTK actors and geometry). ViewerPlot objects in the viewer rely on the plugin information to customize their behavior.

ViewerPlotFactory is a factory class for creating ViewerPlot objects that have been initialized with a plugin's plugin information. The ViewerPlotFactory also uses the plugin information to create current and default plot attributes for each plot type that is identified when VisIt loads plot plugins. The current attributes are those that can be used to set the plot attributes for a plot when commanded by ViewerMethods. The default plot attributes are used as the plot attributes when a new plot is created.

ViewerOperatorFactory

ViewerOperatorFactory serves the same purpose as ViewerPlotFactory, except with operators. The class is responsible for creating ViewerOperator objects that have been initialized using their operator plugin information. Like ViewerPlotFactory, the class also manages the current and default operator attributes.

ViewerProperties

The ViewerProperties class is used to contain simple global properties that affect the viewer's operation. Many of these properties are set via command line switches. ViewerProperties was created to hold these global properties so they would not be spread out across various viewer objects.

Examples of viewer properties:

  • Nowin
  • Stereo
  • Force SSH tunneling

ViewerStateManager

ViewerStateManager ensures that the ViewerState gets created and initialized. This class is responsible for ensuring that config files are read and the settings are used to initialize the various default plot and operator settings. This class also makes sure that host profiles are read from a user's saved host profiles directory. The ViewerStateManager class manages some default attributes for material attributes and mesh management attributes. Also, since the ViewerStateManager can access much of the viewer's state, it coordinates save/restore of VisIt's session files.

ViewerFileServerInterface

ViewerFileServerInterface is a an abstract interface for opening data files and obtaining metadata and SIL information from them. An abstract interface is used to ensure that in the future, no important state gets put into the objects that satisfy the interface. Implementations of the interface delegate to other viewer objects that know how to launch and communicate with VisIt's mdserver. This pattern is used because it allows the viewer to talk to different implementations that satisfy the interface. In the viewer, the viewer's own file server class is used to obtain metadata. In the Libsim runtime library, where parts of the viewer are used, there is a different implementation that uses parts of the compute engine library to obtain metadata from the simulation.

This interface has methods for:

  • Obtaining metadata
  • Obtaining the SIL
  • Opening/closing files
  • Launching and connecting to mdserver
  • Querying some plugin information

ViewerEngineManagerInterface

ViewerEngineManagerInterface is a an abstract interface for setting up pipelines on the compute engine, executing those pipelines, and accepting data returned from the engine. An abstract interface is used to ensure that in the future, no important state gets put into the objects that satisfy the interface. Implementations of the interface delegate to other viewer objects that know how to launch and communicate with VisIt's engine. This pattern is used because it allows the viewer to talk to different implementations that satisfy the interface. In the viewer, the viewer's own viewer engine manager class is used to control the compute engine. In the Libsim runtime library, where parts of the viewer are used, there is a different implementation that talks directly to the compute engine internals.

Important objects that will be accessed via ViewerBase

Prior to the 2014 viewer refactoring, certain functionality was accessed globally through ViewerSubject or was accessed via different Instance() methods that provided access to singleton classes. The viewer still uses singletons but they are accessed via ViewBase's Get methods and the objects are created via ViewerFactory. Object creation using a factory was needed because using the Instance() methods to create objects was not flexible enough to create derived classes, which can be needed when parts of the viewer are used in other contexts.

In the long run there are a couple more objects that need to be transitioned to use the new Get method scheme:

  • ViewerQueryManager
  • ViewerWindowManager

ViewerQueryManager

ViewerQueryManager is the viewer's manager for queries. Queries in VisIt can be divided up into 3 categories: Dataset queries, Line queries, and Pick queries. Dataset queries are calculations performed on a plot's data (original or actual) and they usually result in a number or set of numbers (e.g. surface area, volume). A line query extracts data from a plot along a line and can optionally use that extracted data as the source for another VisIt plot. A pick query returns information about a given element (cell or node) such as the coordinates and variable values at that element.

All queries are associated with a VisIt plot and they usually are calculated/performed on the active plot in the plot list. The ViewerQueryManager is responsible for applying queries to VisIt plots because some queries (line queries mainly) will create new VisIt plots to plot data calculated by the query. When new plots are generated based on query results of some original VisIt plot, there can be a relationship between the original plot and the query-derived plot. For example, when the original plot changes, the lineout plot can update in response. The ViewerQueryManager coordinates these interactions.

ViewerWindowManager

ViewerWindowManager creates a set of ViewerWindow objects. A ViewerWindow contains the visualization window and the plot list for a given VisIt vis window. ViewerWindowManager currently allows up to 16 ViewerWindows and it contains the code to manage ViewerWindow creation, deletion, activity, etc. The ViewerWindowManager includes code that lets windows have synchronized views, synchronized times, save tiled images, etc. For the most part, ViewerWindowManager is the entry point for various operations that control the viewer. Most operations will operate on the active window. ViewerWindowManager methods will often obtain the active ViewerWindow and then call corresponding methods on one or more ViewerWindow objects.

ViewerWindowManager is currently accessed in the code using an Instance method.

ViewerWindowManager::Instance()->method()

ViewerSubject

ViewerSubject is the main viewer class that holds most of the application together and relies on Qt for GUI components and socket connections. ViewerSubject is primarily responsible for application initialization and communication with clients. ViewerSubject can connect to N simultaneous VisIt clients and can process input from all of them by serializing their input into a central buffer that is the input to the master Xfer object. Communication for each client is managed by a ViewerClientConnection object, which contains among other things, a socket notifier, xfer, and ViewerState object. The ViewerState object is a copy of the main ViewerState object that contains all of the state objects available to the viewer after plugins were loaded. When a client is connected to VisIt, a ViewerClientConnection is created and it monitors whether there was input from the application. Complete state object input messages cause the state objects in the ViewerState to Notify, whereupon they are serialized once more into the central input buffer for the master xfer.

The input from the master xfer is processed when it is safe to do so from the main event loop. If the compute engine is executing or if there is another condition under which processing input would be harmful then input is saved for later. Ultimately, the input flows through the master xfer, causing the state objects in the main viewer state to update. This causes the ViewerSubject's HandleViewerRPC method to be called, which dispatches the viewer RPC to various functions inside of ViewerSubject. From those execution functions, control flows to other areas of the viewer, performing the RPC's designated tasks. Some RPC's are handled by action objects. In that case, control flows from ViewerSubject::HandleViewerRPC to the appropriate action object in the active visualization window.

Inside ViewerWindowManager

ViewerWindowManager is an important class because many of the action classes which handle the behavior for the ViewerMethod functions actually turn around and call methods on ViewerWindowManager. ViewerWindowManager may then call methods on windows and plot lists, etc.

ViewerWindow

ViewerWindow is a class that contains all of the state and windowing objects for a visualization window. As such, a ViewerWindow will contain a VisWindow of some type (can be on-screen or off-screen) and it will contain a popup menu and toolbar object associated with the on-screen vis window. Maybe more important of all, ViewerWindow contains a ViewerPlotList, which is contains the plots for the window.

ViewerPlotList

ViewerPlotList is a class that contains multiple ViewerPlot objects. The contents of the ViewerPlotList are represented in the VisIt client state via the "PlotList" state object, which is used in the VisIt GUI to show the plots that the user has created. The ViewerPlotList is mainly devoted to managing the list of ViewerPlot objects (add,delete,etc.) and ensuring that the proper client state is shown. ViewerPlotList can apply actions to multiple ViewerPlot objects when multiple plots are selected. For example, if multiple plots are selected, the ViewerPlotList will delete the selected plots when the DeleteActivePlots action is called via ViewerMethods. ViewerPlotList is also involved in setting the proper defaults for plots when they are created. For example, when a new plot is created, it may inherit the SIL from the active plot. ViewerPlotList provides this coordination between plots.

ViewerPlot

ViewerPlot represents an instance of a VisIt plot in the plot list. A ViewerPlot operates on data from a specific database (given by a filename) and it creates data according to the plugin that has been associated with the ViewerPlot. A ViewerPlot contains the plot attributes for the plot as well as a cache of VTK actor objects that represent the geometry to be plotted in the visualization window. Certain aspects of the ViewerPlot are handled via the plot's "plot information" object, which comes from the plot plugin. This includes the plot's ability to be animated, etc.

When first created, a ViewerPlot is in the "new" state, indicating that no engine executions have taken place to give the plot any geometry to be plotted in the visualization window. When the viewer tells the plot to execute, a series of messages are sent to the compute engine and the plot is executed there, returning VTK datasets with the plot geometry, or a "null" dataset, which causes automatic scalable rendering to kick in at the ViewerWindow level.

A large set of the ViewerMethod functions invoke action classes that ultimately modify the state of the ViewerPlot object and cause a change that requires the plot to be regenerated by the compute engine. The computed geometry is stored in a cache in ViewerPlot if animation caching is enabled so subsequent playback of animations is faster.

Each ViewerPlot can have ViewerOperators applied to it which will insert VisIt operators into the data flow network that gets instantiated on the compute engine. The operators filter and change data before it gets to the plot.

ViewerOperator

ViewerOperator represents an operator that has been added to a plot in the plot list. Each ViewerPlot maintains a list of applied ViewerOperators. Each ViewerOperator contains the type of operator that has been applied as well as the operator attributes state object that contains the parameters for the operator. The ViewerOperator is used also when the viewer makes calls to the compute engine to set up the data flow network for the plot. ViewerOperator is associated with an operator plugin and gets some of its behavior from the operator's plugin information.

VisWindow

VisWindow is an AVT object that represents a visualization window to which AVT plots are added and rendered. This is a layer on top of VTK render windows that do the actual rendering of the VTK datasets within the AVT plots. The VisWindow contains several colleague classes that control aspects of the vis window's appearance, mouse behavior (interaction and tools), toolbars and menus, legends, and plots.

ViewerToolbar

ViewerToolbar is a class that manages access to a QToolbar object. When the viewer is run with a GUI, action classes have a chance to add themselves to the toolbar if they want. The ViewerToolbar manages the addition of various viewer actions to the toolbar and keeps the toolbar up to date with VisIt's state (e.g. the animation toolbar buttons are disabled when there are no plots).

ViewerPopupMenu

ViewerPopupMenu is a class that manages access to a QMenu object that is accessible via right click in each VisIt visualization window. When the viewer is run with a GUI, action classes have a chance to add themselves to the popup menu if they want. The ViewerPopupMenu manages the addition of various viewer actions to the menu and keeps it up to date with VisIt's state (e.g. the animation menu options are disabled when there are no plots).