|
|
|
When Skyblue Systems was founded in 1995, we recognized that we were going to be writing a lot of software. One of our first decisions was the choice of development language. We selected C++ for the following reasons:
Experience has shown this to be a good choice. Our finite element analysis library consists of well-tested modular software components that we can combine as required to create custom and semi-custom application programs for our clients. Dynamic_Array Template Some of the modules that I created for the library are noteworthy. First, we recognized that we required an efficient and easy to use storage scheme for our geometric models and finite element models (geometric models subdivided into very small pieces). For this purpose, I wrote a C++ template class called dynamic_array. Objects of this type can be accessed as if they were simple C arrays, but the underlying algorithm automatically adds storage space as the array components are accessed. The algorithm is both memory and time efficient, carrying an overhead of only 5 bytes per object stored (approximately) and allowing the array reference to any object to be resolved behind the scenes with a maximum of 4 pointer references. Using this method, we have stored finite element models with hundreds of thousands of finite elements in the memory of a typical PC.Here is an example of using the dynamic_array template. Suppose we have already defined an object called finite_element_node with real values (x,y,z) and we want to provide a place to store many objects of that type. We don't know how many we need to store - the number can change during the execution of the program.
The dynamic_array template is useful for many applications, not only finite element analysis. It is used in many places throughout Skyblue Systems' software. Symbolic Parser Another C++ module of general interest that I created for the Skyblue Systems library is the symbolic parser, or s_parser for short. This module allows us to accept expressions from users any place that a number would be entered. For example, if the user needs to enter the value for the mathematical constant pi, he could enter "atan2(0,-1)" instead of "3.14159". More complex expressions, like "sin(angle1+n*angle2)" are also possible. In the latter expression, the user would have previously defined the parameters angle1, angle2, and n. By defining their models using parameters and symbolic expressions, our users can create fully parametric models, meaning models whose dimensions change when the parameters change. We use this feature in our automatic magnet optimization program. Object-Oriented Design for Computer-Aided Engineering As we developed our application programs for computer-aided engineering (CAE), we began from a base in non-object ANSI C. As we progressed, we experienced first-hand many of the difficulties in developing large software projects that led to the creation of C++. One particularly vexing problem was that our C modules were not truly modular - we needed to include the header files of almost every module in every other module, and we needed to link almost every module into our final applications. One changed line in one header file would force a recompilation of the entire project!To get this and other software development problems under control, we started using the object-oriented features of C++. The most important step was to create a type of object (class) we call the executor, along with the project and task associated objects. An class that inherits the type executor has the following properties:
With this scheme, the main routines can determine at run time which modules are present, and then act accordingly. The details of how this all works are complex; an example will help make it clearer: When we develop CAE applications, we generally have two types of models: the geometric model and the finite element model. The geometric model consists of the 2D or 3D shapes that we are dealing with, such as cylinders and spheres. The finite element model represents the same shapes, but broken down into small sub-pieces (like triangles and tetrahedrons) called finite elements. Generally, it is advantageous for the finite element data objects to have reference pointers to the geometric objects from which they came. When we invoke the function in the finite element module that reads a data set, the module internally checks whether the geometry module is present. If it is, it reads the data set with links to the underlying geometric model. If not, it simply skips the geometric model and sets the links to NULL. In this way, we do not need to link the geometry module to an application if it is not needed. Another useful property of this method of organizing our CAE software is the ability to store instances of the modules in the task class. For example, suppose we have an application that requires two interacting models. We can easily use the standard new instance function for the geometric and finite element modules to create two new instances of each and place them in a task. An executor object in a task can check its own instance number so that it can make the correct linkages with other executor objects. In this case, the first finite element model will link itself to the first geometric model and the second finite element model will link itself to the second geometric model. Note that accomplishing this does not require the calling program to know the details of the finite element or geometric modules, or even to include their header files. This scheme also allows us to isolate the effects of changes in a module. To use the geometry module example again, it has gone through seven major versions and dozens of minor revisions without requiring the modules that use it to be changed or recompiled. The final advantage to the executor class is our ability to invoke the functions in an executor object either in the main thread of the program or by spawning a new thread. We have a special function for doing this that can operate on any externally callable function in an executor object. The project-task-executor paradigm for developing CAE applications is my best accomplishment to date in C++ programming. |
|
Last update: July 06, 2000 |