OpenSees Cloud

OpenSees AMI

Hidden Fees

Original Post - 14 Aug 2023 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


Helper functions are often implemented as private methods in a class. For example, here is a private cross product function in an Element class of OpenSees.

Vector
CadillacBeamColumn3d::cross(Vector v1, Vector v2){
   Vector v3(3);
   v3(0) = v1(1)*v2(2)-v1(2)*v2(1);
   v3(1) = v2(0)*v1(2)-v1(0)*v2(2);
   v3(2) = v1(0)*v2(1)-v1(1)*v2(0);
   return v3;
}

Note that the class name has been changed and other identifying information has been removed in order to protect the innocent.

But what is wrong with this implementation?

The math is fine. The problem is the hidden memory management issues.

The two Vector arguments, v1 and v2, are passed by value, meaning temporary copies of v1 and v2 must be created when this method is called. The local Vector, v3, is returned by value, requiring another temporary object. Then, to call the cross method, three temporary Vector objects must be created and destroyed.

const Matrix &
CadillacBeamColumn::getTangentStiff(void)
{
   // Do some stuff
 
   Vector z(3);
   z = cross(x,y);
 
   // Do some more stuff
}

That’s three calls to the Vector constructor and three calls to the Vector destructor–three calls to new and three calls to delete–just to compute a cross product.

Do this 10 million times in your IDA and the hidden fees add up.

So, how do you avoid the overhead? You pass by reference.

int
CadillacBeamColumn3d::cross(Vector &v3, const Vector &v1, const Vector &v2)
{
   v3(0) = v1(1)*v2(2)-v1(2)*v2(1);
   v3(1) = v2(0)*v1(2)-v1(0)*v2(2);
   v3(2) = v1(0)*v2(1)-v1(1)*v2(0);
   return 0;
}

Here we pass in a reference to v3 so that we can write into this Vector. And we pass v1 and v2 by constant reference because all we will do is read from these Vector objects. No extra constructor calls required.

The return value is an integer in case you want to flag an error. Returning void is fine in this case too.

Calling the cross method is a little different than before.

const Matrix &
CadillacBeamColumn::getTangentStiff(void)
{
   // Do some stuff
 
   Vector z(3);
   cross(z,x,y);
 
   // Do some more stuff
}

The cross product method is a simple example, but keep the pass by reference concept in mind when you write helper functions for your element and material models.