Reading model data

The following list describes the objects in model data and the commands you use to read model data. Many of the objects are repositories, and you will find it useful to use the repository iterators to determine the keys of the repositories. For more information on repositories and sequences, see Utility interface.

The root assembly

An output database contains only one root assembly. You access the root assembly through the OdbAssembly object.


  odb_Assembly& rootAssy = odb.rootAssembly();
 
Part instances

Part instances are stored in the instance repository under the OdbAssembly object. The following statements display the repository keys of the part instances in the tutorial output database:

    odb_InstanceRepositoryIT instIter(rootAssy.instances());
    for (instIter.first(); !instIter.isDone(); instIter.next())
        cout << instIter.currentKey().CStr() << endl;
 

The output database contains only one part instance, and the resulting output is

PART-1-1

From a part instance or part you can retrieve the node and element information as follows:

    {
    odb_Instance& instance1 = 
        rootAssy.instances()["PART-1-1"];
    odb_Enum::odb_DimensionEnum instanceType = 
        instance1.embeddedSpace();
    const odb_SequenceNode& nodeList = instance1.nodes();
    int nodeListSize = nodeList.size();
    if (instanceType == odb_Enum::THREE_D) {
      for (int n=0; n<nodeListSize; n++) {
          const odb_Node node = nodeList[n];
          int nodeLabel = node.label();
          const float* const coord = node.coordinates();
          cout << "Xcoord: " << coord[0] << " , Ycoord: " 
              << coord[1] << " , Zcoord: " << coord[2] << endl;
      }
    }
    else if((instanceType == odb_Enum::TWO_D_PLANAR) || 
            (instanceType == odb_Enum::AXISYMMETRIC)) {
      for (int n=0; n<nodeListSize; n++) {
          const odb_Node node = nodeList[n];
          int nodeLabel = node.label();
          const float* const coord = node.coordinates();
          cout << "Xcoord: " << coord[0] << " , Ycoord: " 
              << coord[1] << endl;
      }
    }
    
    const odb_SequenceElement& elementList = 
        instance1.elements();
    int elementListSize = elementList.size();
    cout << "Element Connectivity Data" << endl;
    cout << "Element Label : constituent node labels ..." 
        << endl;
    int numNodes = 0;
    for (int e=0; e<elementListSize; e++) {
        const odb_Element element = elementList[e];
        int elementLabel = element.label();
        cout << elementLabel <<" : ";
        odb_String elementType = element.type();
        const int* const conn = 
            element.connectivity(numNodes);
        for (int j=0; j<numNodes; j++)
          cout << "  " << conn[j];
        cout << endl;
    }
    }
 
Regions

Regions in the output database are OdbSet objects. Regions refer to the part and assembly sets stored in the output database. A part set refers to elements or nodes in an individual part and appears in each instance of the part in the assembly. An assembly set refers to the elements or nodes in part instances in the assembly. A region can be one of the following:

  • A node set

  • An element set

  • A surface

For example, the following statement displays the node sets in the OdbAssembly object:

    cout << "Node set keys:" << endl;
    odb_SetRepositoryIT setIter( rootAssy.nodeSets() );
    for (setIter.first(); !setIter.isDone(); setIter.next())
        cout << setIter.currentKey().CStr() << endl;
 

The resulting output is

Node set keys:
ALL NODES

The following statements display the node sets and the element sets in the PART-1-1 part instance:

    {
    odb_InstanceRepository& iCon = 
        odb.rootAssembly().instances();
    odb_Instance& instance = iCon["PART-1-1"]; 
    
    cout << "Node set keys:" << endl;
    odb_SetRepositoryIT setItN( instance.nodeSets() );
    for (setItN.first(); !setItN.isDone(); setItN.next())
    cout << setItN.currentKey().CStr() << endl;
    
    cout << "Element set keys:" << endl;
    odb_SetRepositoryIT setItE( instance.elementSets() );
    for (setItE.first(); !setItE.isDone(); setItE.next())
        cout << setItE.currentKey().CStr() << endl;
    }
 

The resulting output is

Node set keys:
BOT
N481
TOP
N1
...
Element set keys:
CENT
FOAM
...

