Reading ANSYS Mechanical Result Files (.RST) from C/C++ (Part 2)

Categories:

ansys-fortran-to-c-cpp-1-00 In the last post in this series I illustrated how you can interface C code with FORTRAN code so that it is possible to use the ANSYS, Inc. BinLib routines to read data off of an ANSYS result file within a C or C++ program.  If you recall, the routines in BinLib are written in FORTRAN, and my solution was to use the interoperability features of the Intel FORTRAN compiler to create a shim library that sits between my C++ code and the BinLib code. In essence, I replicated all of the functions in the original BinLib library, but gave them a C interface. I call this library CBinLib.

You may remember from the last post that I wanted to add a more C++ friendly interface on top of the CBinLib functions.  In particular, I showed this piece of code, and alluded to an explanation of how I made this happen.  This post covers the first half of what it takes to make the code below possible.

ansys-fortran-to-c-cpp-2-01

What you see in the code above is the use of C++11 range based “for loops” to iterate over the nodes and elements stored on the result file.  To accomplish this we need to create conformant STL style iterators and ranges that iterate over some space.  I’ll describe the creation of those in a subsequent post.  In this post, however, we have to tackle a different problem.  The solution to the problem is hidden behind the “select” function call shown in the code above.  In order to provide some context for the problem, let me first show you the calling sequence for the procedural interface to BinLib.  This is how you would use BinLib if you were programming in FORTRAN or if you were directly using the CBinLib library described in the previous post.  Here is the recommended calling sequence:

ansys-fortran-to-c-cpp-2-02

You can see the design pattern clearly in this skeleton code.  You start by calling ResRdBegin, which gives you a bunch of useful data about the contents of the file in general.  Then, if you want to read geometric data, you need to call ResRdGeomBegin, which gives you a little more useful metadata.  After that, if you want to read the nodal coordinate data you call ResRdNodeBegin followed by a loop over nodes calling ResRdNode, which gives you the actual data about individual nodes, and then finally call ResRdNodeEnd.  If at that point you are done with reading geometric data, you then call ResRdGeomEnd.  And, if you are done with the file you call ResRdEnd.

Now, one thing jumps off the page immediately.  It looks like it is important to pair up the *Begin and*End calls.  In fact, if you peruse the ResRd.F FORTRAN file included with the ANSYS distribution you will see that in many of the *End functions, they release resources that were allocated and setup in the corresponding *Begin function.

So, if you forget to call the appropriate *End, you might leak resources.  And, if you forget to call the appropriate *Begin, things might not be setup properly for you to iterate.  Therefore, in either case, if you fail to call the right function, things are going to go badly for you.

This type of design pattern where you “construct” some scaffolding, do some work, and then “destruct” the scaffolding is ripe for abstracting away in a C++ type.  In fact, one of the design principles of C++ known as RAII (Resource Acquisition Is Initialization) maps directly to this problem.  Imagine that we create a class in which in the constructor of the class we call the corresponding *Begin function.  Likewise, in the destructor of the class we call the corresponding *End function.  Now, as long as we create an instance of the class before we begin iterating, and then hang onto that instance until we are done iterating, we will properly match up the *Begin, *End calls.  All we have to do is create classes for each of these function pairs and then create an instance of that class before we start iterating.  As long as that instance is still alive until we are finished iterating, we are good.

Ok, so abstracting the *Begin and *End function pairs away into classes is nice, but how does that actually help us?  You would still have to create an instance of the class, hold onto it while you are iterating, and then destroy it when you are done.  That sounds like more work than just calling the *Begin, *End directly.  Well, at first glance it is, but let’s see if we can use the paradigm more intelligently.  For the rest of this article, I’ll refer to these types of classes as BeginEnd classes, though I call them something different in the code.

First, what we really want is to fire and forget with these classes.  That is, we want to eliminate the need to manually manage the lifetime of these BeginEnd classes.  If I don’t accomplish this, then I’ve failed to reduce the complexity of the *Begin and *End requirements.  So, what I would like to do is to create the appropriate BeginEnd class when I’m ready to extract a certain type of data off of the file, and then later on have it magically delete itself (and thus call the appropriate *End function) at the right time.  Now, one more complication.  You will notice that these *Begin and*End function pairs are nested.  That is, I need to call ResRdGeomBegin before I call ResRdNodeBegin.  So, not only do I want a solution that allows me to fire and forget, but I want a solution that manages this nesting.

