Viewer sources of metadata

VisIt's viewer occasionally needs metadata to set up plots and operators. For the most part, this metadata comes from the metadata server, which is a VisIt component that can run on remote computers to browse the file system and read metadata from databases. Metadata comes mainly in the form of an avtDatabaseMetaData object, which contains a collection of objects that provide information about the meshes, variables, materials that are present in a database. The avtDatabaseMetaData object is provided by database plugin readers and the completeness of the metadata has a good deal to do with the capabilities of the file format that stores the data. For example, not all readers fill out all aspects of the metadata because a file format might lack certain information and calculating that information would be expensive. Additional data regarding the structure and composition of the database can be determined by examining the SIL (Subset inclusion Lattice - stored in avtSIL object), which is a graph structure that describes how various mesh subsets in the database make up the whole mesh.

The avtDatabaseMetaData and avtSIL are used in the viewer when it needs to adjust its behavior to the database that has been opened. For example, the viewer has optional plot menus that can show the available variables for the active database. The viewer populates these menus based on the variables obtained from the metadata for the current database. The ViewerPlotList object in each ViewerWindow has a notion of the active database and new plots are made using the active database as the plot source. Each viewer plot in the plot list can come from a different database, so there are convenience methods for obtaining the metadata associated with a plot's database.

VisIt itself uses metadata and the SIL for most aspects of initialization and making decisions based on database-specific inputs. Metadata sometimes does not provide enough information. For example, scalar metadata objects have a field which lets the database reader provide scalar extents but when this information is not available, the scalar extents are not set. This is done because to provide perfect metadata, a reader must sometimes read all of the data in the files, which can be extremely expensive if the data are large. In instances where metadata are not available, VisIt can perform queries on plots to calculate some derived data such as scalar extents. Of course, this means reading the data and calculating quantities based on the data. VisIt's viewer does not do this but the compute engine can calculate such information during a pipeline execution when it is generating a plot. The compute engine can compute various queries once VisIt has committed to making a plot, which is typically only instigated by the user. Still, queries can be a useful mechanism for producing data for which metadata are not adequate.

ViewerFileServerInterface

The ViewerFileServerInterface abstract class defines an interface that can be used to request metadata and SIL objects from the viewer's internal infrastructure. Metadata can be obtained for a database (specified as host + filename) using the GetMetaData method. This method is used when we don't care which timestep's metadata is returned. For transient databases which might change metadata over time (new variables or number of domains) there are GetMetaDataForState() methods that permit a time step index to be passed.

The file server interface is accessible via the ViewerBase::GetViewerFileServer() method, which most viewer classes inherit through ViewerBase.

MetaData methods

    //
    // Use this method when you need metadata about the file but metadata
    // from any time state will suffice.
    //
    virtual const avtDatabaseMetaData *GetMetaData(const std::string &host,
                                           const std::string &filename,
                                           const bool forceReadAllCyclesAndTimes = false) = 0;

    //
    // Use this method when you need metadata about the file at
    // the specified time state.
    //
    virtual const avtDatabaseMetaData *GetMetaDataForState(const std::string &host,
                                                   const std::string &filename,
                                                   int timeState,
                                                   const std::string &forcedFileType = "") = 0;
    virtual const avtDatabaseMetaData *GetMetaDataForState(const std::string &host,
                                                   const std::string &filename,
                                                   int timeState,
                                                   bool forceReadAllCyclesAndTimes,
                                                   const std::string &forcedFileType = "") = 0;

SIL methods

    //
    // Use this method when you need the file's SIL but the SIL from any
    // time state will suffice.
    //
    virtual const avtSIL              *GetSIL(const std::string &host,
                                              const std::string &filename) = 0;

    //
    // Use this method when you need the file's SIL at the specified
    // time state.
    //
    virtual const avtSIL              *GetSILForState(const std::string &host,
                                              const std::string &filename,
                                              int timeState) = 0;

MetaData

These examples show how to access metadata from inside the viewer.

Active Database MetaData

To get the active database's metadata, we will use the plot list for the active visualization window and the viewer's file server. First, we get the plot list for the active window and get its host and database. The host and database are passed to the file server to get an avtDatabaseMetaData object.

