Read and Print Model Data

This example illustrates loading a Model object with a finite element model residing on an external file and then traversing and printing the node coordinates and element connectivity contained in the Mesh object. The finite element model may reside on any external file in a format supported by HOOPS Access. The external file name is entered as the first argument to the example executable. If no file name is entered then the file “bumper.unv”, a simple IDEAS universal file, is assumed.

Quick Navigation:

Overview

The example performs the following main tasks:

  1. Parse command line arguments, set input file and validate license
  2. Open the file using DataSource, check for errors and handle them appropriately
  3. Load the model and check for errors
  4. Get the mesh object and print nodes and elements
  5. Helper functions to print nodes and elements
  6. Print the connectivity of the mesh

Let’s examine each step in detail.

Step 1: Initialize and Setup

First, we include necessary headers, declare variables, and handle command line arguments:

#include "samcpp/core/core.h"
#include "samcpp/access/access.h"
#include "sam/hoops_license.h"
#include <vector>
#include <iostream>
#include <iomanip>

static void
print_nodes(cae::core::MeshPtr& mesh);
static void
print_elements(cae::core::MeshPtr& mesh);

/*----------------------------------------------------------------------
                      Read and Print Model Data
----------------------------------------------------------------------*/
int
main(int argc, char** argv)
{
    char inputfile[cae::core::MAX_NAME_LENGTH] = {};

    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " inputfile\n";
        std::cerr << " inputfile is blank, 'bumper.unv' is assumed\n";
        strcpy(inputfile, "bumper.unv");
    }
    else {
        strcpy(inputfile, argv[1]);
    }

    cae::core::license::validate(HOOPS_LICENSE);

The program provides helpful information about the mesh in the “bumper.unv” file which is provided along with the SDK. The license is validated using the validate() function.

Step 2: Open File with DataSource and check for errors

Next, we create a DataSource and open the input file:

// Open file
cae::access::DataSource dataSource;
cae::core::Status status = dataSource.openFile(inputfile, NULL);

// Check for error
if (!status) {
    std::cerr << "Error: opening file " << inputfile << '\n';
    exit(1);
}

The DataSource provides a high-level interface for file operations using openFile(), automatically detecting the file format. Proper error checking is essential when working with file operations.

Step 3: Load the model and check for errors

Now we instantiate the model and ask the DataSource to load the finite element model information:

// Load the model from the file
cae::core::Model model;
status = dataSource.loadModel(&model);
if (!status) {
    std::cerr << "Error: Unable to load model information\n";
    exit(1);
}

The DataSource’s loadModel() method reads all the model data contained in the file and populates the Model object. The Model encapsulates all objects which define an entire finite element model. This includes the mesh, but also all boundary conditions, initial conditions, materials, global control parameters, etc.

Step 4: Get the mesh object and print nodes and elements

Now we get the mesh object from the model and use helper functions to print its contents:

// Get the mesh and print nodes and elements
cae::core::MeshPtr mesh;
model.getMesh(mesh);
if (mesh != NULL) {
    print_nodes(mesh);
    print_elements(mesh);
}
return 0;

The Mesh manages all data related to the finite element mesh: the coordinates, the connectivities, and the adjacency properties. The getMesh() method gets a pointer to the Mesh object from the model.

Step 5: Print the nodes

The function print_nodes is provided as an example to print out node coordinates, user’s Identification Number and associated coordinate system if any:

static void
print_nodes(cae::core::MeshPtr& mesh)
{
    int nodeCount = 0;
    mesh->getEntityCount(cae::core::EntityType::NODE, &nodeCount);
    std::cout << "Number of nodes=    " << nodeCount << '\n';
    std::cout << "\nNodes\n";
    double coordinates[3]{0.0, 0.0, 0.0};
    auto previousFlags = std::cout.flags();
    std::cout << std::scientific;
    for (int i = 1; i <= nodeCount; i++) {
        mesh->getCoordinates(1, &i, (double (*)[3])coordinates);
        int nodeId = 0;
        mesh->getNodeAssociation<cae::core::NodeAssociationType::PART_ID>(1, &i, &nodeId);
        int coordinateSystemId = 0;
        mesh->getNodeAssociation<cae::core::NodeAssociationType::COORDINATE_SYSTEM_ID>(1, &i, &coordinateSystemId);
        std::cout << "id= " << nodeId << ", cid= " << coordinateSystemId << ", x= " << coordinates[0] << ' ' << coordinates[1]
                  << ' ' << coordinates[2] << '\n';
    }
    std::cout.flags(previousFlags);
}

