OpenSees Cloud
OpenSees AMI
Gotta Catch 'Em All
Original Post - 10 Sep 2023 - Michael H. Scott
Visit Structural Analysis Is Simple on Substack.
Python has
built-in Exception types
for dealing with various run-time
errors. You’ve probably seen a few Exceptions like ModuleNotFoundError
if you had issues installing OpenSeesPy or KeyboardInterrupt
when you
have used Ctrl+C
to get your script out of an infinite loop.
A common Exception encountered within a script is divide by zero, in
which case an Exception of type ZeroDivisionError
is thrown.
Of course you would never actually type 1/0
in your script. Instead, in
the denominator you will use a variable expression that could become
zero.
At any rate, because the Exception was not caught, or dealt with, the script stops immediately.
To catch an Exception, use a try-except
block.
With the Exception caught, the script is able to move on–despite the
divide by zero–and print Hello
to the screen.
Now you may ask, what do Exceptions have to do with OpenSees model building and analysis?
To answer this question, keep in mind that OpenSees is a Python module and in that module are many exceptions waiting to happen–incorrect input commands, errors when saving or restoring a database, failure of an eigenvalue solver–the list goes on. The core of OpenSees simply wasn’t set up to throw exceptions back to a script.
Fortunately, Minjie,
who is always a few years ahead of everyone else,
had the foresight to define a new Exception type, OpenSeesError
, when he
made the OpenSees Python module.
You have undoubtedly seen the OpenSeesError
Exception raised in your
scripts. For example, when you have insufficient or incorrect inputs to
a material model.
The Exception string tells you to see the standard error (stderr) output for more information on what caused the exception.
With the Exception not caught, the script stops. In the simple case above, your OpenSees analysis probably shouldn’t continue anyway. However, there are some cases where it would be nice to keep going.
Imagine a script where you are looping over frame models of various
sizes and performing eigenvalue analysis to get the periods and mode
shapes before launching an awesome IDA with modal damping. But in that
script you ask for too many modes and the eigen()
command will fail and
throw an Exception on smaller models with few dynamic DOFs. You don’t
want one bad eigen()
command to kill the entire parametric IDA, so what
should you do?
You should put the eigen()
command in a try-except
block and catch
exceptions of type OpenSeesError
(EDIT based on comment from P. Talley).
If the default eigen()
command fails, you can
bite the bullet and use the FullGenLapack option,
or try the default eigen()
command again
asking for fewer modes, or set a flag and move on to the next analysis,
or whatever.
try:
w2 = ops.eigen(Nmodes)
except ops.OpenSeesError as e:
print(e) # Not required
w2 = ops.eigen('fullGenLapack',Nmodes)
print(w2)
ops.modalDamping(....)
# etc.
The point is, your script won’t grind to a halt due to an OpenSeesError
Exception emanating from the OpenSees core–you and your parametric IDA
can recover and move on.
I’m not advocating that you put every OpenSees command in a try-except
block, just the commands that routinely stop your scripts.