Whenever you see nesting, you should think of a stack data structure.  To increase the nesting level, you push an item onto the stack.  To decrease the nesting level, you pop and item off of the stack.  So, we’re going to maintain a stack of these BeginEnd classes.  As an added benefit, when we introduce a container into the design space, we’ve introduced something that will control object lifetime for us.  So, this stack is going to serve two functions for us.  It’s going to ensure we call the *Begin’s and *End’s in the right nested order, and second, it’s going to maintain the BeginEnd object lifetimes for us implicitly.

To show some code, here is the prototype for my pure virtual class that serves as a base class for all of the BeginEnd classes.  (In my code, I call these classes FileSection classes)

ansys-fortran-to-c-cpp-2-03

You can see that it is an interface class by noting the pure virtual function getLevel.  You will also notice that this function returns a ResultFileSectionLevel.  This is just an enum over file section types.  I like to use an enum as opposed to relying on RTTI.  Now, for each BeginEnd pair, I create an appropriate derived class from this base ResultFileSection class.  Within the destructor of each of the derived classes I call the appropriate *End function.  Finally, here is my stack data structure definition:

ansys-fortran-to-c-cpp-2-03p5

 

You can see that it is just a std::stack holding objects of the type SectionPtrT.  A SectionPtrT is a std::unique_ptr for objects convertible to my base section class.  This will enable the stack to hold polymorphic data, and the std::unique_ptr will manage the lifetime of the objects appropriately.   That is, when we pop and object off of the stack, the std::unique_ptr will make sure to call delete, which will call the destructor.  The destructor calls the appropriate *End function as we’ve mentioned before.

At this point, we’ve reduced our problem to managing items on a stack.  We’re getting closer to making our lives easier, trust me!  Let’s look at a couple of different functions to show how we pull these pieces together.  The first function is called reduceToLevelOrBegin(level).  See the code below:ansys-fortran-to-c-cpp-2-04

The operation of this function is fairly straightforward, yet it serves an integral role in our BeginEnd management infrastructure.   What this function does is it iteratively pops items off of our section stack until it either reaches the specified level, or it reaches the topmost ResRdBegin level.  Again, through the magic of C++ polymorphism, when an item gets popped off of the stack, eventually its destructor is called and that in turn calls the appropriate *End function.  So, what this function accomplishes is it puts us at a known level in the nested section hierarchy and, while doing so, ensures that any necessary *End functions are called appropriately to free resources on the FORTRAN side of things.  Notice that all of that happens automatically because of the type system in C++.  By popping items off of the stack, I implicitly clean up after myself.

The second function to consider is one of a family of similar functions.  We will look at the function that prepares the result file reader to read element geometry data off of the file.  Here it is:

ansys-fortran-to-c-cpp-2-05

You will notice that we start by reducing the nested level to either the “Geometry” level or the “Begin” level.  Effectively what this does is unwind any nesting we have done previously.  This is the machinery that makes “fire and forget” possible.  That is, whenever in ages past that we requested something to be read off of the result file, we would have pushed onto the stack a series of objects to represent the level needed to read the data in question.  Now that we wish to read something else, we unwind any previously existing nested Begin calls before doing so.   That is, we clean up after ourselves only when we ask to read a different set of data.  By waiting until we ask to read some new set of data to unwind the stack, we implicitly allow the lifetime of our BeginEnd classes to live beyond iteration.

At this point we have the stack in a known state; either it is at the Begin level or the Geometry level.  So, we simply call the appropriate *Begin functions depending on what level we are at, and push the appropriate type of BeginEnd objects onto the stack to record our traversal for later cleanup.  At this point, we are ready to begin iterating.  I’ll describe the process of creating iterators in the next post.  Clearly, there are lots of different select*** functions within my class.  I have chosen to make all of them private and have a single select function that takes an enum descriptor of what to select and some additional information for specifying result data.

One last thing to note with this design.  Closing the result file is easy. All that is required is that we simply fully unwind the stack.  That will ensure all of the appropriate FORTRAN cleanup code is called in the right order.  Here is the close function:

ansys-fortran-to-c-cpp-2-06

As you can see, cleanup is handled automatically.  So, to summarize, we use a stack of polymorphic data to manage the BeginEnd function calls that are necessary in the FORTRAN interface.  By doing this we ensure a level of safety in our class design.  Also, this moves us one step closer to this code:

ansys-fortran-to-c-cpp-2-07

In the next post I will show how I created iterators and range objects to enable clean for loops like the ones shown above.

Categories

Get Your Ansys Products & Support from the Engineers who Contribute to this Blog.

Technical Expertise to Enable your Additive Manufacturing Success.

PADT’s Pulse Newsletter

Keep up to date on what is going on at PADT by subscribing to our newsletter.


By submitting this form, you are consenting to receive marketing emails from: . You can revoke your consent to receive emails at any time by using the SafeUnsubscribe® link, found at the bottom of every email. Emails are serviced by Constant Contact

Share this post:

Upcoming Events

11/15/2023

2023 Governor’s Celebration of Innovation Awards

11/15/2023

Twin Builder Updates in Ansys 2023 R2 - Webinar

11/01/2023

Webinar: Additive's Role in Factory 4.0

10/25/2023

Ansys LevelUp 2023

10/25/2023

Nerdtoberfest 2023

10/25/2023

Mechanical Updates in Ansys 2023 R2 (3) - Webinar

10/18/2023

2023 Southern Arizona Tech + Business Expo

10/18/2023

Fluent GPU Solver Updates in Ansys 2023 R2 - Webinar

10/09/2023

Structural Updates in Ansys 2023 R2 (2) - Webinar

10/02/2023

Colorado Life Sciences Innovation Forum 2023

09/27/2023

2023 AZ Bio Awards

09/26/2023

Experience Stratasys Truck Tour - Houston

09/22/2023

AIAA Rocky Mountain Section Technical Symposium 2023

09/22/2023

Experience Stratasys Truck Tour - Dallas, TX

09/21/2023

Accelerating the Energy Transition through Simulation

09/20/2023

3D Printing vs. CNC Machining - Webinar

09/13/2023

Maxwell Updates in Ansys 2023 R2 - Webinar

09/12/2023

Sandia Science & Technology Park 25th Anniversary

09/12/2023

Experience Stratasys Truck Tour - Tempe, AZ

09/08/2023

26th Annual New Mexico Flying 40 Awards

09/08/2023

New Mexico Tech Summit

09/07/2023

New Mexico Tech Summit

08/30/2023

Structures Updates in Ansys 2023 R2 (1) - Mechanical, Post & Graphics

08/23/2023

Improved Injection Molding with Additive - Webinar

08/22/2023

SPIE Optics & Photonics Exhibition 2023

08/16/2023

Fluids Updates in Ansys 2023 R2 - Webinar

08/04/2023

Experience Stratasys Truck Tour - Salt Lake City, Utah

08/01/2023

Experience Stratasys Truck Tour - Denver Colorado

07/26/2023

Solving Supply Chain Issues with Additive - Webinar

07/25/2023

Arizona Tech Leadership Golf Tournament

07/24/2023

Arizona Tech CEO Leadership Retreat

07/19/2023

System Automation & Optimization Updates in Ansys 2023 R1 - Webinar

07/13/2023

2023 AEROSPACE, AVIATION, DEFENSE AND MANUFACTURING CONFERENCE

07/12/2023

Materials Updates in Ansys Granta 2023 R1 - Webinar

06/30/2023

Turbo Expo 2023

06/29/2023

Turbo Expo 2023

06/28/2023

Turbo Expo 2023

06/28/2023

Revolutionize Packaging Design with Additive - Webinar

06/27/2023

Turbo Expo 2023

06/27/2023

2023 E-MOBILITY AND CLEAN ENERGY SUMMIT

06/26/2023

Turbo Expo 2023

06/21/2023

Optics Updates in Ansys 2023 R1 - Webinar

06/07/2023

LS-DYNA Updates in Ansys 2023 R1 - Webinar

05/31/2023

Driving Automotive Innovation with Additive - Webinar

05/24/2023

Hill Air Force Base Tech Expo

05/24/2023