The getEntityCount() method returns the number of entities of the requested type NODE. The getCoordinates() method gives the node coordinates for a set of nodes (only 1 node in each iteration). The getNodeAssociation() method returns the node association value for a given type. For example, USER_ID requests the user ID of the element, and COORDINATE_SYSTEM_ID requests the ID of the coordinate system associated with the node.

Step 6: Print the connectivity of the mesh

The function print_elements is provided as an example to print out element connectivity and properties:

static void
print_elements(cae::core::MeshPtr& mesh)
{
    int elementCount = 0;
    mesh->getEntityCount(cae::core::EntityType::ELEMENT, &elementCount);
    std::cout << "Number of elements= " << elementCount << '\n';
    std::cout << "\nElements\n";
    int maxNodesInElement = 0;
    mesh->getMaxElementNodes(&maxNodesInElement);
    /* allocate vectors for internal node ids and user ids */
    std::vector<int> nodeIndexes(maxNodesInElement, 0);
    std::vector<int> nodeIds(maxNodesInElement, 0);
    for (int i = 1; i <= elementCount; i++) {
        cae::core::ElementShape shape;
        int maxi = 0, maxj = 0, maxk = 0;
        mesh->getTopology(i, &shape, &maxi, &maxj, &maxk);
        int nodesInElement = 0;
        mesh->getElementNodes(i, &nodesInElement, nodeIndexes.data());
        int elementId = 0;
        int partId = 0;
        int propertyId = 0;
        int materialId = 0;
        int coordinateSystemId = 0;
        cae::core::ElementType elementType;
        mesh->getElementAssociation<cae::core::ElementAssociationType::USER_ID>(1, &i, &elementId);
        mesh->getElementAssociation<cae::core::ElementAssociationType::PART_ID>(1, &i, &partId);
        mesh->getElementAssociation<cae::core::ElementAssociationType::PROPERTY_ID>(1, &i, &propertyId);
        mesh->getElementAssociation<cae::core::ElementAssociationType::MATERIAL_ID>(1, &i, &materialId);
        mesh->getElementAssociation<cae::core::ElementAssociationType::COORDINATE_SYSTEM_ID>(1, &i, &coordinateSystemId);
        mesh->getElementAssociation<cae::core::ElementAssociationType::ELEMENT_TYPE>(1, &i, &elementType);
        std::cout << "id= " << elementId << ", partid= " << partId << ", pid= " << propertyId << ", mid= " << materialId
                  << ", cid= " << coordinateSystemId << ", nodes= " << nodesInElement << '\n';
        /* interpret shape */
        if (shape == cae::core::ElementShape::POINT) {
            std::cout << " shape= Point(s):";
        }
        else if (shape == cae::core::ElementShape::LINE) {
            std::cout << " shape= Line:";
        }
        else if (shape == cae::core::ElementShape::TRIANGLE) {
            std::cout << " shape= Triangle:";
        }
        else if (shape == cae::core::ElementShape::QUADRILATERAL) {
            std::cout << " shape= Quadrilateral:";
        }
        else if (shape == cae::core::ElementShape::TETRAHEDRON) {
            std::cout << " shape= Tetrahedron:";
        }
        else if (shape == cae::core::ElementShape::PYRAMID) {
            std::cout << " shape= Pyramid:";
        }
        else if (shape == cae::core::ElementShape::WEDGE) {
            std::cout << " shape= Pentahedron:";
        }
        else if (shape == cae::core::ElementShape::HEXAHEDRON) {
            std::cout << " shape= Hexahedron:";
        }
        else if (shape == cae::core::ElementShape::POLYGON) {
            std::cout << " shape= Polygon:";
        }
        else if (shape == cae::core::ElementShape::POLYHEDRON) {
            std::cout << " shape= Polyhedron:";
        }
        std::cout << "  maxi= " << maxi << ", maxj= " << maxj << ", maxk= " << maxk << '\n';
        // Convert internal index to user id
        mesh->getNodeAssociation<cae::core::NodeAssociationType::USER_ID>(nodesInElement, nodeIndexes.data(), nodeIds.data());
        // Print element connectivity
        std::cout << " connectivity=";
        for (int j = 0; j < nodesInElement; j++) {
            std::cout << ' ' << nodeIds[j];
        }
        std::cout << '\n';
    }
}

