=============================== Reading from an output database =============================== The following sections describe how you use Abaqus C++ API commands to read data from an output database. The Abaqus/CAE Visualization module tutorial output database ------------------------------------------------------------ The following sections describe how you can access the data in an output database. Examples are included that refer to the Abaqus/CAE Visualization module tutorial output database, `viewer_tutorial.odb`. This database is generated by the input file from Case 2 of the example problem, `Indentation of an elastomeric foam specimen with a hemispherical punch `_. The problem studies the behavior of a soft elastomeric foam block indented by a heavy metal punch. The tutorial shows how you can use the Visualization module to view the data in the output database. The tutorial describes how you can choose the variable to display, how you can step through the steps and frames in the analysis, and how you can create **X - Y** data from history output. You are encouraged to copy the tutorial output database to a local directory and experiment with the Abaqus C++ API. The output database and the example scripts from this guide can be copied to the user's working directory using the **abaqus fetch** utility: .. code-block:: sh abaqus fetch job=name where **name.C** is the name of the program or **name.odb** is the name of the output database (see `Fetching sample input files `_). For example, use the following command to retrieve the tutorial output database: .. code-block:: sh abaqus fetch job=viewer_tutorial Making the Odb commands available --------------------------------- To make the Odb commands available to your program, you first need to include the output database interface classes using the following statement: .. code-block:: cpp #include To make the material and section Odb commands available to your program, you also need to include their output database classes: .. code-block:: cpp #include #include Opening an output database -------------------------- You use the `openOdb` method to open an existing output database. For example, the following statement opens the output database used by the Abaqus/CAE Visualization module tutorial: .. code-block:: cpp odb_Odb& odb = openOdb("viewer_tutorial.odb"); After you open the output database, you can access its contents using the methods and members of the Odb object returned by the `openOdb` method. In the above example the Odb object is referred to by the variable `odb`. For a full description of the `openOdb` command, see :func:`~odbAccess.openOdb`. 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 :doc:`utility`. - **The root assembly** An output database contains only one root assembly. You access the root assembly through the OdbAssembly object. .. code-block:: cpp 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: .. code-block:: cpp 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 .. code-block:: cpp PART-1-1 From a part instance or part you can retrieve the node and element information as follows: .. code-block:: cpp { 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`_. To access the set information on a part instance: .. code-block:: cpp // 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: .. code-block:: cpp // assembly surface information odb_Set& aSurface = rootAssy.surfaces()["TARGET"]; odb_SequenceString instanceNames = aSurface.instanceNames(); int totalNames = instanceNames.size(); for (int name=0; name`_. - **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: .. code-block:: cpp odb_SectionApi sectionApi; odb.extendApi(odb_Enum::odb_SECTION,sectionApi); The following statements display the repository keys of the sections in an output database: .. code-block:: cpp 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: .. code-block:: cpp 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: .. code-block:: cpp 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: .. code-block:: cpp 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: .. code-block:: cpp 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; } } Reading results data -------------------- The following list describes the objects in results data and the commands you use to read results data. As with model data you will find it useful to use the repository iterators to determine the keys of the results data repositories. - **Steps** Steps are stored in the steps repository under the Odb object. The key to the steps repository is the name of the step. The following statements print out the keys of each step in the repository: .. code-block:: cpp odb_StepRepositoryIT stepIter( odb.steps() ); for (stepIter.first(); !stepIter.isDone(); stepIter.next()) cout << stepIter.currentKey().CStr() << endl; The resulting output is .. code-block:: cpp Step-1 Step-2 Step-3 - **Frames** Each step contains a sequence of frames, where each increment of the analysis (or each mode in an eigenvalue analysis) that resulted in output to the output database is called a frame. The following statement assigns a variable to the last frame in the first step: .. code-block:: cpp odb_Step& step = odb.steps()["Step-1"]; odb_SequenceFrame& allFramesInStep = step.frames(); int numFrames = allFramesInStep.size(); odb_Frame& lastFrame = allFramesInStep[numFrames-1]; Reading field output data ------------------------- Field output data are stored in the fieldOutputs repository under the OdbFrame object. The key to the repository is the name of the variable. The following statements list all the variables found in the last frame of the first step (the statements use the variable `lastFrame` that we defined previously): .. code-block:: cpp odb_FieldOutputRepository& fieldOutputRep = lastFrame.fieldOutputs(); odb_FieldOutputRepositoryIT fieldIter( fieldOutputRep ); for (fieldIter.first(); !fieldIter.isDone(); fieldIter.next()) cout << fieldIter.currentKey().CStr() << endl; S U LE CSHEAR1 ASURF/BSURF CSLIP1 ASURF/BSURF CPRESS ASURF/BSURF COPEN ASURF/BSURF UR3 Different variables can be written to the output database at different frequencies. As a result, not all frames will contain all the field output variables. You can use the following to view all the available field data in a frame: .. code-block:: cpp for (fieldIter.first(); !fieldIter.isDone(); fieldIter.next()) { odb_FieldOutput& field = fieldOutputRep[fieldIter.currentKey()]; const odb_SequenceFieldValue& seqVal = field.values(); const odb_SequenceFieldLocation& seqLoc = field.locations(); cout << field.name().CStr() << " : " << field.description().CStr() << endl; cout << " Type: " << field.type() << endl; int numLoc = seqLoc.size(); for (int loc = 0; loc #include Open the output database used by the tutorial. .. code-block:: cpp odb_Odb& odb = openOdb("viewer_tutorial.odb"); Create a variable that refers to the last frame of the first step. .. code-block:: cpp odb_Step& step = odb.steps()["Step-1"]; odb_SequenceFrame& allFramesInStep = step.frames(); int numFrames = allFramesInStep.size(); odb_Frame& lastFrame = allFramesInStep[numFrames-1]; Create a variable that refers to the displacement 'U' in the last frame of the first step. .. code-block:: cpp odb_FieldOutput& displacements = lastFrame.fieldOutputs().get("U"); Create a variable that refers to the node set 'PUNCH' in the part instance'PART-1–1' : .. code-block:: cpp odb_Instance& instance = odb.rootAssembly().instances()["PART-1-1"]; odb_Set& nodeSet = instance.nodeSets()["PUNCH"]; Create a variable that refers to the displacement of the node set in the last frame of the first step: .. code-block:: cpp odb_FieldOutput myDisplacements = displacements.getSubset(nodeSet); Finally, print some field output data from each node in the node set (a single node in this example). .. code-block:: cpp const odb_FieldValue val = myDisplacements.values()[0]; const float* const data = val.data(numComp); cout << " Node: " << val.nodeLabel() << endl; cout << " U = "; for (int comp=0;comp