OpenSees Cloud

OpenSees AMI

Incompetence, Not Malice

Original Post - 25 Jan 2020 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


“Never attribute to malice that which can be explained by incompetence” is a form of Hanlan’s razor, an aphorism that explains many actions in academia and elsewhere. For example, we often perceive omissions of important details in published work as intentional acts to prevent reproduction of the research. In some cases, this is true, while in most, plain ‘ol incompetence is to blame. I will share a personal example of non-malicious incompetence.

The formulation and OpenSees implementation of the KrylovNewton algorithm, an accelerated Newton technique, is described in Scott and Fenves (2010). The algorithm can overcome some of the issues with Newton-Raphson and Modified Newton. Figure 2 of the article shows MATLAB code for the algorithm implementation.

In the years since the article was published, I never paid much attention to the code shown in Figure 2. A few people told me the OpenSees implementation of KrylovNewton worked pretty well for their models and the paper picked up some citations, so all was good.

Then, in 2020, I was developing an example in Python for my nonlinear structural analysis course. Using my hard copy of the 2010 article, I implemented the algorithm based on the code in Figure 2. The algorithm did not work.

After some time, I realized a line of code was missing. The displacement increment, which is required in order to compute updates in subsequent iterations, was not being stored after the least squares calculation. Plus, there was a sign inconsistency implied by naming the tangent function jacobian instead of stiffness. Here’s the correct MATLAB code:

U = U0;
R = residual(U);
m = mmax + 1;

% Main loop
while (norm(R) > tol)

   % Refresh tangent and clear subspace
   if (m > mmax)
      K = stiffness(U); % THIS WAS jacobian(U) IN THE ARTICLE
      [l,u] = lu(K);
      m = 0;
   end

   % Back solve
   r = u \ (l \ R);
   AV(:,m+1) = r;

   % Least squares analysis
   if (m > 0)
      AV(:,m) = AV(:,m) - r;
      c = AV(:,1:m) \ r;
      r = r + V(:,1:m)*c;
      r = r - AV(:,1:m)*c;
   end
   V(:,m+1) = r; % THIS LINE SHOULD HAVE BEEN IN FIGURE 2 OF THE ARTICLE

   % Update state of structure
   U = U + r;
   R = residual(U);
   m = m+1;
end

This was not an intentional act of sabotage like when Raymond’s mother taught Debra her meatball recipe. Although C++ is more difficult to read than MATLAB, the KrylovNewton code had been in the OpenSees repository for some time before the article was published and the code continues to be there for anyone to see and reproduce. I simply left out a line of code when making a figure for an article. Incompetence, not malice.



Formal erratum published in August 2020