The following statement assigns a variable (topNodeSet) to the 'TOP' node set in the PART-1-1 part instance:

    odb_InstanceRepository& iCon = 
        odb.rootAssembly().instances();
    odb_Instance& instance = iCon["PART-1-1"];
    odb_Set& topNodeSet = instance.nodeSets()["TOP"];
 

The type of the object to which topNodeSet refers is OdbSet. After you create a variable that refers to a region, you can use the variable to refer to a subset of field output data, as described in Using regions to read a subset of field output data.

To access the set information on a part instance:

    // node set information
    
    odb_Set& nodeSet = instance.nodeSets()["CENTER"];
    const odb_SequenceNode& nodeList = nodeSet.nodes();
    
    // surface information
    odb_Set& surface = instance.surfaces()["IMPACTOR"];
    const odb_SequenceElement& elementList = 
        surface.elements();
    const odb_SequenceElementFace& faces = 
        surface.faces();

    // iterators are used to get all sets
    odb_SetRepository& elementSetRepository = 
        instance.elementSets();
    odb_SetRepositoryIT elSetRepIter(elementSetRepository);
    for (elSetRepIter.first(); !elSetRepIter.isDone(); 
    elSetRepIter.next()) {
        odb_Set& set = 
            elementSetRepository[elSetRepIter.currentKey()];
        cout << "element set " << elSetRepIter.currentKey().CStr() 
            << endl;
        cout << "        number of elements : ";
        cout << set.size() << endl;
    }
 

The set information in an assembly set is keyed by instance name and can be accessed using the following:

    // assembly surface information
    odb_Set& aSurface = rootAssy.surfaces()["TARGET"];
    odb_SequenceString instanceNames = 
        aSurface.instanceNames();
    int totalNames = instanceNames.size();
    for (int name=0; name<totalNames; name++) {
        const odb_String& iName = instanceNames[name];
        const odb_SequenceElement& els = 
            aSurface.elements(iName);
        const odb_SequenceElementFace& face =
            aSurface.faces(iName);
    }
 
Materials

You can read material data from an output database.

Materials are stored in the materials repository under the Odb object.

Extend the Material commands available to the Odb object using the following statement:

odb_MaterialApi materialApi;
 odb.extendApi(odb_Enum::odb_MATERIAL,materialApi); 