The getEntityCount() method with ELEMENT returns the total number of elements. The getMaxElementNodes() method returns the maximum number of nodes connected to an element. The getElementAssociation() method provides many element associations, such as the user ID, part ID, property ID, material ID, and coordinate system ID. The topology and connectivity of the element are accessible through the getTopology() and getElementNodes() methods.

Complete Source Code

The complete source code for this example can be found at: src/sam/vdm/exam/tutorial_read_model_data.cpp

You can also view the full source here:

  1#include "samcpp/core/core.h"
  2#include "samcpp/access/access.h"
  3#include "sam/hoops_license.h"
  4#include <vector>
  5#include <iostream>
  6#include <iomanip>
  7
  8static void
  9print_nodes(cae::core::MeshPtr& mesh);
 10static void
 11print_elements(cae::core::MeshPtr& mesh);
 12
 13/*----------------------------------------------------------------------
 14                      Read and Print Model Data
 15----------------------------------------------------------------------*/
 16int
 17main(int argc, char** argv)
 18{
 19    char inputfile[cae::core::MAX_NAME_LENGTH] = {};
 20
 21    if (argc < 2) {
 22        std::cerr << "Usage: " << argv[0] << " inputfile\n";
 23        std::cerr << " inputfile is blank, 'bumper.unv' is assumed\n";
 24        strcpy(inputfile, "bumper.unv");
 25    }
 26    else {
 27        strcpy(inputfile, argv[1]);
 28    }
 29
 30    cae::core::license::validate(HOOPS_LICENSE);
 31
 32    // Open file
 33    cae::access::DataSource dataSource;
 34    cae::core::Status status = dataSource.openFile(inputfile, NULL);
 35
 36    // Check for error
 37    if (!status) {
 38        std::cerr << "Error: opening file " << inputfile << '\n';
 39        exit(1);
 40    }
 41
 42    // Load the model from the file
 43    cae::core::Model model;
 44    status = dataSource.loadModel(&model);
 45    if (!status) {
 46        std::cerr << "Error: Unable to load model information\n";
 47        exit(1);
 48    }
 49
 50    // Get the mesh and print nodes and elements
 51    cae::core::MeshPtr mesh;
 52    model.getMesh(mesh);
 53    if (mesh != NULL) {
 54        print_nodes(mesh);
 55        print_elements(mesh);
 56    }
 57
 58    return 0;
 59}
 60
 61static void
 62print_nodes(cae::core::MeshPtr& mesh)
 63{
 64    int nodeCount = 0;
 65    mesh->getEntityCount(cae::core::EntityType::NODE, &nodeCount);
 66    std::cout << "Number of nodes=    " << nodeCount << '\n';
 67    std::cout << "\nNodes\n";
 68    double coordinates[3]{0.0, 0.0, 0.0};
 69    auto previousFlags = std::cout.flags();
 70    std::cout << std::scientific;
 71    for (int i = 1; i <= nodeCount; i++) {
 72        mesh->getCoordinates(1, &i, (double (*)[3])coordinates);
 73        int nodeId = 0;
 74        mesh->getNodeAssociation<cae::core::NodeAssociationType::USER_ID>(1, &i, &nodeId);
 75        int coordinateSystemId = 0;
 76        mesh->getNodeAssociation<cae::core::NodeAssociationType::COORDINATE_SYSTEM_ID>(1, &i, &coordinateSystemId);
 77        std::cout << "id= " << nodeId << ", cid= " << coordinateSystemId << ", x= " << coordinates[0] << ' ' << coordinates[1]
 78                  << ' ' << coordinates[2] << '\n';
 79    }
 80    std::cout.flags(previousFlags);
 81}
 82
 83static void
 84print_elements(cae::core::MeshPtr& mesh)
 85{
 86    int elementCount = 0;
 87    mesh->getEntityCount(cae::core::EntityType::ELEMENT, &elementCount);
 88    std::cout << "Number of elements= " << elementCount << '\n';
 89    std::cout << "\nElements\n";
 90    int maxNodesInElement = 0;
 91    mesh->getMaxElementNodes(&maxNodesInElement);
 92    /* allocate vectors for internal node ids and user ids */
 93    std::vector<int> nodeIndexes(maxNodesInElement, 0);
 94    std::vector<int> nodeIds(maxNodesInElement, 0);
 95    for (int i = 1; i <= elementCount; i++) {
 96        cae::core::ElementShape shape;
 97        int maxi = 0, maxj = 0, maxk = 0;
 98        mesh->getTopology(i, &shape, &maxi, &maxj, &maxk);
 99        int nodesInElement = 0;
100        mesh->getElementNodes(i, &nodesInElement, nodeIndexes.data());
101        int elementId = 0;
102        int partId = 0;
103        int propertyId = 0;
104        int materialId = 0;
105        int coordinateSystemId = 0;
106        cae::core::ElementType elementType;
107        mesh->getElementAssociation<cae::core::ElementAssociationType::USER_ID>(1, &i, &elementId);
108        mesh->getElementAssociation<cae::core::ElementAssociationType::PART_ID>(1, &i, &partId);
109        mesh->getElementAssociation<cae::core::ElementAssociationType::PROPERTY_ID>(1, &i, &propertyId);
110        mesh->getElementAssociation<cae::core::ElementAssociationType::MATERIAL_ID>(1, &i, &materialId);
111        mesh->getElementAssociation<cae::core::ElementAssociationType::COORDINATE_SYSTEM_ID>(1, &i, &coordinateSystemId);
112        mesh->getElementAssociation<cae::core::ElementAssociationType::ELEMENT_TYPE>(1, &i, &elementType);
113        std::cout << "id= " << elementId << ", partid= " << partId << ", pid= " << propertyId << ", mid= " << materialId
114                  << ", cid= " << coordinateSystemId << ", nodes= " << nodesInElement << '\n';
115        /* interpret shape */
116        if (shape == cae::core::ElementShape::POINT) {
117            std::cout << " shape= Point(s):";
118        }
119        else if (shape == cae::core::ElementShape::LINE) {
120            std::cout << " shape= Line:";
121        }
122        else if (shape == cae::core::ElementShape::TRIANGLE) {
123            std::cout << " shape= Triangle:";
124        }
125        else if (shape == cae::core::ElementShape::QUADRILATERAL) {
126            std::cout << " shape= Quadrilateral:";
127        }
128        else if (shape == cae::core::ElementShape::TETRAHEDRON) {
129            std::cout << " shape= Tetrahedron:";
130        }
131        else if (shape == cae::core::ElementShape::PYRAMID) {
132            std::cout << " shape= Pyramid:";
133        }
134        else if (shape == cae::core::ElementShape::WEDGE) {
135            std::cout << " shape= Pentahedron:";
136        }
137        else if (shape == cae::core::ElementShape::HEXAHEDRON) {
138            std::cout << " shape= Hexahedron:";
139        }
140        else if (shape == cae::core::ElementShape::POLYGON) {
141            std::cout << " shape= Polygon:";
142        }
143        else if (shape == cae::core::ElementShape::POLYHEDRON) {
144            std::cout << " shape= Polyhedron:";
145        }
146        std::cout << "  maxi= " << maxi << ", maxj= " << maxj << ", maxk= " << maxk << '\n';
147        // Convert internal index to user id
148        mesh->getNodeAssociation<cae::core::NodeAssociationType::USER_ID>(nodesInElement, nodeIndexes.data(), nodeIds.data());
149        // Print element connectivity
150        std::cout << " connectivity=";
151        for (int j = 0; j < nodesInElement; j++) {
152            std::cout << ' ' << nodeIds[j];
153        }
154        std::cout << '\n';
155    }
156}

