Python is one of the best things to happen with OpenSees. Unfortunately, the break from Tcl has not been squeaky clean.
A very sticky transition point has been element recorders. When we wrote the internal
setResponse functions to identify which element, section, material, or fiber response to record, we put C-style
int argc, char **argv arguments in the method signature. So,
setResponse sees everything as a string. This is not entirely Tcl’s fault, but the “everything is a string” mantra definitely affected the implementation decision.
To demonstrate, let’s suppose you wanted to record the stress response history of the fiber closest to coordinates (10,5) on section 3 of element 1. In Tcl, you’d write something like this:
set y 10.0 set z 5.0 recorder Element -ele 1 section 3 fiber $y $z stress
For brevity, I omitted the
After variable substitution in Tcl, element 1 sees an array of strings in
argv = "section" argv = "3" argv = "fiber" argv = "10.0" argv = "5.0" argv = "stress"
Then, the element uses
atoi(argv) to get the section number and passes the remaining information on to
setResponse of the requested section. The section calls
atof on the coordinates then searches for the fiber closest to those coordinates to figure out which material object to call next.
With Python, you’d be inclined to write the recorder command like this:
y = 10.0 z = 5.0 ops.recorder('Element', '-ele', 1, 'section', 3, 'fiber', y, z, 'stress')
After variable substitution in Python, element 1 will receive the following
argv assignments in
argv = "section" argv = 3 argv = "fiber" argv = 10.0 argv = 5.0 argv = "stress"
Looks reasonable. But look closely and you’ll see we’re dumping integers and floats (with no quotes) into character strings. In fact, if you print to screen (using
opserr <<) the
argv values that are passed to the element
setResponse, you’ll see
Invalid String Input! for
To make matters worse, neither
atof throws an exception, i.e., there is no error when the element calls
atoi(argv). As a result, your recorder command will appear to work, but then not record anything–you’ll get an empty output file.
Fixing this issue will not be easy. Hard coding on the front end what should or should not be a string is not a good idea. Neither is trying to code a workaround in all the
What you can do in the meantime is cast the arguments using Python’s
str function, forcing the OpenSees interpreter to generate strings for everything it passes to
y = 10.0 z = 5.0 ops.recorder('Element', '-ele', 1, 'section', str(3), 'fiber', str(y), str(z), 'stress')
You need to string cast only the arguments that drill down beyond the element
setResponse, not the element tags (notice
str(1) is not used for the element tag after
'-ele' above). Basically, any numeric argument that comes after
'fiber' in an element recorder needs to be cast as a string. Node recorders are not affected.