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:
- Parse command line argument (plugin base name)
- Create and configure a plugin manager
- Load the plugin (shared library extension is omitted)
- Create a Library Manager bound to the plugin (“virtual” file)
- Print the table of contents (datasets provided by the plugin)
- Load a displacement state by name and query a node value
- 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):
#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
):
/* 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.
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:
/* 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.
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:
/* 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