// Get the metadata for the active database.
ViewerPlotList *pL = ViewerWindowManager::Instance()->GetActiveWindow()->GetPlotList();
const avtDatabaseMetaData *md = GetViewerFileServer()->GetMetaData(
    pL->GetHostName(), pL->GetDatabaseName());

// Print the metadata's scalar variables and which mesh they live on.
if(md != NULL)
{
    for(int i = 0; i < md->GetNumScalars(); ++i)
    {
        const avtScalarMetaData &scalar = md->GetScalars(i);
        std::cout << scalar.GetName() << " lives on " << scalar.GetMeshName() << "\n";
    }
}

MetaData for a plot

Each plot can be generated using data from a different database and each plot can also potentially use a different time step of data. To simplify getting the metadata for a plot, there is a convenience method: ViewerPlot::GetMetaData().

// Get the metdata for the first plot in the active window's plot list.
ViewerPlotList *pL = ViewerWindowManager::Instance()->GetActiveWindow()->GetPlotList();
if(pL->GetNumPlots() > 0)
{
    const avtDatabaseMetaData *md = pL->GetPlot(0)->GetMetaData();
    if(md != NULL)
    {
        // do something with the metadata.
    }
}

Number of Domains

Many database readers serve data from parallel codes which write multiple domains. VisIt parallelizes work over domains so it can be important to know the number of domains. This is encoded in the metadata (how the domains are decomposed further is represented in the SIL).

int
DomainsForPlotMesh(const ViewerPlot *plot)
{
    int ndomains = 1;
    const avtDatabaseMetaData *md = plot->GetMetaData();
    if(md != NULL)
    {
        const avtMeshMetaData *mmd = md->GetMesh(plot->GetMeshName());
        if(mmd != NULL)
        {
            ndomains = mmd->GetNumBlocks();
        }
    }
    return ndomains;
}

Queries

VisIt provides queries, which can be executed on a plot to calculate some derived information about the plot. The queries take place on the compute engine on the data that serves as input to the plot. Usually, a query calculates a single number or a small set of numbers, although there are elaborate queries that make images, etc. Queries are initiated by the user once a plot has been created and executed.

In the interest of calculating additional information about a dataset or plot from within the viewer, it is possible to call queries from within the viewer and use the results. Techniques like this which use queries have been applied in fvvBridge (new queries were added to VisIt to generate the needed data).

extern VisItViewer *viewer; // assume we have this. If not, we can use the plugin manager.
// Set up a plot
int pcPlot = viewer->GetPlotIndex("Pseudocolor");
GetViewerMethods()->AddPlot(pcPlot, "density");
GetViewerMethods()->DrawPlots();

// Call a query. Some queries have additional arguments to store in queryParams as key/value pairs.
MapNode queryParams;
queryParams["query_name"] = std::string("MinMax");
GetViewerMethods()->Query(queryParams);

// Get the query results and get the values out of it.
std::string xml_string = viewer->State()->GetQueryAttributes()->GetXmlResult();
XMLNode xml_node(xml_string);
MapNode results(xml_node);
double min = 0., max = 0.;
if(results.HasEntry("min"))
    min = results.GetEntry("min")->AsDouble();
if(results.HasEntry("max"))
    max = results.GetEntry("max")->AsDouble();

The XML returned from the MinMax query.

<map_node>
    <map_node key="max">
        <variant type="double">000000e0008f1740</variant>
    </map_node>
    <map_node key="max_coord">
        <variant type="doubleVector">000000a03e341e40 000000206edbf63f 000000004ec10b40 </variant>
    </map_node>
    <map_node key="max_domain">
        <variant type="int">0</variant>
    </map_node>
    <map_node key="max_element_num">
        <variant type="int">83943</variant>
    </map_node>
    <map_node key="min">
        <variant type="double">000000605887f13f</variant>
    </map_node>
    <map_node key="min_coord">
        <variant type="doubleVector">000000008297e33f 00000000000024c0 0000002049921c40 </variant>
    </map_node>
    <map_node key="min_domain">
        <variant type="int">0</variant>
    </map_node>
    <map_node key="min_element_num">
        <variant type="int">105026</variant>
    </map_node>
</map_node>