Expected Output

When you run this example with a typical Universal file, you will see the list of nodes with their coordinates, as well as the elements with their connectivity and certain properties: Note: Only the first 5 and last entities have been included in the block below for clarity.

Number of nodes=    652

Nodes
id= 4001, cid= 0, x= 3.082680e+01 3.968360e+00 -1.003940e+00
id= 4002, cid= 0, x= 3.082680e+01 6.972330e+00 -1.003940e+00
id= 4003, cid= 0, x= 3.082680e+01 9.976310e+00 -1.003940e+00
id= 4004, cid= 0, x= 3.082680e+01 1.298030e+01 -1.003940e+00
......
......
id= 2245, cid= 0, x= -4.622050e+01 6.409450e+00 -2.007870e+00
id= 2244, cid= 0, x= -4.641730e+01 8.803150e+00 -2.007870e+00
id= 2243, cid= 0, x= -4.661420e+01 1.119680e+01 -2.007870e+00
id= 2242, cid= 0, x= -4.681100e+01 1.359060e+01 -2.007870e+00
id= 2003, cid= 0, x= -4.700790e+01 1.598430e+01 -2.007870e+00
Number of elements= 604

Elements
id= 11001, partid= 1001, pid= 1001, mid= 1, cid= 0, nodes= 2
 shape= Line: feaType= Beam element:  maxi= 0, maxj= 0, maxk= 0
 connectivity= 2012 2021
