10. Examples

This chapter contains example VisTools programs demonstrating the use of the “global” objects. The source code for all examples resides in devtools/src/vis/exam.

10.1. Example 21, Translate Entity Identifiers Using IdTran.

This example illustrates using an IdTran object to translate entity identifiers to a sequential index space. The vis_IdTranDef() function is used to specify the number of entities (5). The identifier for each index is specified using vis_IdTranSetId(). Depending upon the nature of the identifier to index mapping, the IdTran module will attempt to optimize the internal data structures and algorithms used to perform the translation. The identifiers used in this example are a worst case condition in that the index to identifier mapping is non monotonic.

The function vis_IdTranIndex() is used to return the index of each identifier. An index of 0 is returned if an unrecognized identifier is input.

Next the IdTran object is used to manage an element face set. The function IdTranClear is used to clear all identifiers to zero. Three element faces are specified and each element face must be given a unique index. First the element identifier associated with the index must be specified using vis_IdTranSetId() then the face number is set using vis_IdTranSetEnt(). The values returned by vis_IdTranCount() reflect that the number of indices is 3 while the number of unique identifiers is 2.

The example also illustrates managing equivalenced identifiers using vis_IdTranEquId() and vis_IdTranEquSweep(). Any set of equivalenced pairs may be inserted one pair of equivalences at a time using vis_IdTranEquId(). The function vis_IdTranClear() must be called before the equivalences are set. In this case the identifiers 1,2,4 and 5 are equivalenced. The equivalences may be entered using 3 equivalenced pairs. Once the pairs are specified, call vis_IdTranEquSweep() to sweep through and process the equivalences so that all identifiers point to the lowest common equivalenced node. In this case identifiers 2,4 and 5 will point to identifier 1.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

static Vint ids[5] = {2, 33, 14, 25, 8};

/*----------------------------------------------------------------------
                      Build and query an IdTran object
----------------------------------------------------------------------*/
int
main()
{
    vis_IdTran* idtran;
    vis_IdTran* idtrana;
    Vint i;
    Vint index, id, no;
    Vint match;
    Vint num;
    Vint numind, numuni;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create IdTran object */
    idtran = vis_IdTranBegin();

    /* specify 5 entities */
    vis_IdTranDef(idtran, 5);

    /* set identifier for each entity index */
    for (i = 0; i < 5; i++) {
        vis_IdTranSetId(idtran, i + 1, ids[i]);
    }
    /* query and print index of each identifier */
    for (i = 0; i < 5; i++) {
        vis_IdTranIndex(idtran, ids[i], &index);
        printf("identifier = %d, index = %d\n", ids[i], index);
    }
    /* query and print index of illegal identifier */
    vis_IdTranIndex(idtran, -44, &index);
    printf("identifier = %d, index = %d\n", -44, index);

    /* check for matching objects */
    idtrana = vis_IdTranBegin();
    vis_IdTranDef(idtrana, 5);
    for (i = 0; i < 5; i++) {
        vis_IdTranSetId(idtrana, i + 1, ids[i]);
    }
    /* this should match */
    vis_IdTranMatch(idtran, idtrana, &match);
    printf("match = %d\n", match);

    /* this should not match */
    vis_IdTranSetId(idtrana, 2, 3);
    vis_IdTranMatch(idtran, idtrana, &match);
    printf("match = %d\n", match);

    /* query for unique identifiers */
    vis_IdTranSetId(idtran, 2, 25);
    vis_IdTranCount(idtran, IDTRAN_NUMINDICES, &numind);
    vis_IdTranCount(idtran, IDTRAN_NUMUNIQUE, &numuni);
    printf("numind= %d, numuni= %d\n", numind, numuni);
    vis_IdTranSetId(idtran, 3, 0);
    vis_IdTranCount(idtran, IDTRAN_NUMINDICES, &numind);
    vis_IdTranCount(idtran, IDTRAN_NUMUNIQUE, &numuni);
    printf("numind= %d, numuni= %d\n", numind, numuni);
    vis_IdTranClear(idtrana);
    vis_IdTranUnique(idtrana, idtran);
    /* query and print unique identifiers */
    for (i = 1; i <= numuni; i++) {
        vis_IdTranGetId(idtrana, i, &id);
        printf("index = %d, identifier = %d\n", i, id);
    }
    vis_IdTranEnd(idtrana);

    /* manage an element face set */
    vis_IdTranClear(idtran);
    /* element 3, face 2 */
    vis_IdTranSetEntType(idtran, SYS_ELEM, SYS_FACE);
    vis_IdTranSetId(idtran, 1, 3);
    vis_IdTranSetEnt(idtran, 1, 2);
    /* element 4, faces 1 and 3 */
    vis_IdTranSetId(idtran, 2, 4);
    vis_IdTranSetEnt(idtran, 2, 1);
    vis_IdTranSetId(idtran, 3, 4);
    vis_IdTranSetEnt(idtran, 3, 3);
    vis_IdTranCount(idtran, IDTRAN_NUMINDICES, &numind);
    vis_IdTranCount(idtran, IDTRAN_NUMUNIQUE, &numuni);
    printf("numind= %d, numuni= %d\n", numind, numuni);
    /* query and print identifiers and face numbers */
    for (i = 1; i <= numind; i++) {
        vis_IdTranGetId(idtran, i, &id);
        vis_IdTranGetEnt(idtran, i, &no);
        printf("index = %d, identifier = %d, face number= %d\n", i, id, no);
    }

    /* manage equivalenced identifiers, 1,2,4,5 */
    vis_IdTranClear(idtran);
    /* enter identifiers pairs in some arbitrary way */
    vis_IdTranEquId(idtran, 1, 2);
    vis_IdTranEquId(idtran, 4, 5);
    vis_IdTranEquId(idtran, 4, 2);
    vis_IdTranEquSweep(idtran);
    for (i = 1; i <= 5; i++) {
        vis_IdTranGetId(idtran, i, &index);
        if (index) {
            printf("equivalence id = %d to id = %d\n", i, index);
        }
    }
    vis_IdTranEquReNumber(idtran, &num);
    printf("Number of unique nodes= %d\n", num);
    for (i = 1; i <= 5; i++) {
        vis_IdTranGetId(idtran, i, &index);
        printf("index= %d, new id = %d\n", i, index);
    }

    /* free objects */
    vis_IdTranEnd(idtran);
    return 0;
}

10.2. Example 22, Generate an Element Group Object

This example generates an element Group object containing 16 elements with an index offset of one. Initially, elements with index 2 and 13 are set active. The Group module provides two distinct methods for querying for active entities. The first involves using vis_GroupInitIndex() followed by successive calls to vis_GroupNextIndex(). The second uses a straightforward loop calling vis_GroupGetIndex().

The “while” loop illustrates the first method for querying for active elements in a group which is particularly effective if the group is sparsely active. Then the complement of the active elements is generated. This operation sets the original active elements inactive and vice versa. The “for” loop illustrates the second method for querying for the new active elements in the group.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#define MAX_ELEM 16

/*----------------------------------------------------------------------
                      Generate element group object
----------------------------------------------------------------------*/
int
main()
{
    vis_Group *group, *groups;

    Vint i;
    Vint index, flag;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create element group object */
    group = vis_GroupBegin();
    vis_GroupDef(group, MAX_ELEM, SYS_ELEM, SYS_NONE);

    /* activate the 2nd and 13th elements */
    vis_GroupClear(group);
    vis_GroupSetIndex(group, 2, 1);
    vis_GroupSetIndex(group, 13, 1);

    /* return active elements using Init-Next facility */
    vis_GroupInitIndex(group);
    while (vis_GroupNextIndex(group, &index, &flag), index != 0) {
        printf("element index = %d, flag = %d\n", index, flag);
    }

    /* take complement of group */
    vis_GroupComplement(group);

    /* return active elements using GetIndex facility */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag) {
            printf("element index = %d, flag = %d\n", i, flag);
        }
    }
    /* perform boolean operation */
    groups = vis_GroupBegin();
    vis_GroupDef(groups, MAX_ELEM, SYS_ELEM, SYS_NONE);

    /* activate even elements */
    for (i = 2; i <= MAX_ELEM; i += 2) {
        vis_GroupSetIndex(groups, i, flag);
    }
    /* delete all even elements from group */
    vis_GroupBoolean(group, GROUP_DELETE, groups);

    /* return active elements using Init-Next facility */
    vis_GroupInitIndex(group);
    while (vis_GroupNextIndex(group, &index, &flag), index != 0) {
        printf("element index = %d, flag = %d\n", index, flag);
    }

    /* end objects */
    vis_GroupEnd(group);
    vis_GroupEnd(groups);
    return 0;
}

10.3. Example 23, Element Connectivity and Adjacency using Connect

This example generates a small finite element model consisting of two 8-node hexahedra and one 4-node quadrilateral. The connectivity of the three elements is illustrated in the example source below, the elements are indexed from left to right. A Connect object is instanced to hold element topology, connectivity and node coordinates. At this point, these same quantities may be queried as well as other non-adjacency related quantities such as the number of edges in an element, etc. Before element adjacencies may be queries the connection kernel must be formed by calling vis_ConnectKernel(). The connection kernel also allows the generation of derived groups which is discussed in the next example, Example 24.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/
#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Element Connectivity and Adjacency using Connect
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    Vint i;
    Vint nfaces, nedges, nnodes;
    Vint nix, ix[64], no[64];
    Vfloat x[64][3];
    Vint nindices, indices[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }

    /* print element connection info */
    printf("Example 23, Using Connect\n");
    printf("element - number of faces, edges, nodes\n");
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectElemNum(connect, SYS_FACE, i + 1, &nfaces);
        vis_ConnectElemNum(connect, SYS_EDGE, i + 1, &nedges);
        vis_ConnectElemNum(connect, SYS_NODE, i + 1, &nnodes);
        printf("%5d              %5d  %5d  %5d\n", i + 1, nfaces, nedges, nnodes);
    }
    /* node connectivity query for element 1 */
    vis_ConnectElemNode(connect, 1, &nix, ix);
    vis_ConnectCoords(connect, nix, ix, x);
    printf("element node - connected node, coordinates\n");
    for (i = 0; i < nix; i++) {
        printf("%5d                %3d", i + 1, ix[i]);
        printf("       %f  %f  %f\n", x[i][0], x[i][1], x[i][2]);
    }
    /* generate connect kernel */
    vis_ConnectKernel(connect, 0);

    /* element adjacency query for element 1 */
    vis_ConnectElemNum(connect, SYS_FACE, 1, &nfaces);
    printf("element face - adjacent element entity\n");
    for (i = 0; i < nfaces; i++) {
        vis_ConnectElemAdjEnt(connect, SYS_FACE, 1, i + 1, &nix, ix, no);
        /* test for adjacent element */
        if (nix) {
            printf("%5d                %3d %3d\n", i + 1, ix[0], no[0]);
        }
        else {
            printf("%5d               none\n", i + 1);
        }
    }
    /* query elements connected to both nodes 3 and 11 */
    nindices = 2;
    indices[0] = 3;
    indices[1] = 11;
    vis_ConnectNodeAdj(connect, nindices, indices, &nix, ix);
    printf("adjacent element\n");
    for (i = 0; i < nix; i++) {
        printf("%5d\n", ix[i]);
    }
    /* end objects */
    vis_ConnectEnd(connect);
    return 0;
}

10.4. Example 23a, Using a GridFun Object with Example 23.

This example illustrates using a GridFun (grid function) object to query an external source for element topology and connectivity and node coordinates from a Connect object. This is a modification of Example 23 in which the equivalent element and node information is loaded directly into the Connect object. The use of grid functions may be preferred by a host application if it has been designed to maintain the basic element topology and connectivity and node coordinates in data structures external to the Connect object. Using a GridFun object as a query mechanism eliminates the memory required to duplicate the basic model information in data structures internal to the Connect object.

All Connect object query functions are invariant with respect to the two approaches illustrated in this example and Example 23. The output from both examples is identical.

Note that the grid functions registered in the GridFun object provide for a user specified pointer (object) to be passed as the first argument. In this example the pointer argument is not used so it will be passed as a NULL pointer (the default). The four required grid functions are Topology, MaxElemNode, ElemNode and Coords. If query for node and element associations is desired, the NodeAssoc and ElemAssoc functions must also be registered.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
               / .    / . \
              /  .   /  .  \7------8
             /   1../...2../|      |
           12-----13-----14 |      |
            |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/
#define MAX_ELEM 3
#define MAX_NODE 14

static Vint numconn[MAX_ELEM] = {8, 8, 4};

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Grid functions for model description
----------------------------------------------------------------------*/
static void
exam_Topology(Vobject* obj, Vint id, Vint* shape, Vint* maxi, Vint* maxj, Vint* maxk)
{
    *shape = shap[id - 1];
    *maxi = 2;
    *maxj = 0;
    *maxk = 0;
}

static void
exam_MaxElemNode(Vobject* obj, Vint* maxnum)
{
    *maxnum = 8;
}

static void
exam_ElemNode(Vobject* obj, Vint id, Vint* nix, Vint ix[])
{
    int i;

    *nix = numconn[id - 1];
    for (i = 0; i < *nix; i++) {
        ix[i] = conn[id - 1][i];
    }
}

static void
exam_Coords(Vobject* obj, Vint nids, Vint ids[], Vfloat x[][3])
{
    int i;

    for (i = 0; i < nids; i++) {
        x[i][0] = coords[ids[i] - 1][0];
        x[i][1] = coords[ids[i] - 1][1];
        x[i][2] = coords[ids[i] - 1][2];
    }
}

/*----------------------------------------------------------------------
                      Element Connectivity and Adjacency using Connect
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_GridFun* gf;
    Vint i;
    Vint nfaces, nedges, nnodes;
    Vint nix, ix[64];
    Vfloat x[64][3];
    Vint nindices, indices[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* create gridfun object */
    gf = vis_GridFunBegin();

    /* register example grid functions */
    vis_GridFunSet(gf, GRIDFUN_TOPOLOGY, (void (*)(void))exam_Topology);
    vis_GridFunSet(gf, GRIDFUN_MAXELEMNODE, (void (*)(void))exam_MaxElemNode);
    vis_GridFunSet(gf, GRIDFUN_ELEMNODE, (void (*)(void))exam_ElemNode);
    vis_GridFunSet(gf, GRIDFUN_COORDS, (void (*)(void))exam_Coords);

    /* set grid function as attribute to connect */
    vis_ConnectSetObject(connect, VIS_GRIDFUN, gf);

    /* print element connection info */
    printf("Example 23a, Using Connect with a GridFun object\n");
    printf("element - number of faces, edges, nodes\n");
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectElemNum(connect, SYS_FACE, i + 1, &nfaces);
        vis_ConnectElemNum(connect, SYS_EDGE, i + 1, &nedges);
        vis_ConnectElemNum(connect, SYS_NODE, i + 1, &nnodes);
        printf("%5d              %5d  %5d  %5d\n", i + 1, nfaces, nedges, nnodes);
    }
    /* node connectivity query for element 1 */
    vis_ConnectElemNode(connect, 1, &nix, ix);
    vis_ConnectCoords(connect, nix, ix, x);
    printf("element node - connected node, coordinates\n");
    for (i = 0; i < nix; i++) {
        printf("%5d                %3d", i + 1, ix[i]);
        printf("       %f  %f  %f\n", x[i][0], x[i][1], x[i][2]);
    }

    /* generate connect kernel */
    vis_ConnectKernel(connect, 0);

    /* element adjacency query for element 1 */
    vis_ConnectElemNum(connect, SYS_FACE, 1, &nfaces);
    printf("element face - adjacent element\n");
    for (i = 0; i < nfaces; i++) {
        vis_ConnectElemAdj(connect, SYS_FACE, 1, i + 1, &nix, ix);
        /* test for adjacent element */
        if (nix) {
            printf("%5d                %3d\n", i + 1, ix[0]);
        }
        else {
            printf("%5d               none\n", i + 1);
        }
    }

    /* query elements connected to both nodes 3 and 11 */
    nindices = 2;
    indices[0] = 3;
    indices[1] = 11;
    vis_ConnectNodeAdj(connect, nindices, indices, &nix, ix);
    printf("adjacent element\n");
    for (i = 0; i < nix; i++) {
        printf("%5d\n", ix[i]);
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    return 0;
}

10.5. Example 24, Generate Element Face and Edge Groups

This example uses the same finite element model introduced in Example 23 and illustrates the generation of four useful groups, a group of element free faces and three groups of element edges - unique edges, free edges and feature edges. Element free faces are those faces connected to a single element and generally form a set of exterior faces for the finite element model. Unique edges are useful for drawing a wireframe display of the finite element model without drawing any edge more than once. Free edges are those edges connected to only one element. In hexahedral meshes, free edges often represent the corner edges of the mesh. Feature edges are those edges lying on the exterior of the mesh which connect adjacent faces which form a discontinuity at the edge. These edges are relatively expensive to compute since they involve the calculation of geometric normals to the free faces. However, feature edges represent corner edges on meshes containing non hexahedral elements.

Seeded faces are those faces adjacent to a specified seed node or seed element face. In this example a seed element face is specified. The algorithm selects all faces contained in the source face group, in this case the free faces, which are adjacent to the seed face and adjacent to previously selected faces. In this manner, selected faces propagate out from the seed face. The selection process is bounded by an element edge group. Normally the element edge group forms a closed loop about the seed element face.

Silhouette edges are those edges shared by two faces which form an outline when viewed from a given direction. The user must load a 4 by 4 “model view” matrix to specify the orientation of model with respect to the eye coordinate system. An edge is considered to be a silhouette edge if one of the adjacent faces is back facing while the other is front facing.

The connection kernel must be generated before the derived groups may be generated. The contents of the groups are printed. Notice that the internal face shared by elements 1 and 2 is not included in the free element face group. Likewise each edge in the finite element model should be flagged by only one element in the element edge group.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/
static void
printflags(vis_Group* group, Vchar* stg, Vint numelem);

#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Generate Element Face and Edge Groups using Connect
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_Group *groupface, *groupedge;
    vis_Group* groupfaceseed;
    Vfloat c, s, ctm[4][4];

    Vint i;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }

    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }

    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }

    /* generate connect kernel */
    vis_ConnectKernel(connect, 0);

    /* create element face group */
    groupface = vis_GroupBegin();
    vis_GroupDef(groupface, MAX_ELEM, SYS_ELEM, SYS_FACE);

    /* generate group of element free faces */
    vis_ConnectFaceGroup(connect, CONNECT_FREE, NULL, groupface);
    printflags(groupface, "element - free faces", MAX_ELEM);

    /* create element edge group */
    groupedge = vis_GroupBegin();
    vis_GroupDef(groupedge, MAX_ELEM, SYS_ELEM, SYS_EDGE);

    /* generate group of element unique edges */
    vis_ConnectEdgeGroup(connect, CONNECT_UNIQUE, NULL, groupedge);
    printflags(groupedge, "element - unique edges", MAX_ELEM);

    /* generate group of element free edges */
    vis_GroupClear(groupedge);
    vis_ConnectEdgeGroup(connect, CONNECT_FREE, NULL, groupedge);
    printflags(groupedge, "element - free edges", MAX_ELEM);

    /* generate group of element face feature edges */
    vis_GroupClear(groupedge);
    vis_ConnectEdgeGroup(connect, CONNECT_FEATURE, groupface, groupedge);
    printflags(groupedge, "element - element face feature edges", MAX_ELEM);

    /* generate group of element faces from seeded face */
    /* seed element 1 face 4 (top face) */
    /* containing only free faces and bounded by feature edges */
    groupfaceseed = vis_GroupBegin();
    vis_GroupDef(groupfaceseed, MAX_ELEM, SYS_ELEM, SYS_FACE);
    vis_GroupClear(groupfaceseed);
    vis_ConnectSetGroupParami(connect, CONNECT_SEEDELEM, 1);
    vis_ConnectSetGroupParami(connect, CONNECT_SEEDFACE, 4);
    vis_ConnectSetGroupObject(connect, CONNECT_SEEDGROUP, groupedge);
    vis_ConnectFaceGroup(connect, CONNECT_SEED, groupface, groupfaceseed);
    printflags(groupfaceseed, "element - element face seeded", MAX_ELEM);

    /* generate group of element face silhouette edges */
    /* load model view matrix */
    c = 0.866026f;
    s = 0.500000;
    ctm[0][0] = 1.0;
    ctm[1][0] = 0.0;
    ctm[2][0] = 0.0;
    ctm[3][0] = 0.0;
    ctm[0][1] = 0.0;
    ctm[1][1] = c;
    ctm[2][1] = -s;
    ctm[3][1] = 0.0;
    ctm[0][2] = 0.0;
    ctm[1][2] = s;
    ctm[2][2] = c;
    ctm[3][2] = 0.0;
    ctm[0][3] = 0.0;
    ctm[1][3] = 0.0;
    ctm[2][3] = 0.0;
    ctm[3][3] = 1.0;
    vis_ConnectSetGroupParamfv(connect, CONNECT_MODELVIEWMATRIX, (Vfloat*)ctm);

    vis_GroupClear(groupedge);
    vis_ConnectEdgeGroup(connect, CONNECT_SILHOUETTE, groupface, groupedge);
    printflags(groupedge, "element - element face silhouette edges", MAX_ELEM);

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GroupEnd(groupface);
    vis_GroupEnd(groupfaceseed);
    vis_GroupEnd(groupedge);
    return 0;
}

/*----------------------------------------------------------------------
                      print elem edge or elem face flags in a group
----------------------------------------------------------------------*/
static void
printflags(vis_Group* group, Vchar* stg, Vint numelem)
{
    Vint i;
    Vint flags;

    printf("%s\n", stg);
    for (i = 0; i < numelem; i++) {
        vis_GroupGetIndex(group, i + 1, &flags);
        printf("%5d      %3x\n", i + 1, flags);
    }
}

10.6. Example 24a, Convert Linear Elements to Parabolic Elements

This example uses the same finite element model introduced in Example 23 and illustrates using the Connect object and a multi-integer hashtable, IntVHash, to convert a model of linear elements to parabolic Serendipity elements. In this case a midside node is generated on each unique edge. The IntVHash module is used to store the midside node associated with each unique edge. The vis_ConnectEdgeGroup() function is used to generate a Group of unique edges. Each unique edge is visited and a node is generated at the mid-edge location for each edge. A Connect object, connectp is instanced to hold the parabolic elements.

After the midside nodes are generated, the edges of the linear elements are traversed and the midside node for each edge is added to the element connectivity and set in connectp. Note that for parabolic Serendipity elements the corner node connectivity is identical to the linear element and the midside nodes are added in edge order after the corner node connectivity.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/

#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Convert Linear Elements to Parabolic Elements
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j;
    vis_Connect *connect, *connectp;
    vis_Group* groupedge;
    vsy_IntVHash* ivh;
    Vint numnp, numel, numnpp;
    Vint nelem, nedge;
    Vint index, nix, ix[20], ixs, nid, nex, iex[2], ned;
    Vint shape, maxi, maxj, maxk;
    Vfloat xe[2][3], xm[3];
    Vint flags, flag, numno, maxno;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    numnp = MAX_NODE;
    numel = MAX_ELEM;
    printf("number of corner nodes=    %d\n", numnp);
    printf("number of linear elements= %d\n", numel);
    /* create connect object to hold linear elements */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, numnp, numel);
    /* set node coordinates */
    for (i = 0; i < numnp; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* set topologies */
    for (i = 0; i < numel; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < numel; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* generate connect kernel for adjacency type queries */
    vis_ConnectKernel(connect, 0);

    /* generate group of element unique edges */
    groupedge = vis_GroupBegin();
    vis_GroupDef(groupedge, numel, SYS_ELEM, SYS_EDGE);
    vis_ConnectEdgeGroup(connect, CONNECT_UNIQUE, NULL, groupedge);
    /* count unique edges */
    vis_GroupCount(groupedge, &nelem, &nedge);
    printf("number of unique edges= %d\n", nedge);

    /* create connect object to hold parabolic elements */
    numnpp = numnp + nedge;
    connectp = vis_ConnectBegin();
    vis_ConnectDef(connectp, numnpp, numel);
    /* copy original corner nodes */
    for (i = 1; i <= numnp; i++) {
        vis_ConnectCoords(connect, 1, &i, xe);
        vis_ConnectSetCoords(connectp, i, xe[0]);
    }
    /* put unique edges in a hashtable */
    /* one midside node will be generated per unique edge */
    ivh = vsy_IntVHashBegin();
    vsy_IntVHashDef(ivh, 2, nedge);
    nid = numnp;
    vis_GroupInitIndex(groupedge);
    while (vis_GroupNextIndex(groupedge, &index, &flags), index) {
        vis_GroupNumEntFlag(groupedge, index, &numno, &maxno);
        for (j = 1; j <= maxno; j++) {
            vis_GroupGetEntFlag(groupedge, index, j, &flag);
            if (flag) {
                vis_ConnectElemCon(connect, SYS_EDGE, index, j, &nex, iex);
                vis_ConnectCoords(connect, 2, iex, xe);
                xm[0] = .5F * (xe[0][0] + xe[1][0]);
                xm[1] = .5F * (xe[0][1] + xe[1][1]);
                xm[2] = .5F * (xe[0][2] + xe[1][2]);
                /* make sure that the edge nodes are lowest first */
                if (iex[0] > iex[1]) {
                    ixs = iex[0];
                    iex[0] = iex[1];
                    iex[1] = ixs;
                }
                nid += 1;
                vis_ConnectSetCoords(connectp, nid, xm);
                vsy_IntVHashInsert(ivh, iex, nid);
            }
        }
    }
    /* now loop through elements and insert edge midsides */
    /* promote topology to parabolic Serendipity */
    for (i = 1; i <= numel; i++) {
        vis_ConnectTopology(connect, i, &shape, &maxi, &maxj, &maxk);
        vis_ConnectSetTopology(connectp, i, shape, 3, 0, 0);
        vis_ConnectElemNode(connect, i, &nix, ix);
        vis_ConnectElemNum(connect, SYS_EDGE, i, &ned);
        /* look up edge in hashtable to retrieve midside node */
        for (j = 1; j <= ned; j++) {
            vis_ConnectElemCon(connect, SYS_EDGE, i, j, &nex, iex);
            if (iex[0] > iex[1]) {
                ixs = iex[0];
                iex[0] = iex[1];
                iex[1] = ixs;
            }
            vsy_IntVHashLookup(ivh, iex, &nid);
            ix[nix + j - 1] = nid;
        }
        vis_ConnectSetElemNode(connectp, i, ix);
    }
    vis_ConnectWrite(connectp, SYS_NASTRAN_BULKDATA, "exam24a.bdf");

    /* destroy objects */
    vis_ConnectEnd(connect);
    vis_ConnectEnd(connectp);
    vis_GroupEnd(groupedge);
    vsy_IntVHashEnd(ivh);
    return 0;
}

10.7. Example 25, Node Results Data Using State

This example illustrates the use of a State object to manage a vector quantity at nodes. A simple vector field is defined at 4 nodes. Using the vis_StateDef() function, the parent entity type is defined as SYS_NODE, the child type is SYS_NONE and the data type is VIS_VECTOR. The vector data is entered for each node using vis_StateSetData(). The derived quantity is set to VIS_VECTOR_MAG which specifies that all subsequent queries of the state data return this derived quantity until changed by another call to vis_StateSetDerive(). The vector magnitude is queried and printed for each node using vis_StateData(). Then the derived quantity is set to VIS_VECTOR and the primitive vector data is queried and printed for a set of nodes. Finally, the minimum and maximum values of the vector field are queried and printed.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#define MAX_NODE 4

static Vfloat v[MAX_NODE][3] = {{3., 2., 0.}, {-1., 0., 0.}, {1., 1., 0.}, {2., -2., -4.}};

/*----------------------------------------------------------------------
                      Generate node vector state object
----------------------------------------------------------------------*/
int
main()
{
    vis_State* state;
    Vint i;
    Vfloat vs[9], extent[2][3];
    Vint ix[3];
    Vint ids[2][3], nos[2][3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create node state object */
    state = vis_StateBegin();
    vis_StateDef(state, MAX_NODE, SYS_NODE, SYS_NONE, VIS_VECTOR);

    /* load vector data */
    for (i = 0; i < MAX_NODE; i++) {
        vis_StateSetData(state, i + 1, v[i]);
    }
    /* query derived vector magnitude */
    vis_StateSetDerive(state, VIS_VECTOR_MAG);
    for (i = 1; i <= MAX_NODE; i++) {
        vis_StateData(state, 1, &i, vs);
        printf("index= %d, magnitude= %f\n", i, vs[0]);
    }
    /* query for primitive vector at nodes 2, 3 and 4 */
    vis_StateSetDerive(state, VIS_VECTOR);
    ix[0] = 2;
    ix[1] = 3;
    ix[2] = 4;
    vis_StateData(state, 3, ix, vs);
    for (i = 0; i < 3; i++) {
        printf("index= %d, vector= %f %f %f\n", ix[i], vs[3 * i], vs[3 * i + 1], vs[3 * i + 2]);
    }
    /* query for data extent */
    vis_StateExtent(state, NULL, (Vfloat*)extent);
    printf("vector min= %f %f %f\n", extent[0][0], extent[0][1], extent[0][2]);
    printf("vector max= %f %f %f\n", extent[1][0], extent[1][1], extent[1][2]);

    /* query for data extent and locations */
    vis_StateExtentLoc(state, NULL, (Vfloat*)extent, (Vint*)ids, (Vint*)nos);
    printf("vector min= %f %f %f\n", extent[0][0], extent[0][1], extent[0][2]);
    printf("       ids= %d %d %d\n", ids[0][0], ids[0][1], ids[0][2]);
    printf("vector max= %f %f %f\n", extent[1][0], extent[1][1], extent[1][2]);
    printf("       ids= %d %d %d\n", ids[1][0], ids[1][1], ids[1][2]);

    /* double the values */
    vis_StateOperateUnary(state, STATE_MULTIPLYEQUAL, 2., STATE_UNITY, NULL, NULL);

    /* query for data extent */
    vis_StateExtent(state, NULL, (Vfloat*)extent);
    printf("vector min= %f %f %f\n", extent[0][0], extent[0][1], extent[0][2]);
    printf("vector max= %f %f %f\n", extent[1][0], extent[1][1], extent[1][2]);

    /* take the absolute values */
    vis_StateOperateUnary(state, STATE_EQUAL, 1., STATE_ABS, state, NULL);

    /* query and print all vector data */
    for (i = 1; i <= MAX_NODE; i++) {
        vis_StateData(state, 1, &i, vs);
        printf("index= %d, vector= %f %f %f\n", ix[0], vs[0], vs[1], vs[2]);
    }
    /* end objects */
    vis_StateEnd(state);
    return 0;
}

10.8. Example 25a, Node History Results Data using History

This example illustrates the use of a History object to manage a vector quantity at a set of 2 nodes over 5 solution steps. Using the vis_HistoryDef() function, the number of steps and the number of parent entities are defined. The parent entity type is defined as SYS_NODE, the child type is SYS_NONE and the data type is VIS_VECTOR. The vector data is entered for each node at each step using vis_HistorySetData(). The index and step numbers are queried using vis_HistoryIndices() and vis_HistorySteps() respectively. The vector data is queried using vis_HistoryData() and printed. The vector data extent for all steps and nodes is returned using vis_HistoryExtent(). The derived quantity is set to VIS_VECTOR_MAG which specifies that all subsequent queries of the history data return this derived quantity until changed by another call to vis_HistorySetDerive(). The vector magnitude is queried and printed for each node using vis_HistoryData().

The down sampling rankings are computed using vis_HistorySample(). Each step rank is accessed and printed using vis_HistoryGetRank(). The cutoff rank to represent the last 4 time steps with 3 points is determined using vis_HistoryCutoffRank().

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#define MAX_NODE 2
#define MAX_STEP 5

/* history data */
static Vfloat v[MAX_STEP][MAX_NODE][3] = {{{3.0f, 2.0f, 0.}, {-1.0f, 0., 0.}},
                                          {{3.1f, 2.2f, 0.}, {-1.1f, 0., 0.}},
                                          {{3.2f, 2.4f, 0.}, {-1.2f, 0., 0.}},
                                          {{3.3f, 2.2f, 0.}, {-1.3f, 0., 0.}},
                                          {{3.4f, 2.0f, 0.}, {-1.4f, 0., 0.}}};

/* node indices */
static Vint ind[MAX_NODE] = {1801, 2102};

/* step numbers */
static Vint stp[MAX_STEP] = {10, 20, 30, 40, 50};
/* independent step values */
static Vfloat t[MAX_STEP] = {1., 3., 5., 7., 9.};

/*----------------------------------------------------------------------
                      Generate node vector history object
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j;
    vis_History* history;
    Vint istep, index;
    Vfloat vs[3], vmag, ts;
    Vfloat extent[2][3];
    Vint nument, numstp;
    Vint stpnum[MAX_STEP], indval[MAX_NODE];
    Vfloat sval[MAX_STEP];
    Vint rank, cutoffrank;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create node history object */
    history = vis_HistoryBegin();
    vis_HistoryDef(history, MAX_STEP, MAX_NODE, SYS_NODE, SYS_NONE, VIS_VECTOR);

    /* set vector and independent data values */
    for (j = 0; j < MAX_STEP; j++) {
        vis_HistorySetIndep(history, stp[j], t[j]);
        for (i = 0; i < MAX_NODE; i++) {
            vis_HistorySetData(history, stp[j], ind[i], v[j][i]);
        }
    }
    /* get vector and independent value data */
    vis_HistorySteps(history, &numstp, stpnum);
    vis_HistoryIndices(history, &nument, indval);
    for (j = 0; j < numstp; j++) {
        vis_HistoryIndep(history, stpnum[j], &ts);
        for (i = 0; i < nument; i++) {
            vis_HistoryData(history, stpnum[j], 1, &indval[i], vs);
            printf("istep= %d, index= %d, vector= %f %f %f, indep= %f\n", stpnum[j], indval[i], vs[0], vs[1], vs[2], ts);
        }
    }
    /* query for data extent */
    vis_HistoryExtent(history, (Vfloat*)extent);
    printf("vector min= %f %f %f\n", extent[0][0], extent[0][1], extent[0][2]);
    printf("vector max= %f %f %f\n", extent[1][0], extent[1][1], extent[1][2]);

    /* compute vector magnitude */
    vis_HistorySetDerive(history, VIS_VECTOR_MAG);
    istep = 20;
    index = 1801;
    vis_HistoryData(history, istep, 1, &index, &vmag);
    printf("istep= %d, index= %d, mag= %f\n", istep, index, vmag);

    /* get vector magnitude for node 1801 for all steps */
    vis_HistoryDataSteps(history, 1, &index, sval);
    for (i = 0; i < numstp; i++) {
        printf("istep= %d, mag= %f\n", stpnum[i], sval[i]);
    }
    /* generate sampling rank */
    vis_HistorySample(history);
    /* query ranking */
    for (i = 0; i < numstp; i++) {
        vis_HistoryGetRank(history, stpnum[i], &rank);
        printf("istep= %d, rank= %d\n", stpnum[i], rank);
    }
    /* determine cutoff rank to retain 3 points
       for last 4 steps */
    vis_HistoryCutoffRank(history, stpnum[1], stpnum[4], 3, &cutoffrank);
    printf("cutoffrank= %d\n", cutoffrank);

    /* traverse steps, retain first and last points
       and any rank greater than cutoff */
    for (i = 1; i <= 4; i++) {
        vis_HistoryGetRank(history, stpnum[i], &rank);
        if (i == 1 || i == 4 || rank > cutoffrank) {
            printf("draw step %d\n", stpnum[i]);
        }
        else {
            printf("ignore step %d\n", stpnum[i]);
        }
    }
    /* end objects */
    vis_HistoryEnd(history);
    return 0;
}

10.9. Example 25b, Element Node Scalar Section Results using History

This example illustrates the use of a History object to manage element node scalar section data at 2 elements with sections over 5 solution steps. Using the vis_HistoryDef() function, the number of steps and the number of parent entities are defined. The parent entity type is defined as SYS_ELEM, the child type is SYS_NODE and the data type is VIS_SCALAR. In the case of element section data, the number of sections at each element must be specified using vis_HistorySetDataSect() before the data is entered. The step independent value and element scalar data is entered for each element at all sections at each step using vis_HistorySetIndep() and vis_HistorySetData().

To query the data, the number of steps and number of element indices are first queried using vis_HistoryNumSteps() and vis_HistoryNumIndices(). The specific section to return data for is set using vis_HistorySetSection(). In this case, the first section. A double loop is entered over the steps and elements to query and print the data.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#define MAX_ELEM 4
#define NUM_ELEM 2
#define NUM_STEP 5

/* element shape */
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEQUAD, VIS_SHAPEWED, VIS_SHAPETRI};

/* elem indices */
static Vint ind[NUM_ELEM] = {1, 4};
/* number of sections */
static Vint sec[NUM_ELEM] = {1, 3};
/* step numbers */
static Vint stp[NUM_STEP] = {10, 20, 30, 40, 50};
/* independent step values */
static Vfloat t[NUM_STEP] = {1., 3., 5., 7., 9.};

/*----------------------------------------------------------------------
                      Element Node Scalar Section Results Using History
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j, k, n;
    vis_Connect* connect;
    vis_GridFun* gridfun;
    vis_History* history;
    Vint istep, index, in;
    Vfloat dat[12];
    Vfloat ss[8], ts;
    Vint nument, numstp;
    Vint nix;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create element model */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, 0, MAX_ELEM);
    /* define element topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    gridfun = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gridfun);

    /* create element node scalar history object */
    history = vis_HistoryBegin();
    vis_HistoryDef(history, NUM_STEP, NUM_ELEM, SYS_ELEM, SYS_NODE, VIS_SCALAR);
    vis_HistorySetObject(history, VIS_GRIDFUN, gridfun);

    /* set number of sections for each element */
    for (i = 0; i < NUM_ELEM; i++) {
        vis_HistorySetDataSect(history, ind[i], sec[i]);
    }
    /* set scalar and independent data values */
    /*  1  digit is element node index
       10  digit is section index
      100  digit is element index
     1000  digit is time step index  */
    for (j = 0; j < NUM_STEP; j++) {
        vis_HistorySetIndep(history, stp[j], t[j]);
        for (i = 0; i < NUM_ELEM; i++) {
            vis_GridFunNumElemNode(gridfun, ind[i], &nix);
            in = 0;
            for (n = 0; n < sec[i]; n++) {
                for (k = 0; k < nix; k++) {
                    dat[in++] = (Vfloat)((j + 1) * 1000 + ind[i] * 100 + (n + 1) * 10 + k + 1);
                }
            }
            vis_HistorySetData(history, stp[j], ind[i], dat);
        }
    }
    /* get scalar and independent value data */
    /* query for number of steps and indices */
    vis_HistoryNumSteps(history, &numstp);
    printf("numstp= %d\n", numstp);
    vis_HistoryNumIndices(history, &nument);
    printf("nument= %d\n", nument);
    /* set section */
    vis_HistorySetSection(history, 1);
    /* loop through steps */
    for (j = 1; j <= numstp; j++) {
        vis_HistoryGetStep(history, j, &istep);
        vis_HistoryIndep(history, istep, &ts);
        printf("istep= %d, indep= %f\n", istep, ts);
        /* loop through indices */
        for (i = 1; i <= nument; i++) {
            vis_HistoryGetIndex(history, i, &index);
            vis_HistoryData(history, istep, 1, &index, ss);
            vis_GridFunNumElemNode(gridfun, index, &nix);
            printf("index= %d\n", index);
            /* loop through element nodes */
            for (k = 0; k < nix; k++) {
                printf("scalar= %f\n", ss[k]);
            }
        }
    }
    /* end objects */
    vis_HistoryEnd(history);
    vis_GridFunEnd(gridfun);
    vis_ConnectEnd(connect);
    return 0;
}

10.10. Example 25c, Element Face and Face Node Results using State

This example illustrates the use of a State object to manage element face and element face node scalar data. The State object will handle both element face and element edge based data. In these cases the parent type is set to either SYS_FACE or SYS_EDGE respectively. If the data is at face nodes or edge nodes, the subtype is set to SYS_NODE, otherwise it is set to SYS_NONE. Using the vis_StateDef() function, the number of number of elements and entity location is defined for vector data. In the case of element entity data, the number of entities at each element must be specified using vis_StateSetDataEnt() before the data is entered. The data may be queried using vis_StateData() to get the data for all faces of an element or using vis_StateDataElemEnt() to get data for a specified element face.

The case of element face node data requires that a GridFun object be set in State since this type of data requires explicit knowledge of element topology, order, etc.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#define MAX_ELEM 4
#define NUM_ELEM 2

/* element shape */
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEQUAD, VIS_SHAPEWED, VIS_SHAPETRI};

/* elem indices */
static Vint ind[NUM_ELEM] = {1, 4};
static Vint numno[NUM_ELEM] = {2, 1};
static Vint no[NUM_ELEM][2] = {{3, 4}, {1, 0}};

/*----------------------------------------------------------------------
                      Element Face and Face Node Results Using State
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j, k, n;
    vis_Connect* connect;
    vis_GridFun* gridfun;
    vis_State *state, *statefn;
    Vfloat s[24];
    Vint ndat, nloc, nsec;
    Vint shape, maxi, maxj, nfx;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create element model */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, 0, MAX_ELEM);
    /* define element topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    gridfun = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gridfun);

    /* create element face vector state object */
    state = vis_StateBegin();
    vis_StateDef(state, MAX_ELEM, SYS_FACE, SYS_NONE, VIS_VECTOR);
    vis_StateSetObject(state, VIS_GRIDFUN, gridfun);

    /* set number of faces and face numbers for each element */
    for (i = 0; i < NUM_ELEM; i++) {
        vis_StateSetDataEnt(state, ind[i], numno[i], no[i]);
    }
    /* manufacture and set data */
    for (i = 0; i < NUM_ELEM; i++) {
        s[0] = (Vfloat)no[i][0];
        s[1] = s[0] + .01f;
        s[2] = s[0] + .02f;

        s[3] = (Vfloat)no[i][1];
        s[4] = s[3] + .01f;
        s[5] = s[3] + .02f;
        vis_StateSetData(state, ind[i], s);
    }
    /* get data */
    for (i = 0; i < NUM_ELEM; i++) {
        vis_StateData(state, 1, &ind[i], s);
        vis_StateDataNum(state, ind[i], &ndat, &nloc, &nsec);
        printf("element= %d, data= ", ind[i]);
        for (j = 0; j < ndat; j++) {
            printf(" %e", s[j]);
        }
        printf("\n");
    }
    /* get data at first element face 4 */
    vis_StateDataElemEnt(state, SYS_FACE, ind[0], 4, s);
    printf("element= %d, data= %e %e %e\n", ind[0], s[0], s[1], s[2]);

    vis_StateSetDerive(state, VIS_VECTOR_MAG);
    for (i = 0; i < NUM_ELEM; i++) {
        vis_StateData(state, 1, &ind[i], s);
        printf("element= %d, data= %e\n", ind[i], s[0]);
    }
    /* test element face node state */
    statefn = vis_StateBegin();
    vis_StateDef(statefn, MAX_ELEM, SYS_FACE, SYS_NODE, VIS_VECTOR);
    vis_StateSetObject(statefn, VIS_GRIDFUN, gridfun);
    /* set number of faces and face numbers for each element */
    for (i = 0; i < NUM_ELEM; i++) {
        vis_StateSetDataEnt(statefn, ind[i], numno[i], no[i]);
    }
    /* manufacture and set data */
    /* loop over elements */
    for (i = 0; i < NUM_ELEM; i++) {
        n = 0;
        /* loop over faces */
        for (j = 0; j < numno[i]; j++) {
            vis_ConnectElemTopo(connect, SYS_FACE, ind[i], no[i][j], &shape, &maxi, &maxj);
            /* compute number of face nodes */
            if (shape == SYS_SHAPEQUAD) {
                nfx = 4;
            }
            else {
                nfx = 3;
            }
            /* set data at each face node */
            for (k = 0; k < 3 * nfx; k++) {
                s[n++] = (Vfloat)(ind[i] + no[i][j] + k);
            }
        }
        vis_StateSetData(statefn, ind[i], s);
    }
    /* get data at first element face 4 */
    vis_StateDataElemEnt(statefn, SYS_FACE, ind[0], 4, s);
    printf("element= %d\n", ind[0]);
    for (k = 0; k < 4; k++) {
        printf("k= %d, data= %e %e %e\n", k, s[3 * k], s[3 * k + 1], s[3 * k + 2]);
    }

    vis_StateEnd(state);
    vis_StateEnd(statefn);
    vis_GridFunEnd(gridfun);
    vis_ConnectEnd(connect);
    return 0;
}

10.11. Example 26, Element and Node Results Data

This example uses the same finite element model introduced in Example 23 and illustrates the use of two State objects to manage and map tensor results data at element centroids and nodes. Once the finite element domain is defined as in Example 23, the Connect object is queried for its grid functions. A GridFun object is a required attribute for any State object which is used to map results data. The GridFun object is used by State objects for any domain related queries which must be made during a map operation. Two State objects are instanced, one to hold the original element centroidal data, and another to hold the mapped node data. The element tensor data is set using vis_StateSetData(). Next, the principal values and principal directions are queried and printed. The derived type is then set back to the full tensor and the element data is mapped to nodes using vis_StateMap(). Once the tensor data is mapped to nodes, the Von Mises “stress” may be queried at the nodes by setting the derived quantity to VIS_TENSOR_VONMISES and querying the data at nodes using vis_StateData(). Several other derived tensor quantities may be queried by changing the derived quantity type in vis_StateSetDerive().

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#define MAX_ELEM 3
#define MAX_NODE 14
/* element model data */
static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {3., 0., 0.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 0.}, {3., 1., 0.}, {0., 0., 1.}, {1., 0., 1.},
                                     {2., 0., 1.}, {0., 1., 1.}, {1., 1., 1.}, {2., 1., 1.}};

/* element tensor data */
static Vfloat selem[3][6] = {
{1.f, -2.f, 3.f, .1f, .2f, .3f}, {1.2f, -2.1f, 3.5f, .12f, .21f, .31f}, {1.3f, -2.2f, 3.4f, .13f, .24f, .33f}};

void
print_nodestate(vis_State* state, Vchar* stg);

/*----------------------------------------------------------------------
                      Element and Node Tensor Data
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_State *stateelem, *statenode, *stateelemnode;
    vis_GridFun* gf;

    Vint i;
    Vfloat s[6], tm[3][3];
    Vfloat extent[2][6];
    Vint ids[2][6], nos[2][6];
    Vfloat se[8];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }

    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create state object for element data */
    stateelem = vis_StateBegin();
    vis_StateDef(stateelem, MAX_ELEM, SYS_ELEM, SYS_NONE, VIS_TENSOR);
    vis_StateSetObject(stateelem, VIS_GRIDFUN, gf);

    /* create state object for node data */
    statenode = vis_StateBegin();
    vis_StateDef(statenode, MAX_NODE, SYS_NODE, SYS_NONE, VIS_TENSOR);

    /* load element tensor */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_StateSetData(stateelem, i + 1, selem[i]);
    }
    /* compute principal values and directions */
    vis_StateSetDerive(stateelem, VIS_TENSOR_PRINC);
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_StateData(stateelem, 1, &i, s);
        printf("elem= %d, principal stresses= %f %f %f\n", i, s[0], s[1], s[2]);
    }
    vis_StateSetDerive(stateelem, VIS_TENSOR_PRINCDIRCOS);
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_StateData(stateelem, 1, &i, (Vfloat*)tm);
        printf("elem= %d, principal vector 1= %f %f %f\n", i, tm[0][0], tm[0][1], tm[0][2]);
        printf("elem= %d, principal vector 2= %f %f %f\n", i, tm[1][0], tm[1][1], tm[1][2]);
        printf("elem= %d, principal vector 3= %f %f %f\n", i, tm[2][0], tm[2][1], tm[2][2]);
    }
    /* set derived quantity back to full tensor */
    vis_StateSetDerive(stateelem, VIS_TENSOR);

    /* map element data to nodes */
    vis_StateMap(statenode, stateelem, NULL);

    /* set derived quantity to Von Mises stress */
    vis_StateSetDerive(statenode, VIS_TENSOR_VONMISES);

    /* query for Von Mises stress at nodes */
    for (i = 1; i <= MAX_NODE; i++) {
        vis_StateData(statenode, 1, &i, s);
        printf("node= %d, Von Mises stress= %f\n", i, s[0]);
    }
    /* create state object for element node data */
    stateelemnode = vis_StateBegin();
    vis_StateDef(stateelemnode, MAX_ELEM, SYS_ELEM, SYS_NODE, VIS_TENSOR);
    vis_StateSetObject(stateelemnode, VIS_GRIDFUN, gf);

    /* map node data to element nodes */
    vis_StateSetDerive(statenode, VIS_TENSOR);
    vis_StateMap(stateelemnode, statenode, NULL);

    /* find extremes and locations */
    vis_StateExtentLoc(stateelemnode, NULL, (Vfloat*)extent, (Vint*)ids, (Vint*)nos);
    for (i = 0; i < 6; i++) {
        printf("min= %f ids= %d nos= %d, max= %f ids= %d nos= %d\n", extent[0][i], ids[0][i], nos[0][i], extent[1][i], ids[1][i],
               nos[1][i]);
    }
    /* gather element face from node state */
    vis_StateSetObject(statenode, VIS_GRIDFUN, gf);
    vis_StateSetDerive(statenode, VIS_TENSOR_VONMISES);
    vis_StateDataElemEnt(statenode, SYS_FACE, 1, 2, se);
    printf("Element 1, face 2 from node state\n");
    for (i = 0; i < 4; i++) {
        printf("Von Mises stress= %f\n", se[i]);
    }
    /* gather element face from element node state */
    vis_StateSetDerive(stateelemnode, VIS_TENSOR_VONMISES);
    vis_StateDataElemEnt(stateelemnode, SYS_FACE, 1, 2, se);
    printf("Element 1, face 2 from element node state\n");
    for (i = 0; i < 4; i++) {
        printf("Von Mises stress= %f\n", se[i]);
    }
    /* now test some different node mapping options */
    vis_StateSetDerive(statenode, VIS_TENSOR);

    /* strict minimum */
    vis_StateSetParami(statenode, STATE_MAPNODE, STATE_MAPMIN);
    vis_StateMap(statenode, stateelem, NULL);
    print_nodestate(statenode, "Map Minimum");

    /* minimum based on absolute value */
    vis_StateSetParami(statenode, STATE_MAPNODE, STATE_MAPABSMIN);
    vis_StateMap(statenode, stateelem, NULL);
    print_nodestate(statenode, "Map Absolute Value Minimum");

    /* strict maximum */
    vis_StateSetParami(statenode, STATE_MAPNODE, STATE_MAPMAX);
    vis_StateMap(statenode, stateelem, NULL);
    print_nodestate(statenode, "Map Maximum");

    /* maximum based on absolute value */
    vis_StateSetParami(statenode, STATE_MAPNODE, STATE_MAPABSMAX);
    vis_StateMap(statenode, stateelem, NULL);
    print_nodestate(statenode, "Map Absolute Value Maximum");

    /* min-max difference */
    vis_StateSetParami(statenode, STATE_MAPNODE, STATE_MAPDIFF);
    vis_StateMap(statenode, stateelem, NULL);
    print_nodestate(statenode, "Map Difference");

    /* end objects */
    vis_ConnectEnd(connect);
    vis_StateEnd(stateelem);
    vis_StateEnd(statenode);
    vis_StateEnd(stateelemnode);
    vis_GridFunEnd(gf);
    return 0;
}

void
print_nodestate(vis_State* state, Vchar* stg)
{
    Vint i;
    Vfloat s[6];

    printf("%s\n", stg);
    for (i = 1; i <= MAX_NODE; i++) {
        vis_StateData(state, 1, &i, s);
        printf("node= %2d, sxx= %10f,  syy= %10f,  szz= %10f\n", i, s[0], s[1], s[2]);
        printf("          sxy= %10f,  syz= %10f,  szx= %10f\n", s[3], s[4], s[5]);
    }
}

10.12. Example 26a, Element Face Node Data Using ElemDat

This example uses the same finite element model introduced in Example 23 and illustrates the use of a ElemDat object for storing and retrieving element face based data. Once the finite element domain is defined as in Example 23, the Connect object is queried for its grid functions. A GridFun object is a required attribute for any ElemDat object and also proves useful for querying the finite element model for printing the element data. The ElemDat object is instanced and defined to hold element face node scalar data. This data could represent a distributed pressure load that varies across each element face. The data is stored using vis_ElemDatSetData() at the front faces (face number 2) of the hex elements (elements 1 and 2) and varies along the x coordinate (from 1. at x=0. to 2. at x=1. to 1. at x=2.). The element faces at which data has been set may be queried by generating a list of element faces using vis_ElemDatIdTran(). This IdTran is then used to control a loop for accessing and printing the data stored in the ElemDat object.

Then an imaginary component is added to the front face of element 2. Use vis_ElemDatSetComplexMode() to indicate that the imaginary component is begin set. In order access the real and imaginary parts simultaneously, vis_ElemDatSetComplexMode() must be called with SYS_COMPLEX_REALIMAGINARY.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};
static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {3., 0., 0.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 0.}, {3., 1., 0.}, {0., 0., 1.}, {1., 0., 1.},
                                     {2., 0., 1.}, {0., 1., 1.}, {1., 1., 1.}, {2., 1., 1.}};

/*----------------------------------------------------------------------
                      Element Face Node Data
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_ElemDat* elemdat;
    vis_IdTran* idtran;
    vis_GridFun* gf;

    Vint i, j, k, m;
    Vfloat p[8];
    Vint num, nix, ix[4], flag;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create elemdat object for element face node scalars */
    elemdat = vis_ElemDatBegin();
    vis_ElemDatDef(elemdat, MAX_ELEM, SYS_FACE, SYS_NODE, SYS_SCALAR);
    vis_ElemDatSetObject(elemdat, VIS_GRIDFUN, gf);

    /* set pressure for front face of element 1 */
    p[0] = 1.;
    p[1] = 2.;
    p[2] = 2.;
    p[3] = 1.;
    vis_ElemDatSetData(elemdat, 1, 2, p);
    /* set pressure for front face of element 2 */
    p[0] = 2.;
    p[1] = 1.;
    p[2] = 1.;
    p[3] = 2.;
    vis_ElemDatSetData(elemdat, 2, 2, p);

    /* fill idtran with defined element faces */
    idtran = vis_IdTranBegin();
    vis_ElemDatIdTran(elemdat, ELEMDAT_SETDATA, idtran);

    /* loop through defined element faces and print */
    vis_IdTranInq(idtran, &num);
    for (i = 1; i <= num; i++) {
        vis_IdTranGetId(idtran, i, &m);
        vis_IdTranGetEnt(idtran, i, &j);
        vis_ElemDatData(elemdat, m, j, p);
        vis_GridFunElemCon(gf, SYS_FACE, m, j, &nix, ix);
        printf("element= %d, face= %d, number of nodes= %d\n", m, j, nix);
        for (k = 0; k < nix; k++) {
            printf("  p(node= %d)= %f\n", ix[k], p[k]);
        }
    }
    /* now add imaginary data at front face of element 2 */
    vis_ElemDatSetComplexMode(elemdat, SYS_COMPLEX_IMAGINARY);
    p[0] = 4.;
    p[1] = 3.;
    p[2] = 3.;
    p[3] = 4.;
    vis_ElemDatSetData(elemdat, 2, 2, p);
    /* query overall complex data flag, should be 1 now */
    vis_ElemDatGetComplex(elemdat, &flag);
    printf("Complex flag= %d\n", flag);
    /* get complete complex data, entities have not changed */
    vis_ElemDatSetComplexMode(elemdat, SYS_COMPLEX_REALIMAGINARY);
    for (i = 1; i <= num; i++) {
        vis_IdTranGetId(idtran, i, &m);
        vis_IdTranGetEnt(idtran, i, &j);
        vis_ElemDatData(elemdat, m, j, p);
        vis_GridFunElemCon(gf, SYS_FACE, m, j, &nix, ix);
        printf("element= %d, face= %d, number of nodes= %d\n", m, j, nix);
        for (k = 0; k < nix; k++) {
            printf("  p(node= %d)= %f %f(i)\n", ix[k], p[2 * k], p[2 * k + 1]);
        }
    }
    /* end objects */
    vis_ConnectEnd(connect);
    vis_ElemDatEnd(elemdat);
    vis_IdTranEnd(idtran);
    vis_GridFunEnd(gf);
    return 0;
}

10.13. Example 26b, Element Face Node Normals Using ElemDat

This example illustrates the use of an ElemDat object for computing element face normals. These normals are useful for rendering of element faces with accurate shading. They may also be useful for preparing geometry input for some commercial finite element programs. Element face node normals are computed by averaging contributing normals from adjacent faces across edges except for those cases in which a element face discontinuity is meant to exist. The discontinuities may be determined geometrically by entering a feature angle or topologically by setting a element face branch flag.

A Connect object is generated which holds 5 shell elements. The first shell branches with the curved shell formed by elements 2,3,4 and 5. The ElemDat object is instanced and defined to hold element face node vector data. The function vis_ElemDatSetParamf() is used to set a feature angle of 20. degrees. The function vis_ElemDatSetParami() is used to enable the determination of an edge existing at a shell branch as a discontinuity in the shell. Element face normals will not be averaged across a discontinuous edge. The actual computation of element face node normals is performed by the function vis_ElemDatNormal(). The computed normals are accessed using vis_ElemDatData() and printed.

#include <stdio.h>
#include <math.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

#define MAX_ELEM 5
#define MAX_NODE 12

static Vint conn[MAX_ELEM][4] = {{1, 2, 8, 7}, {3, 4, 6, 5}, {5, 6, 8, 7}, {7, 8, 10, 9}, {9, 10, 12, 11}};
static Vfloat coords[MAX_NODE][3];

/*----------------------------------------------------------------------
                      Element Face Node Normals
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_ElemDat* elemdat;
    vis_Group* groupfree;
    vis_IdTran* idtran;
    vis_GridFun* gf;

    Vint i, j, k, m;
    Vfloat p[4][3];
    Vint num, nix, ix[4];
    Vfloat ang;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* generate node coordinates */
    coords[0][0] = 0.;
    coords[0][1] = 0.;
    coords[0][2] = 1.;

    coords[1][0] = coords[0][0];
    coords[1][1] = 1.;
    coords[1][2] = coords[0][2];
    ang = -40.;
    for (i = 2; i < MAX_NODE; i += 2) {
        coords[i][0] = (Vfloat)sin(.017453 * ang);
        coords[i][1] = 0.;
        coords[i][2] = 1.F - (Vfloat)cos(.017453 * ang);

        coords[i + 1][0] = coords[i][0];
        coords[i + 1][1] = 1.;
        coords[i + 1][2] = coords[i][2];
        ang += 20.;
    }

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, VIS_SHAPEQUAD, 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* generate kernel */
    vis_ConnectKernel(connect, 0);

    /* free face group */
    groupfree = vis_GroupBegin();
    vis_GroupDef(groupfree, MAX_ELEM, SYS_ELEM, SYS_FACE);
    vis_ConnectFaceGroup(connect, CONNECT_FREE, NULL, groupfree);

    /* create elemdat object for element face node normals */
    elemdat = vis_ElemDatBegin();
    vis_ElemDatDef(elemdat, MAX_ELEM, SYS_FACE, SYS_NODE, SYS_VECTOR);
    vis_ElemDatSetObject(elemdat, VIS_GRIDFUN, gf);
    vis_ElemDatSetParamf(elemdat, ELEMDAT_FEATUREANGLE, 20.);
    vis_ElemDatSetParami(elemdat, ELEMDAT_FEATUREBRANCH, SYS_ON);
    vis_ElemDatNormal(elemdat, groupfree);

    /* fill idtran with defined element faces */
    idtran = vis_IdTranBegin();
    vis_ElemDatIdTran(elemdat, ELEMDAT_SETDATA, idtran);

    /* loop through defined faces and print */
    vis_IdTranInq(idtran, &num);
    for (i = 1; i <= num; i++) {
        vis_IdTranGetId(idtran, i, &m);
        vis_IdTranGetEnt(idtran, i, &j);
        vis_ElemDatData(elemdat, m, j, (Vfloat*)p);
        vis_GridFunElemCon(gf, SYS_FACE, m, j, &nix, ix);
        printf("element= %d, face= %d, number of nodes= %d\n", m, j, nix);
        for (k = 0; k < nix; k++) {
            printf("  p(node= %d)= %f %f %f\n", ix[k], p[k][0], p[k][1], p[k][2]);
        }
    }
    /* end objects */
    vis_ConnectEnd(connect);
    vis_ElemDatEnd(elemdat);
    vis_GroupEnd(groupfree);
    vis_IdTranEnd(idtran);
    vis_GridFunEnd(gf);
    return 0;
}

10.14. Example 26c, Averaging Element Node Data within Groups

This example illustrates averaging element node data within two mutually exclusive groups of elements. In general, the averaging of element node data such as stress within a group of homogeneous elements is an important operation for visualization and error estimation. In this example a Connect object is filled with a simple quadrilateral element model consisting of 4 elements. It is assumed that elements 1 and 2 are to be averaged separately from elements 3 and 4. The discontinuous, raw element node data to be averaged is manufactured from the element node coordinates by shrinking the element node coordinates towards the element centroid by 10 percent. The basic averaging loop requires looping over the two disjoint element groups. For each group of elements a Group object is filled with the elements to be averaged. The vis_StateMap() function is called to average the raw element node data for the group and fill a working node State with the data averaged at the nodes connected to the elements in the Group. vis_StateMap() is called a second time to distribute the averaged nodal data to final element node state. The final averaged element node data is printed.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*
    7-----8-----9
    |     |     |
    |  3  |  4  |
    |     |     |
    4-----5-----6
    |     |     |
    |  1  |  2  |
    |     |     |
    1-----2-----3
*/
#define MAX_ELEM 4
#define MAX_NODE 9

static Vint conn[MAX_ELEM][4] = {{1, 2, 5, 4}, {2, 3, 6, 5}, {4, 5, 8, 7}, {5, 6, 9, 8}};
static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {0., 1., 0.}, {1., 1., 0.},
                                     {2., 1., 0.}, {0., 2., 0.}, {1., 2., 0.}, {2., 2., 0.}};

/* group 1, elements 1,2;  group 2, elements 3,4 */
static Vint elemgroup[2][2] = {{1, 2}, {3, 4}};

/*----------------------------------------------------------------------
                      Element and Node Tensor Data
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_State *stateraw, *statenode, *stateave;
    vis_GridFun* gf;
    vis_Group* group;

    Vint i, j, k;
    Vint nix, ix[4];
    Vfloat s[4][3];
    Vfloat x[4][3], xc[3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topology and element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, SYS_SHAPEQUAD, 2, 0, 0);
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create state object for original raw data */
    stateraw = vis_StateBegin();
    vis_StateDef(stateraw, MAX_ELEM, SYS_ELEM, SYS_NODE, VIS_VECTOR);
    vis_StateSetObject(stateraw, VIS_GRIDFUN, gf);

    /* fill raw state with element shrink coordinates */
    /* to create a discontinuity across all elements */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_ConnectElemNode(connect, i, &nix, ix);
        vis_ConnectCoords(connect, nix, ix, x);
        /* compute element centroid */
        for (k = 0; k < 3; k++) {
            xc[k] = 0.;
            for (j = 0; j < nix; j++) {
                xc[k] += x[j][k];
            }
            xc[k] /= nix;
        }
        /* shrink coordinates toward centroid by 10 percent */
        for (k = 0; k < 3; k++) {
            for (j = 0; j < nix; j++) {
                x[j][k] = x[j][k] - .1F * (x[j][k] - xc[k]);
            }
        }
        vis_StateSetData(stateraw, i, (Vfloat*)x);
    }
    /* print raw element node data */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_StateData(stateraw, 1, &i, (Vfloat*)s);
        vis_ConnectElemNode(connect, i, &nix, ix);
        printf("raw data\n");
        for (j = 0; j < nix; j++) {
            printf("elem= %d, node=%d, data= %e %e %e\n", i, ix[j], s[j][0], s[j][1], s[j][2]);
        }
    }
    /* create working state object for node data */
    statenode = vis_StateBegin();
    vis_StateDef(statenode, MAX_NODE, SYS_NODE, SYS_NONE, VIS_VECTOR);

    /* create working element group */
    group = vis_GroupBegin();
    vis_GroupDef(group, MAX_ELEM, SYS_ELEM, SYS_NONE);

    /* create state object for final averaged data */
    stateave = vis_StateBegin();
    vis_StateDef(stateave, MAX_ELEM, SYS_ELEM, SYS_NODE, VIS_VECTOR);
    vis_StateSetObject(stateave, VIS_GRIDFUN, gf);

    /* loop through mutually exclusive groups of elements */
    for (j = 0; j < 2; j++) {
        /* fill group with elements */
        vis_GroupClear(group);
        for (i = 0; i < 2; i++) {
            vis_GroupSetIndex(group, elemgroup[j][i], 1);
        }
        /* average data within element group */
        vis_StateMap(statenode, stateraw, group);
        /* distribute averaged node data to element nodes */
        vis_StateMap(stateave, statenode, group);
    }
    /* print averaged element node data */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_StateData(stateave, 1, &i, (Vfloat*)s);
        vis_ConnectElemNode(connect, i, &nix, ix);
        printf("averaged data\n");
        for (j = 0; j < nix; j++) {
            printf("elem= %d, node=%d, data= %e %e %e\n", i, ix[j], s[j][0], s[j][1], s[j][2]);
        }
    }
    /* end objects */
    vis_ConnectEnd(connect);
    vis_GroupEnd(group);
    vis_StateEnd(stateraw);
    vis_StateEnd(statenode);
    vis_StateEnd(stateave);
    vis_GridFunEnd(gf);
    return 0;
}

10.15. Example 26d, Computing Gradient of Normal Stress

This example illustrates computing gradient of stress normal to faces within solid elements. A single linear hexahedral solid element is defined with a linear varying direct stress field in each of the Cartesian coordinate directions. Several steps are involved in this computation. First a free face group is generated using vis_ConnectFaceGroup() and face normals at each node on each free face are computed using vis_ElemDatNormal(). Then for each free face and for each node on the free face, each component of the stress is extracted for each node on the element connected to the free face and the gradient vector of the stress component is computed using vis_ThresholdComputeGrad(). The gradient vector is projected to the node normal and its magnitude in this direction is printed.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

#define MAX_ELEM 1
#define MAX_NODE 8

static Vint conn[MAX_ELEM][8] = {{1, 2, 3, 4, 5, 6, 7, 8}};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {1., 1., 0.}, {0., 1., 0.},
                                     {0., 0., 1.}, {1., 0., 1.}, {1., 1., 1.}, {0., 1., 1.}};

/*----------------------------------------------------------------------
                      Computing Gradient of Normal Stress
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_ElemDat* elemdat;
    vis_Group* groupfree;
    vis_GridFun* gf;
    vis_State* state;
    vis_Threshold* threshold;

    Vint i, j, k, m, n;
    Vfloat x[8][3];
    Vfloat stress[8][6];
    Vfloat s[8][6], sn[8];
    Vint nix, ix[8];
    Vfloat v[4][3];
    Vint flags, nfaces, nifx, jfx[4], nd;
    Vint shape, maxi, maxj, maxk;
    Vfloat sng[8][3], grad;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, VIS_SHAPEHEX, 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* generate kernel */
    vis_ConnectKernel(connect, 0);

    /* create state of global stress data */
    state = vis_StateBegin();
    vis_StateDef(state, MAX_ELEM, SYS_ELEM, SYS_NODE, SYS_TENSOR);
    vis_StateSetObject(state, VIS_GRIDFUN, gf);
    /* generated stress has gradients of 2,3,4 in x,y,z */
    for (i = 0; i < MAX_NODE; i++) {
        stress[i][0] = 2.F * coords[i][0];
        stress[i][1] = 3.F * coords[i][1];
        stress[i][2] = 4.F * coords[i][2];
        stress[i][3] = 0.;
        stress[i][4] = 0.;
        stress[i][5] = 0.;
    }
    vis_StateSetData(state, 1, (Vfloat*)stress);

    /* free face group */
    groupfree = vis_GroupBegin();
    vis_GroupDef(groupfree, MAX_ELEM, SYS_ELEM, SYS_FACE);
    vis_ConnectFaceGroup(connect, CONNECT_FREE, NULL, groupfree);

    /* create elemdat object for element face normals */
    elemdat = vis_ElemDatBegin();
    vis_ElemDatDef(elemdat, MAX_ELEM, SYS_FACE, SYS_NODE, SYS_VECTOR);
    vis_ElemDatSetObject(elemdat, VIS_GRIDFUN, gf);
    vis_ElemDatSetParamf(elemdat, ELEMDAT_FEATUREANGLE, 20.);
    vis_ElemDatSetParami(elemdat, ELEMDAT_FEATUREBRANCH, SYS_ON);
    vis_ElemDatNormal(elemdat, groupfree);

    /* instance a Threshold object */
    threshold = vis_ThresholdBegin();

    /* compute normal stress gradient on free face nodes */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(groupfree, i, &flags);
        if (flags == 0)
            continue;
        printf("elem= %d\n", i);

        /* gather element coordinates, etc. */
        vis_GridFunTopology(gf, i, &shape, &maxi, &maxj, &maxk);
        vis_GridFunElemNode(gf, i, &nix, ix);
        vis_GridFunCoords(gf, nix, ix, x);

        /* gather element stress */
        vis_StateData(state, 1, &i, (Vfloat*)s);
        vis_ConnectElemNum(connect, SYS_FACE, i, &nfaces);

        /* set element topology */
        vis_ThresholdSetTopology(threshold, shape, maxi, maxj, maxk);

        /* loop through element faces */
        for (j = 1; j <= nfaces; j++) {
            if (VIEW_FLAG(flags, j) == 0)
                continue;
            printf(" face= %d\n", j);

            /* gather face normals */
            vis_ElemDatData(elemdat, i, j, (Vfloat*)v);

            /* get face node indices into element connectivity */
            vis_GridFunElemCnn(gf, SYS_FACE, i, j, &nifx, jfx);

            /* loop through nodes on face */
            for (k = 0; k < nifx; k++) {
                /* loop through each component */
                for (n = 0; n < 6; n++) {
                    /* gather each component as a scalar per node */
                    for (m = 0; m < nix; m++) {
                        sn[m] = s[m][n];
                    }
                    /* compute gradients of normal stress field */
                    vis_ThresholdComputeGrad(threshold, sn, x, SYS_OFF, sng);
                    /* project gradient along normal direction */
                    nd = jfx[k] - 1;
                    grad = sng[nd][0] * v[k][0] + sng[nd][1] * v[k][1] + sng[nd][2] * v[k][2];
                    printf("  node= %d, comp= %d, grad= %e\n", ix[nd], n, grad);
                }
                printf("\n");
            }
        }
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_ElemDatEnd(elemdat);
    vis_StateEnd(state);
    vis_GroupEnd(groupfree);
    vis_GridFunEnd(gf);
    vis_ThresholdEnd(threshold);
    return 0;
}

10.16. Example 27, Perform Space Searches Using Space.

This example illustrates the use of a Space object to perform geometric search operations on a small finite element model consisting of two 8-node hexahedra one 4-node quadrilateral and a 2-node line. A Space object is instanced to hold a spatial decomposition for the model using the Connect object instanced for the model (see Example 23). The spatial decomposition allows for a model to be quickly searched for the elements which contain a set of points or which intersect geometric lines, planes or boxes. Before a search operation can be performed, the space kernel must be formed by calling vis_SpaceKernel(). Search operations are then performed for the elements which contain a set of two points, intersect an infinite line, intersect an infinite plane and which are contained in a box. The results of each search operation are printed out.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/* example mesh is two bricks, a quad and a line */
#define MAX_ELEM 4
#define MAX_NODE 15

static Vint conn[MAX_ELEM][8] = {
{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}, {14, 15, 0, 0, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD, VIS_SHAPELINE};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {3., 0., 0.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 0.}, {3., 1., 0.}, {0., 0., 1.}, {1., 0., 1.},
                                     {2., 0., 1.}, {0., 1., 1.}, {1., 1., 1.}, {2., 1., 1.}, {3., 1., 1.}};

/*----------------------------------------------------------------------
                      Perform space searches using a Space object
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_Space* space;
    vis_GridFun* gf;
    vis_IdTran* idtran;
    vis_Group* group;

    Vint i;
    Vint num_pts;
    Vfloat pts[10][3], rst[3];
    Vfloat local[10][3];
    Vfloat line_pts[2][3];
    Vint node, elem;
    Vint flag;
    Vfloat plane_pts[4][3];
    Vfloat box_pts[8][3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set element topologies, connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates and generate kernel */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    vis_ConnectKernel(connect, 0);

    /* create and load a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create space object for elements */
    space = vis_SpaceBegin();
    vis_SpaceSetObject(space, VIS_GRIDFUN, gf);

    /* create kernel for entire mesh */
    vis_SpaceKernel(space, 0);

    /*----------------------------------------------------------------------
                          Search the mesh for elements which contain a set
                          of two points.  The elements which the points are
                          in are returned in an vis_Idtran object.
    ----------------------------------------------------------------------*/
    printf("\n ----------  point search  ---------- \n");

    /* define two points */
    num_pts = 2;
    pts[0][0] = 1.4f;
    pts[0][1] = 0.6f;
    pts[0][2] = 0.5f;
    pts[1][0] = 2.3f;
    pts[1][1] = 0.5f;
    pts[1][2] = 0.5f;

    /* prepare idtran object for output */
    idtran = vis_IdTranBegin();
    vis_IdTranDef(idtran, num_pts);

    /* perform point search */
    vis_SpacePointIdTran(space, num_pts, pts, NULL, idtran, local);

    /* print results */
    for (i = 1; i <= num_pts; i++) {
        vis_IdTranGetId(idtran, i, &elem);
        if (elem > 0) {
            printf("\n point %d is in element [%d].\n", i, elem);
        }
        else {
            printf("\n point %d is out. \n", i);
        }
    }
    /* use alternative function to return natural coordinates */
    /* requires ADTREE kernel to be built */
    vis_SpaceSetParami(space, SPACE_TREE, SPACE_TREE_ADTREE);
    vis_SpaceKernel(space, 0);
    for (i = 1; i <= num_pts; i++) {
        vis_SpaceElemRST(space, pts[i - 1], NULL, &elem, rst);
        if (elem) {
            printf("\n point %d is in element [%d], rst= %f %f %f\n", i, elem, rst[0], rst[1], rst[2]);
        }
        else {
            printf("\n point %d is out. \n", i);
        }
    }

    /*----------------------------------------------------------------------
                          Search the mesh for the elements which intersect a
                          line.  The elements which intersect the line are
                          returned in a vis_Group object.
    ----------------------------------------------------------------------*/
    /* pick 3D elements */
    printf("\n ----------  line search 1 ---------- \n");
    /* define line endpoints */
    line_pts[0][0] = -0.5;
    line_pts[0][1] = 0.5;
    line_pts[0][2] = 0.5;
    line_pts[1][0] = 0.5;
    line_pts[1][1] = 0.5;
    line_pts[1][2] = 0.5;

    /* prepare group object for output */
    group = vis_GroupBegin();
    vis_GroupDef(group, MAX_ELEM, SYS_ELEM, SYS_NONE);
    vis_GroupClear(group);

    /* set infinite line type and perform line search */
    vis_SpaceSetParami(space, SPACE_LINE_INFINITE, VIS_ON);
    vis_SpaceLineGroup(space, line_pts, NULL, group);

    /* print results */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag) {
            printf("\n the line intersects element [%d]. \n", i);
        }
    }

    /* pick 2D and 1D elements */
    printf("\n ----------  line search 2 ---------- \n");
    /* define line endpoints */
    line_pts[0][0] = 2.5f;
    line_pts[0][1] = 1.01f;
    line_pts[0][2] = -0.5f;
    line_pts[1][0] = 2.5f;
    line_pts[1][1] = 1.01f;
    line_pts[1][2] = 0.5f;

    vis_GroupClear(group);

    vis_SpaceSetParamf(space, SPACE_TOLERANCE, .02f);
    vis_SpaceLineGroup(space, line_pts, NULL, group);
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag) {
            printf("\n the line intersects element [%d]. \n", i);
        }
    }

    /*----------------------------------------------------------------------
                          Search the mesh for the elements which intersect a plane.
                          The elements which intersect the plane are returned in
                          a vis_Group object.
    ----------------------------------------------------------------------*/
    printf("\n  ----------  plane search  ---------- \n");

    /* define points in plane */
    plane_pts[0][0] = 0.0;
    plane_pts[0][1] = 0.0;
    plane_pts[0][2] = 0.5;
    plane_pts[1][0] = 1.5;
    plane_pts[1][1] = 0.0;
    plane_pts[1][2] = 0.5;
    plane_pts[2][0] = 1.5;
    plane_pts[2][1] = 2.0;
    plane_pts[2][2] = 0.5;
    plane_pts[3][0] = 0.0;
    plane_pts[3][1] = 2.0;
    plane_pts[3][2] = 0.5;

    vis_GroupClear(group);

    /* perform plane search */
    vis_SpacePlaneGroup(space, plane_pts, NULL, group);

    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag) {
            printf("\n  the plane intersects element [%d]. \n", i);
        }
    }

    /*----------------------------------------------------------------------
                          search the mesh for the elements which intersect or are
                          in a box.  The elements which intersect or are in the
                          box are returned in a vis_Group object.
    ----------------------------------------------------------------------*/
    printf("\n  ----------  box search  ---------- \n");

    /* set the six corners of the box. first the */
    /* back four points, then the front. */
    box_pts[0][0] = 0.0f;
    box_pts[0][1] = 0.1f;
    box_pts[0][2] = 0.2f;
    box_pts[1][0] = 0.4f;
    box_pts[1][1] = 0.1f;
    box_pts[1][2] = 0.2f;
    box_pts[2][0] = 0.4f;
    box_pts[2][1] = 0.15f;
    box_pts[2][2] = 0.2f;
    box_pts[3][0] = 0.0f;
    box_pts[3][1] = 0.15f;
    box_pts[3][2] = 0.2f;

    box_pts[4][0] = 0.0f;
    box_pts[4][1] = 0.1f;
    box_pts[4][2] = 0.4f;
    box_pts[5][0] = 0.4f;
    box_pts[5][1] = 0.1f;
    box_pts[5][2] = 0.4f;
    box_pts[6][0] = 0.4f;
    box_pts[6][1] = 0.15f;
    box_pts[6][2] = 0.4f;
    box_pts[7][0] = 0.0f;
    box_pts[7][1] = 0.15f;
    box_pts[7][2] = 0.4f;

    vis_GroupClear(group);

    /* perform box search */
    vis_SpaceBoxGroup(space, box_pts, NULL, group);

    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag) {
            printf("\n  the element [%d] is in the box. \n", i);
        }
    }
    /*----------------------------------------------------------------------
                          Search the mesh for the nodes which match a set
                          of input points
    ----------------------------------------------------------------------*/
    printf("\n ----------  point node search  ---------- \n");

    num_pts = 2;
    pts[0][0] = 2.0;
    pts[0][1] = 1.0;
    pts[0][2] = 0.;
    pts[1][0] = 2.5;
    pts[1][1] = 0.5;
    pts[1][2] = 0.;

    /* create node kernel */
    vis_SpaceNodeKernel(space);
    vis_SpacePointNodeIdTran(space, num_pts, pts, NULL, idtran);
    /* print results */
    for (i = 1; i <= num_pts; i++) {
        vis_IdTranGetId(idtran, i, &node);
        if (node > 0) {
            printf("\n point %d is coincident with node [%d].\n", i, node);
        }
        else {
            printf("\n point %d is not coincident. \n", i);
        }
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_SpaceEnd(space);
    vis_IdTranEnd(idtran);
    vis_GroupEnd(group);
    return 0;
}

10.17. Example 27a, Intersection and Interpolation.

This example extends the model intersection methodology illustrated in Example 27. In this case, the model is intersected by a line and the precise intersection points of the line with the element faces are computed using the vis_FaceIntersectLine() function. Using this precise intersection information, the function vis_FaceInterpolate() is used to interpolate a scalar field value to the intersection point. Note that the intersection testing performed by the Face module always assumes a finite length for the input line. This means that if the effect of an infinite line is required, the endpoints of the line must be adjusted to be outside of the spatial extent of the model.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

/* example mesh is two bricks and a quad */
#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {3., 0., 0.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 0.}, {3., 1., 0.}, {0., 0., 1.}, {1., 0., 1.},
                                     {2., 0., 1.}, {0., 1., 1.}, {1., 1., 1.}, {2., 1., 1.}};

static Vfloat temps[MAX_NODE] = {0., 0., 0., 0., 0., 0., 0., 0., 2., 2., 2., 2., 2., 2.};

/*----------------------------------------------------------------------
                      Perform space searches, intersection and interpolation
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_Space* space;
    vis_GridFun* gf;
    vis_Group *group, *groupface;
    vis_Face* face;
    vis_VisContext* vc;

    Vint i, j, k;
    Vint nfaces;
    Vfloat line_pts[2][3];
    Vint flag, flags;

    Vint shape, maxi, maxj;
    Vint nix, ix[8];
    Vfloat x[8][3], t[8];
    Vfloat r[2], xr[3], xd[3], tr;
    Vint status;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set element topologies, connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates and generate kernel */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    vis_ConnectKernel(connect, 0);

    /* create and load a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create space object for elements */
    space = vis_SpaceBegin();
    vis_SpaceSetObject(space, VIS_GRIDFUN, gf);

    /* create kernel for entire mesh */
    vis_SpaceKernel(space, 0);

    /* Search the mesh for the elements which intersect line */
    /* define line endpoints */
    line_pts[0][0] = -0.5;
    line_pts[0][1] = 0.5;
    line_pts[0][2] = 0.5;
    line_pts[1][0] = 2.5;
    line_pts[1][1] = 0.5;
    line_pts[1][2] = 0.5;

    /* restrict search to elements with external faces */
    groupface = vis_GroupBegin();
    vis_GroupDef(groupface, MAX_ELEM, SYS_ELEM, SYS_FACE);
    vis_ConnectFaceGroup(connect, CONNECT_FREE, NULL, groupface);

    /* prepare group object for output */
    group = vis_GroupBegin();
    vis_GroupDef(group, MAX_ELEM, SYS_ELEM, SYS_NONE);
    vis_GroupClear(group);

    /* set infinite line type and perform line search */
    vis_SpaceSetParami(space, SPACE_LINE_INFINITE, VIS_ON);
    vis_SpaceLineGroup(space, line_pts, groupface, group);

    face = vis_FaceBegin();
    vc = vis_VisContextBegin();
    vis_FaceSetObject(face, VIS_VISCONTEXT, vc);

    /* find precise face intersect point */
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag == 0)
            continue;
        vis_ConnectElemNum(connect, SYS_FACE, i, &nfaces);
        vis_GroupGetIndex(groupface, i, &flags);
        for (j = 1; j <= nfaces; j++) {
            if (VIEW_FLAG(flags, j) == 0)
                continue;
            vis_ConnectElemCon(connect, SYS_FACE, i, j, &nix, ix);
            vis_ConnectElemTopo(connect, SYS_FACE, i, j, &shape, &maxi, &maxj);
            vis_ConnectCoords(connect, nix, ix, x);
            vis_FaceSetTopology(face, shape, maxi, maxj);
            vis_FaceIntersectLine(face, x, line_pts, r, xr, xd, &status);

            /* intersection */
            if (status) {
                printf("\n the line intersects element= %d, face= %d\n", i, j);
                printf("   face natural coordinates= %f,%f\n", r[0], r[1]);

                /* gather scalar at face */
                for (k = 0; k < nix; k++) {
                    t[k] = temps[ix[k] - 1];
                }

                /* interpolate scalar at intersection */
                vis_FaceInterpolate(face, r, 1, t, &tr);
                printf("   scalar= %f\n", tr);
            }
        }
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_SpaceEnd(space);
    vis_GroupEnd(group);
    vis_GroupEnd(groupface);
    vis_FaceEnd(face);
    vis_VisContextEnd(vc);
    return 0;
}

10.18. Example 28, Perform Range Searches Using Range.

This example illustrates the use of a Range object to perform state search operations on a small finite element model consisting of two 8-node hexahedra and one 4-node quadrilateral. A Range object is instanced to hold lists of state values for a spatial decomposition of the model using a Space object instanced for the model (see Example 27). These lists allow a model to be quickly searched for the elements which contain a specific state value. A search operation is performed for the elements which contain a given state value. The results of each search operation are printed out.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/* example mesh is two bricks and a quad */
#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {3., 0., 0.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 0.}, {3., 1., 0.}, {0., 0., 1.}, {1., 0., 1.},
                                     {2., 0., 1.}, {0., 1., 1.}, {1., 1., 1.}, {2., 1., 1.}};

static Vfloat scalar_1[MAX_NODE] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0};

/*----------------------------------------------------------------------
                      Perform range searches using a Range object
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_Space* space;
    vis_GridFun* gf;
    vis_Group* group;
    vis_State* state;
    vis_Range* range;

    Vint i;
    Vint flag;
    Vint n;
    Vfloat value;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    vis_ConnectKernel(connect, 0);

    /* create and load a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create space object for elements */
    space = vis_SpaceBegin();
    vis_SpaceSetObject(space, VIS_GRIDFUN, gf);

    /* create kernel for entire mesh */
    vis_SpaceKernel(space, 0);

    /* create range object for elements */
    range = vis_RangeBegin();

    /* set grid function and space objects as attributes */
    vis_RangeSetObject(range, VIS_GRIDFUN, gf);
    vis_RangeSetObject(range, VIS_SPACE, space);

    /* create state object to hold data (range information) */
    state = vis_StateBegin();
    vis_StateDef(state, MAX_NODE, SYS_NODE, SYS_NONE, VIS_SCALAR);

    /* load data */
    for (i = 0; i < MAX_NODE; i++) {
        vis_StateSetData(state, i + 1, &scalar_1[i]);
    }

    /* create group object to hold output of queries */
    group = vis_GroupBegin();
    vis_GroupDef(group, MAX_ELEM, SYS_ELEM, SYS_NONE);
    vis_GroupClear(group);

    /* set state object as range 1 */
    vis_RangeSetState(range, 1, state);

    /* get elements which contain a given value */
    value = 10.0;
    vis_RangeSurfGroup(range, 1, value, NULL, group);

    /* print results */
    printf("\n  ------ search elements for value [%f]  ------ \n", value);
    n = 0;
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_GroupGetIndex(group, i, &flag);
        if (flag) {
            n++;
            printf("  element [%d] contains the value. \n", i);
        }
    }
    printf("\n  [%d] elements in group. \n\n", n);

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_SpaceEnd(space);
    vis_RangeEnd(range);
    vis_StateEnd(state);
    vis_GroupEnd(group);
    return 0;
}

10.19. Example 29, Node and Element Associations

This example illustrates the facilities within the Connect module for specifying and querying integer values associated with nodes, elements and element edges and faces. Examples of such values would be the property identifiers associated with an element, the coordinate system identifiers associated with a node, the geometry edge tag associated with an element edge. There are several types of associations which can be assigned, the complete list is documented under vis_ConnectSetElemAssoc(). Each of the types of associations may be assigned to any entity, however some associations, in practice, are specifically designed for either nodes or elements. By default, each entity has a single association value of 0 for each association type (except node and element association VIS_USERID, the default value is the entity index). This default value may be changed by the user by setting the association value explicitly. In the case of element associations, the function vis_ConnectSetElemAssoc() is used. Use the function vis_ConnectElemAssoc() to query this single value.

Multiple values of a single association type may be assigned to a single entity. In the case of elements, use the function vis_ConnectAddElemAssoc() to add associations to the single value which is set using vis_ConnectSetElemAssoc(). Query all set and added associations using the function vis_ConnectAllElemAssoc(). Delete all added associations using vis_ConnectDelElemAssoc(). Note that the deletion only affect the additional associations added using vis_ConnectAddElemAssoc().


#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/
#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Node and Element Associations
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    Vint i;
    Vint id, aid, num, aids[3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* set node association */
    vis_ConnectSetNodeAssoc(connect, VIS_CSYSID, 5, 100);
    /* query node association */
    id = 5;
    vis_ConnectNodeAssoc(connect, VIS_CSYSID, 1, &id, &aid);
    printf("node 5, aid= %d\n", aid);

    /* add another node association of same type to same node */
    vis_ConnectAddNodeAssoc(connect, VIS_CSYSID, id, 101);
    vis_ConnectNumNodeAssoc(connect, VIS_CSYSID, id, &num);
    printf("node 5, num= %d\n", num);
    vis_ConnectAllNodeAssoc(connect, VIS_CSYSID, id, &num, aids);
    for (i = 0; i < num; i++) {
        printf("node 5, aid[%d]= %d\n", i, aids[i]);
    }
    /* now delete added associations */
    vis_ConnectDelNodeAssoc(connect, VIS_CSYSID, id);
    vis_ConnectNumNodeAssoc(connect, VIS_CSYSID, id, &num);
    printf("node 5, num= %d\n", num);
    vis_ConnectAllNodeAssoc(connect, VIS_CSYSID, id, &num, aids);
    for (i = 0; i < num; i++) {
        printf("node 5, aid[%d]= %d\n", i, aids[i]);
    }
    /* now set element face entity associations */
    vis_ConnectSetElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 2, 1, 100);
    vis_ConnectSetElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 3, 1, 100);

    /* set element edge entity association */
    /* element 3, edge 2 */
    vis_ConnectSetElemEntAssoc(connect, VIS_GEOEDGE, SYS_EDGE, 3, 2, 1);

    /* query element edge association */
    /* undefined associations return 0 */
    vis_ConnectElemEntAssoc(connect, VIS_GEOEDGE, SYS_EDGE, 3, 1, &aid);
    printf("element 3, edge 1, aid= %d\n", aid);
    /* element 3, edge 2 */
    vis_ConnectElemEntAssoc(connect, VIS_GEOEDGE, SYS_EDGE, 3, 2, &aid);
    printf("element 3, edge 2, aid= %d\n", aid);

    /* additional associations */
    printf("\nTest adding non-unique associations\n");
    vis_ConnectAddElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 2, 1, 100);
    vis_ConnectAllElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 2, 1, &num, aids);
    printf("element 2, face 1, num= %d\n", num);
    for (i = 0; i < num; i++) {
        printf("element 2, face 1, aid[%d]= %d\n", i, aids[i]);
    }
    /* delete all associations */
    printf("\nTest delete additional associations\n");
    vis_ConnectDelElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 2, 1);
    vis_ConnectAllElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 2, 1, &num, aids);
    printf("element 2, face 1, num= %d\n", num);
    for (i = 0; i < num; i++) {
        printf("element 2, face 1, aid[%d]= %d\n", i, aids[i]);
    }
    /* add associations to elements with no set association */
    printf("\nTest adding associations without set association\n");
    vis_ConnectAddElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 6, 5, 50);
    vis_ConnectAllElemEntAssoc(connect, VIS_GEOFACE, SYS_FACE, 6, 5, &num, aids);
    printf("element 6, face 5, num= %d\n", num);
    for (i = 0; i < num; i++) {
        printf("element 6, face 5, aid[%d]= %d\n", i, aids[i]);
    }
    /* end objects */
    vis_ConnectEnd(connect);
    return 0;
}

10.20. Example 30, Demo Visualizer Progressive Example

This example illustrates the use of both global and local VisTools objects to construct a simple finite element visualizer.

This example is extended using VglTools objects in files exam30avgl.c, exam30bvgl.c and exam30cvgl.c.

#include "base/base.h"
#include "vgl/vgl.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#include "glwin.h"

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

void
draw_ElemEdge(vis_Group* group, vis_Connect* connect, vis_State* stated, vis_Edge* edge);
void
draw_ElemFaceGroup(vis_Group* group, vis_Connect* connect, vis_State* stated, vis_Face* face);
void
draw_ElemFaceIdTran(vis_IdTran* idtran, vis_Connect* connect, vis_State* stated, vis_Face* face);
void
draw_ElemFaceContour(vis_Group* group, vis_Connect* connect, vis_State* state, vis_State* stated, vis_Contour* contour);
void
draw_ElemIsosurface(vis_Group* group, vis_Connect* connect, vis_State* state, vis_State* stated, vis_Threshold* threshold);
void
draw_NodeMark(vis_Group* group, vis_Connect* connect, Vint datatype, vis_State* state, vis_State* stated, vis_Mark* mark);

/* Red,Green,Blue components of entity Colormap */
static Vfloat rgb[8][3] = {{.5, .5, .5}, {1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.},
                           {0., 1., 1.}, {1., 0., 1.}, {1., 1., 0.}, {1., 1., 1.}};

/*----------------------------------------------------------------------
                      Demo visualizer
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_GridFun* gf;
    vis_Group *groupedge, *groupface;
    vis_IdTran* idtranface;
    vis_State* state;

    vis_VisContext* vc;
    vis_Levels* levels;
    vis_ColorMap *cmap, *cmapiso;
    vis_Edge* edge;
    vis_Face* face;
    vis_Mark* mark;
    vis_Contour* contour;
    vis_Threshold* threshold;
    GLWin* glwin;
    vgl_DrawFun* df;

    int i, j;
    Vint nlevels;
    Vfloat sminmax[2];
    Vint numnp, numel;
    Vfloat xtext[3], ctext[3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create GL device */
    glwin = GLWinBegin();
    GLWinCreateWindow(glwin, 200, 200, 400, 400);
    GLWinOrtho(glwin, -3., 3., -3., 3., -300., 300.);

    /* create draw function object for GL */
    df = vgl_DrawFunBegin();
    GLWinDrawFun(glwin, df);

    /* create demo cylindrical brick 1000 element model */
    connect = vis_ConnectBegin();
    vis_ConnectDemo(connect, CONNECT_DEMO_CYLINDER, 1., VIS_SHAPEHEX, 11, 11, 11);
    vis_ConnectNumber(connect, SYS_NODE, &numnp);
    vis_ConnectNumber(connect, SYS_ELEM, &numel);

    /* generate connect kernel */
    vis_ConnectKernel(connect, 0);

    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* instance state object to hold demo node vector result */
    state = vis_StateBegin();
    vis_StateDef(state, numnp, SYS_NODE, SYS_NONE, SYS_VECTOR);
    vis_StateSetObject(state, VIS_GRIDFUN, gf);
    vis_StateDemo(state, STATE_DEMO_PLATE, .25, NULL);

    /* compute results minmax */
    vis_StateSetDerive(state, VIS_VECTOR_MAG);
    vis_StateExtent(state, NULL, sminmax);

    /* build free face group */
    groupface = vis_GroupBegin();
    vis_GroupDef(groupface, numel, SYS_ELEM, SYS_FACE);
    vis_ConnectFaceGroup(connect, CONNECT_FREE, NULL, groupface);
    idtranface = vis_IdTranBegin();
    vis_IdTranGroup(idtranface, groupface);

    /* build free face feature edge group */
    groupedge = vis_GroupBegin();
    vis_GroupDef(groupedge, numel, SYS_ELEM, SYS_EDGE);
    vis_ConnectEdgeGroup(connect, CONNECT_FEATURE, groupface, groupedge);

    /* vis context and set attributes */
    vc = vis_VisContextBegin();

    /* levels, set evenly spaced levels */
    levels = vis_LevelsBegin();
    nlevels = 10;
    vis_LevelsDef(levels, LEVELS_LINEAR, nlevels);
    vis_LevelsSetMinMax(levels, sminmax[0], sminmax[1]);
    vis_LevelsGenerate(levels, LEVELS_PADTOP);

    /* color map for isovalues */
    cmapiso = vis_ColorMapBegin();
    vis_ColorMapRamp(cmapiso, nlevels, 1, COLORMAP_HUE);

    /* color map for entities */
    cmap = vis_ColorMapBegin();
    vis_ColorMapSetRGB(cmap, 8, 0, rgb);

    /* create mark object and set objects */
    mark = vis_MarkBegin();
    vis_MarkSetObject(mark, VGL_DRAWFUN, df);
    vis_MarkSetObject(mark, VIS_VISCONTEXT, vc);
    vis_MarkSetObject(mark, VIS_LEVELS, levels);
    vis_MarkSetObject(mark, VIS_COLORMAP, cmapiso);

    /* create contour object and set objects */
    contour = vis_ContourBegin();
    vis_ContourSetObject(contour, VGL_DRAWFUN, df);
    vis_ContourSetObject(contour, VIS_VISCONTEXT, vc);
    vis_ContourSetObject(contour, VIS_LEVELS, levels);
    vis_ContourSetObject(contour, VIS_COLORMAP, cmapiso);

    /* create threshold object and set objects */
    threshold = vis_ThresholdBegin();
    vis_ThresholdSetObject(threshold, VGL_DRAWFUN, df);
    vis_ThresholdSetObject(threshold, VIS_VISCONTEXT, vc);
    vis_ThresholdSetObject(threshold, VIS_LEVELS, levels);
    vis_ThresholdSetObject(threshold, VIS_COLORMAP, cmapiso);

    /* create edge object and set objects */
    edge = vis_EdgeBegin();
    vis_EdgeSetObject(edge, VGL_DRAWFUN, df);
    vis_EdgeSetObject(edge, VIS_VISCONTEXT, vc);
    vis_EdgeSetObject(edge, VIS_COLORMAP, cmap);

    /* create face object and set objects */
    face = vis_FaceBegin();
    vis_FaceSetObject(face, VGL_DRAWFUN, df);
    vis_FaceSetObject(face, VIS_VISCONTEXT, vc);
    vis_FaceSetObject(face, VIS_COLORMAP, cmap);

    xtext[0] = -2.5;
    xtext[1] = 2.5;
    xtext[2] = 0.;
    ctext[0] = 1.;
    ctext[1] = 1.;
    ctext[2] = 1.;
    /* loop through visualization types */
    for (j = 0; j < 5; j++) {
        for (i = 0; i < 8; i++) {
            GLWinClear(glwin);
            GLWinColor(glwin, ctext);
            if (j == 0) {
                GLWinText(glwin, xtext, "draw_ElemFaceGroup");
            }
            else if (j == 1) {
                GLWinText(glwin, xtext, "draw_ElemFaceIdTran");
            }
            else if (j == 2) {
                GLWinText(glwin, xtext, "draw_ElemFaceContour");
            }
            else if (j == 3) {
                GLWinText(glwin, xtext, "draw_ElemIsosurface");
            }
            else if (j == 4) {
                GLWinText(glwin, xtext, "draw_NodeMark");
            }
            GLWinXfmPush(glwin);
            GLWinRotate(glwin, i * 4.F, 'X');
            GLWinRotate(glwin, -i * 4.F, 'Y');
            vis_VisContextSetColor(vc, 7);
            draw_ElemEdge(groupedge, connect, NULL, edge);
            /* draw elem face subset using a Group object */
            if (j == 0) {
                vis_VisContextSetColor(vc, 0);
                draw_ElemFaceGroup(groupface, connect, NULL, face);
                /* draw elem face subset using an IdTran object */
            }
            else if (j == 1) {
                vis_VisContextSetColor(vc, 0);
                draw_ElemFaceIdTran(idtranface, connect, NULL, face);
                /* draw elem face contours */
            }
            else if (j == 2) {
                vis_StateSetDerive(state, VIS_VECTOR_MAG);
                vis_VisContextSetIsoValType(vc, VIS_ISOVALFRINGE);
                draw_ElemFaceContour(groupface, connect, state, NULL, contour);
                /* draw elem isosurfaces */
            }
            else if (j == 3) {
                vis_StateSetDerive(state, VIS_VECTOR_MAG);
                vis_VisContextSetIsoValType(vc, VIS_ISOVALSURFACE);
                draw_ElemIsosurface(NULL, connect, state, NULL, threshold);
                /* draw node vector markers */
            }
            else if (j == 4) {
                vis_StateSetDerive(state, VIS_VECTOR);
                vis_VisContextSetVectorType(vc, VIS_VECTORUMBRELLA);
                vis_VisContextSetComponent(vc, VIS_COMPONENT_PRINCIPAL);
                vis_VisContextSetSize(vc, .25);
                vis_VisContextSetFlags(vc, VIS_VECTORTAIL | VIS_VECTORTAILREGISTER);
                draw_NodeMark(NULL, connect, VIS_VECTOR, state, NULL, mark);
            }
            GLWinXfmPop(glwin);
            GLWinSwap(glwin);
            sleep(1);
        }
    }
    sleep(5);

    /* free all objects */
    vis_ConnectEnd(connect);
    vis_StateEnd(state);
    vis_GroupEnd(groupface);
    vis_GroupEnd(groupedge);
    vis_GridFunEnd(gf);
    vgl_DrawFunEnd(df);
    vis_VisContextEnd(vc);
    vis_LevelsEnd(levels);
    vis_ColorMapEnd(cmapiso);
    vis_ColorMapEnd(cmap);
    vis_MarkEnd(mark);
    vis_ContourEnd(contour);
    vis_ThresholdEnd(threshold);
    vis_EdgeEnd(edge);
    vis_FaceEnd(face);
    GLWinEnd(glwin);
    return 0;
}

/*----------------------------------------------------------------------
                      Draw Element Edges
----------------------------------------------------------------------*/
void
draw_ElemEdge(vis_Group* group, vis_Connect* connect, vis_State* stated, vis_Edge* edge)
{
    Vint numel;
    Vint n, j;
    Vint flags;
    Vint nedges;
    Vint shape, maxi, maxj;
    Vint nix;
    Vint ix[8];
    Vfloat x[8][3];

    /* get number of elements */
    vis_ConnectNumber(connect, SYS_ELEM, &numel);

    /* draw element edges */
    /* loop through elements */
    for (n = 1; n <= numel; n++) {
        vis_GroupGetIndex(group, n, &flags);
        if (flags == 0)
            continue;
        vis_ConnectElemNum(connect, SYS_EDGE, n, &nedges);

        /* loop through element edges */
        for (j = 1; j <= nedges; j++) {
            if (VIEW_FLAG(flags, j) == 0)
                continue;
            vis_ConnectElemCon(connect, SYS_EDGE, n, j, &nix, ix);
            vis_ConnectElemTopo(connect, SYS_EDGE, n, j, &shape, &maxi, &maxj);
            if (stated != NULL) {
                vis_StateData(stated, nix, ix, (Vfloat*)x);
            }
            else {
                vis_ConnectCoords(connect, nix, ix, x);
            }
            vis_EdgeSetTopology(edge, SYS_SHAPELINE, nix);
            vis_EdgeCurv(edge, x);
        }
    }
}

/*----------------------------------------------------------------------
                      Draw Element Face using Group
----------------------------------------------------------------------*/
void
draw_ElemFaceGroup(vis_Group* group, vis_Connect* connect, vis_State* stated, vis_Face* face)
{
    Vint numel;
    Vint n, j;
    Vint flags;
    Vint nfaces;
    Vint shape, maxi, maxj;
    Vint nix;
    Vint ix[VIS_MAXFACENODE];
    Vfloat x[VIS_MAXFACENODE][3];

    /* get number of elements */
    vis_ConnectNumber(connect, SYS_ELEM, &numel);
    /* draw element faces */
    /* loop through elements */
    for (n = 1; n <= numel; n++) {
        vis_GroupGetIndex(group, n, &flags);
        if (flags == 0)
            continue;
        vis_ConnectElemNum(connect, SYS_FACE, n, &nfaces);
        /* loop through element faces */
        for (j = 1; j <= nfaces; j++) {
            if (VIEW_FLAG(flags, j) == 0)
                continue;
            vis_ConnectElemCon(connect, SYS_FACE, n, j, &nix, ix);
            vis_ConnectElemTopo(connect, SYS_FACE, n, j, &shape, &maxi, &maxj);
            if (stated != NULL) {
                vis_StateData(stated, nix, ix, (Vfloat*)x);
            }
            else {
                vis_ConnectCoords(connect, nix, ix, x);
            }
            vis_FaceSetTopology(face, shape, maxi, maxj);
            vis_FaceCurv(face, x, VIS_NODATA, NULL);
        }
    }
}

/*----------------------------------------------------------------------
                      Draw Element Face using IdTran
----------------------------------------------------------------------*/
void
draw_ElemFaceIdTran(vis_IdTran* idtran, vis_Connect* connect, vis_State* stated, vis_Face* face)
{
    Vint maxind;
    Vint i, n, j;
    Vint shape, maxi, maxj;
    Vint nix;
    Vint ix[VIS_MAXFACENODE];
    Vfloat x[VIS_MAXFACENODE][3];

    /* get number of indices with faces */
    vis_IdTranCount(idtran, IDTRAN_MAXINDEX, &maxind);
    /* draw element faces */
    /* loop through indices */
    for (i = 1; i <= maxind; i++) {
        vis_IdTranGetId(idtran, i, &n);
        if (n == 0)
            continue;
        /* get element face */
        vis_IdTranGetEnt(idtran, i, &j);
        vis_ConnectElemCon(connect, SYS_FACE, n, j, &nix, ix);
        vis_ConnectElemTopo(connect, SYS_FACE, n, j, &shape, &maxi, &maxj);
        if (stated != NULL) {
            vis_StateData(stated, nix, ix, (Vfloat*)x);
        }
        else {
            vis_ConnectCoords(connect, nix, ix, x);
        }
        vis_FaceSetTopology(face, shape, maxi, maxj);
        vis_FaceCurv(face, x, VIS_NODATA, NULL);
    }
}

/*----------------------------------------------------------------------
                      Draw Element Face Contours
----------------------------------------------------------------------*/
void
draw_ElemFaceContour(vis_Group* group, vis_Connect* connect, vis_State* state, vis_State* stated, vis_Contour* contour)
{
    Vint numel;
    Vint n, j;
    Vint flags;
    Vint nfaces;
    Vint shape, maxi, maxj;
    Vint nix;
    Vint ix[8];
    Vfloat x[8][3];
    Vfloat s[8];

    /* get number of elements */
    vis_ConnectNumber(connect, SYS_ELEM, &numel);
    /* contour on element faces */
    /* loop through elements */
    for (n = 1; n <= numel; n++) {
        vis_GroupGetIndex(group, n, &flags);
        if (flags == 0)
            continue;
        vis_ConnectElemNum(connect, SYS_FACE, n, &nfaces);
        /* loop through element faces */
        for (j = 1; j <= nfaces; j++) {
            if (VIEW_FLAG(flags, j) == 0)
                continue;
            vis_ConnectElemCon(connect, SYS_FACE, n, j, &nix, ix);
            vis_ConnectElemTopo(connect, SYS_FACE, n, j, &shape, &maxi, &maxj);
            if (stated != NULL) {
                vis_StateData(stated, nix, ix, (Vfloat*)x);
            }
            else {
                vis_ConnectCoords(connect, nix, ix, x);
            }
            vis_StateData(state, nix, ix, s);
            vis_ContourSetTopology(contour, shape, maxi, maxj);
            vis_ContourCurv(contour, s, x, VIS_NODATA, NULL);
        }
    }
}

/*----------------------------------------------------------------------
                      Draw Element Isosurfaces
----------------------------------------------------------------------*/
void
draw_ElemIsosurface(vis_Group* group, vis_Connect* connect, vis_State* state, vis_State* stated, vis_Threshold* threshold)
{
    Vint numel;
    Vint n;
    Vint shape, maxi, maxj, maxk;
    Vint nix;
    Vint flags;
    Vint ix[VIS_MAXCELLNODE];
    Vfloat x[VIS_MAXCELLNODE][3];
    Vfloat s[VIS_MAXCELLNODE];

    /* get number of elements */
    vis_ConnectNumber(connect, SYS_ELEM, &numel);
    /* loop through all elements */
    for (n = 1; n <= numel; n++) {
        if (group != NULL) {
            vis_GroupGetIndex(group, n, &flags);
            if (flags == 0)
                continue;
        }
        vis_ConnectTopology(connect, n, &shape, &maxi, &maxj, &maxk);
        if (shape == SYS_SHAPETET || shape == SYS_SHAPEPYR || shape == SYS_SHAPEWED || shape == SYS_SHAPEHEX) {
            /* draw isosurfaces */
            vis_ConnectElemNode(connect, n, &nix, ix);
            if (stated != NULL) {
                vis_StateData(stated, nix, ix, (Vfloat*)x);
            }
            else {
                vis_ConnectCoords(connect, nix, ix, x);
            }
            vis_StateData(state, nix, ix, s);
            vis_ThresholdSetTopology(threshold, shape, maxi, maxj, maxk);
            vis_ThresholdCurv(threshold, s, x, VIS_NODATA, NULL);
        }
    }
}

/*----------------------------------------------------------------------
                      Draw Node Markers
----------------------------------------------------------------------*/
void
draw_NodeMark(vis_Group* group, vis_Connect* connect, Vint datatype, vis_State* state, vis_State* stated, vis_Mark* mark)
{
    Vint numnp;
    Vint n;
    Vint flags;
    Vfloat x[3];
    Vfloat s[6];

    /* get number of nodes */
    vis_ConnectNumber(connect, SYS_NODE, &numnp);
    /* markers at nodes */
    /* loop through nodes */
    for (n = 1; n <= numnp; n++) {
        if (group != NULL) {
            vis_GroupGetIndex(group, n, &flags);
            if (flags == 0)
                continue;
        }
        if (stated != NULL) {
            vis_StateData(stated, 1, &n, x);
        }
        else {
            vis_ConnectCoords(connect, 1, &n, (Vfloat(*)[3])x);
        }
        vis_StateData(state, 1, &n, s);
        if (datatype == VIS_SCALAR) {
            vis_MarkScalar(mark, 1, s, (Vfloat(*)[3])x);
        }
        else if (datatype == VIS_VECTOR) {
            vis_MarkVector(mark, 1, (Vfloat(*)[3])s, (Vfloat(*)[3])x);
        }
        else if (datatype == VIS_TENSOR) {
            vis_MarkTensor(mark, 1, (Vfloat(*)[6])s, (Vfloat(*)[3])x);
        }
    }
}

10.21. Example 31, Perform Element Checking Using ElemChk.

This example illustrates the use of an ElemChk object to perform a number of element checks including calculation of shape distortion parameters, consistency of normals and size growth rate. In this example three quadrilateral elements and eight nodes are defined. Each element size and shape is varied to illustrate the shape parameters which are computed. The sense of the connectivity of the third element has been reversed so that the consistent normal or handedness check will detect it. An ElemChk object requires access to finite element model information via a GridFun object. A Connect object is instanced to hold the finite element model and a GridFun object is prepared. An ElemChk object is instanced and the GridFun object is registered with it.

The first element check is the computation of a set of shape parameters using vis_ElemChkData(). A State object is instanced to hold the element area in preparation for the area growth rate calculation to occur later. The function vis_ElemChkSetType() is called to specify the types of shape parameters to be calculated. Next, element normals are computed using vis_ElemChkNorm(). It can be seen that the normal of element 3 is reversed and the edge flags for both element 2 and 3 flag the edge adjacent to the element with the inconsistent connectivity sense. Lastly, the growth rate of the element size of computed for all elements using vis_ElemChkRate(). The results of each element check are printed out.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                8
              . .
             .  .
           7    6
           .  . .
  y        . .  .
  |        5    .
  --x      .    .
           3....4
           .    .
           .    .
           1....2
*/
#define MAX_ELEM 3
#define MAX_NODE 8

static Vint conn[MAX_ELEM][4] = {{1, 2, 4, 3}, {3, 4, 6, 5}, {5, 7, 8, 6}};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {2., 0., 0.}, {0., 2., 0.}, {2., 2., 0.},
                                     {0., 3., 0.}, {2., 4., 0.}, {0., 4., 0.}, {2., 5., 0.}};

/*----------------------------------------------------------------------
                      Element Checking
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Connect* connect;
    vis_ElemChk* elemchk;
    vis_State* state;
    vis_GridFun* gf;
    Vfloat s[ELEMCHK_MAX];
    Vfloat vn[3];
    Vint edgeflags;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies and element connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, SYS_SHAPEQUAD, 2, 0, 0);
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* generate connect kernel */
    vis_ConnectKernel(connect, 0);

    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create a ElemChk object */
    elemchk = vis_ElemChkBegin();

    /* install GridFun object */
    vis_ElemChkSetObject(elemchk, VIS_GRIDFUN, gf);

    /* instance a state object to hold areas */
    state = vis_StateBegin();
    vis_StateDef(state, MAX_ELEM, SYS_ELEM, SYS_NONE, SYS_SCALAR);

    /* set area, taper, skew and aspect ratio */
    vis_ElemChkSetType(elemchk, ELEMCHK_JACOBIAN_SUM, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_FACE_TAPER, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_SKEW, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_ASPECT_RATIO, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_EDGEALT_RATIO, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_CG_X, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_MIN_ANGLE, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_MAX_ANGLE, SYS_ON);
    vis_ElemChkSetType(elemchk, ELEMCHK_HANDEDNESS, SYS_ON);

    /* compute shape parameters */
    printf("Shape Parameters\n");
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_ElemChkData(elemchk, i, s);
        printf("element= %d\n", i);
        printf(" area          = %e\n", s[ELEMCHK_JACOBIAN_SUM]);
        printf(" taper         = %e\n", s[ELEMCHK_FACE_TAPER]);
        printf(" skew          = %e\n", s[ELEMCHK_SKEW]);
        printf(" aspect ratio  = %e\n", s[ELEMCHK_ASPECT_RATIO]);
        printf(" edgealt ratio = %e\n", s[ELEMCHK_EDGEALT_RATIO]);
        printf(" cg            = %e %e %e\n", s[ELEMCHK_CG_X], s[ELEMCHK_CG_Y], s[ELEMCHK_CG_Z]);
        printf(" min angle     = %e\n", s[ELEMCHK_MIN_ANGLE]);
        printf(" max angle     = %e\n", s[ELEMCHK_MAX_ANGLE]);
        printf(" handedness    = %e\n", s[ELEMCHK_HANDEDNESS]);
        vis_StateSetData(state, i, &s[ELEMCHK_JACOBIAN_SUM]);
    }
    /* check normals */
    printf("Check Normals\n");
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_ElemChkNorm(elemchk, NULL, i, vn, &edgeflags);
        printf("element= %d\n", i);
        printf(" normal    = %f,%f,%f\n", vn[0], vn[1], vn[2]);
        printf(" edgeflags = %d\n", edgeflags);
    }
    /* growth rate */
    printf("Growth Rate\n");
    for (i = 1; i <= MAX_ELEM; i++) {
        vis_ElemChkRate(elemchk, state, NULL, i, s);
        printf("element= %d\n", i);
        printf(" maximum rate   = %e\n", s[0]);
        printf(" maximum change = %e\n", s[1]);
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_ElemChkEnd(elemchk);
    vis_StateEnd(state);
    return 0;
}

10.22. Example 31a, Compute Model Mass Properties Using MassPrp

This example illustrates the use of a MassPrp object to compute mass properties of a model. The model consists of 2 solid elements. The density is 1.e-5. The minimum requirements of the model are the node coordinates, element connectivity, type and element property identifier or material identifier and associated element property objects, EProp and/or material property objects, MProp. If an element property identifier is specified, VIS_PROPID, then a HashTable of EProp objects must be generated which contain an EProp object for each unique element property identifier. These EProp objects must in turn contain a material property identifier. Alternatively, a material identifier may be specified, VIS_MATLID, which references an MProp object directly without the need for an intermediate EProp object. A HashTable of MProp objects must be specified and contain an MProp object for each unique material property identifier. A MassPrp object is instanced and the Model object is registered with it.

The mass properties are computed using vis_MassPrpCompute(). The total mass, center of mass and inertia tensor about the center of mass are computed and printed. The function vis_MassPrpPrincipal() is used to compute the principal values and directions of the inertia tensor.

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 4------5------6
                /.     /.     /.
               / .    / .    / .
              /  .   /  .   /  .
             /   1../...2../...3
            10-----11-----12  /
            |  .   |  .   |  /
            | .    | .    | /
            |.     |.     |/
            7------8------9

         y
         |
         --- x
       /
      z
*/
#define MAX_ELEM 2
#define MAX_NODE 12

/* element connectivity */
static Vint conn[MAX_ELEM][8] = {{1, 2, 5, 4, 7, 8, 11, 10}, {2, 3, 6, 5, 8, 9, 12, 11}};

/* element topologies */
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX};
static Vint maxi[MAX_ELEM] = {2, 2};
/* element types */
static Vint featype[MAX_ELEM] = {VIS_ELEM_SOLID, VIS_ELEM_SOLID};

/* element property ids */
static Vint pid[MAX_ELEM] = {1, 1};
/* node coordinates */
static Vdouble coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {0., 1., 0.}, {1., 1., 0.}, {2., 1., 0.},
                                      {0., 0., 3.}, {1., 0., 3.}, {2., 0., 3.}, {0., 1., 3.}, {1., 1., 3.}, {2., 1., 3.}};

/*----------------------------------------------------------------------
                      Model Mass Properties Using MassPrp
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Model* model;
    vis_Connect* connect;
    vis_MassPrp* massprp;
    vis_MProp* mprop;
    vis_EProp* eprop;
    vsy_HashTable *ephash, *mphash;
    Vfloat vtot, mtot, xcom[3], mten[6];
    Vfloat mpri[3], tm[3][3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectPre(connect, SYS_DOUBLE);
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set node coordinates and user ids */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoordsdv(connect, i + 1, coords[i]);
    }
    /* set element topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], maxi[i], 0, 0);
    }
    /* set element node connectivity and associations */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEATYPE, i + 1, featype[i]);
        vis_ConnectSetElemAssoc(connect, VIS_PROPID, i + 1, pid[i]);
    }

    /* create model object hierarchy */
    model = vis_ModelBegin();

    /* hashtables of properties */
    mphash = vsy_HashTableBegin();
    ephash = vsy_HashTableBegin();

    /* material 1 */
    mprop = vis_MPropBegin();
    vis_MPropDef(mprop, SYS_MAT_ISOTROPIC);
    vis_MPropSetValued(mprop, MPROP_E, 1.e+7);
    vis_MPropSetValued(mprop, MPROP_NU, .3);
    vis_MPropSetValued(mprop, MPROP_DENSITY, 1.e-05);
    vsy_HashTableInsert(mphash, 1, mprop);

    /* solid property 1 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SOLID);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vsy_HashTableInsert(ephash, 1, eprop);

    /* register Connect in Model */
    vis_ModelSetObject(model, VIS_CONNECT, connect);

    /* register property hashtables in Model */
    vis_ModelSetHashTable(model, VIS_MPROP, mphash);
    vis_ModelSetHashTable(model, VIS_EPROP, ephash);

    /* compute and print mass properties */
    massprp = vis_MassPrpBegin();
    vis_MassPrpSetObject(massprp, VIS_MODEL, model);
    vis_MassPrpCompute(massprp, NULL, &vtot, &mtot, xcom, mten);

    printf("Total volume   = %e\n", vtot);
    printf("Total mass     = %e\n", mtot);
    printf("Center of mass = %e %e %e\n", xcom[0], xcom[1], xcom[2]);
    printf("Inertia tensor = %e %e %e\n", mten[0], mten[1], mten[2]);
    printf("                 %e %e %e\n", mten[3], mten[4], mten[5]);

    /* compute principal values and directions */
    vis_MassPrpPrincipal(massprp, mten, mpri, tm);
    printf("Principal values = %e %e %e\n", mpri[0], mpri[1], mpri[2]);
    printf("Principal directions = %e %e %e\n", tm[0][0], tm[0][1], tm[0][2]);
    printf("                     = %e %e %e\n", tm[1][0], tm[1][1], tm[1][2]);
    printf("                     = %e %e %e\n", tm[2][0], tm[2][1], tm[2][2]);

    /* delete objects */
    vis_MassPrpEnd(massprp);
    /* Use convenience routine ModelDelete to destroy
       all objects registered in Model */
    vis_ModelDelete(model);
    /* finally destroy Model object */
    vis_ModelEnd(model);
    return 0;
}

10.23. Example 32, Manage Loads Using LCase

This example illustrates the use of a LCase object to manage concentrated nodal loads, distributed element loads and overall model accelerations on a small finite element model consisting of two 8-node hexahedra and one 4-node quadrilateral. The model is loaded into a Connect object. A GridFun object is instanced and loaded with model query functions. This set of functions is required to manage element distributed loads with LCase. A LCase object is instanced and the GridFun object is set in it using vis_LCaseSetObject(). A concentrated nodal force is defined with vis_LCaseSetConc(). Element face distributed loads are defined with vis_LCaseSetDist() and finally overall model accelerations are defined using vis_LCaseSetAccel(). The concentrated nodal loads are queried and printed by first using vis_LCaseNodeGroup() to fill a node group with the nodes at which concentrated loads have been defined. Then a loop over the nodes in the node group is entered. Specific concentrated loads are queried by calling vis_LCaseConcType() and vis_LCaseConc() in succession. The procedure for querying distributed element face and edge loads is similar. Use vis_LCaseFaceGroup() and vis_LCaseEdgeGroup() to fill element face and edge groups with the entities which have had distributed loads defined. Then loop over the respective group calling vis_LCaseDistType() and vis_LCaseDist() in succession to query for the actual distributed load types, coordinate systems and values.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Manage Loads Using LCase
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_GridFun* gf;
    vis_LCase* lcase;
    vis_Group *nodegroup, *facegroup, *edgegroup, *elemgroup;
    Vint i, j;
    Vfloat force[3], dist[3 * 4], body[3 * 8];
    Vint index, no, flags;
    Vint numtypes, types[3];
    Vfloat values[3 * 8];
    Vfloat grav[3], cent[3], w[3], wdot[3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }

    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }

    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create gridfun object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* instance LCase object */
    lcase = vis_LCaseBegin();
    vis_LCaseSetObject(lcase, VIS_GRIDFUN, gf);

    /* specify concentrated nodal load at node 2 */
    force[0] = 1.;
    force[1] = 2.;
    force[2] = 3.;
    vis_LCaseSetConc(lcase, 2, LCASE_FORCE, force);

    /* specify constant pressure on face 2 of element 1 */
    dist[0] = 100.;
    dist[1] = 100.;
    dist[2] = 100.;
    dist[3] = 100.;
    vis_LCaseSetDist(lcase, SYS_FACE, 1, 2, LCASE_PRES, dist);

    /* specify tractions on nodes of face 3 of element 2 */
    dist[0] = 200.;
    dist[1] = 0.;
    dist[2] = 0.;
    dist[3] = 200.;
    dist[4] = 0.;
    dist[5] = 0.;
    dist[6] = 150.;
    dist[7] = 0.;
    dist[8] = 0.;
    dist[9] = 150.;
    dist[10] = 0.;
    dist[11] = 0.;
    vis_LCaseSetDist(lcase, SYS_FACE, 2, 3, LCASE_TRAC, dist);

    /* specify varying moment along edge 1 of element 3 */
    dist[0] = 20.;
    dist[1] = 30.;
    vis_LCaseSetDist(lcase, SYS_EDGE, 3, 1, LCASE_TANGMOMENT, dist);

    /* body force for element 3 */
    body[0] = 100.;
    body[1] = 0.;
    body[2] = 0.;
    body[3] = 200.;
    body[4] = 0.;
    body[5] = 0.;
    body[6] = 200.;
    body[7] = 0.;
    body[8] = 0.;
    body[9] = 100.;
    body[10] = 0.;
    body[11] = 0.;
    vis_LCaseSetElem(lcase, 3, LCASE_ACCLELEM, body);

    /* specify accelerations */
    grav[0] = 0.;
    grav[1] = 0.;
    grav[2] = 32.;
    cent[0] = 0.;
    cent[1] = 0.;
    cent[2] = 0.;
    w[0] = 1.;
    w[1] = 0.;
    w[2] = 0.;
    wdot[0] = 0.;
    wdot[1] = 0.;
    wdot[2] = 0.;
    vis_LCaseSetAccel(lcase, grav, cent, w, wdot);

    /* query concentrated nodal loads */
    nodegroup = vis_GroupBegin();
    vis_GroupDef(nodegroup, MAX_NODE, SYS_NODE, SYS_NONE);
    vis_GroupClear(nodegroup);

    /* group of nodes with concentrated loads */
    vis_LCaseNodeGroup(lcase, NULL, nodegroup);

    /* iterate through node group */
    printf("\nConcentrated Loads\n");
    vis_GroupInitIndex(nodegroup);
    while (vis_GroupNextIndex(nodegroup, &index, &flags), index) {
        printf("node= %d\n", index);
        vis_LCaseConcType(lcase, index, &numtypes, types);

        /* loop through load types */
        for (i = 0; i < numtypes; i++) {
            vis_LCaseConc(lcase, index, types[i], values);
            printf(" values= %f %f %f\n", values[0], values[1], values[2]);
        }
    }
    /* query element loads */
    elemgroup = vis_GroupBegin();
    vis_GroupDef(elemgroup, MAX_ELEM, SYS_ELEM, SYS_NONE);
    vis_GroupClear(elemgroup);

    /* group of elements with element body loads */
    vis_LCaseElemGroup(lcase, NULL, elemgroup);

    /* iterate through element group */
    printf("\nElement Loads\n");
    vis_GroupInitIndex(elemgroup);
    while (vis_GroupNextIndex(elemgroup, &index, &flags), index) {
        printf("elem= %d\n", index);
        vis_LCaseElemType(lcase, index, &numtypes, types);

        /* loop through load types */
        for (i = 0; i < numtypes; i++) {
            vis_LCaseElem(lcase, index, types[i], values);
            for (j = 0; j < 4; j++) {
                printf(" %f %f %f\n", values[3 * j], values[3 * j + 1], values[3 * j + 2]);
            }
        }
    }
    /* query element face distributed loads */
    facegroup = vis_GroupBegin();
    vis_GroupDef(facegroup, MAX_ELEM, SYS_ELEM, SYS_FACE);
    vis_GroupClear(facegroup);

    /* group of element faces with distributed loads */
    vis_LCaseFaceGroup(lcase, NULL, facegroup);

    /* iterate through element face group */
    printf("\nElement Face Loads\n");
    vis_GroupInitIndex(facegroup);
    while (vis_GroupNextIndex(facegroup, &index, &flags), index) {
        printf("elem= %d\n", index);

        /* loop through faces */
        for (no = 1; no <= 6; no++) {
            if (VIEW_FLAG(flags, no) == 0)
                continue;
            printf(" face= %d\n", no);
            vis_LCaseDistType(lcase, SYS_FACE, index, no, &numtypes, types);

            /* loop through load types */
            for (i = 0; i < numtypes; i++) {
                vis_LCaseDist(lcase, SYS_FACE, index, no, types[i], 0, values);
                if (types[i] == LCASE_PRES) {
                    printf("  type= Pressure\n");
                    for (j = 0; j < 4; j++) {
                        printf(" %f\n", values[j]);
                    }
                }
                else if (types[i] == LCASE_TRAC) {
                    printf("  type= Traction\n");
                    for (j = 0; j < 4; j++) {
                        printf(" %f %f %f\n", values[3 * j], values[3 * j + 1], values[3 * j + 2]);
                    }
                }
            }
        }
    }

    /* query element edge distributed loads */
    edgegroup = vis_GroupBegin();
    vis_GroupDef(edgegroup, MAX_ELEM, SYS_ELEM, SYS_EDGE);
    vis_GroupClear(edgegroup);

    /* group of element edges with distributed loads */
    vis_LCaseEdgeGroup(lcase, NULL, edgegroup);

    /* iterate through element edge group */
    printf("\nElement Edge Loads\n");
    vis_GroupInitIndex(edgegroup);
    while (vis_GroupNextIndex(edgegroup, &index, &flags), index) {
        printf("elem= %d\n", index);

        /* loop through edges */
        for (no = 1; no <= 12; no++) {
            if (VIEW_FLAG(flags, no) == 0)
                continue;
            printf(" edge= %d\n", no);
            vis_LCaseDistType(lcase, SYS_EDGE, index, no, &numtypes, types);

            /* loop through load types */
            for (i = 0; i < numtypes; i++) {
                vis_LCaseDist(lcase, SYS_EDGE, index, no, types[i], 0, values);
                if (types[i] == LCASE_TANGMOMENT) {
                    printf("  type= Tangent Moment\n");
                    for (j = 0; j < 2; j++) {
                        printf(" %f\n", values[j]);
                    }
                }
            }
        }
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_LCaseEnd(lcase);
    vis_GroupEnd(nodegroup);
    vis_GroupEnd(elemgroup);
    vis_GroupEnd(facegroup);
    vis_GroupEnd(edgegroup);
    return 0;
}

10.24. Example 32a, Manage Contact Pairs Using CPair

This example illustrates the use of a CPair object to manage pairs of contacting surfaces on a small finite element model consisting of two 8-node hexahedra and one 4-node quadrilateral. The model is loaded into a Connect object. A GridFun object is instanced and loaded with model query functions. This set of functions is required to manage element based surfaces with CPair. A CPair object is instanced and the GridFun object is set in it using vis_CPairSetObject(). In this example the master surface is to be defined as an element face while the slave “surface” is to defined as a set of nodes. The function vis_CPairDef() is used to indicate the entity type to be used to define the master and slave surfaces. A master surface is defined as face 1 of solid element 2 using vis_CPairSetMaster(). A slave surface is defined as nodes 4 and 8 using vis_CPairSetSlaveNode().

The slave surface nodes are queried and printed by first using vis_CPairNodeGroup() to fill a node group with the nodes defined on the slave surface. Then a loop over the nodes in the node group is entered in which vis_CPairSlaveNode() is called to query the slave node area. The master surface element faces are queried by calling vis_CPairFaceGroup().

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7      8-----16
  --x        /   1../...2../|      |      |
 /         12-----13-----14 |      |      |
z           |  .   |  .   |.|      |      |
            | .    | .    | 3      4-----15
            |.     |.     |/
            9-----10-----11
*/

#define MAX_ELEM 3
#define MAX_NODE 16

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {4, 15, 16, 8, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.}, {1., 1., 0.},
                                     {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.}, {2., 0., 2.}, {0., 1., 2.},
                                     {1., 1., 2.}, {2., 1., 2.}, {4., 0., 1.}, {4., 1., 1.}};

/*----------------------------------------------------------------------
                      Manage Contact Pairs Using CPair
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Connect* connect;
    vis_GridFun* gf;
    vis_CPair* cpair;
    vis_IdTran *nodeidtran, *faceidtran;
    Vdouble area;
    Vint index, num, no;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create gridfun object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* instance CPair object */
    cpair = vis_CPairBegin();

    /* master surface is defined by element faces */
    /* slave surface is defined by nodes */
    vis_CPairDef(cpair, SYS_FACE, SYS_NODE);
    vis_CPairSetObject(cpair, VIS_GRIDFUN, gf);

    /* specify master surface as element faces */
    vis_CPairSetMaster(cpair, 2, 1);

    /* specify slave surface as nodes */
    vis_CPairSetSlaveNodedv(cpair, 4, 1.);
    vis_CPairSetSlaveNodedv(cpair, 8, 1.);

    /* define properties */
    vis_CPairSetValuei(cpair, CPAIR_PID, 20);
    /* Adjust parameter */
    vis_CPairSetValued(cpair, CPAIR_ADJUST, .1);

    /* query slave nodes */
    nodeidtran = vis_IdTranBegin();
    /* slave nodes */
    vis_CPairNodeIdTran(cpair, nodeidtran);

    /* iterate through nodes */
    printf("\nSlave Nodes\n");
    vis_IdTranCount(nodeidtran, IDTRAN_NUMINDICES, &num);
    for (i = 1; i <= num; i++) {
        vis_IdTranGetId(nodeidtran, i, &index);
        vis_CPairSlaveNodedv(cpair, index, &area);
        printf("node= %d, area= %e\n", index, area);
    }

    /* query master element faces */
    faceidtran = vis_IdTranBegin();
    /* element faces */
    vis_CPairFaceIdTran(cpair, CPAIR_MASTER, faceidtran);

    /* iterate through element faces */
    printf("\nMaster Element Faces\n");
    vis_IdTranCount(faceidtran, IDTRAN_NUMINDICES, &num);
    for (i = 1; i <= num; i++) {
        vis_IdTranGetId(faceidtran, i, &index);
        vis_IdTranGetEnt(faceidtran, i, &no);
        printf("elem= %d, face= %d\n", index, no);
    }

    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_CPairEnd(cpair);
    vis_IdTranEnd(nodeidtran);
    vis_IdTranEnd(faceidtran);
    return 0;
}

10.25. Example 32b, Manage Analytic Surfaces using ASurf

This example illustrates the use of the ASurf object to manage analytic surfaces. Three ASurf objects are instanced and placed into a HashTable. The three analytic surfaces are a sphere, a plane of finite extent and a surface of revolution. Most analytic surfaces are orientable (the exception is the sphere). In the case of a segmented surface, the input points, defined using vis_ASurfSetPoint(), are in this oriented local coordinate system.

The ASurf objects in the HashTable are then traversed and the appropriate query functions are using to access the analytic surface information and print it to standard output.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Analytic Surfaces using ASurf
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vsy_HashTable* ht;
    vis_ASurf* asurf;
    Vfloat x[3], r;
    Vfloat a[3], b[3], c[3], length, width;
    Vint type, id, segtype;
    Vint ix[3], numpnt, numseg;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create HashTable to hold ASurf objects */
    ht = vsy_HashTableBegin();
    /* create ASurf object for a sphere */
    asurf = vis_ASurfBegin();
    vis_ASurfDef(asurf, ASURF_SPHERE);
    x[0] = 0.;
    x[1] = 1.;
    x[2] = 1.;
    r = 2.;
    vis_ASurfSetSphere(asurf, x, r);
    vsy_HashTableInsert(ht, 10, asurf);
    /* create ASurf object for a plane */
    asurf = vis_ASurfBegin();
    vis_ASurfDef(asurf, ASURF_PLANE);
    a[0] = 0.;
    a[1] = 0.;
    a[2] = 0.;
    b[0] = 1.;
    b[1] = 0.;
    b[2] = 0.;
    c[0] = 0.;
    c[1] = 1.;
    c[2] = 0.;
    length = 3.;
    width = 4.;
    vis_ASurfSetPlane(asurf, a, b, c, length, width);
    vsy_HashTableInsert(ht, 20, asurf);
    /* create ASurf object for a surface of revolution */
    asurf = vis_ASurfBegin();
    vis_ASurfDef(asurf, ASURF_SEGMENT_REV);
    /* set local coordinate system */
    a[0] = 0.;
    a[1] = 0.;
    a[2] = 0.;
    b[0] = 1.;
    b[1] = 0.;
    b[2] = 0.;
    c[0] = 0.;
    c[1] = 1.;
    c[2] = 0.;
    vis_ASurfSetSegmentRev(asurf, a, b, c);
    /* points in local x-z plane, revolve about local z axis */
    /* set points */
    x[0] = 2.;
    x[1] = 0.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 1, x);
    x[0] = 2.;
    x[1] = 2.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 2, x);
    x[0] = 1.;
    x[1] = 3.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 3, x);
    /* circle center */
    x[0] = 1.;
    x[1] = 2.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 4, x);
    /* set segments */
    ix[0] = 1;
    ix[1] = 2;
    vis_ASurfSetSegment(asurf, 1, ASURF_SEG_LINE, ix);
    ix[0] = 2;
    ix[1] = 4;
    ix[2] = 3;
    vis_ASurfSetSegment(asurf, 2, ASURF_SEG_ARC, ix);
    vsy_HashTableInsert(ht, 30, asurf);

    /* loop through HashTable */
    vsy_HashTableInitIter(ht);
    while (vsy_HashTableNextIter(ht, &id, (Vobject**)&asurf), asurf) {
        vis_ASurfInq(asurf, &type);
        if (type == ASURF_SPHERE) {
            vis_ASurfGetSphere(asurf, x, &r);
            printf("Sphere, id= %d, x= %f %f %f, r= %f\n", id, x[0], x[1], x[2], r);
        }
        else if (type == ASURF_PLANE) {
            vis_ASurfGetPlane(asurf, a, b, c, &length, &width);
            printf("Plane, id= %d, a= %f %f %f\n", id, a[0], a[1], a[2]);
            printf("               b= %f %f %f\n", b[0], b[1], b[2]);
            printf("               c= %f %f %f\n", c[0], c[1], c[2]);
            printf("               length= %f, width= %f\n", length, width);
        }
        else if (type == ASURF_SEGMENT_REV) {
            vis_ASurfNumPoints(asurf, &numpnt);
            vis_ASurfNumSegments(asurf, &numseg);
            printf("Segment Rev, id= %d, numpnts= %d, numseg= %d\n", id, numpnt, numseg);
            vis_ASurfGetSegmentRev(asurf, a, b, c);
            printf("             a= %f %f %f\n", a[0], a[1], a[2]);
            printf("             b= %f %f %f\n", b[0], b[1], b[2]);
            printf("             c= %f %f %f\n", c[0], c[1], c[2]);
            for (i = 1; i <= numpnt; i++) {
                vis_ASurfGetPoint(asurf, i, x);
                printf(" point, id= %d, x= %f %f %f\n", i, x[0], x[1], x[2]);
            }
            for (i = 1; i <= numseg; i++) {
                vis_ASurfGetSegment(asurf, i, &segtype, ix);
                if (segtype == ASURF_SEG_LINE) {
                    printf(" seg line, id= %d, ix= %d %d\n", i, ix[0], ix[1]);
                }
                else if (segtype == ASURF_SEG_ARC) {
                    printf(" seg arc,  id= %d, ix= %d %d %d\n", i, ix[0], ix[1], ix[2]);
                }
            }
        }
    }
    /* end objects */
    vsy_HashTableForEach(ht, (void (*)(void*))vis_ASurfEnd);
    vsy_HashTableEnd(ht);
    return 0;
}

10.26. Example 32c, Manage Complex Loads Using LCase

This example is a modification of Example 32 and illustrates the use of a LCase object to manage complex valued concentrated nodal loads and distributed element loads. In this example double precision functions are used.

Complex valued loads are specified using the same functions as real valued loads. The function vis_LCaseSetComplexMode() is used to place the LCase object in the mode to expect either the real and/or imaginary parts of a complex number in all functions which set or query nodal concentrated and element distributed load value. In this case the real and imaginary parts are to be entered simultaneously so the complex mode is set to SYS_COMPLEX_REALIMAGINARY.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Manage Complex Loads Using LCase
----------------------------------------------------------------------*/
int
main()
{
    vis_Connect* connect;
    vis_GridFun* gf;
    vis_LCase* lcase;
    vis_Group *nodegroup, *facegroup, *edgegroup, *elemgroup;
    Vint i, j;
    Vdouble formom[2 * 6], dist[2 * 3 * 4], body[2 * 3 * 8];
    Vint index, no, flags;
    Vint numtypes, types[3];
    Vdouble values[2 * 3 * 8];
    Vint tid[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create gridfun object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* instance LCase object */
    lcase = vis_LCaseBegin();
    vis_LCaseSetObject(lcase, VIS_GRIDFUN, gf);

    /* real and imaginary parts */
    vis_LCaseSetComplexMode(lcase, SYS_COMPLEX_REALIMAGINARY);
    /* specify concentrated nodal force and moment at node 2 */
    formom[0] = 1.;
    formom[1] = 11.;
    formom[2] = 2.;
    formom[3] = 21.;
    formom[4] = 3.;
    formom[5] = 31.;
    vis_LCaseSetConcdv(lcase, 2, LCASE_FORCE, formom);
    formom[0] = 4.;
    formom[1] = 41.;
    formom[2] = 5.;
    formom[3] = 51.;
    formom[4] = 6.;
    formom[5] = 61.;
    vis_LCaseSetConcdv(lcase, 2, LCASE_MOMENT, formom);

    /* specify pressure on face 2 of element 1 */
    dist[0] = 100.;
    dist[1] = 101.;
    dist[2] = 200.;
    dist[3] = 201.;
    dist[4] = 300.;
    dist[5] = 301.;
    dist[6] = 400.;
    dist[7] = 401.;
    vis_LCaseSetDistdv(lcase, SYS_FACE, 1, 2, LCASE_PRES, dist);
    /* set specific table id's for real/imaginary parts */
    tid[0] = 1;
    tid[1] = 2;
    vis_LCaseSetDistTId(lcase, SYS_FACE, 1, 2, LCASE_PRES, tid);

    /* specify varying moment along edge 1 of element 3 */
    dist[0] = 20.;
    dist[1] = 30.;
    dist[2] = 21.;
    dist[3] = 31.;
    vis_LCaseSetDistdv(lcase, SYS_EDGE, 3, 1, LCASE_TANGMOMENT, dist);

    /* body force for element 3,
       complex vector at each of 4 nodes on element */
    body[0] = 100.;
    body[1] = 101.;
    body[2] = 0.;
    body[3] = 0.;
    body[4] = 0.;
    body[5] = 0.;
    body[6] = 200.;
    body[7] = 201.;
    body[8] = 0.;
    body[9] = 0.;
    body[10] = 0.;
    body[11] = 0.;
    body[12] = 200.;
    body[13] = 201.;
    body[14] = 0.;
    body[15] = 0.;
    body[16] = 0.;
    body[17] = 0.;
    body[18] = 100.;
    body[19] = 101.;
    body[20] = 0.;
    body[21] = 0.;
    body[22] = 0.;
    body[23] = 0.;
    vis_LCaseSetElemdv(lcase, 3, LCASE_ACCLELEM, body);

    /* query concentrated nodal loads */
    nodegroup = vis_GroupBegin();
    vis_GroupDef(nodegroup, MAX_NODE, SYS_NODE, SYS_NONE);
    vis_GroupClear(nodegroup);

    /* group of nodes with concentrated loads */
    vis_LCaseNodeGroup(lcase, NULL, nodegroup);

    /* iterate through node group */
    printf("\nConcentrated Loads\n");
    vis_GroupInitIndex(nodegroup);
    while (vis_GroupNextIndex(nodegroup, &index, &flags), index) {
        printf("node= %d\n", index);
        vis_LCaseConcType(lcase, index, &numtypes, types);

        /* loop through load types */
        for (i = 0; i < numtypes; i++) {
            vis_LCaseConcdv(lcase, index, types[i], values);
            printf(" values= %f %f(i) %f %f(i) %f %f(i)\n", values[0], values[1], values[2], values[3], values[4], values[5]);
        }
    }
    /* query element loads */
    elemgroup = vis_GroupBegin();
    vis_GroupDef(elemgroup, MAX_ELEM, SYS_ELEM, SYS_NONE);
    vis_GroupClear(elemgroup);

    /* group of elements with element body loads */
    vis_LCaseElemGroup(lcase, NULL, elemgroup);

    /* iterate through element group */
    printf("\nElement Loads\n");
    vis_GroupInitIndex(elemgroup);
    while (vis_GroupNextIndex(elemgroup, &index, &flags), index) {
        printf("elem= %d\n", index);
        vis_LCaseElemType(lcase, index, &numtypes, types);

        /* loop through load types */
        for (i = 0; i < numtypes; i++) {
            vis_LCaseElemdv(lcase, index, types[i], values);
            for (j = 0; j < 4; j++) {
                printf(" %f %f(i) %f %f(i) %f %f(i)\n", values[2 * 3 * j], values[2 * 3 * j + 1], values[2 * 3 * j + 2],
                       values[2 * 3 * j + 3], values[2 * 3 * j + 4], values[2 * 3 * j + 5]);
            }
        }
    }
    /* query element face distributed loads */
    facegroup = vis_GroupBegin();
    vis_GroupDef(facegroup, MAX_ELEM, SYS_ELEM, SYS_FACE);
    vis_GroupClear(facegroup);

    /* group of element faces with distributed loads */
    vis_LCaseFaceGroup(lcase, NULL, facegroup);

    /* iterate through element face group */
    printf("\nElement Face Loads\n");
    vis_GroupInitIndex(facegroup);
    while (vis_GroupNextIndex(facegroup, &index, &flags), index) {
        printf("elem= %d\n", index);

        /* loop through faces */
        for (no = 1; no <= 6; no++) {
            if (VIEW_FLAG(flags, no) == 0)
                continue;
            printf(" face= %d\n", no);
            vis_LCaseDistType(lcase, SYS_FACE, index, no, &numtypes, types);

            /* loop through load types */
            for (i = 0; i < numtypes; i++) {
                vis_LCaseDistdv(lcase, SYS_FACE, index, no, types[i], 0, values);
                vis_LCaseDistTId(lcase, SYS_FACE, index, no, types[i], tid);
                if (types[i] == LCASE_PRES) {
                    printf("  type= Pressure\n");
                    for (j = 0; j < 4; j++) {
                        printf(" %f %f(i)\n", values[2 * j], values[2 * j + 1]);
                    }
                    printf(" %d %d(i)\n", tid[0], tid[1]);
                }
                else if (types[i] == LCASE_TRAC) {
                    printf("  type= Traction\n");
                    for (j = 0; j < 4; j++) {
                        printf(" %f %f(i) %f %f(i) %f %f(i)\n", values[2 * 3 * j], values[2 * 3 * j + 1], values[2 * 3 * j + 2],
                               values[2 * 3 * j + 3], values[2 * 3 * j + 4], values[2 * 3 * j + 5]);
                    }
                }
            }
        }
    }

    /* query element edge distributed loads */
    edgegroup = vis_GroupBegin();
    vis_GroupDef(edgegroup, MAX_ELEM, SYS_ELEM, SYS_EDGE);
    vis_GroupClear(edgegroup);

    /* group of element edges with distributed loads */
    vis_LCaseEdgeGroup(lcase, NULL, edgegroup);

    /* iterate through element edge group */
    printf("\nElement Edge Loads\n");
    vis_GroupInitIndex(edgegroup);
    while (vis_GroupNextIndex(edgegroup, &index, &flags), index) {
        printf("elem= %d\n", index);

        /* loop through edges */
        for (no = 1; no <= 12; no++) {
            if (VIEW_FLAG(flags, no) == 0)
                continue;
            printf(" edge= %d\n", no);
            vis_LCaseDistType(lcase, SYS_EDGE, index, no, &numtypes, types);

            /* loop through load types */
            for (i = 0; i < numtypes; i++) {
                vis_LCaseDistdv(lcase, SYS_EDGE, index, no, types[i], 0, values);
                if (types[i] == LCASE_TANGMOMENT) {
                    printf("  type= Tangent Moment\n");
                    for (j = 0; j < 2; j++) {
                        printf(" %f %f(i)\n", values[2 * j], values[2 * j + 1]);
                    }
                }
            }
        }
    }
    /* end objects */
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gf);
    vis_LCaseEnd(lcase);
    vis_GroupEnd(nodegroup);
    vis_GroupEnd(elemgroup);
    vis_GroupEnd(facegroup);
    vis_GroupEnd(edgegroup);
    return 0;
}

10.27. Example 32d, Draw Analytic Surfaces using ASurf and Glyph

This example illustrates the use of the ASurf and Glyph objects to manage and draw analytic surfaces. This example is an extension of Example 32b drawing the surfaces using the Glyph object rather than printing the surface data.

The sphere drawing is straight forward, using the default glyph orientation. The plane and segment revolution require the Glyph object to be oriented. This is done by computing the local x and y directions from a, b, and c values. The a location is the origin of the surface data which is present in the arguments to vis_GlyphRectangle() and vis_GlyphSegmentRev(). The ASurfGetPoint function returns 3 coordinate values. Only the first 2 are meaningful for drawing segmented surfaces.

#include <stdio.h>
#include "base/base.h"
#include "vgl/vgl.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

#include "glwin.h"

/*----------------------------------------------------------------------
                      Draw Analytic Surfaces using ASurf and Glyph
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j;
    vsy_HashTable* ht;
    vis_ASurf* asurf;
    Vfloat x[3], r, cg[3], xtxt[3], ctxt[3];
    Vfloat a[3], b[3], c[3], length, width;
    Vfloat xp[3], yp[3];
    Vfloat xs[4][3], xy[3][2];
    Vint type, id, segtype;
    Vint ix[3], numpnt, numseg;

    vgl_DrawFun* df;
    vis_VisContext* vc;
    vis_Glyph* glyph;
    GLWin* glwin;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create HashTable to hold ASurf objects */
    ht = vsy_HashTableBegin();
    /* create ASurf object for a sphere */
    asurf = vis_ASurfBegin();
    vis_ASurfDef(asurf, ASURF_SPHERE);
    x[0] = 0.;
    x[1] = 1.;
    x[2] = 1.;
    r = 2.;
    vis_ASurfSetSphere(asurf, x, r);
    vsy_HashTableInsert(ht, 10, asurf);
    /* create ASurf object for a plane */
    asurf = vis_ASurfBegin();
    vis_ASurfDef(asurf, ASURF_PLANE);
    a[0] = 0.;
    a[1] = 0.;
    a[2] = 0.;
    b[0] = 1.;
    b[1] = 0.;
    b[2] = 0.;
    c[0] = 0.;
    c[1] = 1.;
    c[2] = 0.;
    length = 3.;
    width = 4.;
    vis_ASurfSetPlane(asurf, a, b, c, length, width);
    vsy_HashTableInsert(ht, 20, asurf);
    /* create ASurf object for a surface of revolution */
    asurf = vis_ASurfBegin();
    vis_ASurfDef(asurf, ASURF_SEGMENT_REV);
    /* set local coordinate system */
    a[0] = 0.;
    a[1] = 0.;
    a[2] = 0.;
    b[0] = 1.;
    b[1] = 0.;
    b[2] = 0.;
    c[0] = 0.;
    c[1] = 1.;
    c[2] = 0.;
    vis_ASurfSetSegmentRev(asurf, a, b, c);
    /* points assumed in local x-z plane for revolve */
    /* set points */
    x[0] = 2.;
    x[1] = 0.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 1, x);
    x[0] = 2.;
    x[1] = 2.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 2, x);
    x[0] = 1.;
    x[1] = 3.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 3, x);
    /* circle center */
    x[0] = 1.;
    x[1] = 2.;
    x[2] = 0.;
    vis_ASurfSetPoint(asurf, 4, x);
    /* set segments */
    ix[0] = 1;
    ix[1] = 2;
    vis_ASurfSetSegment(asurf, 1, ASURF_SEG_LINE, ix);
    ix[0] = 2;
    ix[1] = 4;
    ix[2] = 3;
    vis_ASurfSetSegment(asurf, 2, ASURF_SEG_ARC, ix);
    vsy_HashTableInsert(ht, 30, asurf);

    /* now draw */
    /* create GL device */
    glwin = GLWinBegin();
    GLWinCreateWindow(glwin, 200, 200, 800, 800);
    GLWinOrtho(glwin, -4., 4., -4., 4., -4., 4.);

    /* create drawing function object for GL */
    df = vgl_DrawFunBegin();
    GLWinDrawFun(glwin, df);

    /* vis context and set attributes */
    vc = vis_VisContextBegin();
    vis_VisContextSetRefinement(vc, 2);
    vis_VisContextSetShade(vc, VIS_VERTEXSHADE);

    /* create glyph object and set objects */
    glyph = vis_GlyphBegin();
    vis_GlyphSetObject(glyph, VGL_DRAWFUN, df);
    vis_GlyphSetObject(glyph, VIS_VISCONTEXT, vc);

    GLWinXfmPush(glwin);
    GLWinRotate(glwin, 30., 'x');
    GLWinRotate(glwin, 60., 'y');

    /* loop through HashTable */
    vsy_HashTableInitIter(ht);
    while (vsy_HashTableNextIter(ht, &id, (Vobject**)&asurf), asurf) {
        GLWinClear(glwin);
        /* set glyph color to magenta */
        cg[0] = 1.;
        cg[1] = 0.;
        cg[2] = 1.;
        /* set text color to white */
        ctxt[0] = 1.;
        ctxt[1] = 1.;
        ctxt[2] = 1.;
        xtxt[0] = -1.;
        xtxt[1] = 3.5;
        xtxt[2] = 0.;
        vis_ASurfInq(asurf, &type);
        if (type == ASURF_SPHERE) {
            vis_ASurfGetSphere(asurf, x, &r);
            vgl_DrawFunColor(df, ctxt);
            vgl_DrawFunText(df, xtxt, "Sphere");
            vgl_DrawFunColor(df, cg);
            vis_GlyphSphere(glyph, x, r, VIS_ON);
        }
        else if (type == ASURF_PLANE) {
            vis_ASurfGetPlane(asurf, a, b, c, &length, &width);
            /* orient glyph */
            xp[0] = b[0] - a[0];
            xp[1] = b[1] - a[1];
            xp[2] = b[2] - a[2];
            yp[0] = c[0] - a[0];
            yp[1] = c[1] - a[1];
            yp[2] = c[2] - a[2];
            vis_GlyphSetOrientXY(glyph, xp, yp);
            vgl_DrawFunColor(df, ctxt);
            vgl_DrawFunText(df, xtxt, "Plane");
            vgl_DrawFunColor(df, cg);
            vis_GlyphRectangle(glyph, a, length, width, 0., VIS_ON);
        }
        else if (type == ASURF_SEGMENT_REV) {
            vis_ASurfNumPoints(asurf, &numpnt);
            vis_ASurfNumSegments(asurf, &numseg);
            vis_ASurfGetSegmentRev(asurf, a, b, c);
            for (i = 1; i <= numpnt; i++) {
                vis_ASurfGetPoint(asurf, i, xs[i - 1]);
            }
            /* orient glyph */
            xp[0] = b[0] - a[0];
            xp[1] = b[1] - a[1];
            xp[2] = b[2] - a[2];
            yp[0] = c[0] - a[0];
            yp[1] = c[1] - a[1];
            yp[2] = c[2] - a[2];
            vis_GlyphSetOrientXY(glyph, xp, yp);
            vgl_DrawFunColor(df, ctxt);
            vgl_DrawFunText(df, xtxt, "Segment Revolve");
            vgl_DrawFunColor(df, cg);
            for (i = 1; i <= numseg; i++) {
                vis_ASurfGetSegment(asurf, i, &segtype, ix);
                if (segtype == ASURF_SEG_LINE) {
                    for (j = 0; j < 2; j++) {
                        xy[j][0] = xs[ix[j] - 1][0];
                        xy[j][1] = xs[ix[j] - 1][1];
                    }
                    vis_GlyphSegmentRev(glyph, a, 360., GLYPH_SEG_LINE, xy);
                }
                else if (segtype == ASURF_SEG_ARC) {
                    printf(" seg arc,  id= %d, ix= %d %d %d\n", i, ix[0], ix[1], ix[2]);
                    for (j = 0; j < 3; j++) {
                        xy[j][0] = xs[ix[j] - 1][0];
                        xy[j][1] = xs[ix[j] - 1][1];
                    }
                    vis_GlyphSegmentRev(glyph, a, 360., GLYPH_SEG_ARC, xy);
                }
            }
        }
        GLWinSwap(glwin);
        sleep(2);
    }
    /* end objects */
    vsy_HashTableForEach(ht, (void (*)(void*))vis_ASurfEnd);
    vsy_HashTableEnd(ht);

    vgl_DrawFunEnd(df);
    vis_VisContextEnd(vc);
    vis_GlyphEnd(glyph);
    GLWinEnd(glwin);

    return 0;
}

10.28. Example 33, Manage Constraints Using RCase and MCase

This example illustrates the use of RCase and MCase objects to manage single point constraints (SPC’s) at nodes and general constraints, including multipoint (MPC’s) respectively. Three SPC’s are defined: a translational fixity at node 2, an applied rotation at node 4, and a y-rotation equivalence of node 4 to node 2. These SPC’s are defined using vis_RCaseSetSPC(). Two MPC’s are defined between the x and y translation of nodes 5, 100 and 101. The MPC’s represent constraining node 5 to displace as the average of nodes 100 and 101. In addition, a third built-in tie constraint is defined. The SPC’s are queried and printed by first using vis_RCaseNodeGroup() to fill a node group with the nodes at which SPC’s have been defined. Then a loop over the nodes in the node group is entered. Specific SPC tags and information are queried by calling vis_RCaseSPCTag() and vis_RCaseSPC() in succession. The technique for querying and printing constraints involves finding the maximum constraint number defined using vis_MCaseMax() and then looping over the range of constraints and querying for the constraint type and specific type information using vis_MCaseMPC() and vis_MCaseCon(). Any undefined constraint will return nterms equal to zero.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Constraints Using RCase and MCase
----------------------------------------------------------------------*/
int
main()
{
    vis_RCase* rcase;
    vis_MCase* mcase;
    vis_Group* nodegroup;
    Vint i;
    Vint index;
    Vint numtags, tag[SYS_DOF_MAX];
    Vint flags, type, master;
    Vfloat value;
    Vint ix[3], ig[3];
    Vfloat c[3], r;
    Vint maxindex, maxterms, maxrhs, nterms;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* instance RCase object */
    rcase = vis_RCaseBegin();

    /* Define SPC's */
    /* specify x translation fixity at node 2 */
    vis_RCaseSetSPC(rcase, 2, SYS_DOF_TX, RCASE_FIXED, NULL, 0);

    /* specify applied x rotation at node 4 */
    value = 1.;
    vis_RCaseSetSPC(rcase, 4, SYS_DOF_RX, RCASE_APPLIED, &value, 0);

    /* specify master for y rotation at node 4 */
    vis_RCaseSetSPC(rcase, 4, SYS_DOF_RY, RCASE_MASTER, NULL, 2);

    /* instance MCase object */
    mcase = vis_MCaseBegin();

    /* Define MPC's */
    ix[0] = 5;
    ix[1] = 100;
    ix[2] = 101;
    ig[0] = SYS_DOF_TX;
    ig[1] = SYS_DOF_TX;
    ig[2] = SYS_DOF_TX;
    c[0] = -1.;
    c[1] = .5;
    c[2] = .5;
    vis_MCaseSetMPC(mcase, 1, 3, ix, ig, c, 0.);
    ig[0] = SYS_DOF_TY;
    ig[1] = SYS_DOF_TY;
    ig[2] = SYS_DOF_TY;
    vis_MCaseSetMPC(mcase, 2, 3, ix, ig, c, 0.);
    /* define a Tie */
    ix[0] = 2;
    ix[1] = 3;
    vis_MCaseSetCon(mcase, 3, MCASE_TIE, ix);

    /* query SPC's */
    nodegroup = vis_GroupBegin();
    vis_GroupDef(nodegroup, 4, SYS_NODE, SYS_NONE);
    vis_GroupClear(nodegroup);

    /* group of nodes with single point constraints */
    vis_RCaseNodeGroup(rcase, NULL, nodegroup);

    /* iterate through node group */
    printf("\nSingle Point Constraints\n");
    vis_GroupInitIndex(nodegroup);
    while (vis_GroupNextIndex(nodegroup, &index, &flags), index) {
        printf("node= %d\n", index);
        vis_RCaseSPCTag(rcase, index, &numtags, tag);
        for (i = 0; i < numtags; i++) {
            vis_RCaseSPC(rcase, index, tag[i], &type, &value, &master);
            printf("tag= %d, type= %d\n", tag[i], type);
            if (type == RCASE_APPLIED) {
                printf(" value= %f\n", value);
            }
            else if (type == RCASE_MASTER) {
                printf(" master= %d\n", master);
            }
        }
    }
    /* query MPC's */
    vis_MCaseMax(mcase, &maxindex, &maxterms, &maxrhs);

    printf("\nMultiPoint Constraints\n");
    for (index = 1; index <= maxindex; index++) {
        vis_MCaseNum(mcase, index, &nterms);
        vis_MCaseType(mcase, index, &type);
        if (nterms) {
            if (type == MCASE_MPC) {
                vis_MCaseMPC(mcase, index, &nterms, ix, ig, c, &r);
                printf("index= %d, nterms= %d, r= %f\n", index, nterms, r);
                for (i = 0; i < nterms; i++) {
                    printf(" ix= %d, tag= %d, c= %f\n", ix[i], ig[i], c[i]);
                }
            }
            else {
                vis_MCaseCon(mcase, index, &type, &nterms, ix);
                printf("index= %d, type= %d, nterms= %d\n", index, type, nterms);
                for (i = 0; i < nterms; i++) {
                    printf(" ix= %d\n", ix[i]);
                }
            }
        }
    }
    /* end objects */
    vis_RCaseEnd(rcase);
    vis_MCaseEnd(mcase);
    vis_GroupEnd(nodegroup);
    return 0;
}

10.29. Example 33a, Manage Initial Conditions Using ICase

This example illustrates the use of an ICase object to manage initial conditions at nodes. It is recommended that all initial condition values at a node be defined with a single call to vis_ICaseSetSPV(). Assuming that only translational degrees of freedom are to have initial conditions defined, the tag array is initialized with the three translational degree of freedom types. Initial displacements are then defined at two nodes, nodes 3 and 10, and initial velocities at one node, node 2. The initial conditions are queried and printed by first using vis_ICaseNodeGroup() to fill a node group with the nodes at which initial conditions have been defined. Then a loop over the nodes in the node group is entered. Specific initial condition types and information are queried by calling vis_ICaseSPVType() and vis_ICaseSPV() in succession.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Initial Conditions Using ICase
----------------------------------------------------------------------*/
int
main()
{
    vis_ICase* icase;
    vis_Group* nodegroup;
    Vint i, j;
    Vint index;
    Vint flags;
    Vint ntags, tag[SYS_DOF_MAX];
    Vdouble val[SYS_DOF_MAX];
    Vint ntypes, type[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* instance ICase object */
    icase = vis_ICaseBegin();

    /* specify initial conditions for translational freedoms */
    ntags = 3;
    tag[0] = SYS_DOF_TX;
    tag[1] = SYS_DOF_TY;
    tag[2] = SYS_DOF_TZ;

    /* initial displacement at nodes 3 and 10 */
    val[0] = 1.;
    val[1] = 0.;
    val[2] = 0.;
    vis_ICaseSetSPVdv(icase, 3, ICASE_DOF, ntags, tag, val);

    val[0] = -2.;
    val[1] = 0.;
    val[2] = 0.;
    vis_ICaseSetSPVdv(icase, 10, ICASE_DOF, ntags, tag, val);

    /* initial velocity at node 2 */
    val[0] = 0.;
    val[1] = 1000.;
    val[2] = 0.;
    vis_ICaseSetSPVdv(icase, 2, ICASE_DOFDOT, ntags, tag, val);

    /* query initial conditions */
    nodegroup = vis_GroupBegin();
    vis_GroupDef(nodegroup, 10, SYS_NODE, SYS_NONE);
    vis_GroupClear(nodegroup);

    /* group of nodes with initial conditions */
    vis_ICaseNodeGroup(icase, NULL, nodegroup);

    /* iterate through node group */
    printf("\nInitial Conditions\n");
    vis_GroupInitIndex(nodegroup);
    while (vis_GroupNextIndex(nodegroup, &index, &flags), index) {
        printf("node= %d\n", index);
        vis_ICaseSPVType(icase, index, &ntypes, type);
        for (i = 0; i < ntypes; i++) {
            vis_ICaseSPVdv(icase, index, type[i], &ntags, tag, val);
            for (j = 0; j < ntags; j++) {
                printf("tag= %d\n", tag[j]);
                if (type[i] == ICASE_DOF) {
                    printf(" dof= %f\n", val[j]);
                }
                else if (type[i] == ICASE_DOFDOT) {
                    printf(" dofdot= %f\n", val[j]);
                }
            }
        }
    }

    /* end objects */
    vis_ICaseEnd(icase);
    vis_GroupEnd(nodegroup);
    return 0;
}

10.30. Example 33b, Manage Complex Constraints Using RCase

This example illustrates the use of the RCase object to manage time or frequency dependent complex valued single point constraints (SPC’s) at nodes. In this example double precision functions are used.

Complex valued constraints are specified using the same functions as real valued constraints. The function vis_RCaseSetComplexMode() is used to place the RCase object in the mode to expect either the real and/or imaginary parts of a complex number in all functions which set or query nodal applied constraint values. In this case the real and imaginary parts are to be entered simultaneously so the complex mode is set to SYS_COMPLEX_REALIMAGINARY.

Four SPC’s are defined: a translational fixity at node 2, an applied translation at node 3, an applied y-acceleration at node 4 with associated table identifiers for time dependent amplitude, and a y-rotation equivalence of node 7 to node 5. Use vis_RCaseSetSPCDot() to specify a constraint time derivative, in this case acceleration. Use vis_RCaseSetSPCTId() to set associated table identifiers.

#include <stdio.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                    Manage Complex Constraints Using RCase
----------------------------------------------------------------------*/
int
main()
{
    vis_RCase* rcase;
    vis_Group* nodegroup;
    Vint i;
    Vint index;
    Vint numtags, tag[SYS_DOF_MAX], tid[2], dottype;
    Vint flags, type, master;
    Vdouble value[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* instance RCase object */
    rcase = vis_RCaseBegin();

    /* Define SPC's */
    /* specify x translation fixity at node 2 */
    vis_RCaseSetSPCdv(rcase, 2, SYS_DOF_TX, RCASE_FIXED, NULL, 0);

    /* specify applied x translation at node 3 */
    vis_RCaseSetComplexMode(rcase, SYS_COMPLEX_REALIMAGINARY);
    value[0] = 1.;
    value[1] = 2.;
    vis_RCaseSetSPCdv(rcase, 3, SYS_DOF_TX, RCASE_APPLIED, value, 0);
    /* specify applied y acceleration at node 4 */
    value[0] = 10.;
    value[1] = 20.;
    vis_RCaseSetSPCdv(rcase, 4, SYS_DOF_TY, RCASE_APPLIED, value, 0);
    vis_RCaseSetSPCDot(rcase, 4, SYS_DOF_TY, RCASE_DOFDOTDOT);
    tid[0] = 30;
    tid[1] = 40;
    vis_RCaseSetSPCTId(rcase, 4, SYS_DOF_TY, tid);

    /* specify master for y rotation at node 5 */
    vis_RCaseSetSPCdv(rcase, 7, SYS_DOF_RY, RCASE_MASTER, NULL, 5);

    /* query SPC's */
    nodegroup = vis_GroupBegin();
    vis_GroupDef(nodegroup, 4, SYS_NODE, SYS_NONE);
    vis_GroupClear(nodegroup);

    /* group of nodes with single point constraints */
    vis_RCaseNodeGroup(rcase, NULL, nodegroup);

    /* iterate through node group */
    printf("\nSingle Point Constraints\n");
    vis_GroupInitIndex(nodegroup);
    while (vis_GroupNextIndex(nodegroup, &index, &flags), index) {
        printf("node= %d\n", index);
        vis_RCaseSPCTag(rcase, index, &numtags, tag);
        for (i = 0; i < numtags; i++) {
            vis_RCaseSPCdv(rcase, index, tag[i], &type, value, &master);
            printf("tag= %d, type= %d\n", tag[i], type);
            if (type == RCASE_APPLIED) {
                vis_RCaseSPCTId(rcase, index, tag[i], tid);
                vis_RCaseSPCDot(rcase, index, tag[i], &dottype);
                printf(" value= %f %f(i)\n", value[0], value[1]);
                printf(" tid= %d %d(i)\n", tid[0], tid[1]);
                printf(" dottype= %d\n", dottype);
            }
            else if (type == RCASE_MASTER) {
                printf(" master= %d\n", master);
            }
        }
    }
    /* end objects */
    vis_RCaseEnd(rcase);
    vis_GroupEnd(nodegroup);
    return 0;
}

10.31. Example 34, Manage Element Properties Using EProp

This example illustrates the use of a EProp object to manage element properties for a shell element. The real valued properties are defined and queried in double precision. The element material id and 4 corner thicknesses are defined. Given these element properties the element node thicknesses for an 8 node parabolic shell element are computed and printed using vis_EPropEvaldv(). Then the defined element properties are traversed and printed. The number and type of properties defined are first queried using vis_EPropValueType(). A loop over the defined types is entered and the name and parameters for each type are queried and printed. The property values are queried using vis_EPropValueInteger() and vis_EPropValueDouble().

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Element Properties Using EProp
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j, k;
    Vint iparams[1];
    Vdouble dparams[4];
    vis_EProp* eprop;
    Vint ntypes, *type;
    Vint nval, nloc, dtyp;
    Vchar name[64];
    Vdouble cthick[4], thick[8];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create eprop for shell element properties */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SHELL);

    /* set material id */
    vis_EPropSetValuei(eprop, EPROP_MID, 1);

    /* install corner thicknesses */
    cthick[0] = .5;
    cthick[1] = .5;
    cthick[2] = 1.5;
    cthick[3] = 1.5;
    vis_EPropSetValuedv(eprop, EPROP_THICKNESS, cthick);

    /* compute thicknesses for 8 node shell */
    vis_EPropEvaldv(eprop, EPROP_THICKNESS, VIS_SHAPEQUAD, 3, 0, thick);
    printf("\nElement node thickness:\n");
    for (i = 0; i < 8; i++) {
        printf("thickness= %e\n", thick[i]);
    }
    /* traverse defined element properties */
    vis_EPropValueTypeNum(eprop, &ntypes);
    printf("ntypes = %d\n", ntypes);
    type = (Vint*)malloc(ntypes * sizeof(Vint));
    vis_EPropValueType(eprop, &ntypes, type);

    /* loop through types */
    for (i = 0; i < ntypes; i++) {
        vis_EPropValueName(eprop, type[i], name);
        printf("\n name = %s\n", name);
        vis_EPropValueParams(eprop, type[i], &nval, &nloc, &dtyp);
        printf(" nval= %d, nloc= %d\n", nval, nloc);

        /* integer valued */
        if (dtyp == SYS_INTEGER) {
            printf(" Integer\n");
            vis_EPropValueInteger(eprop, type[i], iparams);
            for (j = 0; j < nval; j++) {
                printf("  value= %d\n", iparams[j]);
            }
            /* real valued */
        }
        else {
            vis_EPropValueDouble(eprop, type[i], dparams);
            printf(" Real\n");
            for (k = 0; k < nloc; k++) {
                printf(" Location= %d\n", k);
                for (j = 0; j < nval; j++) {
                    printf("  value= %e\n", dparams[k * nval + j]);
                }
            }
        }
    }
    /* end objects */
    free(type);
    vis_EPropEnd(eprop);
    return 0;
}

10.32. Example 34a, Composite Shell and General Beam Property Using EProp

This example illustrates the use of a EProp object to manage composite shell and general beam properties. The properties in this example are assumed to be constant over the shell surface and along the length of the beam. In general they may vary over the shell and beam elements. The orientation angles of the shell layers are relative to the shell local coordinate system in the plane of the shell.

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

static void
print_EProp(vis_EProp* eprop);

/*----------------------------------------------------------------------
                      Composite Shell and General Beam Property Using EProp
----------------------------------------------------------------------*/
int
main()
{
    vis_EProp *eprop, *epropb;
    Vint nlay, mid[4];
    Vdouble thk[4], phi[4];
    Vint midb;
    Vdouble a, iyy, izz, j, cw;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create eprop for shell element composite property */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SHELL);
    vis_EPropSetValuei(eprop, EPROP_SHELLWALL, SYS_SHELLWALL_LAMINATE);
    /* 4 layers */
    nlay = 4;
    /* material ids */
    mid[0] = 1;
    mid[1] = 2;
    mid[2] = 2;
    mid[3] = 1;
    /* thicknesses */
    thk[0] = .2;
    thk[1] = .1;
    thk[2] = .1;
    thk[3] = .2;
    /* layup angles in degrees */
    phi[0] = 0.;
    phi[1] = 45.;
    phi[2] = -45.;
    phi[3] = 0.;
    vis_EPropSetValuei(eprop, EPROP_LAYER_NUM, nlay);
    vis_EPropSetValueiv(eprop, EPROP_LAYER_MID, mid);
    vis_EPropSetValuedv(eprop, EPROP_LAYER_THK, thk);
    vis_EPropSetValuedv(eprop, EPROP_LAYER_PHI, phi);
    /* set optional eccentricity */
    vis_EPropSetValued(eprop, EPROP_ECC, .3);
    /* print contents of shell EProp */
    print_EProp(eprop);

    /* create eprop for general beam element property */
    epropb = vis_EPropBegin();
    vis_EPropDef(epropb, VIS_ELEM_BEAM);
    vis_EPropSetValuei(epropb, EPROP_BEAMSECT, SYS_BEAMSECT_PROPS);
    /* set material id */
    midb = 10;
    vis_EPropSetValuei(epropb, EPROP_MID, midb);
    /* 3 by 2 rectangular beam */
    a = 6.;
    iyy = 2.;
    izz = 4.5;
    j = 4.7017;
    cw = 0.24272;
    /* set section properties */
    vis_EPropSetValued(epropb, EPROP_AREA, a);
    vis_EPropSetValued(epropb, EPROP_IYY, iyy);
    vis_EPropSetValued(eprop, EPROP_IZZ, izz);
    vis_EPropSetValued(epropb, EPROP_IYZ, 0.);
    vis_EPropSetValued(epropb, EPROP_J, j);
    vis_EPropSetValued(epropb, EPROP_CW, cw);
    /* print contents of beam EProp */
    print_EProp(epropb);

    /* delete objects */
    vis_EPropEnd(eprop);
    vis_EPropEnd(epropb);
}

/*----------------------------------------------------------------------
                      print EProp
----------------------------------------------------------------------*/
static void
print_EProp(vis_EProp* eprop)
{
    Vint i, j, k;
    Vint* iparams = NULL;
    Vdouble* dparams = NULL;
    Vint ntypes, *type;
    Vint nval, nloc, dtyp;
    Vchar name[64];
    /* traverse defined element properties */
    vis_EPropValueTypeNum(eprop, &ntypes);
    printf("ntypes = %d\n", ntypes);
    type = (Vint*)malloc(ntypes * sizeof(Vint));
    vis_EPropValueType(eprop, &ntypes, type);

    /* loop through types */
    for (i = 0; i < ntypes; i++) {
        vis_EPropValueName(eprop, type[i], name);
        printf("\n name = %s\n", name);
        vis_EPropValueParams(eprop, type[i], &nval, &nloc, &dtyp);
        printf(" nval= %d, nloc= %d\n", nval, nloc);

        if (dtyp == SYS_INTEGER) {
            /* integer valued */
            printf(" Integer\n");
            iparams = (Vint*)vut_MemoryMalloc(nval * nloc * sizeof(Vint));
            vis_EPropValueInteger(eprop, type[i], iparams);
            for (j = 0; j < nval; j++) {
                printf("  value= %d\n", iparams[j]);
            }
            vut_MemoryFree(iparams);
        }
        else {
            /* real valued */
            printf(" Real\n");
            dparams = (Vdouble*)vut_MemoryMalloc(nval * nloc * sizeof(Vdouble));
            vis_EPropValueDouble(eprop, type[i], dparams);
            for (k = 0; k < nloc; k++) {
                printf(" Location= %d\n", k);
                for (j = 0; j < nval; j++) {
                    printf("  value= %e\n", dparams[k * nval + j]);
                }
            }
            vut_MemoryFree(dparams);
        }
    }
    free(type);
    return;
}

10.33. Example 35, Manage Material Properties Using MProp

This example illustrates the use of a MProp object to manage material properties for a linear orthotropic material. Both elastic and thermal properties are input. The real valued properties are defined and queried in double precision. The number and type of properties defined are first queried using vis_MPropValueType(). A loop over the defined types is entered and the name and parameters for each type are queried and printed. The property values are queried using vis_MPropValueInteger() and vis_MPropValueDouble().

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Material Properties Using MProp
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j;
    Vint iparams[1];
    Vdouble dparams[3];
    vis_MProp* mprop;
    Vdouble eort[3], nuort[3], gort[3], kort[3];
    Vint ntypes, *type;
    Vint nval, dtyp;
    Vchar name[64];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create mprop for linear orthotropic properties */
    mprop = vis_MPropBegin();
    vis_MPropDef(mprop, SYS_MAT_ORTHOTROPIC);

    /* set material density */
    vis_MPropSetValued(mprop, MPROP_DENSITY, 7800.);

    /* install elastic moduli */
    eort[0] = 2.1e+11;
    eort[1] = 1.1e+11;
    eort[2] = 1.2e+11;
    vis_MPropSetValuedv(mprop, MPROP_EORT, eort);
    nuort[0] = .3;
    nuort[1] = .3;
    nuort[2] = .3;
    vis_MPropSetValuedv(mprop, MPROP_NUORT, nuort);
    gort[0] = .4e+11;
    gort[1] = .3e+11;
    gort[2] = .3e+11;
    vis_MPropSetValuedv(mprop, MPROP_GORT, gort);

    /* thermal conductivity and specific heat */
    kort[0] = 55.;
    kort[1] = 30.;
    kort[2] = 25.;
    vis_MPropSetValuedv(mprop, MPROP_KORT, kort);
    vis_MPropSetValued(mprop, MPROP_CP, 465.);

    /* traverse defined material properties */
    vis_MPropValueTypeNum(mprop, &ntypes);
    printf("ntypes = %d\n", ntypes);
    type = (Vint*)malloc(ntypes * sizeof(Vint));
    vis_MPropValueType(mprop, &ntypes, type);

    /* loop through types */
    for (i = 0; i < ntypes; i++) {
        vis_MPropValueName(mprop, type[i], name);
        printf("\n name = %s\n", name);
        vis_MPropValueParams(mprop, type[i], &nval, &dtyp);
        printf(" nval= %d\n", nval);

        /* integer valued */
        if (dtyp == SYS_INTEGER) {
            printf(" Integer\n");
            vis_MPropValueInteger(mprop, type[i], iparams);
            for (j = 0; j < nval; j++) {
                printf("  value= %d\n", iparams[j]);
            }
            /* real valued */
        }
        else {
            vis_MPropValueDouble(mprop, type[i], dparams);
            printf(" Real\n");
            for (j = 0; j < nval; j++) {
                printf("  value= %e\n", dparams[j]);
            }
        }
    }
    /* end objects */
    free(type);
    vis_MPropEnd(mprop);
    return 0;
}

10.34. Example 36, Manage Solution Properties Using SProp

This example illustrates the use of a SProp object to manage solution properties for a buckling analysis. The number of buckling modes required, the restraint case identifier and loading information are required. The initial preload is defined to be the superposition of two load cases, load cases 2 and 4, with load factors 10. and 20. respectively. The number of load cases defined using vis_SPropSetValuei() with SPROP_LCASE_NUM determines the number of load case identifiers and associated load factors are input using vis_SPropSetValueiv() and vis_SPropSetValuedv(). A title and subtitle are defined using vis_SPropSetValuec(). The real valued properties are defined and queried in double precision. The number and type of properties defined are first queried using vis_SPropValueType(). A loop over the defined types is entered and the name and parameters for each type are queried and printed. The property values are queried using vis_SPropValueInteger(), vis_SPropValueDouble() and vis_SPropValueString().

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Solution Properties Using SProp
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j;
    Vint iparams[2];
    Vdouble dparams[6];
    Vchar cparams[81];
    vis_SProp* sprop;
    Vint ntypes, *type;
    Vint nval, dtyp;
    Vint flag, usernum;
    Vchar name[256];
    Vint dimen, dimes[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create sprop for buckling solution */
    sprop = vis_SPropBegin();
    vis_SPropDef(sprop, SYS_SOL_BUCKLING);

    /* set number of modes */
    vis_SPropSetValuei(sprop, SPROP_EIGEN_NUM, 1);

    /* set restraint case number */
    vis_SPropSetValuei(sprop, SPROP_RCASE, 1);

    /* set load case numbers */
    vis_SPropSetValuei(sprop, SPROP_LCASE_NUM, 2);
    iparams[0] = 2;
    iparams[1] = 4;
    vis_SPropSetValueiv(sprop, SPROP_LCASE, iparams);
    dparams[0] = 10.;
    dparams[1] = 20.;
    vis_SPropSetValuedv(sprop, SPROP_LCASE_FACTOR, dparams);

    /* set results to be saved */
    vis_SPropSetValuei(sprop, SPROP_RESFILE_NUM, 1);
    vis_SPropSetValuei(sprop, SPROP_RESFILE, SYS_RES_D);

    /* set titles */
    vis_SPropSetValuec(sprop, SPROP_TITLE, "Buckling solution");
    vis_SPropSetValuec(sprop, SPROP_SUBTITLE, "Example");

    /* set a couple of user properties */
    vis_SPropSetValuei(sprop, SPROP_USER_NUM, 2);

    /* set "user scalar" to scalar integer value 6 */
    vis_SPropSetValuei(sprop, SPROP_USERDIMENUM + 0, 1);
    vis_SPropSetValuei(sprop, SPROP_USERDIME + 0, 1);
    vis_SPropSetValuec(sprop, SPROP_USERNAME + 0, "user scalar");
    vis_SPropSetValuei(sprop, SPROP_USERDATATYPE + 0, SYS_INTEGER);
    vis_SPropSetValuei(sprop, SPROP_USERDATA + 0, 6);

    /* set "user 1" to 2x3 array of real values */
    vis_SPropSetValuei(sprop, SPROP_USERDIMENUM + 1, 2);
    dimes[0] = 3;
    dimes[1] = 2;
    vis_SPropSetValueiv(sprop, SPROP_USERDIME + 1, dimes);
    vis_SPropSetValuec(sprop, SPROP_USERNAME + 1, "user 2x3 array ");
    vis_SPropSetValuei(sprop, SPROP_USERDATATYPE + 1, SYS_REAL);
    dparams[0] = 1.;
    dparams[1] = 2.;
    dparams[2] = 3.;
    dparams[3] = 4.;
    dparams[4] = 5.;
    dparams[5] = 6.;
    vis_SPropSetValuedv(sprop, SPROP_USERDATA + 1, dparams);

    /* traverse defined solution properties */
    /* query for number of types and allocate array */
    vis_SPropValueTypeNum(sprop, &ntypes);
    printf("ntypes = %d\n", ntypes);
    type = (Vint*)malloc(ntypes * sizeof(Vint));
    /* query for types */
    vis_SPropValueType(sprop, &ntypes, type);
    /* loop through types generically */
    for (i = 0; i < ntypes; i++) {
        vis_SPropValueName(sprop, type[i], name);
        printf("\n name = %s\n", name);
        vis_SPropValueParams(sprop, type[i], &nval, &dtyp);
        printf(" nval= %d\n", nval);

        /* integer valued */
        if (dtyp == SYS_INTEGER) {
            printf(" Integer\n");
            vis_SPropValueInteger(sprop, type[i], iparams);
            for (j = 0; j < nval; j++) {
                printf("  value= %d\n", iparams[j]);
            }
            /* real valued */
        }
        else if (dtyp == SYS_REAL) {
            vis_SPropValueDouble(sprop, type[i], dparams);
            printf(" Real\n");
            for (j = 0; j < nval; j++) {
                printf("  value= %e\n", dparams[j]);
            }
            /* character valued */
        }
        else if (dtyp == SYS_CHAR) {
            vis_SPropValueString(sprop, type[i], cparams);
            printf("  value= %s\n", cparams);
        }
    }
    free(type);
    /* specifically access user data */
    printf("\nUser data\n");
    usernum = 0;
    vis_SPropValueFlag(sprop, SPROP_USER_NUM, &flag);
    if (flag) {
        vis_SPropValueInteger(sprop, SPROP_USER_NUM, &usernum);
    }
    for (i = 0; i < usernum; i++) {
        vis_SPropValueInteger(sprop, SPROP_USERDIMENUM + i, &dimen);
        vis_SPropValueInteger(sprop, SPROP_USERDIME + i, dimes);
        vis_SPropValueString(sprop, SPROP_USERNAME + i, name);
        vis_SPropValueInteger(sprop, SPROP_USERDATATYPE + i, &dtyp);
        printf("\n");
        printf("name= %s\n", name);
        printf("number of dimensions= %d\n", dimen);
        printf("dimensions=");
        nval = 1;
        for (j = 0; j < dimen; j++) {
            printf(" %d", dimes[j]);
            nval *= dimes[j];
        }
        printf("\n");
        printf("datatype= %d\n", dtyp);
        /* integer valued */
        if (dtyp == SYS_INTEGER) {
            printf(" Integer\n");
            vis_SPropValueInteger(sprop, SPROP_USERDATA + i, iparams);
            for (j = 0; j < nval; j++) {
                printf("  value= %d\n", iparams[j]);
            }
            /* real valued */
        }
        else if (dtyp == SYS_REAL) {
            vis_SPropValueDouble(sprop, SPROP_USERDATA + i, dparams);
            printf(" Real\n");
            for (j = 0; j < nval; j++) {
                printf("  value= %e\n", dparams[j]);
            }
            /* character valued */
        }
        else if (dtyp == SYS_CHAR) {
            vis_SPropValueString(sprop, SPROP_USERDATA + i, cparams);
            printf("  value= %s\n", cparams);
        }
    }
    /* end objects */
    vis_SPropEnd(sprop);
    return 0;
}

10.35. Example 37, Manage Tabular Functions Using TCurve

This example illustrates the use of a TCurve object to manage tables of temperature dependent material data. Two TCurve objects are instanced, one to store the temperature dependent values of elastic modulus and Poisson’s ratio, and a second to store the temperature dependent values of density. The material data for the two curves is entered as piecewise linear functions using vis_TCurveSetPWLineardv(). A third function object is instanced and defined as a piece wise linear function which is generated as a combination of the first two functions. The result is a vector valued function of dimension 3 which holds elastic modulus, Poisson’s ratio and density at a common set of temperature values.

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Tabular Functions Using TCurve
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_TCurve *tcurve1, *tcurve2, *tcurve;
    vis_TCurve* tc[2];
    Vdouble temp[5];
    Vdouble elas[4][2], dens[5];
    Vdouble t, f[3];
    Vint npts;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create tcurve for temperature dependent E, Nu, data */
    tcurve1 = vis_TCurveBegin();
    vis_TCurveDef(tcurve1, TCURVE_PWLINEAR, 2);

    /* set data */
    temp[0] = 20.;
    temp[1] = 100.;
    temp[2] = 150.;
    temp[3] = 180.;
    elas[0][0] = 12000000.;
    elas[0][1] = .30;
    elas[1][0] = 11000000.;
    elas[1][1] = .31;
    elas[2][0] = 10000000.;
    elas[2][1] = .33;
    elas[3][0] = 9000000.;
    elas[3][1] = .35;
    vis_TCurveSetPWLineardv(tcurve1, 4, temp, (Vdouble*)elas);

    for (i = 0; i <= 10; i++) {
        t = 20. * i;
        vis_TCurveEvaldv(tcurve1, 1, &t, f);
        printf("t= %f: E= %f,  Nu= %f\n", t, f[0], f[1]);
    }

    /* create curve for density */
    tcurve2 = vis_TCurveBegin();
    vis_TCurveDef(tcurve2, TCURVE_PWLINEAR, 1);

    /* set data */
    temp[0] = 0.;
    temp[1] = 80.;
    temp[2] = 120.;
    temp[3] = 150.;
    temp[4] = 200.;
    dens[0] = 1.0e-4;
    dens[1] = 1.2e-4;
    dens[2] = 1.3e-4;
    dens[3] = 1.4e-4;
    dens[4] = 1.5e-4;
    vis_TCurveSetPWLineardv(tcurve2, 5, temp, dens);

    /* merge curves */
    tcurve = vis_TCurveBegin();
    vis_TCurveDef(tcurve, TCURVE_PWLINEAR, 3);
    tc[0] = tcurve1;
    tc[1] = tcurve2;
    vis_TCurveMerge(tcurve, 2, tc);

    /* query for merged independent points */
    vis_TCurveNum(tcurve, &npts);
    printf("npts= %d\n", npts);
    for (i = 1; i <= npts; i++) {
        vis_TCurveIndepdv(tcurve, 1, &i, &t);
        printf("pt= %d, t= %f\n", i, t);
    }

    /* evaluate at equally spaced intervals */
    for (i = 0; i <= 10; i++) {
        t = 20. * i;
        vis_TCurveEvaldv(tcurve, 1, &t, f);
        printf("t= %f: E= %f,  Nu= %f,  rho= %f\n", t, f[0], f[1], f[2]);
    }

    /* end objects */
    vis_TCurveEnd(tcurve1);
    vis_TCurveEnd(tcurve2);
    vis_TCurveEnd(tcurve);
    return 0;
}

10.36. Example 38, Manage Results Properties Using RProp

This example illustrates the use of an RProp object to manage results properties for element stress for a shell section. Optional qualifiers for Equivalent Plastic stress are specified using vis_RPropSetQual(). The numeric identifier 1 and 2 are specified using vis_RPropSetIds(). These identifiers could be interpreted, for example, as solution sequence 1, time step 2. The function vis_RPropGetDatasetName() can be used to query for the equivalent dataset name.

A title and subtitle are defined using vis_RPropSetValuec(). The real valued properties are defined and queried in double precision. The number and type of properties defined are first queried using vis_RPropValueType(). A loop over the defined types is entered and the name and parameters for each type are queried and printed. The property values are queried using vis_RPropValueInteger(), vis_RPropValueDouble() and vis_RPropValueString().

Conversely, a dataset name can be specified using vis_RPropSetDatasetName() and the equivalent component values are queried.

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage Result Properties Using RProp
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j;
    Vint type, id1, id2, id3;
    Vint iparams[2];
    Vdouble dparams[2];
    Vchar cparams[81];
    vis_RProp* rprop;
    Vint ntypes, types[RPROP_MAX];
    Vint nval, dtyp;
    Vchar name[64];
    Vint nqua, iqua[SYS_NQUA_MAX];
    Vchar cqua[64];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create rprop for stress results */
    rprop = vis_RPropBegin();
    vis_RPropDef(rprop, SYS_ELEM, SYS_NONE);

    /* set type */
    vis_RPropSetType(rprop, SYS_RES_S);

    /* set optional qualifier(s) */
    iqua[0] = SYS_QUA_EQUIV;
    iqua[1] = SYS_QUA_PLAST;
    vis_RPropSetQual(rprop, 2, iqua, NULL);

    /* set ids */
    vis_RPropSetIds(rprop, 1, 2, 0);

    /* query primary properties */
    vis_RPropGetType(rprop, &type);
    vis_RPropGetQual(rprop, &nqua, iqua, cqua);
    vis_RPropGetIds(rprop, &id1, &id2, &id3);
    printf("type = %d\n", type);
    printf("nqua = %d\n", nqua);
    for (i = 0; i < nqua; i++) {
        printf("iqua[%d] = %d\n", i, iqua[i]);
    }
    printf("cqua = %s\n", cqua);
    printf("id1,id2,id3 = %d %d %d\n", id1, id2, id3);

    /* query equivalent dataset name */
    vis_RPropGetDatasetName(rprop, name);
    printf("dataset name = %s\n", name);

    /* set titles */
    vis_RPropSetValuec(rprop, RPROP_TITLE, "Drop test case");
    vis_RPropSetValuec(rprop, RPROP_SUBTITLE, "Oblique strike");

    /* set load factor */
    vis_RPropSetValued(rprop, RPROP_LOADFACTOR, 1.);

    /* traverse defined solution properties */
    vis_RPropValueType(rprop, &ntypes, types);
    printf("\n ntypes = %d\n", ntypes);

    /* loop through types */
    for (i = 0; i < ntypes; i++) {
        vis_RPropValueName(rprop, types[i], name);
        printf("\n name = %s\n", name);
        vis_RPropValueParams(rprop, types[i], &nval, &dtyp);
        printf(" nval= %d\n", nval);

        /* integer valued */
        if (dtyp == SYS_INTEGER) {
            printf(" Integer\n");
            vis_RPropValueInteger(rprop, types[i], iparams);
            for (j = 0; j < nval; j++) {
                printf("  value= %d\n", iparams[j]);
            }
            /* real valued */
        }
        else if (dtyp == SYS_REAL) {
            vis_RPropValueDouble(rprop, types[i], dparams);
            printf(" Real\n");
            for (j = 0; j < nval; j++) {
                printf("  value= %e\n", dparams[j]);
            }
            /* character valued */
        }
        else if (dtyp == SYS_CHAR) {
            vis_RPropValueString(rprop, types[i], cparams);
            printf("  value= %s\n", cparams);
        }
    }
    /* now conversely, set dataset name */
    vis_RPropSetDatasetName(rprop, "D.N:1");
    /* query for equivalent primary properties */
    vis_RPropGetType(rprop, &type);
    vis_RPropGetQual(rprop, &nqua, iqua, cqua);
    vis_RPropGetIds(rprop, &id1, &id2, &id3);
    printf("type = %d\n", type);
    printf("nqua = %d\n", nqua);
    for (i = 0; i < nqua; i++) {
        printf("iqua[%d] = %d\n", i, iqua[i]);
    }
    printf("cqua = %s\n", cqua);
    printf("id1,id2,id3 = %d %d %d\n", id1, id2, id3);

    /* end objects */
    vis_RPropEnd(rprop);
    return 0;
}

10.37. Example 38avdm, Export Simple Finite Element Model and Results

This example uses the same finite element model introduced in Example 23 and illustrates the use of the Model and State objects to export a finite element model with displacement and stress results to SDRC Universal file file format. It then illustrates using VdmTools objects to export to NASTRAN OUTPUT2 file format.

Initially, the finite element model is loaded into a Connect object. A Model object is instanced and the Connect object is installed in it using vis_ModelSetObject(). The function vis_ModelWrite() is then called to write the model information to a SDRC Universal file. The amount of information written depends upon the types of objects installed in Model. In this example only basic element type and connectivity and node coordinates are be written.

In order to illustrate exporting a node vector and element node tensor, the node coordinate data is used for convenience as the data source for the components of a node displacement vector and the direct stress components of an element node stress tensor. A GridFun object must be created to be used by the State object whenever the State object data is exported. A node State object is instanced and filled with the node coordinate data. In order to export the State data an associated RProp object must be used to describe the global properties of the results quantity. In this example the function vis_RPropSetType() is used to set the basic result type, vis_RPropSetIds() is used to define a case identifier and vis_RPropSetValuec() is used to specify a title. The function vis_StateWrite() is called to write the node displacement vector to a SDRC Universal file. Note that if an existing file is used when exporting to SDRC Universal file format, the data will be appended to the existing file. SDRC Universal file format supports model and result quantities in a single file. An element node State object is then instanced and filled with the node coordinate data for the direct stress components and zeroes for the shear stress components. An associated RProp object is created and the stress results are written using vis_StateWrite().

Finally, the Model and State objects are exported to a NASTRAN .op2 file using VdmTools modules. A DataFun and LMan object are required to do the exporting. For each file type to be exported to the appropriate interface object must be used, ie NASLib for NASTRAN. The function vdm_LManSaveModel() exports the model information and vdm_LManSaveState() exports the results data.

#include <stdio.h>
#include "base/base.h"
#include "vis/visdata.h"
#include "vdm/vdm.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 6------7
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \8------9
  --x        /   1../...2../|      | \
 /         13-----14-----15 |      |  \
z           |  .   |  .   |.|      |   \
            | .    | .    | 3------4-----5
            |.     |.     |/
           10-----11-----12
*/
#define MAX_ELEM 4
#define MAX_NODE 15

static Vint conn[MAX_ELEM][8] = {
{1, 2, 7, 6, 10, 11, 14, 13}, {2, 3, 8, 7, 11, 12, 15, 14}, {3, 4, 9, 8, 0, 0, 0, 0}, {4, 5, 9, 0, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD, VIS_SHAPETRI};

static Vint etyp[MAX_ELEM] = {VIS_ELEM_SOLID, VIS_ELEM_SOLID, VIS_ELEM_SHELL, VIS_ELEM_SHELL};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {4., 0., 1.},
                                     {0., 1., 0.}, {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.},
                                     {1., 0., 2.}, {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Export Simple Finite Element Model and Results
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j, k;
    vis_Connect* connect;
    vis_Model* model;
    vis_State *staten, *stateen;
    vis_RProp *rpropn, *rpropen;
    vis_GridFun* gf;
    Vint nix, ix[8], nsec = 0;
    Vfloat enstress[8][6];

    vdm_LMan* lman;
    vdm_DataFun* datafun;
    vdm_NASLib* naslib;
    vdm_SDRCLib* sdrclib;
    vdm_CGNSVLib* cgnsvlib;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topology and connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEATYPE, i + 1, etyp[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }

    /* create model object and install connect object */
    model = vis_ModelBegin();
    vis_ModelSetObject(model, VIS_CONNECT, connect);

    /* write model data */
    vis_ModelWrite(model, SYS_SDRC_UNIVERSAL, "exam38avdm.unv1");

    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create a node vector state */
    staten = vis_StateBegin();
    vis_StateDef(staten, MAX_NODE, SYS_NODE, SYS_NONE, VIS_VECTOR);
    vis_StateSetObject(staten, VIS_GRIDFUN, gf);

    /* use node coordinates as "displacements" for convenience */
    for (i = 0; i < MAX_NODE; i++) {
        vis_StateSetData(staten, i + 1, coords[i]);
    }
    /* create result property for node state */
    rpropn = vis_RPropBegin();
    vis_RPropDef(rpropn, SYS_NODE, SYS_NONE);
    /* set displacement quantity */
    vis_RPropSetType(rpropn, SYS_RES_D);
    /* set ids, eg. step 1, increment 1 */
    vis_RPropSetIds(rpropn, 1, 1, 0);
    vis_RPropSetValued(rpropn, RPROP_TIME, 1.);
    vis_RPropSetValuec(rpropn, RPROP_TITLE, "Displacements under load case 1");

    /* write node state data */
    /* SDRC, previous file can be appended to */
    vis_StateWrite(staten, rpropn, SYS_SDRC_UNIVERSAL, "exam38avdm.unv1");

    /* create an element node state */
    stateen = vis_StateBegin();
    vis_StateDef(stateen, MAX_ELEM, SYS_ELEM, SYS_NODE, VIS_TENSOR);
    vis_StateSetObject(stateen, VIS_GRIDFUN, gf);

    /* set number of sections for solids and shells */
    for (i = 0; i < MAX_ELEM; i++) {
        if (etyp[i] == VIS_ELEM_SOLID) {
            nsec = 1;
        }
        else if (etyp[i] == VIS_ELEM_SHELL) {
            nsec = 2;
        }
        vis_StateSetDataSect(stateen, i + 1, nsec);
    }
    /* use node coordinates as "stress" for convenience */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectElemNode(connect, i + 1, &nix, ix);
        /* gather */
        if (etyp[i] == VIS_ELEM_SOLID) {
            for (j = 0; j < nix; j++) {
                enstress[j][0] = coords[ix[j] - 1][0];
                enstress[j][1] = coords[ix[j] - 1][1];
                enstress[j][2] = coords[ix[j] - 1][2];
                enstress[j][3] = 0.;
                enstress[j][4] = 0.;
                enstress[j][5] = 0.;
            }
            /* double coordinates for second section for shells */
        }
        else if (etyp[i] == VIS_ELEM_SHELL) {
            for (k = 0; k < 2; k++) {
                for (j = 0; j < nix; j++) {
                    enstress[k * nix + j][0] = (k + 1) * coords[ix[j] - 1][0];
                    enstress[k * nix + j][1] = (k + 1) * coords[ix[j] - 1][1];
                    enstress[k * nix + j][2] = 0.;
                    enstress[k * nix + j][3] = (k + 1) * coords[ix[j] - 1][2];
                    enstress[k * nix + j][4] = 0.;
                    enstress[k * nix + j][5] = 0.;
                }
            }
        }
        vis_StateSetData(stateen, i + 1, (Vfloat*)enstress);
    }
    /* create result property for element node state */
    rpropen = vis_RPropBegin();
    vis_RPropDef(rpropen, SYS_ELEM, SYS_NODE);
    /* set stress quantity */
    vis_RPropSetType(rpropen, SYS_RES_S);
    /* set ids, eg. step 1, increment 1 */
    vis_RPropSetIds(rpropen, 1, 1, 0);
    vis_RPropSetValued(rpropen, RPROP_TIME, 1.);
    /* set name of section dataset */
    vis_RPropSetValuec(rpropen, RPROP_LINK_SECTION, "ELEM.SECT.E:1");
    vis_RPropSetValuec(rpropen, RPROP_TITLE, "Stress under load case 1");

    /* write element node state data */
    /* SDRC, previous file can be appended to */
    vis_StateWrite(stateen, rpropen, SYS_SDRC_UNIVERSAL, "exam38avdm.unv1");

    /* now export to VdmTools supported results files */
    datafun = vdm_DataFunBegin();
    lman = vdm_LManBegin();
    vdm_LManSetObject(lman, VDM_DATAFUN, datafun);

    /* write to NASTRAN .op2 */
    naslib = vdm_NASLibBegin();
    vdm_NASLibDataFun(naslib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38avdm.op2", SYS_NASTRAN_OUTPUT2);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, stateen, rpropen);
    vdm_DataFunClose(datafun);
    vdm_NASLibEnd(naslib);

    /* write to SDRC .unv */
    sdrclib = vdm_SDRCLibBegin();
    vdm_SDRCLibDataFun(sdrclib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38avdm.unv", SYS_SDRC_UNIVERSAL);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, stateen, rpropen);
    vdm_DataFunClose(datafun);
    vdm_SDRCLibEnd(sdrclib);

    /* write to CGNS .cgns */
    cgnsvlib = vdm_CGNSVLibBegin();
    vdm_CGNSVLibDataFun(cgnsvlib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38avdm.cgns", SYS_CGNS);
    if (vdm_DataFunError(datafun) == 0) {
        vdm_LManSaveModel(lman, model);
        vdm_LManSaveState(lman, staten, rpropn);
        vdm_LManSaveState(lman, stateen, rpropen);
        vdm_DataFunClose(datafun);
    }
    vdm_CGNSVLibEnd(cgnsvlib);

    /* end objects */
    vis_ModelEnd(model);
    vis_ConnectEnd(connect);
    vis_StateEnd(staten);
    vis_RPropEnd(rpropn);
    vis_StateEnd(stateen);
    vis_RPropEnd(rpropen);
    vis_GridFunEnd(gf);

    vdm_DataFunEnd(datafun);
    vdm_LManEnd(lman);
    return 0;
}

10.38. Example 38bvdm, Export Simple CFD Finite Element Model and Results

This example illustrates the use of the Model and State objects to export a CFD style finite element model with node velocity results and element pressure results to SDRC Universal file, CGNS file, Fluent .msh file and EnSight .case file format.

Initially, the finite element model is loaded into a Connect object. A Model object is instanced and the Connect object is installed in it using vis_ModelSetObject(). The finite element model consists of some features characteristic of CFD models. The external faces of the volume elements are explicitly represented by interface elements. The interface elements are used to specify boundary conditions of some type, in this case “wall”, “outlet” and “inlet”. These types are reflected in the VIS_FEASPEC element association. Another feature is the assignment of a “zone” to the volume and interface elements. In this case the VIS_PROPID (appropriate for structural analysis related file formats) and VIS_PARTID (appropriate for CFD related file formats) element associations are used to assign a zone identifier.

An optional, user defined name is specified for the interface element associated with the outlet. Note that elements in different zones should not be given the same name. This name will be exported if the target file format supports user defined names.

A node velocity state is generated in a manner similar to Example 38avdm. An element scalar pressure state is generated. The Model and two State objects are exported using VdmTools modules.

#include <stdio.h>
#include "base/base.h"
#include "vis/visdata.h"
#include "vdm/vdm.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
  y            4------5------6
  |           /.     /.     /|
  --x        / .    / .    / |
 /         10-----11-----12  |
z           |  1...|..2...|..3
            | .    | .    | /
            |.     |.     |/
            7------8------9
*/
#define MAX_ELEM 12
#define MAX_NODE 12

static Vint conn[MAX_ELEM][8] = {{1, 2, 5, 4, 7, 8, 11, 10}, {2, 3, 6, 5, 8, 9, 12, 11}, {1, 4, 5, 2, 0, 0, 0, 0},
                                 {2, 5, 6, 3, 0, 0, 0, 0},   {4, 10, 11, 5, 0, 0, 0, 0}, {5, 11, 12, 6, 0, 0, 0, 0},
                                 {10, 7, 8, 11, 0, 0, 0, 0}, {11, 8, 9, 12, 0, 0, 0, 0}, {7, 1, 2, 8, 0, 0, 0, 0},
                                 {8, 2, 3, 9, 0, 0, 0, 0},   {3, 6, 12, 9, 0, 0, 0, 0},  {1, 4, 10, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {SYS_SHAPEHEX,  SYS_SHAPEHEX,  SYS_SHAPEQUAD, SYS_SHAPEQUAD, SYS_SHAPEQUAD, SYS_SHAPEQUAD,
                              SYS_SHAPEQUAD, SYS_SHAPEQUAD, SYS_SHAPEQUAD, SYS_SHAPEQUAD, SYS_SHAPEQUAD, SYS_SHAPEQUAD};

static Vint etyp[MAX_ELEM] = {VIS_ELEM_SOLID, VIS_ELEM_SOLID, VIS_ELEM_INTER, VIS_ELEM_INTER, VIS_ELEM_INTER, VIS_ELEM_INTER,
                              VIS_ELEM_INTER, VIS_ELEM_INTER, VIS_ELEM_INTER, VIS_ELEM_INTER, VIS_ELEM_INTER, VIS_ELEM_INTER};

static Vint espc[MAX_ELEM] = {SYS_SOLID_FLUID, SYS_SOLID_FLUID, SYS_INTER_WALL,   SYS_INTER_WALL,
                              SYS_INTER_WALL,  SYS_INTER_WALL,  SYS_INTER_WALL,   SYS_INTER_WALL,
                              SYS_INTER_WALL,  SYS_INTER_WALL,  SYS_INTER_OUTLET, SYS_INTER_INLET};

static Vint prop[MAX_ELEM] = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {0., 1., 0.}, {1., 1., 0.}, {2., 1., 0.},
                                     {0., 0., 2.}, {1., 0., 2.}, {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
                      Export Simple CFD Finite Element Model and Results
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Connect* connect;
    vis_Model* model;
    vis_State *staten, *statee, *stateg;
    vis_RProp *rpropn, *rprope, *rpropg;
    vis_GridFun* gf;

    vdm_LMan* lman;
    vdm_DataFun* datafun;
    vdm_SDRCLib* sdrclib;
    vdm_CGNSVLib* cgnsvlib;
    vdm_FLUENTLib* fluentlib;
    vdm_EnSightLib* ensightlib;
    vdm_TecplotLib* tecplotlib;
    vdm_NatLib* natlib;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topology and connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEATYPE, i + 1, etyp[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEASPEC, i + 1, espc[i]);
        vis_ConnectSetElemAssoc(connect, VIS_PROPID, i + 1, prop[i]);
        vis_ConnectSetElemAssoc(connect, VIS_PARTID, i + 1, prop[i]);
        if (espc[i] == SYS_INTER_OUTLET) {
            vis_ConnectSetPartName(connect, prop[i], "outlet");
        }
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create model object and install connect object */
    model = vis_ModelBegin();
    vis_ModelSetObject(model, VIS_CONNECT, connect);

    /* create a grid function object */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* create a node vector state */
    staten = vis_StateBegin();
    vis_StateDef(staten, MAX_NODE, SYS_NODE, SYS_NONE, VIS_VECTOR);
    vis_StateSetObject(staten, VIS_GRIDFUN, gf);

    /* use node coordinates as "velocity" for convenience */
    for (i = 0; i < MAX_NODE; i++) {
        vis_StateSetData(staten, i + 1, coords[i]);
    }
    /* create result property for node velocity state */
    rpropn = vis_RPropBegin();
    vis_RPropDef(rpropn, SYS_NODE, SYS_NONE);
    /* set velocity quantity */
    vis_RPropSetType(rpropn, SYS_RES_V);
    /* set ids, eg. step 1 */
    vis_RPropSetIds(rpropn, 1, 0, 0);
    vis_RPropSetValuec(rpropn, RPROP_TITLE, "Velocity step 1");

    /* create a element scalar pressure state */
    statee = vis_StateBegin();
    vis_StateDef(statee, MAX_ELEM, SYS_ELEM, SYS_NONE, VIS_SCALAR);
    vis_StateSetObject(statee, VIS_GRIDFUN, gf);
    /* use element number as "pressure" for convenience */
    for (i = 0; i < MAX_ELEM; i++) {
        Vfloat s;
        s = (Vfloat)i + 1;
        vis_StateSetData(statee, i + 1, &s);
    }
    /* create result property for element pressure state */
    rprope = vis_RPropBegin();
    vis_RPropDef(rprope, SYS_ELEM, SYS_NONE);
    vis_RPropSetType(rprope, SYS_RES_PRES);
    vis_RPropSetIds(rprope, 1, 0, 0);
    vis_RPropSetValuec(rprope, RPROP_TITLE, "Pressure step 1");

    /* create a element scalar generic state */
    stateg = vis_StateBegin();
    vis_StateDef(stateg, MAX_ELEM, SYS_ELEM, SYS_NONE, VIS_SCALAR);
    vis_StateSetObject(stateg, VIS_GRIDFUN, gf);
    /* use negative element number as data for convenience */
    for (i = 0; i < MAX_ELEM; i++) {
        Vfloat s;
        s = (Vfloat)i + 1;
        vis_StateSetData(stateg, i + 1, &s);
    }
    /* create result property for element generic state */
    rpropg = vis_RPropBegin();
    vis_RPropDef(rpropg, SYS_ELEM, SYS_NONE);
    vis_RPropSetType(rpropg, SYS_RES_UNKNOWN);
    vis_RPropSetQual(rpropg, 0, NULL, "MyGenericData");
    vis_RPropSetIds(rpropg, 1, 0, 0);
    vis_RPropSetValuec(rpropg, RPROP_TITLE, "GenericData step 1");

    /* now export to VdmTools supported results files */
    datafun = vdm_DataFunBegin();
    lman = vdm_LManBegin();
    vdm_LManSetObject(lman, VDM_DATAFUN, datafun);

    /* write to SDRC .unv */
    sdrclib = vdm_SDRCLibBegin();
    vdm_SDRCLibDataFun(sdrclib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38bvdm.unv", SYS_SDRC_UNIVERSAL);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, statee, rprope);
    vdm_LManSaveState(lman, stateg, rpropg);
    vdm_DataFunClose(datafun);
    vdm_SDRCLibEnd(sdrclib);

    /* write to CGNS .cgns */
    cgnsvlib = vdm_CGNSVLibBegin();
    vdm_CGNSVLibDataFun(cgnsvlib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38bvdm.cgns", SYS_CGNS);
    if (vdm_DataFunError(datafun) == 0) {
        vdm_LManSaveModel(lman, model);
        vdm_LManSaveState(lman, staten, rpropn);
        vdm_LManSaveState(lman, statee, rprope);
        vdm_LManSaveState(lman, stateg, rpropg);
    }
    vdm_DataFunClose(datafun);
    vdm_CGNSVLibEnd(cgnsvlib);

    /* write to FLUENT .msh */
    fluentlib = vdm_FLUENTLibBegin();
    vdm_FLUENTLibDataFun(fluentlib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38bvdm.msh", SYS_FLUENT_MESH);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, statee, rprope);
    vdm_LManSaveState(lman, stateg, rpropg);
    vdm_DataFunClose(datafun);
    vdm_FLUENTLibEnd(fluentlib);

    /* write to EnSight .case */
    ensightlib = vdm_EnSightLibBegin();
    vdm_EnSightLibDataFun(ensightlib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38bvdm.case", SYS_ENSIGHT);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, statee, rprope);
    vdm_LManSaveState(lman, stateg, rpropg);
    vdm_DataFunClose(datafun);
    vdm_EnSightLibEnd(ensightlib);

    /* write to Tecplot .plt */
    tecplotlib = vdm_TecplotLibBegin();
    vdm_TecplotLibDataFun(tecplotlib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38bvdm.plt", SYS_TECPLOT);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, statee, rprope);
    vdm_LManSaveState(lman, stateg, rpropg);
    vdm_DataFunClose(datafun);
    vdm_TecplotLibEnd(tecplotlib);

    /* write to Native .vdm */
    natlib = vdm_NatLibBegin();
    vdm_NatLibDataFun(natlib, datafun);
    vdm_DataFunSetStatus(datafun, VDM_STATUS_NEW);
    vdm_DataFunOpen(datafun, 0, "exam38bvdm.vdm", SYS_NATIVE);
    vdm_LManSaveModel(lman, model);
    vdm_LManSaveState(lman, staten, rpropn);
    vdm_LManSaveState(lman, statee, rprope);
    vdm_LManSaveState(lman, stateg, rpropg);
    vdm_DataFunClose(datafun);
    vdm_NatLibEnd(natlib);

    /* end objects */
    vis_ModelEnd(model);
    vis_ConnectEnd(connect);
    vis_StateEnd(staten);
    vis_StateEnd(statee);
    vis_StateEnd(stateg);
    vis_RPropEnd(rpropn);
    vis_RPropEnd(rprope);
    vis_RPropEnd(rpropg);
    vis_GridFunEnd(gf);

    vdm_DataFunEnd(datafun);
    vdm_LManEnd(lman);
    return 0;
}

10.39. Example 39, Export a Simple Linear Static Solveable Model

This example illustrates the use of a Model object hierarchy to manage a simple structural analysis finite element model. The Model object acts as a container object for other VisTools and DevTools base objects which together define the finite element model. These objects are then registered in the Model object using vis_ModelSetObject(), vis_ModelSetHashTable() and vis_ModelSetList().

The basic finite element node coordinates, element type, connectivity and property identifiers are defined in a Connect object in the usual way. A single Connect object is registered in the Model hierarchy using vis_ModelSetObject(). Element and material properties are defined using one or more EProp and MProp objects respectively. These objects are entered into HashTable objects ephash and mphash using the property identifier as a key. These HashTable objects are in turn registered in the Model hierarchy using vis_ModelSetHashTable(). Restraint and load cases are defined using RCase and LCase objects respectively. Since there may generally be several restraint cases and load cases, these objects are registered in HashTable objects using the case identifiers as keys in a manner similar to element and material properties. These HashTable objects are also registered in the Model object using vis_ModelSetHashTable().

Solution properties are managed using the SProp object. It is assumed that one or more solutions are executed serially by a finite element solver. As a result the sequence of solutions are registered in a List object using the solution sequence number as a key starting from 1. In this example there is a single solution sequence SProp object which is entered into the first position of a List object. The List of solution procedures is registered with the Model object using vis_ModelSetList().

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 4------5------6
       r        /.     /.     /.
       e       / .    / .    / .
       s      /  .   /  .   /  .
       t     /   1../...2../...3
       r    20-----21-----22  /    +--- pressure 50.
       a    |  .   |  .   |  /
       i    | .    | .    | /
       t    |.     |.     |/
            7------8------9

         y
         |
         --- x
       /
      z
*/
#define MAX_ELEM 2
#define MAX_NODE 12

/* element connectivity */
static Vint conn[MAX_ELEM][8] = {{1, 2, 5, 4, 7, 8, 21, 20}, {2, 3, 6, 5, 8, 9, 22, 21}};

/* user element ids */
static Vint eid[MAX_ELEM] = {10, 20};
/* element topologies */
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX};
static Vint maxi[MAX_ELEM] = {2, 2};
/* element types */
static Vint featype[MAX_ELEM] = {VIS_ELEM_SOLID, VIS_ELEM_SOLID};

/* element property ids */
static Vint pid[MAX_ELEM] = {1, 1};
/* node coordinates */
static Vdouble coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 0.}, {0., 1., 0.}, {1., 1., 0.}, {2., 1., 0.},
                                      {0., 0., 2.}, {1., 0., 2.}, {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/* user node ids */
static Vint nid[MAX_NODE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 21, 22};

/*----------------------------------------------------------------------
                      Export a simple linear static solveable Model
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Model* model;
    vis_Connect* connect;
    vis_GridFun* gf;
    vis_MProp* mprop;
    vis_EProp* eprop;
    vis_SProp* sprop;
    vis_RCase* rcase;
    vis_LCase* lcase;
    vsy_HashTable *ephash, *mphash, *rchash, *lchash;
    vsy_List* splist;
    Vdouble pres[4];
    Vint nix, conntran[8];
    Vint id;
    Vint res[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectPre(connect, SYS_DOUBLE);
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set node coordinates and user ids */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoordsdv(connect, i + 1, coords[i]);
        vis_ConnectSetNodeAssoc(connect, VIS_USERID, i + 1, nid[i]);
    }
    /* set element topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], maxi[i], 0, 0);
    }
    /* set element node connectivity and associations */
    for (i = 0; i < MAX_ELEM; i++) {
        /* translate connectivity in user ids to
           1,...,MAX_NODE index space */
        vis_ConnectElemNum(connect, SYS_NODE, i + 1, &nix);
        vis_ConnectNodeIndices(connect, nix, conn[i], conntran);
        vis_ConnectSetElemNode(connect, i + 1, conntran);
        vis_ConnectSetElemAssoc(connect, VIS_USERID, i + 1, eid[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEATYPE, i + 1, featype[i]);
        vis_ConnectSetElemAssoc(connect, VIS_PROPID, i + 1, pid[i]);
    }

    /* create model object hierarchy */
    model = vis_ModelBegin();

    /* hashtables of element and material properties */
    ephash = vsy_HashTableBegin();
    mphash = vsy_HashTableBegin();

    /* hashtables of restraint and load cases */
    rchash = vsy_HashTableBegin();
    lchash = vsy_HashTableBegin();

    /* list of solution procedures */
    splist = vsy_ListBegin();

    /* material 1 */
    mprop = vis_MPropBegin();
    vis_MPropDef(mprop, SYS_MAT_ISOTROPIC);
    vis_MPropSetValued(mprop, MPROP_E, 1.e+7);
    vis_MPropSetValued(mprop, MPROP_NU, .3);
    vis_MPropSetValued(mprop, MPROP_DENSITY, 1.e-05);
    vsy_HashTableInsert(mphash, 1, mprop);

    /* solid property 1 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SOLID);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vsy_HashTableInsert(ephash, 1, eprop);

    /* GridFun for use with LCase objects with element loads */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* restraint case 1 */
    /* fix nodes 1, 4, 7, 20 in x */
    /* fix node 4 in z, node 7 in y */
    rcase = vis_RCaseBegin();
    vis_ConnectNodeIndex(connect, 1, &id);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TX, RCASE_FIXED, NULL, 0);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TY, RCASE_FIXED, NULL, 0);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TZ, RCASE_FIXED, NULL, 0);
    vis_ConnectNodeIndex(connect, 4, &id);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TX, RCASE_FIXED, NULL, 0);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TZ, RCASE_FIXED, NULL, 0);
    vis_ConnectNodeIndex(connect, 7, &id);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TX, RCASE_FIXED, NULL, 0);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TY, RCASE_FIXED, NULL, 0);
    vis_ConnectNodeIndex(connect, 20, &id);
    vis_RCaseSetSPC(rcase, id, SYS_DOF_TX, RCASE_FIXED, NULL, 0);
    vsy_HashTableInsert(rchash, 1, rcase);

    /* load case 1 */
    /* uniform pressure on face 6 element 20 */
    /* register GridFun object with LCase */
    lcase = vis_LCaseBegin();
    vis_LCaseSetObject(lcase, VIS_GRIDFUN, gf);
    pres[0] = 50.;
    pres[1] = 50.;
    pres[2] = 50.;
    pres[3] = 50.;
    vis_ConnectElemIndex(connect, 20, &id);
    vis_LCaseSetDistdv(lcase, SYS_FACE, id, 6, LCASE_PRES, pres);
    vsy_HashTableInsert(lchash, 1, lcase);

    /* solution step 1 */
    sprop = vis_SPropBegin();
    vis_SPropDef(sprop, SYS_SOL_STATIC);
    vis_SPropSetValuei(sprop, SPROP_ANALYSIS, SYS_ANALYSIS_STRUCTURAL);
    vis_SPropSetValuei(sprop, SPROP_CASEID, 1);
    vis_SPropSetValuei(sprop, SPROP_RCASE, 1);
    vis_SPropSetValued(sprop, SPROP_RCASE_FACTOR, 1.);
    vis_SPropSetValuei(sprop, SPROP_LCASE_NUM, 1);
    vis_SPropSetValuei(sprop, SPROP_LCASE, 1);
    vis_SPropSetValued(sprop, SPROP_LCASE_FACTOR, 1.);
    /* output requests, displacement, stress */
    res[0] = SYS_RES_D;
    res[1] = SYS_RES_S;
    vis_SPropSetValuei(sprop, SPROP_RESPRINT_NUM, 2);
    vis_SPropSetValueiv(sprop, SPROP_RESPRINT, res);
    vis_SPropSetValuei(sprop, SPROP_RESFILE_NUM, 2);
    vis_SPropSetValueiv(sprop, SPROP_RESFILE, res);
    vsy_ListInsert(splist, 1, sprop);

    /* register Connect in Model */
    vis_ModelSetObject(model, VIS_CONNECT, connect);

    /* register property hashtables in Model */
    vis_ModelSetHashTable(model, VIS_MPROP, mphash);
    vis_ModelSetHashTable(model, VIS_EPROP, ephash);

    /* register case hashtables in Model */
    vis_ModelSetHashTable(model, VIS_RCASE, rchash);
    vis_ModelSetHashTable(model, VIS_LCASE, lchash);

    /* register solution property list in Model */
    vis_ModelSetList(model, VIS_SPROP, splist);

    /* write NASTRAN Bulk Data File */
    vis_ModelWrite(model, SYS_NASTRAN_BULKDATA, "exam39.bdf");
    /* write ABAQUS Input Data File */
    vis_ModelWrite(model, SYS_ABAQUS_INPUT, "exam39.inp");
    /* write ANSYS Input Data File */
    vis_ModelWrite(model, SYS_ANSYS_INPUT, "exam39.cdb");
    /* write LS-DYNA Input Data File */
    vis_ModelWrite(model, SYS_LSTC_INPUT, "exam39.k");

    /* end objects */
    vis_GridFunEnd(gf);
    /* Use convenience routine ModelDelete to destroy
       all objects registered in Model */
    vis_ModelDelete(model);
    /* finally destroy Model object */
    vis_ModelEnd(model);
    return 0;
}

10.40. Example 39a, Structural Finite Element Model Using Model

This example illustrates the use of a Model object hierarchy to manage a more complex structural finite element model than in Example 39. All supported element types for export are illustrated.

The objects contained in the Model object are explicitly deleted in this example, however the vis_ModelDelete() function could have been used to perform the same operation.

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
               / .    / . \
              /  .   /  .  \70------80             20
             /   1../...2../|       |  \           |
           12-----13-----14 |       |    \        rbe2
            |  .   |  .   |.|       |      \       |
            | .    | .    | 30------40------15-----18
            |.     |.     |/                 |\      \
            9-----10-----11                  rbe3      \
            \      /    /                    |  \        \
             \tet /wed /                    21   22       19
              \  /    /
               16----17
*/
#define MAX_ELEM 11
#define MAX_NODE 22

/* element connectivity */
static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 30, 70, 6, 10, 11, 14, 13}, {30, 40, 80, 70, 0, 0, 0, 0},
                                 {40, 15, 80, 0, 0, 0, 0, 0}, {9, 10, 13, 16, 0, 0, 0, 0},    {10, 13, 16, 11, 14, 17, 0, 0},
                                 {15, 18, 0, 0, 0, 0, 0, 0},  {18, 0, 0, 0, 0, 0, 0, 0},      {18, 19, 0, 0, 0, 0, 0, 0},
                                 {18, 20, 0, 0, 0, 0, 0, 0},  {15, 21, 22, 0, 0, 0, 0, 0}};

/* user element ids */
static Vint eid[MAX_ELEM] = {10, 11, 20, 21, 30, 31, 100, 101, 102, 103, 104};

/* element topologies */
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX,  VIS_SHAPEHEX,   VIS_SHAPEQUAD, VIS_SHAPETRI,   VIS_SHAPETET,  VIS_SHAPEWED,
                              VIS_SHAPELINE, VIS_SHAPEPOINT, VIS_SHAPELINE, VIS_SHAPEPOINT, VIS_SHAPEPOINT};
static Vint maxi[MAX_ELEM] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3};

/* element types */
static Vint featype[MAX_ELEM] = {VIS_ELEM_SOLID,         VIS_ELEM_SOLID, VIS_ELEM_SHELL, VIS_ELEM_SHELL,
                                 VIS_ELEM_SOLID,         VIS_ELEM_SOLID, VIS_ELEM_BEAM,  VIS_ELEM_MASS,
                                 VIS_ELEM_SPRINGDASHPOT, VIS_ELEM_RIGID, VIS_ELEM_RIGID};

/* element specs */
static Vint feaspec[MAX_ELEM] = {0, 0, 0, 0, 0, 0, 0, 0, SYS_SPRINGDASHPOT_LINK, SYS_RIGID_KINE, SYS_RIGID_DIST};

/* element property ids */
static Vint pid[MAX_ELEM] = {1, 1, 2, 2, 1, 1, 3, 4, 5, 6, 8};

/* element coordinate system indicators and ids */
static Vint ecid[MAX_ELEM] = {0, 0, 0, 0, 0, 0, SYS_ELEMSYS_VECTOR, 0, 1, 0, 0};

/* node coordinates */
static Vdouble coords[MAX_NODE][3] = {{0., 0., 0.},  {1., 0., 0.}, {2., 0., 1.},  {3., 0., 1.},  {0., 1., 0.}, {1., 1., 0.},
                                      {2., 1., 1.},  {3., 1., 1.}, {0., 0., 2.},  {1., 0., 2.},  {2., 0., 2.}, {0., 1., 2.},
                                      {1., 1., 2.},  {2., 1., 2.}, {4., 0., 1.},  {1., 0., 3.},  {2., 0., 3.}, {5., 0., 1.},
                                      {6., -1., 1.}, {5., 1., 1.}, {4., -1., 1.}, {4.5, -1., 1.}};

/* user node ids */
static Vint nid[MAX_NODE] = {1, 2, 30, 40, 5, 6, 70, 80, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22};

/*----------------------------------------------------------------------
                      Manage a Structural Finite Element Model Using Model
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Model* model;
    vis_Connect* connect;
    vis_Units* units;
    vis_ElemDat *elemdatthk, *elemdatvec;
    vis_GridFun* gf;
    vis_CoordSys* coordsys;
    vis_MProp* mprop;
    vis_EProp* eprop;
    vis_SProp* sprop;
    vis_RCase* rcase;
    vis_LCase* lcase;
    vis_CPair* cpair;
    vsy_HashTable *cshash, *ephash, *mphash, *edhash, *rchash, *lchash, *cphash;
    vsy_List* splist;
    Vdouble xo[3], tm[3][3];
    Vdouble force[3], temp;
    Vdouble thk[3];
    Vdouble vec[3], pres[4];
    Vint dofflag[2];
    vis_IdTran *idtrannode, *idtranelem;
    Vint nix, conntran[8];
    Vint id;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectPre(connect, SYS_DOUBLE);
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set up user node and element id translation */
    idtrannode = vis_IdTranBegin();
    for (i = 0; i < MAX_NODE; i++) {
        vis_IdTranSetId(idtrannode, i + 1, nid[i]);
    }
    idtranelem = vis_IdTranBegin();
    for (i = 0; i < MAX_ELEM; i++) {
        vis_IdTranSetId(idtranelem, i + 1, eid[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoordsdv(connect, i + 1, coords[i]);
        vis_ConnectSetNodeAssoc(connect, VIS_USERID, i + 1, nid[i]);
    }

    /* set element topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], maxi[i], 0, 0);
    }

    /* set element node connectivity and associations */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectElemNum(connect, SYS_NODE, i + 1, &nix);
        vis_IdTranIndices(idtrannode, nix, conn[i], conntran);
        vis_ConnectSetElemNode(connect, i + 1, conntran);
        vis_ConnectSetElemAssoc(connect, VIS_USERID, i + 1, eid[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEATYPE, i + 1, featype[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEASPEC, i + 1, feaspec[i]);
        vis_ConnectSetElemAssoc(connect, VIS_PROPID, i + 1, pid[i]);
        vis_ConnectSetElemAssoc(connect, VIS_CSYSID, i + 1, ecid[i]);
    }

    /* create model object hierarchy */
    model = vis_ModelBegin();

    /* hashtables of coordinate systems */
    cshash = vsy_HashTableBegin();

    /* hashtables of element and material properties */
    ephash = vsy_HashTableBegin();
    mphash = vsy_HashTableBegin();

    /* hashtables of element data */
    edhash = vsy_HashTableBegin();

    /* hashtables of restraint and load cases */
    rchash = vsy_HashTableBegin();
    lchash = vsy_HashTableBegin();

    /* hashtable of contact pairs */
    cphash = vsy_HashTableBegin();

    /* list of solution procedures */
    splist = vsy_ListBegin();

    /* units */
    units = vis_UnitsBegin();
    vis_UnitsSetBase(units, UNITS_LENGTH, UNITS_LENGTH_MILLIMETER);
    vis_UnitsSetBase(units, UNITS_MASS, UNITS_MASS_KILOGRAM);
    vis_UnitsSetBase(units, UNITS_TEMP, UNITS_TEMP_KELVIN);

    /* coordinate system 1 for spring element */
    coordsys = vis_CoordSysBegin();
    vis_CoordSysDef(coordsys, SYS_CARTESIAN);
    xo[0] = 0.;
    xo[1] = 0.;
    xo[2] = 0.;
    tm[0][0] = .7071;
    tm[0][1] = -.7071;
    tm[0][2] = 0.;
    tm[1][0] = .7071;
    tm[1][1] = .7071;
    tm[1][2] = 0.;
    tm[2][0] = 0.;
    tm[2][1] = 0.;
    tm[2][2] = 1.;
    vis_CoordSysSetOriginTriaddv(coordsys, xo, tm);
    vsy_HashTableInsert(cshash, 1, coordsys);

    /* material 1 */
    mprop = vis_MPropBegin();
    vis_MPropDef(mprop, SYS_MAT_ISOTROPIC);
    vis_MPropSetValued(mprop, MPROP_E, 1.e+7);
    vis_MPropSetValued(mprop, MPROP_NU, .3);
    vis_MPropSetValued(mprop, MPROP_DENSITY, 0.0000133);
    vsy_HashTableInsert(mphash, 1, mprop);

    /* solid property 1 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SOLID);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vsy_HashTableInsert(ephash, 1, eprop);

    /* shell property 2 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SHELL);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vis_EPropSetValued(eprop, EPROP_THICKNESS, .5);
    vsy_HashTableInsert(ephash, 2, eprop);

    /* beam property 3 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_BEAM);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vis_EPropSetValued(eprop, EPROP_AREA, 2.0);
    vsy_HashTableInsert(ephash, 3, eprop);

    /* mass property 4 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_MASS);
    vis_EPropSetValued(eprop, EPROP_MASS, 3.0);
    vsy_HashTableInsert(ephash, 4, eprop);

    /* spring property 5 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SPRINGDASHPOT);
    /* x-translation at node 1, y-translation at node 2 */
    vis_EPropSetValuei(eprop, EPROP_DOF1, SYS_DOF_TX);
    vis_EPropSetValuei(eprop, EPROP_DOF2, SYS_DOF_TY);
    vis_EPropSetValued(eprop, EPROP_STIFF, 100000.0);
    vsy_HashTableInsert(ephash, 5, eprop);

    /* rigid (RBE2 type) element property 6 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, SYS_ELEM_RIGID);
    vis_EPropSetValuei(eprop, EPROP_DOFFLAG_NUM, 2);
    /* x,y,z translations and rotations at independent node */
    dofflag[0] = (1 << (SYS_DOF_TX - 1)) | (1 << (SYS_DOF_TY - 1)) | (1 << (SYS_DOF_TZ - 1)) | (1 << (SYS_DOF_RX - 1)) |
                 (1 << (SYS_DOF_RY - 1)) | (1 << (SYS_DOF_RZ - 1));
    dofflag[1] = 0;
    vis_EPropSetValueiv(eprop, EPROP_DOFFLAG_IND, dofflag);
    /* x,y,z translations at dependent node */
    dofflag[0] = 0;
    dofflag[1] = (1 << (SYS_DOF_TX - 1)) | (1 << (SYS_DOF_TY - 1)) | (1 << (SYS_DOF_TZ - 1));
    vis_EPropSetValueiv(eprop, EPROP_DOFFLAG_DEP, dofflag);
    /* optional penalty, may or may not be used */
    vis_EPropSetValued(eprop, EPROP_PENALTY, 1.0e+12);
    vsy_HashTableInsert(ephash, 6, eprop);

    /* gap property 7 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_GAP);
    vis_EPropSetValuei(eprop, EPROP_NOSLIP, SYS_ON);
    vis_EPropSetValuei(eprop, EPROP_NOSEPARATION, SYS_ON);
    vsy_HashTableInsert(ephash, 7, eprop);

    /* rigid (RBE3 type) element property 8 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, SYS_ELEM_RIGID);
    vis_EPropSetValuei(eprop, EPROP_DOFFLAG_NUM, 2);
    /* x,y,z translations and rotations at reference node */
    dofflag[0] = (1 << (SYS_DOF_TX - 1)) | (1 << (SYS_DOF_TY - 1)) | (1 << (SYS_DOF_TZ - 1)) | (1 << (SYS_DOF_RX - 1)) |
                 (1 << (SYS_DOF_RY - 1)) | (1 << (SYS_DOF_RZ - 1));
    dofflag[1] = 0;
    vis_EPropSetValueiv(eprop, EPROP_DOFFLAG_DEP, dofflag);
    /* x,y,z translations at distributing nodes */
    dofflag[0] = 0;
    dofflag[1] = (1 << (SYS_DOF_TX - 1)) | (1 << (SYS_DOF_TY - 1)) | (1 << (SYS_DOF_TZ - 1));
    vis_EPropSetValueiv(eprop, EPROP_DOFFLAG_IND, dofflag);
    vis_EPropSetValued(eprop, EPROP_DOFFLAG_WGTS, 2.);
    /* optional penalty, may or may not be used */
    vis_EPropSetValued(eprop, EPROP_PENALTY, 1.0e+12);
    vsy_HashTableInsert(ephash, 8, eprop);

    /* GridFun */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* ElemDat of shell element node thickness */
    elemdatthk = vis_ElemDatBegin();
    vis_ElemDatDef(elemdatthk, MAX_ELEM, SYS_ELEM, SYS_NODE, SYS_SCALAR);
    vis_ElemDatSetObject(elemdatthk, VIS_GRIDFUN, gf);

    /* ElemDat of beam element orientation vectors */
    elemdatvec = vis_ElemDatBegin();
    vis_ElemDatDef(elemdatvec, MAX_ELEM, SYS_ELEM, SYS_NONE, SYS_VECTOR);
    vis_ElemDatSetObject(elemdatvec, VIS_GRIDFUN, gf);

    /* shell element 21 is tapered */
    thk[0] = .5;
    thk[1] = .3;
    thk[2] = .5;
    vis_IdTranIndex(idtranelem, 21, &id);
    vis_ElemDatSetDatadv(elemdatthk, id, 0, thk);
    vsy_HashTableInsert(edhash, SYS_PROP_THICKNESS, elemdatthk);

    /* beam element 100 orientation vector */
    vec[0] = 0.;
    vec[1] = 1.;
    vec[2] = 0.;
    vis_IdTranIndex(idtranelem, 100, &id);
    vis_ElemDatSetDatadv(elemdatvec, id, 0, vec);
    vsy_HashTableInsert(edhash, SYS_PROP_ELEMVEC, elemdatvec);

    /* contact pair, hex element 11 face 6 and shell element 20
       use gap property 7 */
    cpair = vis_CPairBegin();
    vis_CPairDef(cpair, SYS_FACE, SYS_FACE);
    vis_CPairSetObject(cpair, VIS_GRIDFUN, gf);
    vis_IdTranIndex(idtranelem, 11, &id);
    vis_CPairSetMaster(cpair, id, 6);
    vis_IdTranIndex(idtranelem, 20, &id);
    vis_CPairSetSlaveElem(cpair, id, 1);
    vis_CPairSetValuei(cpair, CPAIR_PID, 7);
    vis_CPairSetValued(cpair, CPAIR_ADJUST, .1);
    vsy_HashTableInsert(cphash, 1, cpair);

    /* restraint case 1 */
    rcase = vis_RCaseBegin();
    for (i = 1; i <= 3; i++) {
        vis_RCaseSetSPC(rcase, i, SYS_DOF_TX, RCASE_FIXED, NULL, 0);
        vis_RCaseSetSPC(rcase, i, SYS_DOF_TY, RCASE_FIXED, NULL, 0);
        vis_RCaseSetSPC(rcase, i, SYS_DOF_TZ, RCASE_FIXED, NULL, 0);
    }
    vsy_HashTableInsert(rchash, 1, rcase);

    /* load case 1 */
    lcase = vis_LCaseBegin();

    /* concentrated force on node 12 */
    force[0] = 1.;
    force[1] = 2.;
    force[2] = 3.;
    vis_IdTranIndex(idtrannode, 12, &id);
    vis_LCaseSetConcdv(lcase, id, LCASE_FORCE, force);

    /* temperatures on nodes 16 and 17 */
    vis_IdTranIndex(idtrannode, 16, &id);
    temp = 100.;
    vis_LCaseSetConcdv(lcase, id, LCASE_TEMP, &temp);
    vis_IdTranIndex(idtrannode, 17, &id);
    temp = 200.;
    vis_LCaseSetConcdv(lcase, id, LCASE_TEMP, &temp);

    /* uniform pressure on face 2 element 10 */
    /* register GridFun object with LCase */
    vis_LCaseSetObject(lcase, VIS_GRIDFUN, gf);
    pres[0] = 50.;
    pres[1] = 50.;
    pres[2] = 50.;
    pres[3] = 50.;
    vis_IdTranIndex(idtranelem, 10, &id);
    vis_LCaseSetDistdv(lcase, SYS_FACE, id, 2, LCASE_PRES, pres);
    vsy_HashTableInsert(lchash, 1, lcase);

    /* solution step 1 */
    sprop = vis_SPropBegin();
    vis_SPropDef(sprop, SYS_SOL_STATIC);
    vis_SPropSetValuei(sprop, SPROP_CASEID, 1);
    vis_SPropSetValuei(sprop, SPROP_NONLINEAR, 1);
    vis_SPropSetValuei(sprop, SPROP_RCASE, 1);
    vis_SPropSetValued(sprop, SPROP_RCASE_FACTOR, 1.);
    vis_SPropSetValuei(sprop, SPROP_LCASE_NUM, 1);
    vis_SPropSetValuei(sprop, SPROP_LCASE, 1);
    vis_SPropSetValued(sprop, SPROP_LCASE_FACTOR, 1.);
    vis_SPropSetValued(sprop, SPROP_TIME_INIT, .2);
    vis_SPropSetValued(sprop, SPROP_TIME_STEP, .1);
    vis_SPropSetValued(sprop, SPROP_TIME_TERM, 1.);
    vsy_ListInsert(splist, 1, sprop);

    /* register Connect in Model */
    vis_ModelSetObject(model, VIS_CONNECT, connect);

    /* register Units in Model */
    vis_ModelSetObject(model, VIS_UNITS, units);

    /* register coordinate system hashtables in Model */
    vis_ModelSetHashTable(model, VIS_COORDSYS, cshash);

    /* register property hashtables in Model */
    vis_ModelSetHashTable(model, VIS_MPROP, mphash);
    vis_ModelSetHashTable(model, VIS_EPROP, ephash);

    /* register element data hashtables in Model */
    vis_ModelSetHashTable(model, VIS_ELEMDAT, edhash);

    /* register case hashtables in Model */
    vis_ModelSetHashTable(model, VIS_RCASE, rchash);
    vis_ModelSetHashTable(model, VIS_LCASE, lchash);

    /* register contact pair hashtable in Model */
    vis_ModelSetHashTable(model, VIS_CPAIR, cphash);

    /* register solution property list in Model */
    vis_ModelSetList(model, VIS_SPROP, splist);

    /* print to standard output */
    vis_ModelPrint(model);
    /* write NASTRAN Bulk Data File */
    vis_ModelWrite(model, SYS_NASTRAN_BULKDATA, "exam39a.bdf");
    /* write ABAQUS Input Data File */
    vis_ModelWrite(model, SYS_ABAQUS_INPUT, "exam39a.inp");
    /* write ANSYS Input Data File */
    vis_ModelWrite(model, SYS_ANSYS_INPUT, "exam39a.cdb");
    /* write Ideas Universal File */
    vis_ModelWrite(model, SYS_SDRC_UNIVERSAL, "exam39a.unv");
    /* write PATRAN Neutral File */
    vis_ModelWrite(model, SYS_PATRAN_NEUTRAL, "exam39a.out");
    /* write LS-DYNA Input Data File */
    vis_ModelWrite(model, SYS_LSTC_INPUT, "exam39a.k");

    /* end objects */
    vis_IdTranEnd(idtrannode);
    vis_IdTranEnd(idtranelem);
    vis_GridFunEnd(gf);
    vis_ModelDelete(model);
    vis_ModelEnd(model);
    return 0;
}

10.41. Example 39b, Traverse and Print Contents of a Model Object

This example illustrates loading a Model object with a finite element model residing on an external file and then traversing and printing the contents of the Model object. The finite element model may reside on any external file in a format supported by VdmTools. The external file name is entered as the first argument to the example executable. If no file name is entered then the file “shell.bdf”, a simple NASTRAN bulk data file, is assumed. The model object is created and then loaded using the function vdm_LManLoadModel(). During this process many objects are created and registered in the Model object by the function. These objects represent the various components of the finite element model. Once the model is loaded then all VdmTools objects required to load the model may be deleted.

The Model object is now systematically traversed by accessing the component objects registered in it in turn.

  • Single Connect object containing node coordinates and element connectivity. The Connect object also contains several integer “associations” for each node and element. Examples of associations are user identifier, property identifier, displacement coordinate system identifier, etc.

  • Single ColorMap object relating color indices, such as the VIS_COLORID node and element associations, to actual RGB color components.

  • Single Units object containing the units for physical quantities.

  • HashTable of IdTran objects, one hashtable for node sets, another hashtable for element sets, and a third hashtable for element entity sets (element edge and element face). The hashtable key of each IdTran object is the integer identifier of the set. Use the vis_IdTranGetName() function to access the set name. Use the vis_IdTranGetEntType() function to access the set entity types.

  • HashTable of CoordSys objects, each CoordSys object contains the origin and orientation of a single coordinate system. The hashtable key of each CoordSys object is the coordinate system identifier.

  • HashTable of EProp objects, each EProp object contains element property information such as shell thickness, beam cross sections, etc. The hashtable key of each EProp object is the property identifier.

  • HashTable of MProp objects, each MProp object contains material property information such as Young’s modulus, density, coefficients of thermal expansion, etc. The hashtable key of each MProp object is the material identifier.

  • HashTable of TCurve objects, each TCurve object contains tabular functions such as temperature dependent material properties or time varying load factors. The hashtable key of each TCurve object is the function identifier.

  • HashTable of ElemDat objects, each ElemDat object contains element geometry information which varies with each element. These properties may duplicate properties specified in an EProp object. In this case the properties in ElemDat supercede properties in EProp. The hashtable key of each ElemDat object is a property type defined constant. For example, the hashtable key for thicknesses is SYS_PROP_THICKNESS.

  • HashTable of LCase objects, each LCase object contains loading information such as location and magnitude of concentrated loads, pressure loads and gravity loads. The hashtable key of each LCase object is the load case identifier.

  • HashTable of RCase objects, each RCase object contains information concerning single point constraints of individual nodal degrees of freedom. The hashtable key of each RCase object is the restraint case identifier.

  • HashTable of MCase objects, each MCase object contains information concerning constraints. The hashtable key of each MCase object is the constraint case identifier.

  • HashTable of CPair objects, each CPair object contains information concerning contact pairs. The hashtable key of each CPair object is the contact pair identifier.

  • HashTable of ASurf objects, each ASurf object contains information concerning analytic surfaces. The hashtable key of each ASurf object is the analytic surface identifier.

  • List of SProp objects, each SProp object contains information concerning solution properties for one of a series of solution steps. Solution properties include load case and restraint case identifiers, load factors, save data controls, analysis type, etc. The list key of each SProp object is the sequence number of the solution step. The sequence numbers start from 1 for the first solution step and increment for each subsequent step.

Each Model component is traversed and printed by an associated function within the example. All objects registered in the Model object may be conveniently deleted using vis_ModelDelete(). The Model object itself is deleted using vis_ModelEnd().

#include <stdlib.h>
#include "base/base.h"
#include "vis/visdata.h"
#include "vdm/vdm.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

static void
printGProp(vis_GProp* gprop);
static void
printConnect(vis_Connect* connect);
static void
printIdTran(vsy_HashTable* nehash);
static void
printCoordSys(vsy_HashTable* coordsyshash);
static void
printUnits(vis_Units* units);
static void
printEProp(vsy_HashTable* ephash);
static void
printMProp(vsy_HashTable* mphash);
static void
printTCurve(vsy_HashTable* tchash);
static void
printElemDat(vsy_HashTable* edhash, vis_Connect* connect);
static void
printLCase(vsy_HashTable* lchash, vis_Connect* connect);
static void
printRCase(vsy_HashTable* rchash, vis_Connect* connect);
static void
printMCase(vsy_HashTable* mchash, vis_Connect* connect);
static void
printCPair(vsy_HashTable* cphash, vis_Connect* connect);
static void
printRBody(vsy_HashTable* rbhash, vis_Connect* connect);
static void
printASurf(vsy_HashTable* ashash, vis_Connect* connect);
static void
printSProp(vsy_List* splist);

/* useful macro for parsing group activity flags */
#define VIEW_FLAG(flags, ind) (((flags) >> ((ind)-1)) & 1)

/*----------------------------------------------------------------------
                      Traverse and print contents of a Model object
----------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    char inputfile[256];
    vdm_ABAFil* abafil = NULL;
    vdm_ABALib* abalib = NULL;
    vdm_ANSFil* ansfil = NULL;
    vdm_ANSLib* anslib = NULL;
    vdm_D3DFil* d3dfil = NULL;
    vdm_D3DLib* d3dlib = NULL;
    vdm_NASFil* nasfil = NULL;
    vdm_PAMFil* pamfil = NULL;
    vdm_NASLib* naslib = NULL;
    vdm_NatLib* natlib = NULL;
    vdm_RASLib* raslib = NULL;
    vdm_MarcLib* marclib = NULL;
    vdm_SDRCLib* sdrclib = NULL;
    vdm_PatLib* patlib = NULL;
    vdm_CGNSVLib* cgnsvlib = NULL;
    vdm_FLUENTLib* fluentlib = NULL;
    vdm_DataFun* datafun = NULL;
    vdm_LMan* lman = NULL;
    Vint filetype = 0;
    vis_Model* model = NULL;
    vis_GProp* gprop = NULL;
    vis_Connect* connect = NULL;
    vis_Units* units = NULL;
    vsy_HashTable* coordsyshash = NULL;
    vsy_HashTable* eprophash = NULL;
    vsy_HashTable* mprophash = NULL;
    vsy_HashTable* tcurvehash = NULL;
    vsy_HashTable* lcasehash = NULL;
    vsy_HashTable* rcasehash = NULL;
    vsy_HashTable* mcasehash = NULL;
    vsy_HashTable* cpairhash = NULL;
    vsy_HashTable* rbodyhash = NULL;
    vsy_HashTable* asurfhash = NULL;
    vsy_HashTable* elemdathash = NULL;
    vsy_HashTable* nsethash = NULL;
    vsy_HashTable* esethash = NULL;
    vsy_HashTable* eenthash = NULL;
    vsy_List* sproplist = NULL;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s inputfile\n", argv[0]);
        fprintf(stderr, " inputfile is blank, 'shell.bdf' is assumed\n");
        strcpy(inputfile, "shell.bdf");
    }
    else {
        strcpy(inputfile, argv[1]);
    }

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create data function object */
    datafun = vdm_DataFunBegin();

    /* determine file type from file extension */
    if (strstr(inputfile, ".bdf") != NULL || strstr(inputfile, ".dat") != NULL) {
        filetype = VDM_NASTRAN_BULKDATA;
        nasfil = vdm_NASFilBegin();
        vdm_NASFilDataFun(nasfil, datafun);
        printf("Nastran Bulk Data File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".op2") != NULL) {
        filetype = VDM_NASTRAN_OUTPUT2;
        naslib = vdm_NASLibBegin();
        vdm_NASLibDataFun(naslib, datafun);
        printf("Nastran Output2 File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".vdm") != NULL) {
        filetype = VDM_NATIVE;
        natlib = vdm_NatLibBegin();
        vdm_NatLibDataFun(natlib, datafun);
        printf("Native File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".pc") != NULL) {
        filetype = VDM_PAM_INPUT;
        pamfil = vdm_PAMFilBegin();
        vdm_PAMFilDataFun(pamfil, datafun);
        printf("PAM Input File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".inp") != NULL) {
        filetype = VDM_ABAQUS_INPUT;
        abafil = vdm_ABAFilBegin();
        vdm_ABAFilDataFun(abafil, datafun);
        printf("Abaqus Input File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".fil") != NULL) {
        filetype = VDM_ABAQUS_FIL;
        abalib = vdm_ABALibBegin();
        vdm_ABALibDataFun(abalib, datafun);
        printf("Abaqus Binary (.fil) File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".odb") != NULL) {
        filetype = VDM_ABAQUS_ODB;
        abalib = vdm_ABALibBegin();
        vdm_ABALibDataFun(abalib, datafun);
        printf("Abaqus Output (.odb) File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".cdb") != NULL) {
        filetype = VDM_ANSYS_INPUT;
        ansfil = vdm_ANSFilBegin();
        vdm_ANSFilDataFun(ansfil, datafun);
        printf("Ansys Input File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".rst") != NULL) {
        filetype = VDM_ANSYS_RESULT;
        anslib = vdm_ANSLibBegin();
        vdm_ANSLibDataFun(anslib, datafun);
        printf("Ansys Result (.rst) File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".k") != NULL) {
        filetype = VDM_LSTC_INPUT;
        d3dfil = vdm_D3DFilBegin();
        vdm_D3DFilDataFun(d3dfil, datafun);
        printf("LS-DYNA Input File: %s\n", inputfile);
    }
    else if (strstr(inputfile, "d3plot") != NULL) {
        filetype = VDM_LSTC_STATE;
        d3dlib = vdm_D3DLibBegin();
        vdm_D3DLibDataFun(d3dlib, datafun);
        printf("LS-DYNA State Database: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".neu") != NULL) {
        filetype = VDM_MECHANICA_STUDY;
        raslib = vdm_RASLibBegin();
        vdm_RASLibDataFun(raslib, datafun);
        printf("PTC Mechanica Study: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".unv") != NULL || strstr(inputfile, ".bun") != NULL) {
        filetype = VDM_SDRC_UNIVERSAL;
        sdrclib = vdm_SDRCLibBegin();
        vdm_SDRCLibDataFun(sdrclib, datafun);
        printf("SDRC Universal File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".out") != NULL) {
        filetype = VDM_PATRAN_NEUTRAL;
        patlib = vdm_PatLibBegin();
        vdm_PatLibDataFun(patlib, datafun);
        printf("MSC/PATRAN Neutral File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".cgns") != NULL) {
        filetype = VDM_CGNS;
        cgnsvlib = vdm_CGNSVLibBegin();
        vdm_CGNSVLibDataFun(cgnsvlib, datafun);
        printf("CGNS Data File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".cas") != NULL || strstr(inputfile, ".msh") != NULL) {
        filetype = VDM_FLUENT_MESH;
        fluentlib = vdm_FLUENTLibBegin();
        vdm_FLUENTLibDataFun(fluentlib, datafun);
        printf("Fluent Mesh File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".t16") != NULL || strstr(inputfile, ".t19") != NULL) {
        filetype = VDM_MARC_POST;
        marclib = vdm_MarcLibBegin();
        vdm_MarcLibDataFun(marclib, datafun);
        printf("Marc File: %s\n", inputfile);
    }
    else {
        fprintf(stderr, "Error: Bad input file %s\n", inputfile);
        exit(1);
    }
    /* open library device */
    vdm_DataFunOpen(datafun, 0, inputfile, filetype);

    /* instance model object for finite element model */
    model = vis_ModelBegin();

    /* use Library Manager object to load model */
    lman = vdm_LManBegin();
    vdm_LManSetObject(lman, VDM_DATAFUN, datafun);
    vdm_LManLoadModel(lman, model);
    if (vdm_LManError(lman)) {
        fprintf(stderr, "Error: Unable to load model information\n");
        exit(1);
    }
    /* close library device and delete interface */
    vdm_DataFunClose(datafun);
    vdm_DataFunEnd(datafun);
    if (filetype == VDM_NASTRAN_BULKDATA) {
        vdm_NASFilEnd(nasfil);
    }
    else if (filetype == VDM_NASTRAN_OUTPUT2) {
        vdm_NASLibEnd(naslib);
    }
    else if (filetype == VDM_NATIVE) {
        vdm_NatLibEnd(natlib);
    }
    else if (filetype == VDM_PAM_INPUT) {
        vdm_PAMFilEnd(pamfil);
    }
    else if (filetype == VDM_ABAQUS_INPUT) {
        vdm_ABAFilEnd(abafil);
    }
    else if (filetype == VDM_ABAQUS_FIL) {
        vdm_ABALibEnd(abalib);
    }
    else if (filetype == VDM_ABAQUS_ODB) {
        vdm_ABALibEnd(abalib);
    }
    else if (filetype == VDM_ANSYS_INPUT) {
        vdm_ANSFilEnd(ansfil);
    }
    else if (filetype == VDM_ANSYS_RESULT) {
        vdm_ANSLibEnd(anslib);
    }
    else if (filetype == VDM_LSTC_INPUT) {
        vdm_D3DFilEnd(d3dfil);
    }
    else if (filetype == VDM_LSTC_STATE) {
        vdm_D3DLibEnd(d3dlib);
    }
    else if (filetype == VDM_MECHANICA_STUDY) {
        vdm_RASLibEnd(raslib);
    }
    else if (filetype == VDM_SDRC_UNIVERSAL) {
        vdm_SDRCLibEnd(sdrclib);
    }
    else if (filetype == VDM_PATRAN_NEUTRAL) {
        vdm_PatLibEnd(patlib);
    }
    else if (filetype == VDM_CGNS) {
        vdm_CGNSVLibEnd(cgnsvlib);
    }
    else if (filetype == VDM_FLUENT_MESH) {
        vdm_FLUENTLibEnd(fluentlib);
    }
    else if (filetype == VDM_MARC_POST) {
        vdm_MarcLibEnd(marclib);
    }
    vdm_LManEnd(lman);

    /* traverse Model object */
    /* global properties */
    vis_ModelGetObject(model, VIS_GPROP, (Vobject**)&gprop);
    if (gprop != NULL) {
        printGProp(gprop);
    }
    /* get Connect object and print nodes and elements */
    vis_ModelGetObject(model, VIS_CONNECT, (Vobject**)&connect);
    if (connect != NULL) {
        printConnect(connect);
    }
    /* node sets */
    vis_ModelGetHashTable(model, VIS_IDTRAN_NODE, &nsethash);
    if (nsethash != NULL) {
        printIdTran(nsethash);
    }
    /* element sets */
    vis_ModelGetHashTable(model, VIS_IDTRAN_ELEM, &esethash);
    if (esethash != NULL) {
        printIdTran(esethash);
    }
    /* element entity sets */
    vis_ModelGetHashTable(model, VIS_IDTRAN_ELEMENT, &eenthash);
    if (eenthash != NULL) {
        printIdTran(eenthash);
    }
    /* coordinate systems */
    vis_ModelGetHashTable(model, VIS_COORDSYS, &coordsyshash);
    if (coordsyshash != NULL) {
        printCoordSys(coordsyshash);
    }
    /* units */
    vis_ModelGetObject(model, VIS_UNITS, (Vobject**)&units);
    if (units != NULL) {
        printUnits(units);
    }
    /* element properties */
    vis_ModelGetHashTable(model, VIS_EPROP, &eprophash);
    if (eprophash != NULL) {
        printEProp(eprophash);
    }
    /* material properties */
    vis_ModelGetHashTable(model, VIS_MPROP, &mprophash);
    if (mprophash != NULL) {
        printMProp(mprophash);
    }
    /* tabular functions */
    vis_ModelGetHashTable(model, VIS_TCURVE, &tcurvehash);
    if (tcurvehash != NULL) {
        printTCurve(tcurvehash);
    }
    /* element data */
    vis_ModelGetHashTable(model, VIS_ELEMDAT, &elemdathash);
    if (elemdathash != NULL) {
        printElemDat(elemdathash, connect);
    }
    /* load cases */
    vis_ModelGetHashTable(model, VIS_LCASE, &lcasehash);
    if (lcasehash != NULL) {
        printLCase(lcasehash, connect);
    }
    /* restraint cases */
    vis_ModelGetHashTable(model, VIS_RCASE, &rcasehash);
    if (rcasehash != NULL) {
        printRCase(rcasehash, connect);
    }
    /* multipoint constraint cases */
    vis_ModelGetHashTable(model, VIS_MCASE, &mcasehash);
    if (mcasehash != NULL) {
        printMCase(mcasehash, connect);
    }
    /* contact pairs */
    vis_ModelGetHashTable(model, VIS_CPAIR, &cpairhash);
    if (cpairhash != NULL) {
        printCPair(cpairhash, connect);
    }
    /* rigid bodies */
    vis_ModelGetHashTable(model, VIS_RBODY, &rbodyhash);
    if (rbodyhash != NULL) {
        printRBody(rbodyhash, connect);
    }
    /* analytic surfaces */
    vis_ModelGetHashTable(model, VIS_ASURF, &asurfhash);
    if (asurfhash != NULL) {
        printASurf(asurfhash, connect);
    }
    /* solution properties */
    vis_ModelGetList(model, VIS_SPROP, &sproplist);
    if (sproplist != NULL) {
        printSProp(sproplist);
    }
    /* delete objects registered in Model */
    vis_ModelDelete(model);
    /* destroy Model object itself */
    vis_ModelEnd(model);
    return 0;
}

/*----------------------------------------------------------------------
                      print nodes and elements
----------------------------------------------------------------------*/
static void
printConnect(vis_Connect* connect)
{
    Vint i, j, k;
    Vint numnp, numel;
    Vint nid, cid;
    Vint eid, pid, mid, partid;
    Vint featype;
    Vchar extname[9];
    Vdouble x[3];
    Vint maxelemnode;
    Vint nix, *ix, *ux;
    Vint shape, maxi, maxj, maxk;
    Vint nfaces;
    Vint numpartname;
    Vchar partname[256];
    Vint numpartijk, ijk[3];

    vis_ConnectNumber(connect, SYS_NODE, &numnp);
    vis_ConnectNumber(connect, SYS_ELEM, &numel);
    printf("\n");
    printf("Number of nodes=    %d\n", numnp);
    printf("Number of elements= %d\n", numel);
    /* nodes: coordinates, user id and
       displacement coordinate system id */
    printf("\nNodes\n");
    for (i = 1; i <= numnp; i++) {
        vis_ConnectCoordsdv(connect, 1, &i, (Vdouble(*)[3])x);
        vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &i, &nid);
        vis_ConnectNodeAssoc(connect, VIS_CSYSID, 1, &i, &cid);
        printf("id= %d, cid= %d, x= %e %e %e\n", nid, cid, x[0], x[1], x[2]);
        /* check for scalar node */
        vis_ConnectNodeAssoc(connect, VIS_FEATYPE, 1, &i, &featype);
        if (featype == SYS_NODE_SCALAR) {
            printf("featype= Scalar node\n");
        }
    }
    /* elements: connectivity, user id, material and
       property id, etc. */
    printf("\nElements\n");
    vis_ConnectMaxElemNode(connect, &maxelemnode);
    /* allocate vectors for internal node ids and user ids */
    ix = (Vint*)malloc(maxelemnode * sizeof(Vint));
    ux = (Vint*)malloc(maxelemnode * sizeof(Vint));
    for (i = 1; i <= numel; i++) {
        vis_ConnectTopology(connect, i, &shape, &maxi, &maxj, &maxk);
        vis_ConnectElemNode(connect, i, &nix, ix);
        vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &eid);
        vis_ConnectElemAssoc(connect, VIS_PARTID, 1, &i, &partid);
        vis_ConnectElemAssoc(connect, VIS_PROPID, 1, &i, &pid);
        vis_ConnectElemAssoc(connect, VIS_MATLID, 1, &i, &mid);
        vis_ConnectElemAssoc(connect, VIS_CSYSID, 1, &i, &cid);
        vis_ConnectElemAssoc(connect, VIS_FEATYPE, 1, &i, &featype);
        printf("id= %d, partid= %d, pid= %d, mid= %d, cid= %d, nodes= %d\n", eid, partid, pid, mid, cid, nix);
        /* interpret shape */
        if (shape == SYS_SHAPEPOINT) {
            printf(" shape= Point(s):");
        }
        else if (shape == SYS_SHAPELINE) {
            printf(" shape= Line:");
        }
        else if (shape == SYS_SHAPETRI) {
            printf(" shape= Triangle:");
        }
        else if (shape == SYS_SHAPEQUAD) {
            printf(" shape= Quadrilateral:");
        }
        else if (shape == SYS_SHAPETET) {
            printf(" shape= Tetrahedron:");
        }
        else if (shape == SYS_SHAPEPYR) {
            printf(" shape= Pyramid:");
        }
        else if (shape == SYS_SHAPEWED) {
            printf(" shape= Pentahedron:");
        }
        else if (shape == SYS_SHAPEHEX) {
            printf(" shape= Hexahedron:");
        }
        else if (shape == SYS_SHAPEPOLYGON) {
            printf(" shape= Polygon:");
        }
        else if (shape == SYS_SHAPEPOLYHED) {
            printf(" shape= Polyhedron:");
        }
        printf("  maxi= %d, maxj= %d, maxk= %d\n", maxi, maxj, maxk);
        /* interpret featype */
        if (featype == SYS_ELEM_SOLID) {
            printf(" featype= Solid\n");
        }
        else if (featype == SYS_ELEM_SHELL) {
            printf(" featype= Shell\n");
        }
        else if (featype == SYS_ELEM_MEMBRANE) {
            printf(" featype= Membrane\n");
        }
        else if (featype == SYS_ELEM_BEAM) {
            printf(" featype= Beam\n");
        }
        else if (featype == SYS_ELEM_TRUSS) {
            printf(" featype= Truss\n");
        }
        else if (featype == SYS_ELEM_GAP) {
            printf(" featype= Gap\n");
        }
        else if (featype == SYS_ELEM_SPRINGDASHPOT) {
            printf(" featype= Spring Dashpot\n");
        }
        else if (featype == SYS_ELEM_RIGID) {
            printf(" featype= Rigid\n");
        }
        else if (featype == SYS_ELEM_CONSTRAINT) {
            printf(" featype= Constraint\n");
        }
        else if (featype == SYS_ELEM_PLOT) {
            printf(" featype= Plot\n");
        }
        else if (featype == SYS_ELEM_MASS) {
            printf(" featype= Mass\n");
        }
        else if (featype == SYS_ELEM_INTER) {
            printf(" featype= Interface\n");
        }
        /* get external name */
        vis_ConnectElemAssoc(connect, VIS_EXTNAMEA, 1, &i, (Vint*)extname);
        vis_ConnectElemAssoc(connect, VIS_EXTNAMEB, 1, &i, (Vint*)&extname[4]);
        extname[8] = '\0';
        printf(" extname= %s\n", extname);
        /* convert internal index to user id */
        vis_ConnectNodeAssoc(connect, VIS_USERID, nix, ix, ux);
        /* print element connectivity */
        printf(" connectivity=");
        for (j = 0; j < nix; j++) {
            printf(" %d", ux[j]);
        }
        printf("\n");
        /* print element face connectivity */
        vis_ConnectElemNum(connect, SYS_FACE, i, &nfaces);
        printf(" number of faces= %d\n", nfaces);
        for (k = 1; k <= nfaces; k++) {
            vis_ConnectElemCon(connect, SYS_FACE, i, k, &nix, ix);
            vis_ConnectElemTopo(connect, SYS_FACE, i, k, &shape, &maxi, &maxj);
            printf(" face= %d\n", k);
            if (shape == SYS_SHAPETRI) {
                printf("   shape= Triangle:");
            }
            else if (shape == SYS_SHAPEQUAD) {
                printf("   shape= Quadrilateral:");
            }
            else if (shape == SYS_SHAPEPOLYGON) {
                printf(" shape= Polygon:");
            }
            printf("  maxi= %d, maxj= %d\n", maxi, maxj);
            /* convert internal index to user id */
            vis_ConnectNodeAssoc(connect, VIS_USERID, nix, ix, ux);
            printf("   connectivity=");
            for (j = 0; j < nix; j++) {
                printf(" %d", ux[j]);
            }
            printf("\n");
        }
    }
    /* list part names */
    vis_ConnectNumPartName(connect, &numpartname);
    for (i = 1; i <= numpartname; i++) {
        vis_ConnectIthPartName(connect, i, &partid, partname);
        printf("partid= %d, partname= %s\n", partid, partname);
    }
    /* list part ijk structure */
    vis_ConnectNumPartIJK(connect, &numpartijk);
    for (i = 1; i <= numpartijk; i++) {
        vis_ConnectIthPartIJK(connect, i, &partid, ijk);
        printf("partid= %d, partijk= %d %d %d\n", partid, ijk[0], ijk[1], ijk[2]);
    }

    /* free vectors */
    free(ix);
    free(ux);
}

/*----------------------------------------------------------------------
                      print uprop
----------------------------------------------------------------------*/
static void
printUProp(vis_UProp* uprop)
{
    Vint i, j;
    Vint num, nval, dtype;
    Vchar name[256];
    Vchar cval[256];
    Vfloat fval[16];
    Vint ival[16];

    vis_UPropNum(uprop, &num);
    printf("number of user properties= %d\n", num);
    for (i = 1; i <= num; i++) {
        vis_UPropGetType(uprop, i, name, &nval, &dtype);
        printf("property= %d\n", i);
        printf(" name= %s\n", name);
        printf(" nval= %d\n", nval);
        printf(" dtype= %d\n", dtype);
        if (dtype == SYS_INTEGER) {
            vis_UPropValueInteger(uprop, i, ival);
            for (j = 0; j < nval; j++) {
                printf(" ival= %d\n", ival[j]);
            }
        }
        else if (dtype == SYS_FLOAT) {
            vis_UPropValueFloat(uprop, i, fval);
            for (j = 0; j < nval; j++) {
                printf(" fval= %e\n", fval[j]);
            }
        }
        else if (dtype == SYS_CHAR) {
            vis_UPropValueString(uprop, i, cval);
            printf(" cval= %s\n", cval);
        }
    }
}

/*----------------------------------------------------------------------
                      print set
----------------------------------------------------------------------*/
static void
printIdTran(vsy_HashTable* nehash)
{
    Vint i;
    Vint iset;
    Vint nument;
    Vint id, no;
    vis_IdTran* idtran;
    vis_UProp* uprop;
    Vint enttype, subtype;
    Vint type, spec;
    Vchar name[256];

    vsy_HashTableInitIter(nehash);
    while (vsy_HashTableNextIter(nehash, &iset, (Vobject**)&idtran), idtran) {
        /* print set name, etc. */
        vis_IdTranGetEntType(idtran, &enttype, &subtype);
        vis_IdTranGetName(idtran, name);
        if (enttype == SYS_NODE && subtype == SYS_NONE) {
            printf("\nNode Set, iset= %d, Name= %s\n", iset, name);
        }
        else if (enttype == SYS_ELEM && subtype == SYS_NONE) {
            printf("\nElement Set, iset= %d, Name= %s\n", iset, name);
        }
        else if (enttype == SYS_ELEM && subtype == SYS_EDGE) {
            printf("\nElement Edge Set, iset= %d, Name= %s\n", iset, name);
        }
        else if (enttype == SYS_ELEM && subtype == SYS_FACE) {
            printf("\nElement Face Set, iset= %d, Name= %s\n", iset, name);
        }
        /* print type and spec */
        vis_IdTranGetType(idtran, &type);
        vis_IdTranGetSpec(idtran, &spec);
        printf("type= %d, spec= %d\n", type, spec);
        /* print possible user defined data */
        vis_IdTranGetUProp(idtran, &uprop);
        if (uprop) {
            printUProp(uprop);
        }
        /* print entity indices in set */
        /* note, these are not the node or element user id */
        vis_IdTranInq(idtran, &nument);
        for (i = 1; i <= nument; i++) {
            vis_IdTranGetId(idtran, i, &id);
            if (subtype == SYS_NONE) {
                printf("id= %d\n", id);
            }
            else {
                vis_IdTranGetEnt(idtran, i, &no);
                printf("id= %d, no= %d\n", id, no);
            }
        }
    }
}

/*----------------------------------------------------------------------
                      print coordinate systems
----------------------------------------------------------------------*/
static void
printCoordSys(vsy_HashTable* cshash)
{
    vis_CoordSys* coordsys;
    Vint id;
    Vint type;
    Vdouble x[3], tm[3][3];

    printf("\nCoordinate Systems\n");
    vsy_HashTableInitIter(cshash);
    while (vsy_HashTableNextIter(cshash, &id, (Vobject**)&coordsys), coordsys) {
        printf("id= %d, type= ", id);
        vis_CoordSysInq(coordsys, &type);
        if (type == SYS_CARTESIAN) {
            printf(" Cartesian\n");
        }
        else if (type == SYS_CYLINDRICAL) {
            printf(" Cylindrical\n");
        }
        else if (type == SYS_SPHERICAL) {
            printf(" Spherical\n");
        }
        else if (type == SYS_SPHERICAL_ALT) {
            printf(" Spherical Alternate\n");
        }
        else if (type == SYS_TOROIDAL) {
            printf(" Toroidal\n");
        }
        else if (type == SYS_CYLINDRICAL_ALT) {
            printf(" Cylindrical Alternate\n");
        }
        vis_CoordSysOriginTriaddv(coordsys, x, tm);
        printf(" origin= %e %e %e\n", x[0], x[1], x[2]);
        printf(" dircos= %e %e %e\n", tm[0][0], tm[1][0], tm[2][0]);
        printf("         %e %e %e\n", tm[0][1], tm[1][1], tm[2][1]);
        printf("         %e %e %e\n", tm[0][2], tm[1][2], tm[2][2]);
    }
}

/*----------------------------------------------------------------------
                      print global properties
----------------------------------------------------------------------*/
static void
printGProp(vis_GProp* gprop)
{
    Vint i;
    Vint flag;
    Vint iparams[2];
    Vfloat fparams[3];
    Vdouble dparams[3];
    Vchar cparams[81];
    Vint user_num, user_ith, userdimenum, userdime, userdatatype;
    Vint symmnum, *isymm;

    printf("\nGProp\n");

    vis_GPropValueFlag(gprop, GPROP_TITLE, &flag);
    if (flag) {
        vis_GPropValueString(gprop, GPROP_TITLE, cparams);
        printf("TITLE: %s\n", cparams);
    }
    vis_GPropValueFlag(gprop, GPROP_SUBTITLE, &flag);
    if (flag) {
        vis_GPropValueString(gprop, GPROP_SUBTITLE, cparams);
        printf("SUBTITLE: %s\n", cparams);
    }
    vis_GPropValueFlag(gprop, GPROP_2DPLANE, &flag);
    if (flag) {
        vis_GPropValueInteger(gprop, GPROP_2DPLANE, iparams);
        printf("2DPLANE: %d\n", iparams[0]);
    }
    vis_GPropValueFlag(gprop, GPROP_2DTYPE, &flag);
    if (flag) {
        vis_GPropValueInteger(gprop, GPROP_2DTYPE, iparams);
        printf("2DTYPE: %d\n", iparams[0]);
    }
    /* cyclic symmetry information */
    vis_GPropValueFlag(gprop, GPROP_CYCLIC_NSEC, &flag);
    if (flag) {
        vis_GPropValueInteger(gprop, GPROP_CYCLIC_NSEC, iparams);
        printf("CYCLIC_NSEC: %d\n", iparams[0]);
    }
    vis_GPropValueFlag(gprop, GPROP_CYCLIC_ORIG, &flag);
    if (flag) {
        vis_GPropValueFloat(gprop, GPROP_CYCLIC_ORIG, fparams);
        printf("CYCLIC_ORIG: %e %e %e\n", fparams[0], fparams[1], fparams[2]);
    }
    vis_GPropValueFlag(gprop, GPROP_CYCLIC_AXIS, &flag);
    if (flag) {
        vis_GPropValueFloat(gprop, GPROP_CYCLIC_AXIS, fparams);
        printf("CYCLIC_AXIS: %e %e %e\n", fparams[0], fparams[1], fparams[2]);
    }
    /* generalized symmetry set information */
    vis_GPropValueFlag(gprop, GPROP_SYMM_NUM, &flag);
    if (flag) {
        vis_GPropValueInteger(gprop, GPROP_SYMM_NUM, &symmnum);
        printf("SYMM_NUM: %d\n", symmnum);
        isymm = (Vint*)malloc(symmnum * sizeof(Vint));
        vis_GPropValueFlag(gprop, GPROP_SYMM_ID, &flag);
        if (flag) {
            vis_GPropValueInteger(gprop, GPROP_SYMM_ID, isymm);
            printf("SYMM_ID:");
            for (i = 0; i < symmnum; i++) {
                printf(" %d", isymm[i]);
            }
            printf("\n");
        }
        vis_GPropValueFlag(gprop, GPROP_SYMM_NSEC, &flag);
        if (flag) {
            vis_GPropValueInteger(gprop, GPROP_SYMM_NSEC, isymm);
            printf("SYMM_NSEC:");
            for (i = 0; i < symmnum; i++) {
                printf(" %d", isymm[i]);
            }
            printf("\n");
        }
        free(isymm);
        /* other GPROP_SYMM_XXX are similar */
    }
    /* user defined scalar values */
    vis_GPropValueFlag(gprop, GPROP_USER_NUM, &flag);
    if (flag) {
        vis_GPropValueInteger(gprop, GPROP_USER_NUM, &user_num);
        for (user_ith = 0; user_ith < user_num; user_ith++) {
            vis_GPropValueInteger(gprop, GPROP_USERDIMENUM + user_ith, &userdimenum);
            if (userdimenum > 1)
                continue;
            vis_GPropValueInteger(gprop, GPROP_USERDIME + user_ith, &userdime);
            if (userdime > 1)
                continue;
            vis_GPropValueString(gprop, GPROP_USERNAME + user_ith, cparams);
            printf("user name= %s\n", cparams);
            vis_GPropValueInteger(gprop, GPROP_USERDATATYPE + user_ith, &userdatatype);
            if (userdatatype == SYS_INTEGER) {
                vis_GPropValueInteger(gprop, GPROP_USERDATA + user_ith, iparams);
                printf("user data= %d\n", iparams[0]);
            }
            else if (userdatatype == SYS_DOUBLE || userdatatype == SYS_FLOAT) {
                vis_GPropValueDouble(gprop, GPROP_USERDATA + user_ith, dparams);
                printf("user data= %le\n", dparams[0]);
            }
        }
    }
}

/*----------------------------------------------------------------------
                      print units
----------------------------------------------------------------------*/
static void
printUnits(vis_Units* units)
{
    Vint length, mass, time, temp, angle, charge;
    Vint clength, cmass, ctime, ctemp, cangle, ccharge;
    Vdouble lengthfac, massfac, timefac, tempfac, tempoff, anglefac, chargefac;
    Vchar cstg[33];

    printf("\nUnits\n");
    /* get basic unit types */
    vis_UnitsGetBase(units, UNITS_LENGTH, &length);
    vis_UnitsGetBase(units, UNITS_MASS, &mass);
    vis_UnitsGetBase(units, UNITS_TIME, &time);
    vis_UnitsGetBase(units, UNITS_TEMP, &temp);
    vis_UnitsGetBase(units, UNITS_ANGLE, &angle);
    vis_UnitsGetBase(units, UNITS_CHARGE, &charge);

    /* print */
    vis_UnitsGetDesc(units, UNITS_LENGTH, length, cstg);
    printf("length type= %d, %s\n", length, cstg);
    vis_UnitsGetDesc(units, UNITS_MASS, mass, cstg);
    printf("mass type=  %d, %s\n", mass, cstg);
    vis_UnitsGetDesc(units, UNITS_TIME, time, cstg);
    printf("time type=  %d, %s\n", time, cstg);
    vis_UnitsGetDesc(units, UNITS_TEMP, temp, cstg);
    printf("temp type=  %d, %s\n", temp, cstg);
    vis_UnitsGetDesc(units, UNITS_ANGLE, angle, cstg);
    printf("angle type= %d, %s\n", angle, cstg);
    vis_UnitsGetDesc(units, UNITS_CHARGE, charge, cstg);
    printf("charge type= %d, %s\n", charge, cstg);

    /* get conversion unit types */
    vis_UnitsGetConv(units, UNITS_LENGTH, &clength);
    vis_UnitsGetConv(units, UNITS_MASS, &cmass);
    vis_UnitsGetConv(units, UNITS_TIME, &ctime);
    vis_UnitsGetConv(units, UNITS_TEMP, &ctemp);
    vis_UnitsGetConv(units, UNITS_ANGLE, &cangle);
    vis_UnitsGetConv(units, UNITS_CHARGE, &ccharge);
    /* print all generically */
    printf("length type= %d\n", clength);
    printf("mass type=   %d\n", cmass);
    printf("time type=   %d\n", ctime);
    printf("temp type=   %d\n", ctemp);
    printf("angle type=  %d\n", cangle);
    printf("charge type= %d\n", ccharge);

    /* get conversion unit factors, offset */
    vis_UnitsGetFactor(units, UNITS_LENGTH, &lengthfac);
    vis_UnitsGetFactor(units, UNITS_MASS, &massfac);
    vis_UnitsGetFactor(units, UNITS_TIME, &timefac);
    vis_UnitsGetFactor(units, UNITS_TEMP, &tempfac);
    vis_UnitsGetFactor(units, UNITS_TEMP_OFFSET, &tempoff);
    vis_UnitsGetFactor(units, UNITS_ANGLE, &anglefac);
    vis_UnitsGetFactor(units, UNITS_CHARGE, &chargefac);
    /* print */
    printf("length factor= %e\n", lengthfac);
    printf("mass factor=   %e\n", massfac);
    printf("time factor=   %e\n", timefac);
    printf("temp factor=   %e\n", tempfac);
    printf("temp offset=   %e\n", tempoff);
    printf("angle factor=  %e\n", anglefac);
    printf("charge factor= %e\n", chargefac);
}

/*----------------------------------------------------------------------
                      print element properties
----------------------------------------------------------------------*/
static void
printEProp(vsy_HashTable* ephash)
{
    Vint i, j, k;
    vis_EProp* eprop;
    Vint id;
    Vint eptype;
    Vint ntypes, *type;
    Vint flag, nval, nloc, dtyp;
    Vchar ename[256], name[64];
    Vint iparams[100];
    Vdouble dparams[100];
    Vchar cval[256];

    printf("\nElement Properties\n");
    vsy_HashTableInitIter(ephash);
    while (vsy_HashTableNextIter(ephash, &id, (Vobject**)&eprop), eprop) {
        printf("id= %d, type= ", id);
        vis_EPropInq(eprop, &eptype);
        if (eptype == SYS_ELEM_SOLID) {
            printf(" Solid Property\n");
        }
        else if (eptype == SYS_ELEM_SHELL) {
            printf(" Shell Property\n");
        }
        else if (eptype == SYS_ELEM_MEMBRANE) {
            printf(" Membrane Property\n");
        }
        else if (eptype == SYS_ELEM_BEAM) {
            printf(" Beam Property\n");
        }
        else if (eptype == SYS_ELEM_TRUSS) {
            printf(" Truss Property\n");
        }
        else if (eptype == VIS_ELEM_SPRINGDASHPOT) {
            printf(" Spring Dashpot Property\n");
        }
        else if (eptype == SYS_ELEM_RIGID) {
            printf(" Rigid Property\n");
        }
        else if (eptype == SYS_ELEM_MASS) {
            printf(" Mass Property\n");
        }
        vis_EPropGetName(eprop, ename);
        if (ename[0] != '\0') {
            printf("name= %s", ename);
        }
        vis_EPropValueTypeNum(eprop, &ntypes);
        type = (Vint*)malloc(ntypes * sizeof(Vint));
        vis_EPropValueType(eprop, &ntypes, type);

        /* loop through types generically */
        for (i = 0; i < ntypes; i++) {
            vis_EPropValueName(eprop, type[i], name);
            printf("\n name= %s\n", name);
            vis_EPropValueFlag(eprop, type[i], &flag);
            if (flag == EPROP_UNDEFINED) {
                printf("Undefined\n");
            }
            else {
                vis_EPropValueParams(eprop, type[i], &nval, &nloc, &dtyp);
                printf(" nval= %d, nloc= %d\n", nval, nloc);
                /* check for too many values for array size */
                if (nval * nloc > 100)
                    continue;
                /* integer valued */
                if (dtyp == SYS_INTEGER) {
                    printf(" Integer\n");
                    vis_EPropValueInteger(eprop, type[i], iparams);
                    for (k = 0; k < nloc; k++) {
                        if (nloc > 1)
                            printf(" Location= %d\n", k);
                        for (j = 0; j < nval; j++) {
                            printf("  value= %d\n", iparams[k * nval + j]);
                        }
                    }
                    /* real valued */
                }
                else if (dtyp == SYS_REAL) {
                    vis_EPropValueDouble(eprop, type[i], dparams);
                    printf(" Real\n");
                    for (k = 0; k < nloc; k++) {
                        if (nloc > 1)
                            printf(" Location= %d\n", k);
                        for (j = 0; j < nval; j++) {
                            printf("  value= %e\n", dparams[k * nval + j]);
                        }
                    }
                    /* character valued */
                }
                else if (dtyp == SYS_CHAR) {
                    vis_EPropValueString(eprop, type[i], cval);
                    printf(" Character\n");
                    printf("  value= %s\n", cval);
                }
            }
        }
        free(type);
    }
}

/*----------------------------------------------------------------------
                      print material properties
----------------------------------------------------------------------*/
static void
printMProp(vsy_HashTable* mphash)
{
    Vint i, j;
    vis_MProp* mprop;
    Vint id;
    Vint mptype;
    Vint ntypes, *type;
    Vint flag, nval, dtyp;
    Vchar mname[256], name[64];
    Vint iparams[100];
    Vdouble dparams[100];
    Vint tid;

    printf("\nMaterial Properties\n");
    vsy_HashTableInitIter(mphash);
    while (vsy_HashTableNextIter(mphash, &id, (Vobject**)&mprop), mprop) {
        printf("id= %d, type= ", id);
        vis_MPropInq(mprop, &mptype);
        if (mptype == SYS_MAT_ISOTROPIC) {
            printf(" Isotropic Property\n");
        }
        else if (mptype == SYS_MAT_ORTHOTROPIC) {
            printf(" Orthotropic Property\n");
        }
        else if (mptype == SYS_MAT_ANISOTROPIC) {
            printf(" Anisotropic Property\n");
        }
        vis_MPropGetName(mprop, mname);
        if (mname[0] != '\0') {
            printf("name= %s", mname);
        }
        vis_MPropValueTypeNum(mprop, &ntypes);
        type = (Vint*)malloc(ntypes * sizeof(Vint));
        vis_MPropValueType(mprop, &ntypes, type);

        /* loop through types */
        for (i = 0; i < ntypes; i++) {
            vis_MPropValueName(mprop, type[i], name);
            printf("\n name = %s\n", name);
            vis_MPropValueFlag(mprop, type[i], &flag);
            if (flag == MPROP_UNDEFINED) {
                printf("Undefined\n");
            }
            else if (flag == MPROP_VALUE) {
                vis_MPropValueParams(mprop, type[i], &nval, &dtyp);
                printf(" nval= %d\n", nval);
                /* check for too many values for array size */
                if (nval > 100)
                    continue;
                /* integer valued */
                if (dtyp == SYS_INTEGER) {
                    printf(" Integer\n");
                    vis_MPropValueInteger(mprop, type[i], iparams);
                    for (j = 0; j < nval; j++) {
                        printf("  value= %d\n", iparams[j]);
                    }
                    /* real valued */
                }
                else if (dtyp == SYS_REAL) {
                    vis_MPropValueDouble(mprop, type[i], dparams);
                    printf(" Real\n");
                    for (j = 0; j < nval; j++) {
                        printf("  value= %e\n", dparams[j]);
                    }
                }
            }
            else if (flag == MPROP_IDENTIFIER) {
                vis_MPropValueId(mprop, type[i], &tid);
                printf(" TCurve identifier= %d\n", tid);
            }
        }
        free(type);
    }
}

/*----------------------------------------------------------------------
                      print tabular functions
----------------------------------------------------------------------*/
static void
printTCurve(vsy_HashTable* tchash)
{
    Vint i, j;
    vis_TCurve* tcurve;
    Vint id;
    Vint tctype, nval, npts;
    Vdouble t, val[100];

    printf("\nTabular Funtions\n");
    vsy_HashTableInitIter(tchash);
    while (vsy_HashTableNextIter(tchash, &id, (Vobject**)&tcurve), tcurve) {
        vis_TCurveInq(tcurve, &tctype, &nval);
        printf("id= %d, nval= %d, type= ", id, nval);
        /* check for too many values for array size */
        if (nval > 100)
            continue;
        if (tctype == TCURVE_PWLINEAR) {
            printf(" Piecewise Linear Function\n");
        }
        /* print function values */
        vis_TCurveNum(tcurve, &npts);
        printf("npts= %d\n", npts);
        /* loop through points one at a time */
        for (i = 1; i <= npts; i++) {
            vis_TCurveIndepdv(tcurve, 1, &i, &t);
            printf("point= %d, t= %e, v= ", i, t);
            /* evaluate function at this point */
            vis_TCurveEvaldv(tcurve, 1, &t, val);
            for (j = 0; j < nval; j++) {
                printf(" %e", val[j]);
            }
            printf("\n");
        }
    }
}

/*----------------------------------------------------------------------
                      print element data
----------------------------------------------------------------------*/
static void
printElemDat(vsy_HashTable* edhash, vis_Connect* connect)
{
    Vint i, j;
    vis_ElemDat* elemdat;
    Vint id;
    Vint iprop;
    Vint numel;
    Vint flags;
    Vdouble thk[9], vec[9][3], fib[9];
    Vint nix, ix[9], ux[9];
    Vint nument, enttype, subtype, datatype;

    vis_ConnectNumber(connect, SYS_ELEM, &numel);

    printf("\nElement Data\n");
    vsy_HashTableInitIter(edhash);
    while (vsy_HashTableNextIter(edhash, &iprop, (Vobject**)&elemdat), elemdat) {
        vis_ElemDatInq(elemdat, &nument, &enttype, &subtype, &datatype);
        /* element thickness, surface elements */
        if (iprop == SYS_PROP_THICKNESS) {
            printf("\nElement Thicknesses\n");
            for (i = 1; i <= numel; i++) {
                vis_ElemDatDataStat(elemdat, i, 1, &flags);
                if (flags == 0)
                    continue;
                vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &id);
                printf("elem= %d\n", id);
                vis_ElemDatDatadv(elemdat, i, 1, thk);
                if (subtype == SYS_NONE) {
                    printf(" thickness= %e\n", thk[0]);
                }
                else {
                    vis_ConnectElemNode(connect, i, &nix, ix);
                    vis_ConnectNodeAssoc(connect, VIS_USERID, nix, ix, ux);
                    for (j = 0; j < nix; j++) {
                        printf(" node= %d, thickness= %e\n", ux[j], thk[j]);
                    }
                }
            }
            /* element offset vectors */
        }
        else if (iprop == SYS_PROP_OFFSETVEC) {
            printf("\nElement Offset Vectors\n");
            for (i = 1; i <= numel; i++) {
                vis_ElemDatDataStat(elemdat, i, 1, &flags);
                if (flags == 0)
                    continue;
                vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &id);
                printf("elem= %d\n", id);
                vis_ElemDatDatadv(elemdat, i, 1, (Vdouble*)vec);
                if (subtype == SYS_NONE) {
                    printf(" offset vector= %e %e %e\n", vec[0][0], vec[0][1], vec[0][2]);
                }
                else {
                    vis_ConnectElemNode(connect, i, &nix, ix);
                    vis_ConnectNodeAssoc(connect, VIS_USERID, nix, ix, ux);
                    for (j = 0; j < nix; j++) {
                        printf(" node= %d, offset vector= %e %e %e\n", ux[j], vec[j][0], vec[j][1], vec[j][2]);
                    }
                }
            }
            /* element orientation vectors */
        }
        else if (iprop == SYS_PROP_ELEMVEC) {
            printf("\nElement Orientation Vectors\n");
            for (i = 1; i <= numel; i++) {
                vis_ElemDatDataStat(elemdat, i, 1, &flags);
                if (flags == 0)
                    continue;
                vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &id);
                printf("elem= %d\n", id);
                vis_ElemDatDatadv(elemdat, i, 1, (Vdouble*)vec);
                if (subtype == SYS_NONE) {
                    printf(" orientation vector= %e %e %e\n", vec[0][0], vec[0][1], vec[0][2]);
                }
                else {
                    vis_ConnectElemNode(connect, i, &nix, ix);
                    vis_ConnectNodeAssoc(connect, VIS_USERID, nix, ix, ux);
                    for (j = 0; j < nix; j++) {
                        printf(" node= %d, orientation vector= %e %e %e\n", ux[j], vec[j][0], vec[j][1], vec[j][2]);
                    }
                }
            }
            /* element material orientation vectors */
        }
        else if (iprop == SYS_PROP_MATLVEC) {
            printf("\nElement Material Orientation Vectors\n");
            /* element bottom and top fiber locations */
        }
        else if (iprop == SYS_PROP_FIBERBOT || iprop == SYS_PROP_FIBERTOP) {
            printf("\nElement Fiber Locations\n");
            for (i = 1; i <= numel; i++) {
                vis_ElemDatDataStat(elemdat, i, 1, &flags);
                if (flags == 0)
                    continue;
                vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &id);
                printf("elem= %d\n", id);
                vis_ElemDatDatadv(elemdat, i, 1, fib);
                if (subtype == SYS_NONE) {
                    if (iprop == SYS_PROP_FIBERBOT) {
                        printf(" fiber (bottom)= %e\n", fib[0]);
                    }
                    else {
                        printf(" fiber (top)= %e\n", fib[0]);
                    }
                }
                else {
                    vis_ConnectElemNode(connect, i, &nix, ix);
                    vis_ConnectNodeAssoc(connect, VIS_USERID, nix, ix, ux);
                    for (j = 0; j < nix; j++) {
                        if (iprop == SYS_PROP_FIBERBOT) {
                            printf(" node= %d, fiber (bottom)= %e\n", ux[j], fib[j]);
                        }
                        else {
                            printf(" node= %d, fiber (top)= %e\n", ux[j], fib[j]);
                        }
                    }
                }
            }
        }
    }
}

/*----------------------------------------------------------------------
                      print load cases
----------------------------------------------------------------------*/
static void
printLCase(vsy_HashTable* lchash, vis_Connect* connect)
{
    Vint i, j, k;
    vis_LCase* lcase;
    Vint id;
    Vint maxindex;
    Vint flags;
    Vint nface;
    Vint nixf, ixf[9], uxf[9];
    Vdouble v[2 * 3 * 9];
    Vdouble grav[3], cent[3], w[3], wdot[3];
    Vint complexflag, complexmode;

    printf("\nLoad Cases\n");
    vsy_HashTableInitIter(lchash);
    while (vsy_HashTableNextIter(lchash, &id, (Vobject**)&lcase), lcase) {
        printf("id= %d\n", id);
        /* determine if complex data */
        vis_LCaseGetComplex(lcase, &complexflag);
        vis_LCaseGetComplexMode(lcase, &complexmode);
        /* concentrated forces, illustrate possible complex */
        vis_LCaseConcMax(lcase, LCASE_FORCE, &maxindex);
        for (i = 1; i <= maxindex; i++) {
            vis_LCaseConcFlag(lcase, i, LCASE_FORCE, &flags);
            if (flags == 0)
                continue;
            vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &i, &id);
            if (complexflag) {
                vis_LCaseSetComplexMode(lcase, SYS_COMPLEX_REALIMAGINARY);
                vis_LCaseConcdv(lcase, i, LCASE_FORCE, v);
                printf("node= %d, force vector= %e %e(i) %e %e(i) %e %e(i)\n", id, v[0], v[1], v[2], v[3], v[4], v[5]);
                vis_LCaseSetComplexMode(lcase, complexmode);
            }
            else {
                vis_LCaseConcdv(lcase, i, LCASE_FORCE, v);
                printf("node= %d, force vector= %e %e %e\n", id, v[0], v[1], v[2]);
            }
        }
        /* concentrated moments */
        vis_LCaseConcMax(lcase, LCASE_MOMENT, &maxindex);
        for (i = 1; i <= maxindex; i++) {
            vis_LCaseConcFlag(lcase, i, LCASE_MOMENT, &flags);
            if (flags == 0)
                continue;
            vis_LCaseConcdv(lcase, i, LCASE_MOMENT, v);
            vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &i, &id);
            printf("node= %d, moment vector= %e %e %e\n", id, v[0], v[1], v[2]);
        }
        /* pressure loads */
        vis_LCaseDistMax(lcase, SYS_FACE, LCASE_PRES, &maxindex);
        for (i = 1; i <= maxindex; i++) {
            vis_LCaseDistFlag(lcase, SYS_FACE, i, LCASE_PRES, &flags);
            if (flags == 0)
                continue;
            vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &id);
            vis_ConnectElemNum(connect, SYS_FACE, i, &nface);
            for (j = 1; j <= nface; j++) {
                if (VIEW_FLAG(flags, j) == 0)
                    continue;
                vis_LCaseDistdv(lcase, SYS_FACE, i, j, LCASE_PRES, 0, v);
                vis_ConnectElemCon(connect, SYS_FACE, i, j, &nixf, ixf);
                vis_ConnectNodeAssoc(connect, VIS_USERID, nixf, ixf, uxf);
                printf("elem= %d, face= %d\n", id, j);
                for (k = 0; k < nixf; k++) {
                    printf(" node= %d, pressure= %e\n", uxf[k], v[k]);
                }
            }
        }
        /* traction loads */
        vis_LCaseDistMax(lcase, SYS_FACE, LCASE_TRAC, &maxindex);
        for (i = 1; i <= maxindex; i++) {
            vis_LCaseDistFlag(lcase, SYS_FACE, i, LCASE_TRAC, &flags);
            if (flags == 0)
                continue;
            vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &id);
            vis_ConnectElemNum(connect, SYS_FACE, i, &nface);
            for (j = 1; j <= nface; j++) {
                if (VIEW_FLAG(flags, j) == 0)
                    continue;
                vis_LCaseDistdv(lcase, SYS_FACE, i, j, LCASE_TRAC, 0, v);
                vis_ConnectElemCon(connect, SYS_FACE, i, j, &nixf, ixf);
                vis_ConnectNodeAssoc(connect, VIS_USERID, nixf, ixf, uxf);
                printf("elem= %d, face= %d\n", id, j);
                for (k = 0; k < nixf; k++) {
                    printf(" node= %d, traction vector= %e %e %e\n", uxf[k], v[3 * k], v[3 * k + 1], v[3 * k + 2]);
                }
            }
        }
        /* accelerations */
        vis_LCaseAccelFlag(lcase, &flags);
        if (flags) {
            vis_LCaseAcceldv(lcase, grav, cent, w, wdot);
            if (grav[0] != 0. || grav[1] != 0. || grav[2] != 0.) {
                printf(" gravity vector= %e %e %e\n", grav[0], grav[1], grav[2]);
            }
            printf(" center of rotation= %e %e %e\n", cent[0], cent[1], cent[2]);
            if (w[0] != 0. || w[1] != 0. || w[2] != 0.) {
                printf(" angular velocity vector= %e %e %e\n", w[0], w[1], w[2]);
            }
            if (wdot[0] != 0. || wdot[1] != 0. || wdot[2] != 0.) {
                printf(" angular acceleration vector= %e %e %e\n", wdot[0], wdot[1], wdot[2]);
            }
        }
    }
}

/*----------------------------------------------------------------------
                      print restraint cases
----------------------------------------------------------------------*/
static void
printRCase(vsy_HashTable* rchash, vis_Connect* connect)
{
    Vint i, j;
    vis_RCase* rcase;
    Vint id;
    Vint maxindex;
    Vint numtags, tag[SYS_DOF_MAX];
    Vint nid;
    Vint rtype, master;
    Vdouble value;

    printf("\nRestraint Cases\n");
    vsy_HashTableInitIter(rchash);
    while (vsy_HashTableNextIter(rchash, &id, (Vobject**)&rcase), rcase) {
        printf("id= %d\n", id);
        vis_RCaseSPCMax(rcase, &maxindex);
        for (i = 1; i <= maxindex; i++) {
            vis_RCaseSPCTag(rcase, i, &numtags, tag);
            if (numtags == 0)
                continue;
            vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &i, &nid);
            /* loop through dof tags */
            for (j = 0; j < numtags; j++) {
                vis_RCaseSPCdv(rcase, i, tag[j], &rtype, &value, &master);
                if (rtype == RCASE_FIXED) {
                    printf(" node= %d, fixed dof tag= %d\n", nid, tag[j]);
                }
                else if (rtype == RCASE_APPLIED) {
                    printf(" node= %d, applied dof tag= %d, value= %e\n", nid, tag[j], value);
                }
            }
        }
    }
}

/*----------------------------------------------------------------------
                      print multipoint constraint cases
----------------------------------------------------------------------*/
static void
printMCase(vsy_HashTable* mchash, vis_Connect* connect)
{
    Vint i, j;
    vis_MCase* mcase;
    Vint id;
    Vint maxindex, maxterms, maxrhs;
    Vint type, nterms;
    Vint nid;
    Vint *ix, *ig;
    Vdouble* c;
    Vdouble rhs;

    printf("\nMultipoint Constraint Cases\n");
    vsy_HashTableInitIter(mchash);
    while (vsy_HashTableNextIter(mchash, &id, (Vobject**)&mcase), mcase) {
        printf("id= %d\n", id);
        vis_MCaseMax(mcase, &maxindex, &maxterms, &maxrhs);
        ix = (Vint*)malloc(maxterms * sizeof(Vint));
        ig = (Vint*)malloc(maxterms * sizeof(Vint));
        c = (Vdouble*)malloc(maxterms * sizeof(Vdouble));
        for (i = 1; i <= maxindex; i++) {
            vis_MCaseNum(mcase, i, &nterms);
            if (nterms) {
                vis_MCaseType(mcase, i, &type);
                /* constraint equation */
                if (type == MCASE_MPC) {
                    vis_MCaseMPCdv(mcase, i, &nterms, ix, ig, c, &rhs);
                    printf("index= %d, nterms= %d, rhs= %f\n", i, nterms, rhs);
                    for (j = 0; j < nterms; j++) {
                        vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &ix[j], &nid);
                        printf(" ix= %d, tag= %d, c= %f\n", nid, ig[j], c[j]);
                    }
                    /* constraint node based entity */
                }
                else {
                    vis_MCaseCon(mcase, i, &type, &nterms, ix);
                    printf("index= %d, type= %d, nterms= %d\n", i, type, nterms);
                    for (j = 0; j < nterms; j++) {
                        vis_ConnectNodeAssoc(connect, VIS_USERID, 1, &ix[j], &nid);
                        printf(" ix= %d\n", nid);
                    }
                }
            }
        }
        free(ix);
        free(ig);
        free(c);
    }
}

/*----------------------------------------------------------------------
                      print contact pairs
----------------------------------------------------------------------*/
static void
printCPair(vsy_HashTable* cphash, vis_Connect* connect)
{
    Vint i;
    vis_CPair* cpair;
    Vint id, asid;
    Vint mastent, slavent, ctype;
    Vint index, numno, no[32];

    printf("\nContact Pairs\n");
    vsy_HashTableInitIter(cphash);
    while (vsy_HashTableNextIter(cphash, &id, (Vobject**)&cpair), cpair) {
        printf("id= %d\n", id);
        vis_CPairInq(cpair, &mastent, &slavent);
        if (mastent == SYS_EDGE) {
            printf(" Master Edge\n");
        }
        else if (mastent == SYS_FACE) {
            printf(" Master Face\n");
        }
        else if (mastent == SYS_ASURF) {
            vis_CPairMasterASurf(cpair, &asid);
            printf(" Master Analytic Surface id= %d\n", asid);
        }
        if (slavent == SYS_NONE) {
            printf(" Slave None\n");
        }
        else if (slavent == SYS_NODE) {
            printf(" Slave Node\n");
        }
        else if (slavent == SYS_EDGE) {
            printf(" Slave Edge\n");
        }
        else if (slavent == SYS_FACE) {
            printf(" Slave Face\n");
        }
        vis_CPairGetType(cpair, &ctype);
        if (ctype == CPAIR_CONTACT) {
            printf(" Contact Pair\n");
        }
        else if (ctype == CPAIR_COSIM) {
            printf(" Co-simulation Pair\n");
        }
        else if (ctype == CPAIR_CYCLIC) {
            printf(" Cyclic Symmetry Pair\n");
        }
        /* traverse master entities */
        if (mastent == SYS_EDGE || mastent == SYS_FACE) {
            vis_CPairMasterInitIter(cpair);
            while (vis_CPairMasterNextIter(cpair, &index), index) {
                printf("master elem= %d\n", index);
                vis_CPairMasterEnt(cpair, index, &numno, no);
                printf("elem face or edge= ");
                for (i = 0; i < numno; i++) {
                    printf(" %d", no[i]);
                }
                printf("\n");
            }
        }
        /* traverse slave entities */
        if (slavent) {
            vis_CPairSlaveInitIter(cpair);
            while (vis_CPairSlaveNextIter(cpair, &index), index) {
                if (slavent == SYS_NODE) {
                    printf("slave node= %d\n", index);
                }
                else {
                    printf("slave elem= %d\n", index);
                    vis_CPairSlaveEnt(cpair, index, &numno, no);
                    printf("elem face or edge= ");
                    for (i = 0; i < numno; i++) {
                        printf(" %d", no[i]);
                    }
                    printf("\n");
                }
            }
            /* traverse slave nodes */
            vis_CPairSlaveNodeInitIter(cpair);
            while (vis_CPairSlaveNodeNextIter(cpair, &index), index) {
                printf("slave node= %d\n", index);
            }
        }
    }
}

/*----------------------------------------------------------------------
                      print rigid bodies
----------------------------------------------------------------------*/
static void
printRBody(vsy_HashTable* rbhash, vis_Connect* connect)
{
    vis_RBody* rbody;
    Vint id;
    Vint enttype, refnode, asid, numelem, nument, numnode;

    printf("\nRigid Bodies\n");
    vsy_HashTableInitIter(rbhash);
    while (vsy_HashTableNextIter(rbhash, &id, (Vobject**)&rbody), rbody) {
        printf("id= %d\n", id);
        vis_RBodyInq(rbody, &enttype);
        if (enttype == SYS_EDGE) {
            printf(" Element Edge\n");
        }
        else if (enttype == SYS_FACE) {
            printf(" Element Face\n");
        }
        else if (enttype == SYS_ELEM) {
            printf(" Element\n");
        }
        vis_RBodyElemNum(rbody, &numelem, &nument);
        if (numelem) {
            printf("Number of elements= %d\n", numelem);
            printf("Number of element entities= %d\n", nument);
        }
        vis_RBodyASurf(rbody, &asid);
        if (asid) {
            printf("Analytic Surface id= %d\n", asid);
        }

        vis_RBodyNodeNum(rbody, &numnode);
        if (numnode) {
            printf("Number of nodes= %d\n", numnode);
        }

        vis_RBodyGetRefNode(rbody, &refnode);
        printf(" Ref Node= %d\n", refnode);
    }
}

/*----------------------------------------------------------------------
                      print analytic surfaces
----------------------------------------------------------------------*/
static void
printASurf(vsy_HashTable* ashash, vis_Connect* connect)
{
    vis_ASurf* asurf;
    Vint id, type;
    Vchar name[64];
    Vdouble x[3], r;
    Vdouble a[3], b[3], c[3], length, width, height, radius;
    Vint numpnt, numseg;

    printf("\nAnalytic Surfaces\n");
    vsy_HashTableInitIter(ashash);
    while (vsy_HashTableNextIter(ashash, &id, (Vobject**)&asurf), asurf) {
        printf("id= %d\n", id);
        vis_ASurfInq(asurf, &type);
        vis_ASurfGetName(asurf, name);
        if (name[0] != '\0') {
            printf("name= %s\n", name);
        }
        if (type == ASURF_SPHERE) {
            vis_ASurfGetSpheredv(asurf, x, &r);
            printf("Sphere, id= %d, x= %f %f %f, r= %f\n", id, x[0], x[1], x[2], r);
        }
        else if (type == ASURF_CYLINDER) {
            vis_ASurfGetCylinderdv(asurf, a, b, c, &radius, &height);
            printf("Cylinder, id= %d, a= %f %f %f\n", id, a[0], a[1], a[2]);
            printf("                  b= %f %f %f\n", b[0], b[1], b[2]);
            printf("                  c= %f %f %f\n", c[0], c[1], c[2]);
            printf("                  radius= %f\n", radius);
            printf("                  height= %f\n", height);
        }
        else if (type == ASURF_PLANE) {
            vis_ASurfGetPlanedv(asurf, a, b, c, &length, &width);
            printf("Plane, id= %d, a= %f %f %f\n", id, a[0], a[1], a[2]);
            printf("               b= %f %f %f\n", b[0], b[1], b[2]);
            printf("               c= %f %f %f\n", c[0], c[1], c[2]);
            printf("               length= %f, width= %f\n", length, width);
        }
        else if (type == ASURF_BOX) {
            vis_ASurfGetBoxdv(asurf, a, b, c, &length, &width, &height);
            printf("Box, id= %d, a= %f %f %f\n", id, a[0], a[1], a[2]);
            printf("             b= %f %f %f\n", b[0], b[1], b[2]);
            printf("             c= %f %f %f\n", c[0], c[1], c[2]);
            printf("             length= %f, width= %f, height= %f\n", length, width, height);
        }
        else if (type == ASURF_SEGMENT) {
            vis_ASurfNumPoints(asurf, &numpnt);
            vis_ASurfNumSegments(asurf, &numseg);
            printf("Segment, id= %d, numpnts= %d, numseg= %d\n", id, numpnt, numseg);
        }
        else if (type == ASURF_SEGMENT_REV) {
            vis_ASurfNumPoints(asurf, &numpnt);
            vis_ASurfNumSegments(asurf, &numseg);
            printf("Segment Rev, id= %d, numpnts= %d, numseg= %d\n", id, numpnt, numseg);
            vis_ASurfGetSegmentRevdv(asurf, a, b, c);
            printf("             a= %f %f %f\n", a[0], a[1], a[2]);
            printf("             b= %f %f %f\n", b[0], b[1], b[2]);
            printf("             c= %f %f %f\n", c[0], c[1], c[2]);
        }
        else if (type == ASURF_SEGMENT_RULE) {
            vis_ASurfNumPoints(asurf, &numpnt);
            vis_ASurfNumSegments(asurf, &numseg);
            printf("Segment Rule, id= %d, numpnts= %d, numseg= %d\n", id, numpnt, numseg);
            vis_ASurfGetSegmentRuledv(asurf, a, b, c);
            printf("             a= %f %f %f\n", a[0], a[1], a[2]);
            printf("             b= %f %f %f\n", b[0], b[1], b[2]);
            printf("             c= %f %f %f\n", c[0], c[1], c[2]);
        }
    }
}

/*----------------------------------------------------------------------
                      print solution properties
----------------------------------------------------------------------*/
static void
printSProp(vsy_List* splist)
{
    Vint i, j;
    vis_SProp* sprop;
    Vint id;
    Vint sptype;
    Vint ntypes, *type;
    Vint flag, nval, dtyp;
    Vchar name[64];
    Vint iparams[100];
    Vdouble dparams[100];
    Vchar cparams[81];

    printf("\nSolution Properties\n");
    vsy_ListInitIter(splist);
    while (vsy_ListNextIter(splist, &id, (Vobject**)&sprop), sprop) {
        printf("id= %d, type= ", id);
        vis_SPropInq(sprop, &sptype);
        if (sptype == SYS_SOL_STATIC) {
            printf(" Static Analysis Property\n");
        }
        else if (sptype == SYS_SOL_VIBRATION) {
            printf(" Vibration Analysis Property\n");
        }
        else if (sptype == SYS_SOL_BUCKLING) {
            printf(" Buckling Analysis Property\n");
        }
        else if (sptype == SYS_SOL_TRANSIENT) {
            printf(" Transient Analysis Property\n");
        }
        vis_SPropValueTypeNum(sprop, &ntypes);
        type = (Vint*)malloc(ntypes * sizeof(Vint));
        vis_SPropValueType(sprop, &ntypes, type);

        /* loop through types generically */
        for (i = 0; i < ntypes; i++) {
            vis_SPropValueName(sprop, type[i], name);
            printf("\n name = %s\n", name);
            vis_SPropValueFlag(sprop, type[i], &flag);
            if (flag == SPROP_UNDEFINED) {
                printf("Undefined\n");
            }
            else {
                vis_SPropValueParams(sprop, type[i], &nval, &dtyp);
                printf(" nval= %d\n", nval);
                /* check for too many values for array size */
                if (nval > 100)
                    continue;
                /* integer valued */
                if (dtyp == SYS_INTEGER) {
                    printf(" Integer\n");
                    vis_SPropValueInteger(sprop, type[i], iparams);
                    for (j = 0; j < nval; j++) {
                        printf("  value= %d\n", iparams[j]);
                    }
                    /* real valued */
                }
                else if (dtyp == SYS_REAL) {
                    vis_SPropValueDouble(sprop, type[i], dparams);
                    printf(" Real\n");
                    for (j = 0; j < nval; j++) {
                        printf("  value= %e\n", dparams[j]);
                    }
                    /* character valued */
                }
                else if (dtyp == SYS_CHAR) {
                    vis_SPropValueString(sprop, type[i], cparams);
                    printf("  value= %s\n", cparams);
                }
            }
        }
        free(type);
    }
}

10.42. Example 39c, Heat Transfer Finite Element Model Using Model

This example illustrates the use of a Model object hierarchy to manage a heat transfer finite element model. This example is similar to the structural model illustrated in Example 39a. In this case material properties, restraints and loads are changed to reflect heat transfer analysis. Also the analysis type in the SProp object is changed to SYS_ANALYSIS_THERMAL.

#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"
/*
                 5------6
                /.     /.\
               / .    / . \
              /  .   /  .  \70------80
             /   1../...2../|       |  \
           12-----13-----14 |       |    \
            |  .   |  .   |.|       |      \
            | .    | .    | 30------40------15-----18
            |.     |.     |/
            9-----10-----11
            \      /    /
             \tet /wed /
              \  /    /
               16----17
*/
#define MAX_ELEM 7
#define MAX_NODE 18

/* element connectivity */
static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 30, 70, 6, 10, 11, 14, 13}, {30, 40, 80, 70, 0, 0, 0, 0},
                                 {40, 15, 80, 0, 0, 0, 0, 0}, {9, 10, 13, 16, 0, 0, 0, 0},    {10, 13, 16, 11, 14, 17, 0, 0},
                                 {15, 18, 0, 0, 0, 0, 0, 0}};

/* user element ids */
static Vint eid[MAX_ELEM] = {10, 11, 20, 21, 30, 31, 100};

/* element topologies */
static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD, VIS_SHAPETRI, VIS_SHAPETET, VIS_SHAPEWED, VIS_SHAPELINE};
static Vint maxi[MAX_ELEM] = {0, 0, 0, 0, 0, 0, 0};

/* element types */
static Vint featype[MAX_ELEM] = {VIS_ELEM_SOLID, VIS_ELEM_SOLID, VIS_ELEM_SHELL, VIS_ELEM_SHELL,
                                 VIS_ELEM_SOLID, VIS_ELEM_SOLID, VIS_ELEM_BEAM};

/* element specs */
static Vint feaspec[MAX_ELEM] = {0, 0, 0, 0, 0, 0, 0};

/* element property ids */
static Vint pid[MAX_ELEM] = {1, 1, 2, 2, 1, 1, 3};

/* element coordinate system indicators and ids */
static Vint ecid[MAX_ELEM] = {0, 0, 0, 0, 0, 0, SYS_ELEMSYS_VECTOR};

/* node coordinates */
static Vdouble coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.}, {1., 1., 0.},
                                      {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.}, {2., 0., 2.}, {0., 1., 2.},
                                      {1., 1., 2.}, {2., 1., 2.}, {4., 0., 1.}, {1., 0., 3.}, {2., 0., 3.}, {5., 0., 1.}};

/* user node ids */
static Vint nid[MAX_NODE] = {1, 2, 30, 40, 5, 6, 70, 80, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};

/*----------------------------------------------------------------------
                      Manage a Heat Transfer Finite Element Model Using Model
----------------------------------------------------------------------*/
int
main()
{
    Vint i;
    vis_Model* model;
    vis_Connect* connect;
    vis_ElemDat *elemdatthk, *elemdatvec;
    vis_GridFun* gf;
    vis_MProp* mprop;
    vis_EProp* eprop;
    vis_SProp* sprop;
    vis_ICase* icase;
    vis_RCase* rcase;
    vis_LCase* lcase;
    vsy_HashTable *ephash, *mphash, *edhash, *ichash, *rchash, *lchash;
    vsy_List* splist;
    Vdouble cflux;
    Vdouble thk[4];
    Vdouble vec[3], flux[4], conv[8];
    Vdouble val;
    Vint tag;
    vis_IdTran *idtrannode, *idtranelem;
    Vint nix, conntran[8];
    Vint id;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectPre(connect, SYS_DOUBLE);
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set up user node and element id translation */
    idtrannode = vis_IdTranBegin();
    for (i = 0; i < MAX_NODE; i++) {
        vis_IdTranSetId(idtrannode, i + 1, nid[i]);
    }
    idtranelem = vis_IdTranBegin();
    for (i = 0; i < MAX_ELEM; i++) {
        vis_IdTranSetId(idtranelem, i + 1, eid[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoordsdv(connect, i + 1, coords[i]);
        vis_ConnectSetNodeAssoc(connect, VIS_USERID, i + 1, nid[i]);
    }

    /* set element topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], maxi[i], 0, 0);
    }

    /* set element node connectivity and associations */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectElemNum(connect, SYS_NODE, i + 1, &nix);
        vis_IdTranIndices(idtrannode, nix, conn[i], conntran);
        vis_ConnectSetElemNode(connect, i + 1, conntran);
        vis_ConnectSetElemAssoc(connect, VIS_USERID, i + 1, eid[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEATYPE, i + 1, featype[i]);
        vis_ConnectSetElemAssoc(connect, VIS_FEASPEC, i + 1, feaspec[i]);
        vis_ConnectSetElemAssoc(connect, VIS_PROPID, i + 1, pid[i]);
        vis_ConnectSetElemAssoc(connect, VIS_CSYSID, i + 1, ecid[i]);
    }

    /* create model object hierarchy */
    model = vis_ModelBegin();

    /* hashtables of element and material properties */
    ephash = vsy_HashTableBegin();
    mphash = vsy_HashTableBegin();

    /* hashtables of element data */
    edhash = vsy_HashTableBegin();

    /* hashtables of initial condition, restraint, load cases */
    ichash = vsy_HashTableBegin();
    rchash = vsy_HashTableBegin();
    lchash = vsy_HashTableBegin();

    /* list of solution procedures */
    splist = vsy_ListBegin();

    /* material 1 */
    mprop = vis_MPropBegin();
    vis_MPropDef(mprop, SYS_MAT_ISOTROPIC);
    vis_MPropSetValued(mprop, MPROP_K, 1.e+3);
    vsy_HashTableInsert(mphash, 1, mprop);

    /* solid property 1 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SOLID);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vsy_HashTableInsert(ephash, 1, eprop);

    /* shell property 2 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_SHELL);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vis_EPropSetValued(eprop, EPROP_THICKNESS, .5);
    vsy_HashTableInsert(ephash, 2, eprop);

    /* beam property 3 */
    eprop = vis_EPropBegin();
    vis_EPropDef(eprop, VIS_ELEM_BEAM);
    vis_EPropSetValuei(eprop, EPROP_MID, 1);
    vis_EPropSetValued(eprop, EPROP_AREA, 2.0);
    vsy_HashTableInsert(ephash, 3, eprop);

    /* GridFun for element data objects */
    gf = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gf);

    /* ElemDat of shell element node thickness */
    elemdatthk = vis_ElemDatBegin();
    vis_ElemDatDef(elemdatthk, MAX_ELEM, SYS_ELEM, SYS_NODE, SYS_SCALAR);
    vis_ElemDatSetObject(elemdatthk, VIS_GRIDFUN, gf);

    /* ElemDat of beam element orientation vectors */
    elemdatvec = vis_ElemDatBegin();
    vis_ElemDatDef(elemdatvec, MAX_ELEM, SYS_ELEM, SYS_NONE, SYS_VECTOR);
    vis_ElemDatSetObject(elemdatvec, VIS_GRIDFUN, gf);

    /* shell element 21 is tapered */
    thk[0] = .5;
    thk[1] = .3;
    thk[2] = .5;
    vis_IdTranIndex(idtranelem, 21, &id);
    vis_ElemDatSetDatadv(elemdatthk, id, 0, thk);
    vsy_HashTableInsert(edhash, SYS_PROP_THICKNESS, elemdatthk);

    /* beam element 100 orientation vector */
    vec[0] = 0.;
    vec[1] = 1.;
    vec[2] = 0.;
    vis_IdTranIndex(idtranelem, 100, &id);
    vis_ElemDatSetDatadv(elemdatvec, id, 0, vec);
    vsy_HashTableInsert(edhash, SYS_PROP_ELEMVEC, elemdatvec);

    /* restraint case 1 */
    rcase = vis_RCaseBegin();
    val = 120.;
    for (i = 1; i <= 3; i++) {
        vis_RCaseSetSPCdv(rcase, i, SYS_DOF_TEMP, RCASE_APPLIED, &val, 0);
    }
    vsy_HashTableInsert(rchash, 1, rcase);

    /* load case 1 */
    lcase = vis_LCaseBegin();

    /* concentrated flux on node 12 */
    cflux = 2.;
    vis_IdTranIndex(idtrannode, 12, &id);
    vis_LCaseSetConcdv(lcase, id, LCASE_HEAT, &cflux);

    /* initial condition case number 2,
       try to avoid using load or restraint case number */
    icase = vis_ICaseBegin();
    tag = SYS_DOF_TEMP;
    val = 120.;
    for (i = 1; i <= MAX_NODE; i++) {
        vis_ICaseSetSPVdv(icase, i, ICASE_DOF, 1, &tag, &val);
    }
    vsy_HashTableInsert(ichash, 2, icase);

    /* register GridFun object with LCase */
    vis_LCaseSetObject(lcase, VIS_GRIDFUN, gf);
    /* uniform edge flux on edge 1 element 20 */
    flux[0] = 50.;
    flux[1] = 50.;
    vis_IdTranIndex(idtranelem, 20, &id);
    vis_LCaseSetDistdv(lcase, SYS_EDGE, id, 1, LCASE_HEATFLUX, flux);
    /* uniform edge flux on edge 1 element 21 */
    vis_IdTranIndex(idtranelem, 21, &id);
    vis_LCaseSetDistdv(lcase, SYS_EDGE, id, 1, LCASE_HEATFLUX, flux);
    /* uniform face convection on face 2 element 10 */
    conv[0] = 100.;
    conv[1] = 4.;
    conv[2] = 100.;
    conv[3] = 4.;
    conv[4] = 100.;
    conv[5] = 4.;
    conv[6] = 100.;
    conv[7] = 4.;
    vis_IdTranIndex(idtranelem, 10, &id);
    vis_LCaseSetDistdv(lcase, SYS_FACE, id, 2, LCASE_HEATCONV, conv);
    vsy_HashTableInsert(lchash, 1, lcase);

    /* solution step 1 */
    sprop = vis_SPropBegin();
    vis_SPropDef(sprop, SYS_SOL_TRANSIENT);
    vis_SPropSetValuei(sprop, SPROP_ANALYSIS, SYS_ANALYSIS_THERMAL);
    vis_SPropSetValuei(sprop, SPROP_CASEID, 1);
    vis_SPropSetValuei(sprop, SPROP_ICASE, 2);
    vis_SPropSetValuei(sprop, SPROP_RCASE, 1);
    vis_SPropSetValued(sprop, SPROP_RCASE_FACTOR, 1.);
    vis_SPropSetValuei(sprop, SPROP_LCASE_NUM, 1);
    vis_SPropSetValuei(sprop, SPROP_LCASE, 1);
    vis_SPropSetValued(sprop, SPROP_LCASE_FACTOR, 1.);
    vis_SPropSetValued(sprop, SPROP_TIME_INIT, 0.);
    vis_SPropSetValued(sprop, SPROP_TIME_STEP, .1);
    vis_SPropSetValued(sprop, SPROP_TIME_TERM, 2.);
    vsy_ListInsert(splist, 1, sprop);

    /* register Connect in Model */
    vis_ModelSetObject(model, VIS_CONNECT, connect);

    /* register property hashtables in Model */
    vis_ModelSetHashTable(model, VIS_MPROP, mphash);
    vis_ModelSetHashTable(model, VIS_EPROP, ephash);

    /* register element data hashtables in Model */
    vis_ModelSetHashTable(model, VIS_ELEMDAT, edhash);

    /* register case hashtables in Model */
    vis_ModelSetHashTable(model, VIS_ICASE, ichash);
    vis_ModelSetHashTable(model, VIS_RCASE, rchash);
    vis_ModelSetHashTable(model, VIS_LCASE, lchash);

    /* register solution property list in Model */
    vis_ModelSetList(model, VIS_SPROP, splist);

    /* print to standard output */
    vis_ModelPrint(model);
    /* write NASTRAN Bulk Data File */
    vis_ModelWrite(model, SYS_NASTRAN_BULKDATA, "exam39c.bdf");
    /* write ABAQUS Input Data File */
    vis_ModelWrite(model, SYS_ABAQUS_INPUT, "exam39c.inp");
    /* write ANSYS Input Data File */
    vis_ModelWrite(model, SYS_ANSYS_INPUT, "exam39c.cdb");
    /* write Ideas Universal File */
    vis_ModelWrite(model, SYS_SDRC_UNIVERSAL, "exam39c.unv");
    /* write PATRAN Neutral File */
    vis_ModelWrite(model, SYS_PATRAN_NEUTRAL, "exam39c.out");

    /* end objects */
    vis_IdTranEnd(idtrannode);
    vis_IdTranEnd(idtranelem);
    vis_GridFunEnd(gf);
    vis_ModelDelete(model);
    vis_ModelEnd(model);
    return 0;
}

10.43. Example 40vdm, Compute Shell and Beam Local Coordinate Systems

This example illustrates loading a Model object with a finite element model residing on an external file and then computing and printing the local coordinate system direction cosine matrices associated with shell and beam elements in the model. The external file name is entered as the first argument to the example executable. The model object is created and then loaded using the function vdm_LManLoadModel(). All elements in the model are traversed and all shell and beam elements are processed. In general, computing local coordinate systems requires accessing the user defined coordinate systems, element geometry and auxiliary vectors used to define the element local and material local coordinate systems.

The VIS_CSYSID element association specifies the element local system in which element results are expressed by default. The VIS_CMATID element association specifies the material local system in which element material properties are aligned. The VIS_CMATID is only applicable if the VIS_CMATFLAG element association is non zero. Any positive integer points to a user defined CoordSys object which resides in the HashTable of coordinate systems. Any negative integer represents an algorithm dependent on element geometry and possibly an auxiliary vector. The auxiliary vectors are contained in ElemDat objects which reside in a HashTable. Use vis_ModelGetHashTable() to get the HashTable objects associated with CoordSys and ElemDat objects.

The ShellElem and BeamElem objects are used to compute the direction cosine matrices of the element local systems. They require the element geometry and auxiliary local system information. Use vis_ShellElemDirCos() and vis_BeamElemDirCos() to compute the element local systems.

#include <stdlib.h>
#include "base/base.h"
#include "vis/vis.h"
#include "vdm/vdm.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

static void
printShellBeam(vis_Model* model);

/*----------------------------------------------------------------------
                      Compute Shell and Beam Local Coordinate Systems
----------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    char inputfile[256];
    vdm_ABAFil* abafil = NULL;
    vdm_ABALib* abalib = NULL;
    vdm_ANSFil* ansfil = NULL;
    vdm_ANSLib* anslib = NULL;
    vdm_NASFil* nasfil = NULL;
    vdm_NASLib* naslib = NULL;
    vdm_NatLib* natlib = NULL;
    vdm_SDRCLib* sdrclib = NULL;
    vdm_DataFun* datafun = NULL;
    vdm_LMan* lman = NULL;
    Vint filetype = 0;
    vis_Model* model = NULL;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s inputfile\n", argv[0]);
        fprintf(stderr, " inputfile is blank, 'shell.bdf' is assumed\n");
        strcpy(inputfile, "shell.bdf");
    }
    else {
        strcpy(inputfile, argv[1]);
    }

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create data function object */
    datafun = vdm_DataFunBegin();

    /* determine file type from file extension */
    if (strstr(inputfile, ".bdf") != NULL || strstr(inputfile, ".dat") != NULL) {
        filetype = VDM_NASTRAN_BULKDATA;
        nasfil = vdm_NASFilBegin();
        vdm_NASFilDataFun(nasfil, datafun);
        printf("Nastran Bulk Data File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".op2") != NULL) {
        filetype = VDM_NASTRAN_OUTPUT2;
        naslib = vdm_NASLibBegin();
        vdm_NASLibDataFun(naslib, datafun);
        printf("Nastran Output2 File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".vdm") != NULL) {
        filetype = VDM_NATIVE;
        natlib = vdm_NatLibBegin();
        vdm_NatLibDataFun(natlib, datafun);
        printf("Native File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".inp") != NULL) {
        filetype = VDM_ABAQUS_INPUT;
        abafil = vdm_ABAFilBegin();
        vdm_ABAFilDataFun(abafil, datafun);
        printf("Abaqus Input File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".fil") != NULL) {
        filetype = VDM_ABAQUS_FIL;
        abalib = vdm_ABALibBegin();
        vdm_ABALibDataFun(abalib, datafun);
        printf("Abaqus Binary (.fil) File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".cdb") != NULL) {
        filetype = VDM_ANSYS_INPUT;
        ansfil = vdm_ANSFilBegin();
        vdm_ANSFilDataFun(ansfil, datafun);
        printf("Ansys Input File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".rst") != NULL) {
        filetype = VDM_ANSYS_RESULT;
        anslib = vdm_ANSLibBegin();
        vdm_ANSLibDataFun(anslib, datafun);
        printf("Ansys Result (.rst) File: %s\n", inputfile);
    }
    else if (strstr(inputfile, ".unv") != NULL) {
        filetype = VDM_SDRC_UNIVERSAL;
        sdrclib = vdm_SDRCLibBegin();
        vdm_SDRCLibDataFun(sdrclib, datafun);
        printf("SDRC Universal File: %s\n", inputfile);
    }
    else {
        fprintf(stderr, "Error: Bad input file %s\n", inputfile);
        exit(1);
    }
    /* open library device */
    vdm_DataFunOpen(datafun, 0, inputfile, filetype);

    /* instance model object for finite element model */
    model = vis_ModelBegin();

    /* use Library Manager object to load model */
    lman = vdm_LManBegin();
    vdm_LManSetObject(lman, VDM_DATAFUN, datafun);
    vdm_LManLoadModel(lman, model);
    if (vdm_LManError(lman)) {
        fprintf(stderr, "Error: Unable to load model information\n");
        exit(1);
    }
    /* close library device and delete interface */
    vdm_DataFunClose(datafun);
    vdm_DataFunEnd(datafun);
    if (filetype == VDM_NASTRAN_BULKDATA) {
        vdm_NASFilEnd(nasfil);
    }
    else if (filetype == VDM_NASTRAN_OUTPUT2) {
        vdm_NASLibEnd(naslib);
    }
    else if (filetype == VDM_NATIVE) {
        vdm_NatLibEnd(natlib);
    }
    else if (filetype == VDM_ABAQUS_INPUT) {
        vdm_ABAFilEnd(abafil);
    }
    else if (filetype == VDM_ABAQUS_FIL) {
        vdm_ABALibEnd(abalib);
    }
    else if (filetype == VDM_ANSYS_INPUT) {
        vdm_ANSFilEnd(ansfil);
    }
    else if (filetype == VDM_ANSYS_RESULT) {
        vdm_ANSLibEnd(anslib);
    }
    else if (filetype == VDM_SDRC_UNIVERSAL) {
        vdm_SDRCLibEnd(sdrclib);
    }
    vdm_LManEnd(lman);

    /* print shell and beam systems */
    printShellBeam(model);
    /* delete objects registered in Model */
    vis_ModelDelete(model);
    /* destroy Model object itself */
    vis_ModelEnd(model);
    return 0;
}

/*----------------------------------------------------------------------
                      print shell and beam coordinate systems
----------------------------------------------------------------------*/
static void
computeShellBeam(Vint index, Vint featype, Vint cid, Vint shape, Vint maxi, Vint maxj, vis_ShellElem* shellelem,
                 vis_BeamElem* beamelem, vsy_HashTable* coordsyshash, vis_ElemDat* elemdat, Vfloat xe[][3], Vfloat tme[3][3])
{
    Vfloat xo[3], tm[3][3];
    vis_CoordSys* coordsys;
    Vint type;
    Vfloat vec[3];
    /* user defined coordinate system */
    if (cid > 0) {
        if (coordsyshash == NULL) {
            printf("Error: no HashTable of CoordSys objects\n");
            exit(0);
        }
        vsy_HashTableLookup(coordsyshash, cid, (Vobject**)&coordsys);
        if (coordsys == NULL) {
            printf("Error: no CoordSys object\n");
            exit(0);
        }
        vis_CoordSysOriginTriad(coordsys, xo, tm);
        type = SYS_ELEMSYS_VECTOR;
        vec[0] = tm[0][0];
        vec[1] = tm[0][1];
        vec[2] = tm[0][2];
        /* algorithmic */
    }
    else if (cid < 0) {
        type = cid;
        if (elemdat) {
            vis_ElemDatData(elemdat, index, 0, vec);
        }
        /* global, cid = 0 */
    }
    else {
        type = cid;
    }
    /* shell or beam */
    if (featype == SYS_ELEM_SHELL) {
        vis_ShellElemSetTopology(shellelem, shape, maxi, maxj);
        vis_ShellElemSetLocalSystem(shellelem, type, vec, 0.);
        vis_ShellElemDirCos(shellelem, SYS_ON, xe, (Vfloat(*)[3][3])tme);
    }
    else if (featype == SYS_ELEM_BEAM) {
        vis_BeamElemSetTopology(beamelem, shape, maxi);
        vis_BeamElemSetLocalSystem(beamelem, type, vec, 0.);
        vis_BeamElemDirCos(beamelem, SYS_ON, xe, VIS_NODATA, NULL, VIS_NODATA, NULL, (Vfloat(*)[3][3])tme);
    }
}

static void
printShellBeam(vis_Model* model)
{
    Vint i;
    Vint numnp, numel;
    Vint eid, csysid, cmatid, cmatflag;
    Vint featype;
    Vfloat xe[16][3], tme[3][3];
    Vint nix, ix[16];
    Vint shape, maxi, maxj, maxk;
    vis_Connect* connect;
    vis_ShellElem* shellelem;
    vis_BeamElem* beamelem;
    vsy_HashTable *elemdathash, *coordsyshash;
    vis_ElemDat *edcsysid = NULL, *edcmatid = NULL;

    vis_ModelGetObject(model, VIS_CONNECT, (Vobject**)&connect);
    if (connect == NULL) {
        printf("Error: no Connect object\n");
        exit(0);
    }
    vis_ModelGetHashTable(model, VIS_ELEMDAT, &elemdathash);
    if (elemdathash) {
        vsy_HashTableLookup(elemdathash, SYS_PROP_ELEMVEC, (Vobject**)&edcsysid);
        vsy_HashTableLookup(elemdathash, SYS_PROP_MATLVEC, (Vobject**)&edcmatid);
    }
    vis_ModelGetHashTable(model, VIS_COORDSYS, &coordsyshash);

    vis_ConnectNumber(connect, SYS_NODE, &numnp);
    vis_ConnectNumber(connect, SYS_ELEM, &numel);
    printf("Number of nodes=    %d\n", numnp);
    printf("Number of elements= %d\n", numel);
    shellelem = vis_ShellElemBegin();
    beamelem = vis_BeamElemBegin();

    /* process shell and beam elements */
    for (i = 1; i <= numel; i++) {
        vis_ConnectElemAssoc(connect, VIS_FEATYPE, 1, &i, &featype);
        if (featype != SYS_ELEM_SHELL && featype != SYS_ELEM_BEAM)
            continue;
        vis_ConnectTopology(connect, i, &shape, &maxi, &maxj, &maxk);
        vis_ConnectElemNode(connect, i, &nix, ix);
        vis_ConnectCoords(connect, nix, ix, xe);
        vis_ConnectElemAssoc(connect, VIS_USERID, 1, &i, &eid);
        vis_ConnectElemAssoc(connect, VIS_CSYSID, 1, &i, &csysid);
        vis_ConnectElemAssoc(connect, VIS_CMATFLAG, 1, &i, &cmatflag);
        vis_ConnectElemAssoc(connect, VIS_CMATID, 1, &i, &cmatid);
        /* element results in CSYSID system */
        computeShellBeam(i, featype, csysid, shape, maxi, maxj, shellelem, beamelem, coordsyshash, edcsysid, xe, tme);
        printf("element= %d, element result system= %d\n", eid, csysid);
        printf("x'= %10f %10f %10f\n", tme[0][0], tme[0][1], tme[0][2]);
        printf("y'= %10f %10f %10f\n", tme[1][0], tme[1][1], tme[1][2]);
        printf("z'= %10f %10f %10f\n", tme[2][0], tme[2][1], tme[2][2]);
        /* element CMATID system */
        if (cmatflag) {
            computeShellBeam(i, featype, cmatid, shape, maxi, maxj, shellelem, beamelem, coordsyshash, edcmatid, xe, tme);
            printf("element= %d, element material system= %d\n", eid, cmatid);
            printf("x'= %10f %10f %10f\n", tme[0][0], tme[0][1], tme[0][2]);
            printf("y'= %10f %10f %10f\n", tme[1][0], tme[1][1], tme[1][2]);
            printf("z'= %10f %10f %10f\n", tme[2][0], tme[2][1], tme[2][2]);
        }
    }
    vis_ShellElemEnd(shellelem);
    vis_BeamElemEnd(beamelem);
}

10.44. Example 53, Manage System Degree of Freedom Data Using RedMat

This example illustrates the use of a RedMat object to manage degree of freedom data. The normal use of this object is to store superelement mass and/or stiffness matrices and superelement loads. The RedMat object can be configured to hold vectors as well as diagonal, symmetric and unsymmetric matrices. The data may be real or complex. By default the data is help internally in double precision. The vis_RedMatDef() function is used to specify the number of columns of the vector or matrix and the vector or matrix structure. The function vis_RedMatSetDatadv() is used to set the double precision values of the vector or matrix. The function vis_RedMatSetDof() may be optionally used to associate a entity index and degree of freedom tag with each row of the vector or matrix. Use vis_RedMatDatadv() to query the double precision values of the vector or matrix and vis_RedMatGetDof() to get the associated entity index and degree of freedom tags. Note that the function vis_RedMatSetComplexMode() must be called with SYS_COMPLEX_REALIMAGINARY to enter real and imaginary parts of complex valued data. By default the complex mode is SYS_COMPLEX_REAL.

#include "base/base.h"
#include "vgl/vgl.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Manage System Degree of Freedom Data Using RedMat
----------------------------------------------------------------------*/
int
main()
{
    vis_RedMat* redmat;
    Vint i, j, n, doftag;
    Vfloat fv[2];
    Vdouble dv[2];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    redmat = vis_RedMatBegin();
    /* define a diagonal matrix */
    vis_RedMatDef(redmat, 10, SYS_MATRIX_DIAG);
    for (i = 1; i <= 10; ++i) {
        dv[0] = i;
        vis_RedMatSetDatadv(redmat, i, i, dv);
    }
    printf("SYS_MATRIX_DIAG:\n");
    for (i = 1; i <= 10; ++i) {
        vis_RedMatData(redmat, i, i, fv);
        printf("   i= %2d, j= %2d, fv= %11.4e\n", i, i, fv[0]);
    }
    for (i = 1; i <= 10; ++i) {
        vis_RedMatDatadv(redmat, i, i, dv);
        printf("   i= %2d, j= %2d, dv= %11.4e\n", i, i, dv[0]);
    }
    /* define a complex symmetric matrix, lower triangle */
    vis_RedMatDef(redmat, 10, SYS_MATRIX_SYMM);
    vis_RedMatSetComplexMode(redmat, SYS_COMPLEX_REALIMAGINARY);
    for (n = 1, j = 1; j <= 10; ++j) {
        for (i = 1; i <= j; ++i, ++n) {
            dv[0] = 2 * n;
            dv[1] = 2 * n + 1;
            vis_RedMatSetDatadv(redmat, i, j, dv);
        }
    }
    /* add associated entity index and dof tag */
    /* nodes 1 throught 5, doftags translation x and y */
    for (i = 1; i <= 10; ++i) {
        n = (i - 1) / 2 + 1;
        if ((i - 1) % 2 == 0) {
            doftag = SYS_DOF_TX;
        }
        else {
            doftag = SYS_DOF_TY;
        }
        vis_RedMatSetDof(redmat, i, n, doftag);
    }

    printf("SYS_MATRIX_SYMM:\n");
    for (j = 1; j <= 10; ++j) {
        vis_RedMatGetDof(redmat, j, &n, &doftag);
        printf("   j= %2d, n= %d, doftag= %d\n", j, n, doftag);
        for (i = 1; i <= j; ++i) {
            vis_RedMatData(redmat, i, j, fv);
            printf("   i= %2d, j= %2d, fv= %11.4e %11.4e\n", i, j, fv[0], fv[1]);
        }
    }
    for (j = 1; j <= 10; ++j) {
        for (i = 1; i <= j; ++i) {
            vis_RedMatDatadv(redmat, i, j, dv);
            printf("   i= %2d, j= %2d, dv= %11.4e\n", i, j, dv[0]);
        }
    }
    /* define an unsymmetric matrix */
    vis_RedMatDef(redmat, 10, SYS_MATRIX_USYMM);
    vis_RedMatSetComplexMode(redmat, SYS_COMPLEX_REAL);
    for (n = 1, j = 1; j <= 10; ++j) {
        for (i = 1; i <= 10; ++i, ++n) {
            dv[0] = n;
            vis_RedMatSetDatadv(redmat, i, j, dv);
        }
    }
    printf("SYS_MATRIX_USYMM:\n");
    for (j = 1; j <= 10; ++j) {
        for (i = 1; i <= 10; ++i) {
            vis_RedMatData(redmat, i, j, fv);
            printf("   i= %2d, j= %2d, fv= %11.4e\n", i, j, fv[0]);
        }
    }
    for (j = 1; j <= 10; ++j) {
        for (i = 1; i <= 10; ++i) {
            vis_RedMatDatadv(redmat, i, j, dv);
            printf("   i= %2d, j= %2d, dv= %11.4e\n", i, j, dv[0]);
        }
    }
    /* define a vector, single row */
    vis_RedMatDef(redmat, 10, SYS_VECTOR);
    i = 1;
    for (j = 1; j <= 10; ++j) {
        dv[0] = j;
        vis_RedMatSetDatadv(redmat, i, j, dv);
    }
    printf("SYS_VECTOR:\n");
    for (j = 1; j <= 10; ++j) {
        vis_RedMatData(redmat, i, j, fv);
        printf("   i= %2d, j= %2d, fv= %11.4e\n", i, j, fv[0]);
    }
    for (j = 1; j <= 10; ++j) {
        vis_RedMatDatadv(redmat, i, j, dv);
        printf("   i= %2d, j= %2d, dv= %11.4e\n", i, j, dv[0]);
    }
    /* destroy object */
    vis_RedMatEnd(redmat);
    return 0;
}

10.45. Example 55, Computational Features of Edge, Face, Cell

This example illustrates using the computational features of the Edge, Face and Cell objects. In general each object will compute the natural coordinates of the center and nodes of edges, faces and cells respectively. They will also compute gradient vectors tangent to the natural coordinate directions at a given natural coordinate and perform interpolations of nodal variables to any natural coordinate location. In addition, the Face object will compute normal vectors to the face at each node. The Edge object will compute normalized tangent vectors to the edge at each node.

The geometries for the edge, face and cell are extracted from an array of coordinates generated cylindrically for a 10 node Lagrange tetrahedron.

#include <math.h>
#include "base/base.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Computational Features of Edge, Face, Cell
----------------------------------------------------------------------*/
int
main()
{
    Vint i, j, k, n;
    vis_Edge* edge;
    vis_Face* face;
    vis_Cell* cell;
    Vint nix;
    Vfloat r[4], rs[16][2], rst[64][3];
    Vfloat radin, dr, ang, da, z, dz, mag, rad;
    Vfloat x[64][3];
    Vfloat v[64][3], g[3][3];
    Vfloat rc[3], vc[3], xc[3];
    /* generate cononical tet structure of nodes */
    /* radin 10., radout = 20., height 2., ang= 45 degrees */
    /* use for edge, face, cell geometry */
    n = 0;
    radin = 10.;
    dr = (20. - 10.) / 2.;
    ang = 3.14149f / 4.f;
    da = ang / 2;
    z = 2.;
    dz = z / 2;
    for (i = 0; i < 3; i++) {
        rad = radin + i * dr;
        for (j = 0; j < 3 - i; j++) {
            for (k = 0; k < 3 - j; k++) {
                x[n][0] = rad * (Vfloat)cos(k * da);
                x[n][1] = rad * (Vfloat)sin(k * da);
                x[n][2] = j * dz;
                n += 1;
            }
        }
    }
    printf("Tet coordinates at nodes\n");
    for (i = 0; i < n; i++) {
        printf("i= %d, x= %f %f %f\n", i, x[i][0], x[i][1], x[i][2]);
    }

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create edge object */
    /* reuse first 3 nodes of tet geometry */
    edge = vis_EdgeBegin();
    /* compute natural coordinates at nodes */
    /* parabolic edge */
    vis_EdgeSetTopology(edge, VIS_SHAPELINE, 3);
    vis_EdgeRST(edge, rc, &nix, r);
    printf("Natural coordinates at center\n");
    printf("center rc= %f\n", rc[0]);
    printf("Natural coordinates at nodes\n");
    for (i = 0; i < nix; i++) {
        printf("i= %d, r= %f\n", i, r[i]);
    }
    /* edge tangents, normalized */
    vis_EdgeComputeTang(edge, x, v);
    printf("Edge normalized tangent vectors at nodes\n");
    for (i = 0; i < nix; i++) {
        printf("i= %d, v= %f %f %f\n", i, v[i][0], v[i][1], v[i][2]);
    }
    /* edge gradient tangents */
    printf("Edge tangent vectors at nodes\n");
    for (i = 0; i < nix; i++) {
        vis_EdgeTangRST(edge, x, r[i], g[0]);
        printf("i= %d, g[0]= %f %f %f\n", i, g[0][0], g[0][1], g[0][2]);
    }
    /* interpolate coordinates to center */
    vis_EdgeInterpolate(edge, rc[0], 3, (Vfloat*)x, xc);
    printf("Edge center coordinate\n");
    printf("center xc= %f %f %f\n", xc[0], xc[1], xc[2]);

    vis_EdgeEnd(edge);

    /* create face object */
    /* reuse first 6 nodes of tet geometry */
    face = vis_FaceBegin();
    /* compute natural coordinates at nodes */
    /* parabolic, Lagrange triangle */
    vis_FaceSetTopology(face, VIS_SHAPETRI, 3, 3);
    vis_FaceRST(face, rc, &nix, rs);
    printf("Natural coordinates at center\n");
    printf("center rc= %f %f\n", rc[0], rc[1]);
    printf("Natural coordinates at nodes\n");
    for (i = 0; i < nix; i++) {
        printf("i= %d, rs= %f %f\n", i, rs[i][0], rs[i][1]);
    }
    /* face normals */
    vis_FaceComputeNorm(face, x, v);
    printf("Face normal vectors at nodes\n");
    for (i = 0; i < nix; i++) {
        printf("i= %d, v= %f %f %f\n", i, v[i][0], v[i][1], v[i][2]);
    }
    /* face tangents */
    printf("Face gradient tangent vectors at nodes\n");
    for (i = 0; i < nix; i++) {
        vis_FaceTangRST(face, x, rs[i], g);
        printf("i= %d, g[0]= %f %f %f, g[1]= %f %f %f\n", i, g[0][0], g[0][1], g[0][2], g[1][0], g[1][1], g[1][2]);
    }
    /* interpolate normal to center */
    vis_FaceInterpolate(face, rc, 3, (Vfloat*)v, vc);
    printf("Face center normal vector\n");
    /* normalize */
    mag = (Vfloat)sqrt(vc[0] * vc[0] + vc[1] * vc[1] + vc[2] * vc[2]);
    vc[0] = vc[0] / mag;
    vc[1] = vc[1] / mag;
    vc[2] = vc[2] / mag;
    printf("center v= %f %f %f\n", vc[0], vc[1], vc[2]);

    vis_FaceEnd(face);

    /* create cell object */
    cell = vis_CellBegin();
    /* compute natural coordinates at nodes */
    /* parabolic, Lagrange tet */
    vis_CellSetTopology(cell, VIS_SHAPETET, 3, 3, 3);
    vis_CellRST(cell, rc, &nix, rst);
    printf("Natural coordinates at center\n");
    printf("center rc= %f %f\n", rc[0], rc[1]);
    printf("Natural coordinates at nodes\n");
    for (i = 0; i < nix; i++) {
        printf("i= %d, rst= %f %f %f\n", i, rst[i][0], rst[i][1], rst[i][2]);
    }
    /* cell tangents */
    printf("Cell gradient tangent vectors at nodes\n");
    for (i = 0; i < nix; i++) {
        vis_CellTangRST(cell, x, rst[i], g);
        printf("i= %d, g[0]= %f %f %f, g[1]= %f %f %f, g[2]= %f %f %f\n", i, g[0][0], g[0][1], g[0][2], g[1][0], g[1][1], g[1][2],
               g[2][0], g[2][1], g[2][2]);
    }
    /* interpolate coordinates to center */
    vis_CellInterpolate(cell, rc, 3, (Vfloat*)x, xc);
    printf("Cell center coordinate\n");
    printf("center xc= %f %f %f\n", xc[0], xc[1], xc[2]);

    vis_CellEnd(cell);

    return 0;
}

10.46. Example 56, Using Units

This example illustrates using the Units module to store and retrieve a set of units termed base units. It also allows for the definition of a set of conversion units and associated conversion factors for transforming from base units to the conversion units. In this example the base units are set to SI. Note that setting the base unit also sets the conversion unit to the same value. The conversion units are set to typical British units. The call to vis_UnitsComputeFactors() will automatically set the conversion factors between the defined base and conversion units. The user need only set factors manually using vis_UnitsSetFactor() if either the base or conversion unit is user defined, for example if the conversion length unit is set to UNITS_LENGTH_USER. The computed conversion factors are queried using vis_UnitsGetFactor().

#include "base/base.h"
#include "vis/vis.h"
#include "glwin.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                      Using Units
----------------------------------------------------------------------*/
int
main()
{
    vis_Units* units;
    Vdouble lfac, mfac, tfac, tempfac, tempoff;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create Units */
    units = vis_UnitsBegin();

    /* set base units to SI */
    vis_UnitsSetBase(units, UNITS_LENGTH, UNITS_LENGTH_METER);
    vis_UnitsSetBase(units, UNITS_MASS, UNITS_MASS_KILOGRAM);
    vis_UnitsSetBase(units, UNITS_TIME, UNITS_TIME_SECOND);
    vis_UnitsSetBase(units, UNITS_TEMP, UNITS_TEMP_KELVIN);

    /* set conversion units to British */
    vis_UnitsSetConv(units, UNITS_LENGTH, UNITS_LENGTH_FOOT);
    vis_UnitsSetConv(units, UNITS_MASS, UNITS_MASS_POUND);
    vis_UnitsSetConv(units, UNITS_TIME, UNITS_TIME_SECOND);
    vis_UnitsSetConv(units, UNITS_TEMP, UNITS_TEMP_FAHRENHEIT);

    /* compute conversion factors */
    vis_UnitsComputeFactors(units);

    /* get and print factors */
    vis_UnitsGetFactor(units, UNITS_LENGTH, &lfac);
    vis_UnitsGetFactor(units, UNITS_MASS, &mfac);
    vis_UnitsGetFactor(units, UNITS_TIME, &tfac);
    vis_UnitsGetFactor(units, UNITS_TEMP, &tempfac);
    vis_UnitsGetFactor(units, UNITS_TEMP_OFFSET, &tempoff);
    printf("length, one meter is %e feet\n", lfac);
    printf("mass,   one kilogram is %e pounds\n", mfac);
    printf("time,   one second is %e seconds\n", tfac);
    printf("temp,   fahrenheit= %e * (kelvin + %e)\n", tempfac, tempoff);

    /* free object */
    vis_UnitsEnd(units);
    return 0;
}

10.47. Example 57, Compress and Uncompress Coordinate Field with ZState

This example illustrates using the ZState module to compress and uncompress a node coordinate field. In general ZState is most successful compressing fields with a high degree of spatial continuity. A ZState object is instanced and the function vis_ZStateDef() is used to define a node based field for compression. A GridFun object is required to provide access to the model node locations and element connectivity, this object is set in ZState using vis_ZStateSetObject().

The ZState object first is used to generate the compression kernel. This is a model dependent data structure which is required for compressing field data and subsequently uncompressing any compressed field data. The compression kernel is computed using vis_ZStateKernel(). Get a maximum length for the kernel using vis_ZStateLngKernel(). Use this length to allocate memory for the kernel data structure. Use vis_ZStateSaveKernel() to access the kernel, the actual length of the kernel is returned in newbytes and is, in general, less than the length returned by vis_ZStateLngKernel(). Generally this data structure is written to a file by the user along with the compressed states for later access and decompression.

A State object is instanced and the node coordinate vector data is entered. The vis_ZStateState() function is used to compress the state. In a manner similar to the kernel, the maximum length of the compressed state is returned using vis_ZStateLngState(). Return the compressed state data and the actual length using vis_ZStateSaveState().

The uncompression process instances a new ZState and uses vis_ZStateLoadKernel() to reestablish the compression kernel and vis_ZStateLoadState() is uncompress the compressed state data into a new State object.

#include "base/system.h"
#include "base/base.h"
#include "vgl/vgl.h"
#include "vis/vis.h"
#include "vis/vismesh.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*
                 5------6
                /.     /.\
  y            / .    / . \
  |           /  .   /  .  \7------8
  --x        /   1../...2../|      |
 /         12-----13-----14 |      |
z           |  .   |  .   |.|      |
            | .    | .    | 3------4
            |.     |.     |/
            9-----10-----11
*/

#define MAX_ELEM 3
#define MAX_NODE 14

static Vint conn[MAX_ELEM][8] = {{1, 2, 6, 5, 9, 10, 13, 12}, {2, 3, 7, 6, 10, 11, 14, 13}, {3, 4, 8, 7, 0, 0, 0, 0}};

static Vint shap[MAX_ELEM] = {VIS_SHAPEHEX, VIS_SHAPEHEX, VIS_SHAPEQUAD};

static Vfloat coords[MAX_NODE][3] = {{0., 0., 0.}, {1., 0., 0.}, {2., 0., 1.}, {3., 0., 1.}, {0., 1., 0.},
                                     {1., 1., 0.}, {2., 1., 1.}, {3., 1., 1.}, {0., 0., 2.}, {1., 0., 2.},
                                     {2., 0., 2.}, {0., 1., 2.}, {1., 1., 2.}, {2., 1., 2.}};

/*----------------------------------------------------------------------
          Compress and Uncompress Coordinate Field with ZState
----------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    vis_ZState* zstate;
    vis_Connect* connect;
    vis_GridFun* gridfun;
    vis_State* state;
    Vuchar *bkernel, *bstate;
    Vint i;
    Vulong nbytes, newbytes;
    Vfloat x[3];

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* create connect object */
    connect = vis_ConnectBegin();
    vis_ConnectDef(connect, MAX_NODE, MAX_ELEM);

    /* set topologies */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetTopology(connect, i + 1, shap[i], 2, 0, 0);
    }
    /* set element node connectivity */
    for (i = 0; i < MAX_ELEM; i++) {
        vis_ConnectSetElemNode(connect, i + 1, conn[i]);
    }
    /* set node coordinates */
    for (i = 0; i < MAX_NODE; i++) {
        vis_ConnectSetCoords(connect, i + 1, coords[i]);
    }
    /* create GridFun */
    gridfun = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gridfun);

    /* create ZState and Def it for nodal data */
    zstate = vis_ZStateBegin();
    vis_ZStateDef(zstate, MAX_NODE, SYS_NODE, SYS_NONE);
    vis_ZStateSetObject(zstate, VIS_GRIDFUN, (Vobject*)gridfun);

    /* create ZState kernel and save it */
    vis_ZStateKernel(zstate, NULL);
    vis_ZStateLngKernel(zstate, &nbytes);
    bkernel = (Vuchar*)malloc(nbytes * sizeof(Vuchar));
    vis_ZStateSaveKernel(zstate, bkernel, &newbytes);
    printf("Kernel size= %lld bytes, actual= %lld\n", nbytes, newbytes);
    /* create coordinate state */
    state = vis_StateBegin();
    vis_StateSetObject(state, VIS_GRIDFUN, (Vobject*)gridfun);
    vis_StateDef(state, MAX_NODE, SYS_NODE, SYS_NONE, SYS_VECTOR);
    for (i = 1; i <= MAX_NODE; i++) {
        vis_ConnectCoords(connect, 1, &i, &x);
        vis_StateSetData(state, i, x);
    }
    /* compress and save coordinate state */
    vis_ZStateState(zstate, state);
    vis_ZStateLngState(zstate, &nbytes);
    bstate = (Vuchar*)malloc(nbytes * sizeof(Vuchar));
    vis_ZStateSaveState(zstate, state, bstate, &newbytes);
    printf("State size= %lld bytes, actual= %lld\n", nbytes, newbytes);

    /* clean-up ZState and State */
    vis_ZStateEnd(zstate);
    vis_StateEnd(state);

    /* instance new ZState and State to reload */
    zstate = vis_ZStateBegin();
    vis_ZStateSetObject(zstate, VIS_GRIDFUN, (Vobject*)gridfun);
    vis_ZStateLoadKernel(zstate, bkernel);
    state = vis_StateBegin();
    vis_StateSetObject(state, VIS_GRIDFUN, (Vobject*)gridfun);
    vis_ZStateLoadState(zstate, bstate, state);

    /* compare compressed and uncompressed values */
    for (i = 1; i <= MAX_NODE; i++) {
        vis_ConnectCoords(connect, 1, &i, &x);
        printf("%5d, %11.4e %11.4e %11.4e, ", i, x[0], x[1], x[2]);
        vis_StateData(state, 1, &i, x);
        printf("%11.4e %11.4e %11.4e\n", x[0], x[1], x[2]);
    }
    /* clean-up */
    vis_ZStateEnd(zstate);
    vis_ConnectEnd(connect);
    vis_GridFunEnd(gridfun);
    vis_StateEnd(state);
    free(bstate);
    free(bkernel);
    return 0;
}

10.48. Example 58vdm, Compress and Uncompress Results with ZState

This example illustrates using the ZState module to compress and uncompress nodal and element State data.

The example takes as its single argument any file supported by VdmTools. The VdmTools interface used is determined by the file extension (e.g., .op2). The Model is extracted from the file and a GridFun object is generated from the Connect object.

The example is divided into two steps. In the first, a nodal kernel is generated and all nodal states are compressed. In the second an element kernel is generated and all element states are compressed. For each of these steps a ZState object is instanced and configured. The kernel is then computed with vis_ZStateKernel() and an upper bound limit on the memory required to save the kernel is returned in vis_ZStateLngKernel(). This memory is then allocated and the kernel is saved with vis_ZStateSaveKernel(), which returns the true amount of memory required to save the kernel. Then all nodal datasets are compressed in a similar manner, by first calling vis_ZStateState(), followed by vis_ZStateLngState(), and by vis_ZStateSaveState(). In a typical usage the kernel and state memory are saved in external storage for later retrieval.

The example also demonstrates what would done in a separate program to perform the uncompression. vis_ZStateLoadKernel() recreates the kernel and, for each State, vis_ZStateLoadState() recreates the lossy State.

#include "base/system.h"
#include "base/base.h"
#include "vgl/vgl.h"
#include "vis/vis.h"
#include "vdm/vdm.h"
#include "vdm/exam/datafile.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

/*----------------------------------------------------------------------
                   Compress and Uncompress Results with ZState
----------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    vis_ZState* zstate;
    vis_Connect* connect;
    vis_GridFun* gridfun;
    vis_Model* model;
    vis_State* state;
    vis_RProp* rprop;
    vdm_DataFun* datafun;
    vdm_LMan* lman;
    vdm_Library* library;
    vdm_Dataset* dataset;
    vis_IdTran* idtran;
    Vuchar *bkernel, *bstate;
    Vint filetype, ierr, numdatasets, numnp, numel, idst, i, j;
    Vint nodeinc, eleminc, pid;
    Vchar root[256], cqua[256], caux[256], dsname[DATASET_MAXNAME];
    Vint type, hist, nqua, iqua[SYS_NQUA_MAX], sect, enttype, subtype, cplx;
    Vint id1, id2, id3;
    Vlong lrec;
    Vint nrow, ncol, dtype;
    Vulong nbytes, newbytes;
    Vfloat value[100];
    Vfloat ratio;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s results_file\n", argv[0]);
        return 1;
    }
    /* open results file */
    datafiletype(argv[1], &filetype);
    if (filetype == 0) {
        fprintf(stderr, "Error: Bad input file %s\n", argv[1]);
        return 1;
    }

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    datafun = vdm_DataFunBegin();
    datafileinit(filetype, datafun);
    vdm_DataFunOpen(datafun, 0, argv[1], filetype);
    ierr = vdm_DataFunError(datafun);
    if (ierr) {
        fprintf(stderr, "Error: opening file %s\n", argv[1]);
        return 1;
    }
    printf("Processing file= %s\n", argv[1]);
    vdm_DataFunNumDatasets(datafun, &numdatasets);
    vdm_DataFunGetLibrary(datafun, &library);

    /* extract model/connect */
    lman = vdm_LManBegin();
    vdm_LManSetObject(lman, VDM_DATAFUN, (Vobject*)datafun);
    model = vis_ModelBegin();
    vdm_LManLoadModel(lman, model);
    vis_ModelGetObject(model, VIS_CONNECT, (Vobject**)&connect);
    vis_ConnectNumber(connect, SYS_NODE, &numnp);
    vis_ConnectNumber(connect, SYS_ELEM, &numel);
    printf("   numnp= %d\n", numnp);
    printf("   numel= %d\n", numel);
    nodeinc = numnp / 10;
    if (nodeinc == 0) {
        nodeinc = 1;
    }
    eleminc = numel / 10;
    if (eleminc == 0) {
        eleminc = 1;
    }

    /* create GridFun */
    gridfun = vis_GridFunBegin();
    vis_ConnectGridFun(connect, gridfun);

    /* create State and RProp */
    rprop = vis_RPropBegin();
    state = vis_StateBegin();
    vis_StateSetObject(state, VIS_GRIDFUN, (Vobject*)gridfun);

    /* create ZState and Def it for nodal data */
    zstate = vis_ZStateBegin();
    vis_ZStateSetObject(zstate, VIS_GRIDFUN, (Vobject*)gridfun);

    /* Setup for nodal results */
    vis_ZStateDef(zstate, numnp, SYS_NODE, SYS_NONE);

    /* create ZState kernel and save it */
    vis_ZStateKernel(zstate, NULL);
    vis_ZStateLngKernel(zstate, &nbytes);
    printf("   Nodal kernel size= %lld bytes\n", nbytes);
    bkernel = (Vuchar*)malloc(nbytes * sizeof(Vuchar));
    vis_ZStateSaveKernel(zstate, bkernel, &newbytes);
    vis_ZStateEnd(zstate);

    /* load ZState kernel */
    zstate = vis_ZStateBegin();
    vis_ZStateSetObject(zstate, VIS_GRIDFUN, (Vobject*)gridfun);
    vis_ZStateLoadKernel(zstate, bkernel);
    free(bkernel);

    /* loop over all nodal states */
    vis_RPropDef(rprop, SYS_NODE, SYS_NONE);
    for (idst = 0; idst < numdatasets; idst++) {
        vdm_LibraryGetDataset(library, idst, &dataset);
        vdm_DatasetResult(dataset, root, &type, &hist, &nqua, iqua, cqua, &cplx, caux, &sect, &enttype, &subtype, &id1, &id2,
                          &id3);

        /* skip non-result datasets */
        if (type == SYS_RES_NONE)
            continue;

        /* skip non-nodal results */
        if (enttype != SYS_NODE || subtype != SYS_NONE)
            continue;

        /* load this nodal state */
        vdm_DatasetInq(dataset, dsname, &lrec, &nrow, &ncol, &dtype);
        printf("   Dataset= %s\n", dsname);
        vis_RPropSetDatasetName(rprop, dsname);
        vdm_LManLoadState(lman, state, rprop);
        printf("      Original values:\n");
        for (i = 1; i <= numnp; i += nodeinc) {
            vis_StateData(state, 1, &i, value);
            printf("      %10d", i);
            for (j = 0; j < nrow; ++j) {
                printf(" %11.4e", value[j]);
            }
            printf("\n");
        }

        /* compress and save coordinate state */
        vis_ZStateState(zstate, state);
        vis_ZStateLngState(zstate, &nbytes);
        printf("      Original   state size= %lld bytes\n", lrec * sizeof(Vfloat));
        printf("      Compressed state size= %lld bytes\n", nbytes);
        ratio = (Vfloat)((lrec * sizeof(Vfloat)) / (Vfloat)nbytes);
        printf("      Compression ratio= %f\n", ratio);
        bstate = (Vuchar*)malloc(nbytes * sizeof(Vuchar));
        vis_ZStateSaveState(zstate, state, bstate, &newbytes);

        /* clean-up ZState and State */
        vis_StateEnd(state);

        /* instance new ZState and State to reload */
        state = vis_StateBegin();
        vis_StateSetObject(state, VIS_GRIDFUN, (Vobject*)gridfun);
        vis_ZStateLoadState(zstate, bstate, state);
        free(bstate);

        /* compare compressed and uncompressed values */
        printf("      Compressed values:\n");
        for (i = 1; i <= numnp; i += nodeinc) {
            vis_StateData(state, 1, &i, value);
            printf("      %10d", i);
            for (j = 0; j < nrow; ++j) {
                printf(" %11.4e", value[j]);
            }
            printf("\n");
        }
    }
    /* Setup for element results */
    vis_ZStateDef(zstate, numel, SYS_ELEM, SYS_NONE);

    /* Create idtran and assign propid */
    idtran = vis_IdTranBegin();
    vis_IdTranDef(idtran, numel);
    for (i = 1; i <= numel; ++i) {
        vis_ConnectElemAssoc(connect, VIS_PROPID, 1, &i, &pid);
        vis_IdTranSetId(idtran, i, pid + 1);
    }
    /* create ZState kernel and save it */
    vis_ZStateKernel(zstate, idtran);
    vis_IdTranEnd(idtran);

    vis_ZStateLngKernel(zstate, &nbytes);
    printf("   Element kernel size= %lld bytes\n", nbytes);
    bkernel = (Vuchar*)malloc(nbytes * sizeof(Vuchar));
    vis_ZStateSaveKernel(zstate, bkernel, &newbytes);
    vis_ZStateEnd(zstate);

    /* load ZState kernel */
    zstate = vis_ZStateBegin();
    vis_ZStateSetObject(zstate, VIS_GRIDFUN, (Vobject*)gridfun);
    vis_ZStateLoadKernel(zstate, bkernel);
    free(bkernel);

    /* loop over all element states */
    vis_RPropDef(rprop, SYS_ELEM, SYS_NONE);
    for (idst = 0; idst < numdatasets; idst++) {
        vdm_LibraryGetDataset(library, idst, &dataset);
        vdm_DatasetResult(dataset, root, &type, &hist, &nqua, iqua, cqua, &cplx, caux, &sect, &enttype, &subtype, &id1, &id2,
                          &id3);

        /* skip non-result datasets */
        if (type == SYS_RES_NONE)
            continue;

        /* skip non-element results */
        if (enttype != SYS_ELEM || subtype != SYS_NONE)
            continue;

        /* load this nodal state */
        vdm_DatasetInq(dataset, dsname, &lrec, &nrow, &ncol, &dtype);
        printf("   Dataset= %s\n", dsname);
        vis_RPropSetDatasetName(rprop, dsname);
        vdm_LManLoadState(lman, state, rprop);
        printf("      Original values:\n");
        for (i = 1; i <= numel; i += eleminc) {
            vis_StateData(state, 1, &i, value);
            printf("      %10d", i);
            for (j = 0; j < nrow; ++j) {
                printf(" %11.4e", value[j]);
            }
            printf("\n");
        }

        /* compress and save coordinate state */
        vis_ZStateState(zstate, state);
        vis_ZStateLngState(zstate, &nbytes);
        printf("      Original   state size= %lld bytes\n", lrec * sizeof(Vfloat));
        printf("      Compressed state size= %lld bytes\n", nbytes);
        ratio = (Vfloat)((lrec * sizeof(Vfloat)) / (Vfloat)nbytes);
        printf("      Compression ratio= %f\n", ratio);
        bstate = (Vuchar*)malloc(nbytes * sizeof(Vuchar));
        vis_ZStateSaveState(zstate, state, bstate, &newbytes);

        /* clean-up ZState and State */
        vis_StateEnd(state);
        state = vis_StateBegin();
        vis_StateSetObject(state, VIS_GRIDFUN, (Vobject*)gridfun);
        vis_ZStateLoadState(zstate, bstate, state);
        free(bstate);

        /* compare compressed and uncompressed values */
        printf("      Compressed values:\n");
        for (i = 1; i <= numel; i += eleminc) {
            vis_StateData(state, 1, &i, value);
            printf("      %10d", i);
            for (j = 0; j < nrow; ++j) {
                printf(" %11.4e", value[j]);
            }
            printf("\n");
        }
    }
    vdm_DataFunClose(datafun);

    /* clean-up */
    vis_RPropEnd(rprop);
    vis_StateEnd(state);
    vis_ZStateEnd(zstate);
    vis_ModelDelete(model);
    vis_ModelEnd(model);
    vis_GridFunEnd(gridfun);
    vdm_LManEnd(lman);
    datafileterm(filetype, datafun);
    vdm_DataFunEnd(datafun);
    return 0;
}

10.49. Example 59vgl, Demonstrate Parallel Contour and Threshold Generation

This example illustrates the generation of DList objects done in parallel with multiple processors.

A drawing window is opened and configured with OpenGL. Then VisContext, vis_Levels(), and vis_ColorMap() objects common to all threads are instanced and configured.

The PTask object is used to generate and run N threads simultaneously, where N is the number of processors available in the machine and is obtained using vut_MachInfoNumProc(). Starting a thread requires an object per thread and a function to be executed. N parallel objects of type ParObj are then created. These will be used twice later on: to generate a display list using a Threshold object, then another display list using a Contour object. Note that each ParObj objects has its own instance of a Threshold and a Contour object as they will be executed simultaneously on different data.

The contour and threshold generation functions require that the Contour and Threshold objects are thread safe as well as the DrawFun and DList objects. It is also required that the Connect object query functions are const as well as the visualization attribute objects ColorMap, Levels and VisContext.

The example first generates a mesh containing both hexahedral and quadrilateral elements. The Threshold object only operates on 3D elements. The total number of 3D elements in the model is counted and equally divided among all processors. The IdTran object idtranthreshold is stored in each ParObj object and contains the list of elements that Threshold will operate on in each processor.

The Contour object operates on faces which are present in both 2D and 3D elements. Like in the Threshold usage above, the IdTran object idtrancontour stores the element and face number to be used in each processor by the Contour object. As in a typical application, only the free faces in the model are displayed by the Contour object.

The function vsy_PTaskExec() is used twice, once to generate the display lists created by Threshold, and once to generate the display lists created by Contour. These lists are initially cleared with vgl_DListErase() then serially displayed with vgl_DListCall().

#include "base/base.h"
#include "vgl/vgl.h"
#include "vis/vis.h"
#include "base/license.h"
#include "CEETRON_SAM_license.h"

static Vfloat rgb[6][3] = {{1., 0., 0.}, {0., 1., 0.}, {0., 0., 1.}, {0., 1., 1.}, {1., 0., 1.}, {1., 1., 0.}};

/* common parallel object */
typedef struct {
    Vint iproc;
    Vint nel;
    Vint nface;
    Vint numel;
    Vint numproc;
    vis_Threshold* threshold;
    vis_Contour* contour;
    vgl_DList* dl;
    vgl_DrawFun* dfdl;
    vis_Connect* connect;
    vis_IdTran* idtranthreshold;
    vis_IdTran* idtrancontour;
} ParObj;

#define NNODEX 101
#define NNODEY 101
#define NNODEZ 101
#define NELEMX (NNODEX - 1)
#define NELEMY (NNODEY - 1)
#define NELEMZ (NNODEZ - 1)

/* threshold generation function */
static void
gen_threshold(Vobject* obj)
{
    ParObj* par = (ParObj*)obj;
    Vfloat s[8], x[8][3];
    Vint nix, ix[8], i, n, id;
    /* generate display list */
    vis_ThresholdSetTopology(par->threshold, SYS_SHAPEHEX, 0, 0, 0);
    for (n = 1; n <= par->nel; ++n) {
        vis_IdTranGetId(par->idtranthreshold, n, &id);
        vis_ConnectElemNode(par->connect, id, &nix, ix);
        vis_ConnectCoords(par->connect, nix, ix, x);
        for (i = 0; i < nix; ++i) {
            s[i] = (Vfloat)sqrt(x[i][0] * x[i][0] + x[i][1] * x[i][1] + x[i][2] * x[i][2]);
        }
        vis_ThresholdCurv(par->threshold, s, x, VIS_NODATA, NULL);
    }
}

/* threshold generation function */
static void
gen_contour(Vobject* obj)
{
    ParObj* par = (ParObj*)obj;
    Vfloat s[8], x[8][3];
    Vint nix, ix[8], i, n, id, no;
    Vint shape, maxi, maxj;

    /* generate display list */
    for (n = 1; n <= par->nface; ++n) {
        vis_IdTranGetId(par->idtrancontour, n, &id);
        vis_IdTranGetEnt(par->idtrancontour, n, &no);
        vis_ConnectElemTopo(par->connect, SYS_FACE, id, no, &shape, &maxi, &maxj);
        vis_ContourSetTopology(par->contour, shape, maxi, maxj);

        vis_ConnectElemCon(par->connect, SYS_FACE, id, no, &nix, ix);
        vis_ConnectCoords(par->connect, nix, ix, x);
        for (i = 0; i < nix; ++i) {
            s[i] = (Vfloat)sqrt(x[i][0] * x[i][0] + x[i][1] * x[i][1] + x[i][2] * x[i][2]);
        }
        vis_ContourCurv(par->contour, s, x, VIS_NODATA, NULL);
    }
}

/* serial drawing of display lists */
static void
draw_display(vgl_DrawFun* df, Vint numproc, ParObj** objs)
{
    Vint i, n;
    Vfloat tm[4][4];
    vgl_Xfm* xfm;

    xfm = vgl_XfmBegin();
    /* draw display lists */
    for (i = 0; i < 30; i++) {
        vgl_DrawFunClear(df);
        vgl_DrawFunXfmPush(df);
        vgl_XfmRotate(xfm, i * 12.F * .017453F, XFM_XAXIS);
        vgl_XfmGetMatrix(xfm, tm);
        vgl_DrawFunXfmLoad(df, tm);
        for (n = 0; n < numproc; ++n) {
            vgl_DListCall(objs[n]->dl);
        }
        vgl_DrawFunXfmPop(df);
        vgl_DrawFunSwap(df);
        vgl_DrawFunDelay(df, 1.);
    }

    vgl_XfmEnd(xfm);
}

static void
createMesh(vis_Connect* connect, Vint* numel)
{
    Vint i, j, k, ix[8], numnode, numelem, numnodehex;
    Vfloat dx, dy, dz, x[3];

    numnode = 0;
    numelem = 0;
    dx = 1.f / NELEMX;
    dy = 1.f / NELEMY;
    dz = 1.f / NELEMZ;
    /* generate nodes for hex elements */
    for (k = 0; k < NNODEZ; ++k) {
        x[2] = k * dz;
        for (j = 0; j < NNODEY; ++j) {
            x[1] = j * dy;
            for (i = 0; i < NNODEX; ++i) {
                x[0] = i * dx;
                ++numnode;
                vis_ConnectSetCoords(connect, numnode, x);
            }
        }
    }
    numnodehex = numnode;

    /* generate nodes for quad elements */
    x[2] = 0.;
    for (j = 0; j < NNODEY; ++j) {
        x[1] = j * dy;
        for (i = 0; i < NNODEX; ++i) {
            x[0] = i * dx - 1.F;
            ++numnode;
            vis_ConnectSetCoords(connect, numnode, x);
        }
    }
    /* generate hex elements */
    for (k = 0; k < NELEMZ; ++k) {
        for (j = 0; j < NELEMY; ++j) {
            for (i = 0; i < NELEMX; ++i) {
                ix[0] = NNODEX * NNODEY * k + NNODEX * j + i + 1;
                ix[1] = ix[0] + 1;
                ix[2] = ix[1] + NNODEX;
                ix[3] = ix[2] - 1;
                ix[4] = ix[0] + NNODEX * NNODEY;
                ix[5] = ix[1] + NNODEX * NNODEY;
                ix[6] = ix[2] + NNODEX * NNODEY;
                ix[7] = ix[3] + NNODEX * NNODEY;
                ++numelem;
                vis_ConnectSetTopology(connect, numelem, SYS_SHAPEHEX, 0, 0, 0);
                vis_ConnectSetElemNode(connect, numelem, ix);
            }
        }
    }
    /* generate quad elements */
    for (j = 0; j < NELEMY; ++j) {
        for (i = 0; i < NELEMX; ++i) {
            ix[0] = NNODEX * j + i + numnodehex + 1;
            ix[1] = ix[0] + 1;
            ix[2] = ix[1] + NNODEX;
            ix[3] = ix[2] - 1;
            ++numelem;
            vis_ConnectSetTopology(connect, numelem, SYS_SHAPEQUAD, 0, 0, 0);
            vis_ConnectSetElemNode(connect, numelem, ix);
        }
    }
    vis_ConnectKernel(connect, 0);
    *numel = numelem;
}

/*----------------------------------------------------------------------
                      Demonstrate Parallel Contour and Threshold Generation
----------------------------------------------------------------------*/
int
main()
{
    ParObj** objs;
#ifdef VKI_WIND_X11
    Display* display;
    int screen;
#endif

    vsy_PTask* ptask;
    vgl_DrawFun* df;
    vis_VisContext* vc;
    vis_Levels* levels;
    vis_ColorMap* cmap;
    vgl_OpenGLDev* ogldev;
    vis_Connect* connect;
    vis_Group* group;

    int n, m, no, iproc;
    Vint nlevels;
    Vfloat c[3], x[3];
    Vint flag, numproc, numel;
    Vint nel, numparent, nfaces, nfproc, neproc;
    Vint shape, maxi, maxj, maxk;

    vsy_LicenseValidate(CEETRON_SAM_LICENSE);

    /* generate mesh */
    connect = vis_ConnectBegin();
    createMesh(connect, &numel);
    printf("mesh generation complete\n");
#ifdef VKI_WIND_X11
    /* open X display */
    display = XOpenDisplay(0);
    screen = DefaultScreen(display);
    vgl_OpenGLDevConnectX(display, screen);
#endif
#ifdef VKI_WIND_WIN32
    vgl_OpenGLDevConnectWIN();
#endif
    /* create GL device */
    ogldev = vgl_OpenGLDevBegin();

    /* create draw function object for GL */
    df = vgl_DrawFunBegin();
    vgl_OpenGLDevDrawFun(ogldev, df);

    vgl_DrawFunPositionWindow(df, 200, 200, 400, 400);
    vgl_DrawFunOpenWindow(df, "Example 59vgl");
    vgl_DrawFunProjOrtho(df, -2., 2., -2., 2., -2., 2.);
    vgl_DrawFunSetMode(df, VGL_ZBUFFERMODE, VGL_ON);
    vgl_DrawFunSetMode(df, VGL_LIGHTMODE, VGL_ON);
    c[0] = .4f;
    c[1] = .4f;
    c[2] = .4f;
    x[0] = 0.;
    x[1] = 0.;
    x[2] = 0.;
    vgl_DrawFunLight(df, 0, LIGHT_AMBIENT, c, x);
    c[0] = .6f;
    c[1] = .6f;
    c[2] = .6f;
    x[0] = 1.;
    x[1] = 1.;
    x[2] = 1.;
    vgl_DrawFunLight(df, 1, LIGHT_DISTANT, c, x);
    x[0] = -1.;
    x[1] = -1.;
    x[2] = -1.;
    vgl_DrawFunLight(df, 2, LIGHT_DISTANT, c, x);

    /* vis context and set attributes */
    vc = vis_VisContextBegin();

    /* levels, set three evenly spaced levels */
    levels = vis_LevelsBegin();
    nlevels = 5;
    vis_LevelsDef(levels, LEVELS_LINEAR, nlevels);
    vis_LevelsSetMinMax(levels, 0., 1);
    vis_LevelsGenerate(levels, LEVELS_PADENDS);

    /* color map */
    cmap = vis_ColorMapBegin();
    vis_ColorMapSetType(cmap, COLORMAP_TRUECOLOR);
    vis_ColorMapSetRGB(cmap, nlevels + 1, 0, rgb);

    /* retrieve number of processors */
    vut_MachInfoNumProc(&flag, &numproc);
    if (!flag) {
        numproc = 1;
    }
    /* instance PTask object for parallelization tasks */
    ptask = vsy_PTaskBegin();
    vsy_PTaskDef(ptask, numproc, PTASK_EXEC);

    /* instance parallel objects */
    objs = (ParObj**)vut_MemoryMalloc(numproc * sizeof(ParObj**));
    for (iproc = 0; iproc < numproc; iproc++) {
        objs[iproc] = (ParObj*)vut_MemoryMalloc(sizeof(ParObj));
        objs[iproc]->iproc = iproc;
        objs[iproc]->connect = connect;
        objs[iproc]->numel = numel;
        objs[iproc]->numproc = numproc;
        /* create threshold DList and its DrawFun */
        objs[iproc]->dl = vgl_DListBegin();
        objs[iproc]->dfdl = vgl_DrawFunBegin();
        vgl_DListDrawFun(objs[iproc]->dl, objs[iproc]->dfdl);
        vgl_DListSetObject(objs[iproc]->dl, VGL_DRAWFUN, df);

        /* create threshold object and set objects */
        objs[iproc]->threshold = vis_ThresholdBegin();
        vis_ThresholdSetObject(objs[iproc]->threshold, VGL_DRAWFUN, objs[iproc]->dfdl);
        vis_ThresholdSetObject(objs[iproc]->threshold, VIS_VISCONTEXT, vc);
        vis_ThresholdSetObject(objs[iproc]->threshold, VIS_LEVELS, levels);
        vis_ThresholdSetObject(objs[iproc]->threshold, VIS_COLORMAP, cmap);

        /* create list of threshold elements for this processor */
        objs[iproc]->idtranthreshold = vis_IdTranBegin();

        /* create contour object and set objects */
        objs[iproc]->contour = vis_ContourBegin();
        vis_ContourSetObject(objs[iproc]->contour, VGL_DRAWFUN, objs[iproc]->dfdl);
        vis_ContourSetObject(objs[iproc]->contour, VIS_VISCONTEXT, vc);
        vis_ContourSetObject(objs[iproc]->contour, VIS_LEVELS, levels);
        vis_ContourSetObject(objs[iproc]->contour, VIS_COLORMAP, cmap);

        /* create list of contour faces for this processor */
        objs[iproc]->idtrancontour = vis_IdTranBegin();
        vis_IdTranSetEntType(objs[iproc]->idtrancontour, SYS_ELEM, SYS_FACE);
    }
    /* count list of 3D elements for threshold */
    nel = 0;
    for (n = 1; n <= numel; ++n) {
        vis_ConnectTopology(connect, n, &shape, &maxi, &maxj, &maxk);
        if (shape == SYS_SHAPEHEX) {
            ++nel;
        }
    }
    /* populate list of 3D elements for threshold */
    iproc = 0;
    m = 0;
    neproc = nel / numproc;
    for (n = 1; n <= numel; ++n) {
        vis_ConnectTopology(connect, n, &shape, &maxi, &maxj, &maxk);
        if (shape != SYS_SHAPEHEX)
            continue;

        ++m;
        vis_IdTranSetId(objs[iproc]->idtranthreshold, m, n);

        /* check whether to populate next processor */
        if (m == neproc && iproc != numproc - 1) {
            objs[iproc]->nel = neproc;
            m = 0;
            ++iproc;
        }
    }
    objs[numproc - 1]->nel = m;

    /* generate free faces */
    group = vis_GroupBegin();
    vis_GroupDef(group, numel, SYS_ELEM, SYS_FACE);
    vis_ConnectFaceGroup(connect, CONNECT_FREE, NULL, group);
    /* count list of faces for contour */
    vis_GroupCount(group, &numparent, &nfaces);
    /* populate list of contour faces */
    iproc = 0;
    m = 0;
    nfproc = nfaces / numproc;
    for (n = 1; n <= numel; ++n) {
        for (no = 1; no <= 6; ++no) {
            if (vis_GroupElemEnt(group, n, no) == 0)
                continue;

            ++m;
            vis_IdTranSetId(objs[iproc]->idtrancontour, m, n);
            vis_IdTranSetEnt(objs[iproc]->idtrancontour, m, no);

            /* check whether to populate next processor */
            if (m == nfproc && iproc != numproc - 1) {
                objs[iproc]->nface = nfproc;
                m = 0;
                ++iproc;
            }
        }
    }
    objs[numproc - 1]->nface = m;
    printf("parallel objects complete\n");

    /* erase display list (actually not needed first time) */
    for (n = 0; n < numproc; ++n) {
        vgl_DListErase(objs[n]->dl);
    }
    /* generate threshold display list */
    printf("begin threshold generation\n");
    vis_VisContextSetIsoValType(vc, VIS_ISOVALSURFACE);
    vsy_PTaskExec(ptask, numproc, gen_threshold, (Vobject*)objs);
    printf("thresold generation complete\n");

    /* draw threshold isosurfaces */
    draw_display(df, numproc, objs);

    /* erase display list */
    for (n = 0; n < numproc; ++n) {
        vgl_DListErase(objs[n]->dl);
    }
    /* generate contour display list */
    printf("begin contour generation\n");
    vis_VisContextSetIsoValType(vc, VIS_ISOVALFRINGE);
    vsy_PTaskExec(ptask, numproc, gen_contour, (Vobject*)objs);
    printf("contour generation complete\n");

    /* draw contoured surfaces */
    draw_display(df, numproc, objs);

    /* close window */
    vgl_DrawFunCloseWindow(df);

    /* free all objects */
    vgl_DrawFunEnd(df);
    vis_VisContextEnd(vc);
    vis_LevelsEnd(levels);
    vis_ColorMapEnd(cmap);
    vgl_OpenGLDevEnd(ogldev);
    vsy_PTaskEnd(ptask);
    vis_ConnectEnd(connect);
    vis_GroupEnd(group);
    for (n = 0; n < numproc; ++n) {
        vgl_DListEnd(objs[n]->dl);
        vgl_DrawFunEnd(objs[n]->dfdl);
        vis_ThresholdEnd(objs[n]->threshold);
        vis_ContourEnd(objs[n]->contour);
        vis_IdTranEnd(objs[n]->idtranthreshold);
        vis_IdTranEnd(objs[n]->idtrancontour);
        vut_MemoryFree(objs[n]);
    }
    vut_MemoryFree(objs);

    /* disconnect from window system */
    vgl_OpenGLDevDisconnect();

    /* close X display */
#ifdef VKI_WIND_X11
    XCloseDisplay(display);
#endif
    return 0;
}