11. Examples

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

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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, const 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, const 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);
    }
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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, const 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, const 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]);
    }
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "legacy/vis/vislegacy.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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);

    /*----------------------------------------------------------------------
                          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);
    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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "legacy/vis/vislegacy.h"
#include "sam/base/license.h"
#include "sam/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);

    /* 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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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);

    /* 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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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.cpp, exam30bvgl.cpp and exam30cvgl.cpp.

#include "sam/base/base.h"
#include "legacy/vgl/vgl.h"
#include "sam/vis/vis.h"
#include "legacy/vis/vislegacy.h"
#include "sam/base/license.h"
#include "sam/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, (Vchar*)"draw_ElemFaceGroup");
            }
            else if (j == 1) {
                GLWinText(glwin, xtext, (Vchar*)"draw_ElemFaceIdTran");
            }
            else if (j == 2) {
                GLWinText(glwin, xtext, (Vchar*)"draw_ElemFaceContour");
            }
            else if (j == 3) {
                GLWinText(glwin, xtext, (Vchar*)"draw_ElemIsosurface");
            }
            else if (j == 4) {
                GLWinText(glwin, xtext, (Vchar*)"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);
        }
    }
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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;
}

11.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 "sam/base/base.h"
#include "sam/vis/vis.h"
#include "sam/base/license.h"
#include "sam/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.;