id= 11002, partid= 1001, pid= 1001, mid= 1, cid= 0, nodes= 2
 shape= Line: feaType= Beam element:  maxi= 0, maxj= 0, maxk= 0
 connectivity= 2021 2020
id= 11003, partid= 1001, pid= 1001, mid= 1, cid= 0, nodes= 2
 shape= Line: feaType= Beam element:  maxi= 0, maxj= 0, maxk= 0
 connectivity= 2020 2019
id= 12001, partid= 1002, pid= 1002, mid= 1, cid= 0, nodes= 2
 shape= Line: feaType= Beam element:  maxi= 0, maxj= 0, maxk= 0
 connectivity= 2019 2018
id= 12002, partid= 1002, pid= 1002, mid= 1, cid= 0, nodes= 2
 shape= Line: feaType= Beam element:  maxi= 0, maxj= 0, maxk= 0
 connectivity= 2018 2033
 ......
 ......
 id= 212, partid= 1, pid= 1, mid= 1, cid= -9, nodes= 3
  shape= Triangle: feaType= Shell element:  maxi= 0, maxj= 0, maxk= 0
  connectivity= 260 251 256
 id= 2003, partid= 1, pid= 1, mid= 1, cid= -9, nodes= 3
  shape= Triangle: feaType= Shell element:  maxi= 0, maxj= 0, maxk= 0
  connectivity= 2007 2005 2004
 id= 2004, partid= 1, pid= 1, mid= 1, cid= -9, nodes= 3
  shape= Triangle: feaType= Shell element:  maxi= 0, maxj= 0, maxk= 0
  connectivity= 2007 2006 2005
 id= 2211, partid= 1, pid= 1, mid= 1, cid= -9, nodes= 3
  shape= Triangle: feaType= Shell element:  maxi= 0, maxj= 0, maxk= 0
  connectivity= 2246 2250 2249
 id= 2212, partid= 1, pid= 1, mid= 1, cid= -9, nodes= 3
  shape= Triangle: feaType= Shell element:  maxi= 0, maxj= 0, maxk= 0
  connectivity= 2246 2241 2250