Structural Updates in Ansys 2023 R1 (3) – Structural Optimization & Ex

05/23/2023

CROSSTALK 2023: Emerging Opportunities for Advanced Manufacturing Smal

05/10/2023

Signal & Power Integrity Updates in Ansys 2023 R1 - Webinar

04/26/2023

Additive Manufacturing Updates in Ansys 2023 R1 - Webinar

04/20/2023

38th Space Symposium Arizona Space Industry

More Info

04/19/2023

38th Space Symposium
Arizona Space Industry

04/19/2023

Additive Aids for Manufacturing - Webinar

04/18/2023

38th Space Symposium
Arizona Space Industry

04/17/2023

38th Space Symposium

04/13/2023

Venture Madness 2023

04/12/2023

Fluid Meshing & GPU-Solver Updates in Ansys 2023 R1 - Webinar

03/29/2023

8th Thermal and Fluids Engineering Conference

03/29/2023

Structural Updates in Ansys 2023 R1 - Composites, Fracture & MAPDL

03/28/2023

8th Thermal and Fluids Engineering Conference

03/27/2023

8th Thermal and Fluids Engineering Conference

03/26/2023

8TH Thermal and Fluids Engineering Conference

03/24/2023

Arizona BioPreneur Conference | Spring 2023

03/22/2023

2023 Arizona MedTech Conference

03/22/2023

Optimize Jigs & Fixtures with Additive - Webinar

03/15/2023

3D Design Updates in Ansys 2023 R1 - Webinar

03/08/2023

Competitive Advantages of 1D/3D Coupled Simulation - Webinar

03/01/2023

High Frequency Updates in Ansys 2023 R1 - Webinar

02/22/2023

Additive Advantages in Aerospace - Webinar

02/15/2023

Structural Updates in Ansys 2023 R1 (1) - Webinar

02/09/2023

IME 2023: MD&M | WestPack | ATX | D&M | Plastek

02/08/2023

IME 2023 MD&M | WestPack | ATX | D&M | Plastek

02/07/2023

IME 2023 MD&M | WestPack | ATX | D&M | Plastek

01/27/2023

Arizona Photonics Days, 2023

01/26/2023

Arizona Photonics Days, 2023

01/26/2023

TIPE 3D Printing | 2023

01/26/2023

Venture Cafe Phoenix Talent Night - Job Fari

01/26/2023

VFS 2023 Autonomous/Electric VTOL Symposium

01/25/2023

Arizona Photonics Days, 2023

01/25/2023

Building A.M.- Utah: Kickoff!

01/25/2023

TIPE 3D Printing | 2023

01/25/2023

VFS 2023 Autonomous/Electric VTOL Symposium

01/24/2023

VFS 2023 Autonomous/Electric VTOL Symposium

01/24/2023

TIPE 3D Printing | 2023

01/18/2023

2023 AZ Tech Council Golf Tournament

12/21/2022

Simulation Best Practices for 5G Technology - Webinar

12/14/2022

Digital Twins Updates in Ansys 2022 R2 - Webinar

12/08/2022

Tech the Halls - AZ Tech Council Holiday Mixer

12/07/2022

Electric Vehicle and Other Infrastructure Update Panel

11/30/2022

SPEOS Updates in Ansys 2022 R2 - Webinar

11/23/2022

Simulation Best Practices for Electronics Reliability - Webinar

11/16/2022

Discovery Updates in Ansys 2022 R2

11/10/2022

VentureCafe Phoenix Panel: Venture Capital in AZ

11/08/2022

2022 GOVERNOR’S CELEBRATION OF INNOVATION AWARDS + TECH SHOWCASE

11/03/2022

VentureCafe Phoenix Panel: Angel Investment in AZ

11/02/2022

High & Low Frequency Electromagnetics Updates in Ansys 2022 R2

10/26/2022

Simulation Best Practices For Chip-Package-System Design & Development

10/20/2022

Nerdtoberfest 2022

10/19/2022

2022 Southern Arizona Tech + Business Expo

10/19/2022

LS-DYNA Updates in Ansys 2022 R2 - Webinar

Search in PADT site

Contact Us

Most of our customers receive their support over the phone or via email. Customers who are close by can also set up a face-to-face appointment with one of our engineers.

For most locations, simply contact us: