Use Custom Reader

This tutorial demonstrates how to load and use a custom data provider plugin via the PluginManager and access its datasets through the Access Library Manager (LMan). We’ll cover plugin discovery, error handling, printing a table of contents, and loading a specific result dataset (D.N displacement) for a node.

Overview

The example performs these steps:

  1. Parse command line argument (plugin base name)
  2. Create and configure a plugin manager
  3. Load the plugin (shared library extension is omitted)
  4. Create a Library Manager bound to the plugin (“virtual” file)
  5. Print the table of contents (datasets provided by the plugin)
  6. Load a displacement state by name and query a node value
  7. Clean up all resources

Prerequisites

  • The build must include the Data Provider Framework (CEE_SAM_DATA_PROVIDER_FRAMEWORK defined)
  • The minimal plugin (e.g. cdp_MinimalPlugin) must be built and discoverable on the system library path or in the working directory. The source code for minimal plugin is provided with the SDK.
  • A valid license (HOOPS_LICENSE) is required.

Step 1: Includes and Argument Handling

We start by including headers and capturing the plugin library base name (without extension):

C
#ifdef CEE_SAM_DATA_PROVIDER_FRAMEWORK
#include <stdlib.h>
#include "sam/base/base.h"
#include "sam/vdm/vdm.h"
#include "sam/vdm/plugins/pluginmanager.h"
#include "sam/vdm/datafile.h"
#include "sam/base/license.h"
#include "sam/hoops_license.h"

int main(int argc, char** argv)
{
     Vchar pluginLibraryPath[SYS_MAXPATHCHAR] = {0};

     /* check input arguments */
     if (argc < 2) {
           fprintf(stderr, "Usage: %s cdp_MinimalPluginPath\n", argv[0]);
           fprintf(stderr, " cdp_MinimalPluginPath is blank, 'cdp_MinimalPlugin' is assumed\n");
           strcpy(pluginLibraryPath, "cdp_MinimalPlugin");
     }
     else {
           strcpy(pluginLibraryPath, argv[1]);
     }

     /* Set the license */
     vsy_LicenseValidate(HOOPS_LICENSE);

Step 2: Create and Configure Plugin Manager

We create a plugin manager, set an error verbosity level, and attempt to load the plugin. The base name is used and do not append platform-specific extensions of plugin library (.so, .dll):

C
/* Look for the plugin */
vdm_PluginManager* pluginManager = vdm_PluginManagerBegin();
/* Set the error level as INFO=3 */
vdm_PluginManagerSetErrorLevel(pluginManager, 3);
vdm_PluginManagerLoadPlugin(pluginManager, pluginLibraryPath);
Vint error = vdm_PluginManagerError(pluginManager);
if (error) {
      vdm_PluginManagerEnd(pluginManager);
      fprintf(stderr, "%s file does not exists. The library extension must not be included in the path.\n", pluginLibraryPath);
      exit(1);
}

Step 3: Open a Plugin File with Library Manager

Create an LMan instance and open the special plugin “file” — we pass “MINIMAL”. Please refer to the source code of the minimal plugin for details on how it registers datasets and why this name is used. An error is thrown if the file cannot be opened.

C
vdm_LMan* libraryManager = vdm_LManBegin();
vdm_LManOpenFile(libraryManager, (Vchar*)"MINIMAL", nullptr);
/* check for error */
Vint ierr = vdm_LManError(libraryManager);
if (ierr) {
    fprintf(stderr, "Error: opening MinimalPlugin \n");
    vdm_LManCloseFile(libraryManager);
    vdm_LManEnd(libraryManager);
    vdm_PluginManagerEnd(pluginManager);
    exit(1);
}

Step 4: Print Table of Contents

Enable verbose output and print all datasets provided by the plugin:

C
/* Print table of contents */
vdm_LManSetParami(libraryManager, LMAN_VERBOSE, SYS_ON);
vdm_LManTOC(libraryManager, "*");

LMAN_VERBOSE instructs the Library Manager to include dataset attribute details.

Step 5: Load a Displacement State

We load a state by its dataset name (D.N) and extract displacement for a selected node (node 3). We used vdm_LManLoadStateFromName to load the result data into a State object.

C
vis_State* stateDisplacement = vis_StateBegin();
vdm_LManLoadStateFromName(libraryManager, (Vchar*)"D.N", stateDisplacement);
Vfloat values[3] = {0};
Vint nodeIdsCount = 1;
Vint nodeIds[1] = {3};
vis_StateData(stateDisplacement, nodeIdsCount, nodeIds, values);
printf("Displacement:\n");
printf("Node %d: %14e, %14e, %14e\n", nodeIds[0], values[0], values[1], values[2]);
vis_StateEnd(stateDisplacement);

Step 6: Cleanup

Free all resources in reverse order of acquisition:

C
     /* Free memory */
     vdm_LManCloseFile(libraryManager);
     vdm_LManEnd(libraryManager);
     vdm_PluginManagerEnd(pluginManager);
     return 0;
}
#endif

Expected Output

Typical console output (truncated) might look like:

Library Table of Contents
Path: MINIMAL
Type: Plugin-compatible Files
IDst         LRec  NRow     NCol Type NAtt  Dataset
    0          200     1      200    1    2  PARAMETER.INT.T
                Model = Parameters
        Description = Model Integer Parameters
    1          200     1      200    3    2  PARAMETER.HOL.T
                Model = Parameters
        Description = Model Hollerith Parameters
    ...
    ...
    ...
Displacement:
Node 3:   0.000000e+00,  -2.000000e+00,   5.000000e-01

Complete Source Code

The complete source file resides at: src/sam/vdm/exam/exam14_minimalplugin.cpp

You can also view it directly:

  1#ifdef CEE_SAM_DATA_PROVIDER_FRAMEWORK
  2#include <stdlib.h>
  3#include "sam/base/base.h"
  4#include "sam/vdm/vdm.h"
  5#include "sam/vdm/plugins/pluginmanager.h"
  6#include "sam/vdm/datafile.h"
  7#include "sam/base/license.h"
  8#include "sam/hoops_license.h"
  9
 10/*----------------------------------------------------------------------
 11                     Plugin use example
 12----------------------------------------------------------------------*/
 13int
 14main(int argc, char** argv)
 15{
 16    Vchar pluginLibraryPath[SYS_MAXPATHCHAR] = {0};
 17
 18    /* check input arguments */
 19    if (argc < 2) {
 20        fprintf(stderr, "Usage: %s cdp_MinimalPluginPath\n", argv[0]);
 21        fprintf(stderr, " cdp_MinimalPluginPath is blank, 'cdp_MinimalPlugin' is assumed\n");
 22        strcpy(pluginLibraryPath, "cdp_MinimalPlugin");
 23    }
 24    else {
 25        strcpy(pluginLibraryPath, argv[1]);
 26    }
 27
 28    /* Set the license */
 29    vsy_LicenseValidate(HOOPS_LICENSE);
 30
 31    /* Look for the plugin */
 32    vdm_PluginManager* pluginManager = vdm_PluginManagerBegin();
 33    /* Set the error level as INFO=3 */
 34    vdm_PluginManagerSetErrorLevel(pluginManager, 3);
 35    vdm_PluginManagerLoadPlugin(pluginManager, pluginLibraryPath);
 36    Vint error = vdm_PluginManagerError(pluginManager);
 37    if (error) {
 38        vdm_PluginManagerEnd(pluginManager);
 39        fprintf(stderr, "%s file does not exists. The library extension must not be included in the path.\n", pluginLibraryPath);
 40        exit(1);
 41    }
 42
 43    vdm_LMan* libraryManager = vdm_LManBegin();
 44    vdm_LManOpenFile(libraryManager, (Vchar*)"MINIMAL", nullptr);
 45    /* check for error */
 46    Vint ierr = vdm_LManError(libraryManager);
 47    if (ierr) {
 48        fprintf(stderr, "Error: opening MinimalPlugin \n");
 49        vdm_LManCloseFile(libraryManager);
 50        vdm_LManEnd(libraryManager);
 51        vdm_PluginManagerEnd(pluginManager);
 52        exit(1);
 53    }
 54
 55    /* Print table of contents */
 56    vdm_LManSetParami(libraryManager, LMAN_VERBOSE, SYS_ON);
 57    vdm_LManTOC(libraryManager, "*");
 58
 59    /* Load state 1: temperature */
 60    {
 61        vis_State* stateTemperature = vis_StateBegin();
 62        vdm_LManLoadStateFromName(libraryManager, (Vchar*)"TEMP.N", stateTemperature);
 63        Vfloat values[2] = {0};
 64        Vint nodeIdsCount = 2;
 65        Vint nodeIds[2] = {2, 4};
 66        vis_StateData(stateTemperature, nodeIdsCount, nodeIds, values);
 67        printf("Temperature:\n");
 68        /*  Node 2:   2.000000e+00  */
 69        printf("Node %d: %14e\n", nodeIds[0], values[0]);
 70        /*  Node 4:   4.000000e+00  */
 71        printf("Node %d: %14e\n", nodeIds[1], values[1]);
 72        vis_StateEnd(stateTemperature);
 73    }
 74
 75    /* Load state 2: displacement */
 76    {
 77        vis_State* stateDisplacement = vis_StateBegin();
 78        vdm_LManLoadStateFromName(libraryManager, (Vchar*)"D.N", stateDisplacement);
 79        Vfloat values[3] = {0};
 80        Vint nodeIdsCount = 1;
 81        Vint nodeIds[1] = {3};
 82        vis_StateData(stateDisplacement, nodeIdsCount, nodeIds, values);
 83        printf("Displacement:\n");
 84        /* Node 3:   0.000000e+00,  -2.000000e+00,   5.000000e-01 */
 85        printf("Node %d: %14e, %14e, %14e\n", nodeIds[0], values[0], values[1], values[2]);
 86        vis_StateEnd(stateDisplacement);
 87    }
 88
 89    /* Load state 3: stresses */
 90    {
 91        vis_State* stateStresses = vis_StateBegin();
 92        vdm_LManLoadStateFromName(libraryManager, (Vchar*)"S.EL", stateStresses);
 93        Vfloat values[6 * 3] = {0};
 94        Vint elementIdsCount = 1;
 95        Vint elementIds[1] = {2};
 96        vis_StateData(stateStresses, elementIdsCount, elementIds, values);
 97
 98        /* Retrieve the connect */
 99        vis_Connect* connect = nullptr;
100        vdm_LManGetConnect(libraryManager, &connect);
101
102        /* check for error */
103        ierr = vdm_LManError(libraryManager);
104        if (ierr) {
105            fprintf(stderr, "Error: loading mesh info\n");
106            vis_StateEnd(stateStresses);
107            vdm_LManEnd(libraryManager);
108            vdm_PluginManagerEnd(pluginManager);
109            exit(1);
110        }
111
112        /* Retrieve the element user id */
113        Vint elementUserId = 0;
114        vis_ConnectElemAssoc(connect, VIS_USERID, 1, &elementIds[0], &elementUserId);
115
116        /* Retrieve the element connectivity */
117        Vint numberOfElementNodes = 0;
118        Vint elementNodes[3] = {0};
119        vis_ConnectElemNode(connect, elementIds[0], &numberOfElementNodes, elementNodes);
120
121        printf("Stress:\n");
122        for (unsigned i = 0; i < 3; ++i) {
123            /* Retrieve the node user id */
124            Vint nodeUserId = 0;
125            vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &elementNodes[i], &nodeUserId);
126
127            /* Element 17, Node   3: 3.000000e+01,   0.000000e+00,  0.000000e+00,  0.000000e+00,  0.000000e+00,  0.000000e+00 */
128            /* Element 17, Node   5: 0.000000e+00,   0.000000e+00,  5.000000e+00,  0.000000e+00,  0.000000e+00,  0.000000e+00 */
129            /* Element 17, Node  11: 0.000000e+00,  -1.000000e+01,  0.000000e+00,  0.000000e+00,  0.000000e+00,  0.000000e+00 */
130            printf("Element %d, Node %3d: %14e, %14e, %14e, %14e, %14e, %14e\n", elementUserId, nodeUserId, values[6 * i + 0],
131                   values[6 * i + 1], values[6 * i + 2], values[6 * i + 3], values[6 * i + 4], values[6 * i + 5]);
132        }
133        vis_StateEnd(stateStresses);
134    }
135
136    /* Free memory */
137    vdm_LManCloseFile(libraryManager);
138    vdm_LManEnd(libraryManager);
139    vdm_PluginManagerEnd(pluginManager);
140
141    return 0;
142}
143
144#endif