Access the materials repository using the command:

 odb_MaterialContainer&  materialContainer = materialApi.materials();
 odb_MaterialContainerIT matIT(materialContainer);
 for (matIT.first(); !matIT.isDone(); matIT.next()) {
    cout << "Material Name : " << matIT.currentKey().CStr() << endl;
    const odb_Material& myMaterial = matIT.currentValue(); 

To print isotropic elastic material properties in a material object:

odb_Elastic elastic = myMaterial.elastic();
if (elastic.hasValue()) {
   if (elastic.type() == "ISOTROPIC") {
       cout << "isotropic elastic behavior, type = " 
            << elastic.moduli().CStr() << endl;
       odb_String tableHeader("Youngs modulus   Poisson's ratio ");
       if (elastic.temperatureDependency())
           tableHeader.append("Temperature  ");
       for (int i = 0, max = elastic.dependencies(); i < max; ++i)
           tableHeader.append(" field # ").append(i);
       cout << tableHeader.CStr() << endl;
       odb_SequenceSequenceFloat table = elastic.table();	
       for (int r = 0, rows = table.size(); r <rows; ++r) {
           const odb_SequenceFloat& data = table[r];
           for (int c = 0, cols = data.size(); c < cols; ++c) {    
               cout << data[c] << "   ";
           }
           cout << endl;
       }
   }
}

Some Material definitions have suboptions. For example, to access the smoothing type used for biaxial test data specified for a hyperelastic material:

odb_Hyperelastic hyperelastic = myMaterial.hyperelastic();
if (hyperelastic.hasValue()) {
    bool testData = hyperelastic.testData(); 
    odb_BiaxialTestData biaxialTestData = 
        hyperelastic.biaxialTestData(); 
    odb_String smoothingType("smoothing type: "); 
    if (biaxialTestData.hasValue()) { 
        odb_Union smoothing = biaxialTestData.smoothing();
        switch(smoothing.type()) {
            case (odb_UNION_STRING):	 
                smoothingType.append(smoothing.getString());
                break;
            case (odb_UNION_INT):               
                smoothingType.append(smoothing.getInt());  
                break;
            case (odb_UNION_FLOAT):
                smoothingType.append(smoothing.getFloat()); 	   
                break;
            case (odb_UNION_DOUBLE):
                smoothingType.append(smoothing.getDouble()); 
                break;
            case (odb_UNION_BOOL):
                smoothingType.append(smoothing.getBool()); 	   
                break;
        }
        cout  << smoothingType.CStr() << endl;
    }
}

Material commands describes the Material object commands in more detail; the odb_Union object is defined in Union object.

Sections

You can read section data from an output database.

Sections are stored in the sections repository under the Odb object.

Extend the Section commands available to the Odb object using the following statement:

    odb_SectionApi sectionApi;
    odb.extendApi(odb_Enum::odb_SECTION,sectionApi); 

The following statements display the repository keys of the sections in an output database:

  odb_SectionContainer&  sectionContainer = 
    sectionApi.sections();
odb_SectionContainerIT scIT(sectionContainer);
for (scIT.first(); !scIT.isDone(); scIT.next()) {
    cout << "Section Name : " << scIT.currentKey().CStr() << endl;
}

The Section object can be one of the various section types. The odb_isA method can be used to determine the section type. For example, to determine whether a section is of type homogeneous solid section and to print its thickness and associated material name:

    for (scIT.first(); !scIT.isDone(); scIT.next()) {
    const odb_Section& mySection = scIT.currentValue();
    if (odb_isA(odb_HomogeneousSolidSection,mySection)) {
        odb_HomogeneousSolidSection homogeneousSolidSection = 
            odb_dynamicCast(
                odb_HomogeneousSolidSection, mySection);
        odb_String material = 
            homogeneousSolidSection.material(); 
        cout << "material name = " << material.CStr() << endl;
        float thickness = homogeneousSolidSection.thickness(); 
        cout << "thickness = " << thickness << endl;
    }
}

Similarily, to access the beam profile repository:

odb_ProfileContainer profileContainer = 
    sectionApi.profiles();
int numProfiles = sectionApi.numProfiles();
cout << "Total Number of profiles in the ODB: " 
     << numProfiles << endl;

The Profile object can be one of the various profile types. The odb_isA method can be used to determine the profile type. For example, to output the radius of all circular profiles in the odb:

    odb_ProfileContainerIT pcIT(profileContainer);
for (pcIT.first(); !pcIT.isDone(); pcIT.next()) {
    const odb_Profile& myProfile = pcIT.currentValue();
    if (odb_isA(odb_CircularProfile,myProfile)) {
        odb_CircularProfile circularProfile = 
            odb_dynamicCast( odb_CircularProfile, myProfile );
        cout << "profile name = " << myProfile.name().CStr() 
             << " radius = " << circularProfile.r();
    }
}
Section assignments

Section assignments are stored in the sectionAssignments repository under the OdbAssembly object.

All elements in an Abaqus analysis need to be associated with section and material properties. Section assignments provide the relationship between elements in a part instance and their section properties. The section properties include the associated material name. To access the sectionAssignments repository from the PartInstance object:

odb_InstanceRepository& instanceRepository = 
    odb.rootAssembly().instances();
odb_InstanceRepositoryIT instIT(instanceRepository);
for (instIT.first(); !instIT.isDone(); instIT.next()) {
    const odb_Instance& instance = instIT.currentValue();      
    odb_SequenceSectionAssignment sectionAssignmentSeq = 
        instance.sectionAssignments();  
    int sects = sectionAssignmentSeq.size();
    cout << "Instance : " << instance.name().CStr() << endl;
    for (int s = 0; s < sects; ++s) {
	odb_SectionAssignment sa = sectionAssignmentSeq[s];
	odb_String sectionName = sa.sectionName();
        cout << "  Section : " << sectionName.CStr() << endl; 
	odb_Set set = sa.region();
	const odb_SequenceElement& elements = set.elements();
	int size = elements.size();
        cout << "  Elements associated with this section : " 
             << endl;
	for (int e = 0; e< size; ++e)
	    cout << elements[e].label() << endl;	  
    } 
}