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.