The with
command offers a clean approach to manage Python resources, particularly file streams. Without going into detail, the with
command is a shortcut for exception handling.
The nice thing about reading and writing files using the with
command is you don’t have to worry about closing the file stream. Immediately after the with
block goes out of scope, the stream is closed automatically.
So, instead of doing this:
output = open('concrete23.txt','w')
output.write('I love Concrete23!\n')
output.close()
and potentially forgetting to call close()
, you can do this:
with open('concrete23.txt','w') as output:
output.write('I love Concrete23!\n')
and the file stream will be closed for you.
It has taken me a while to get familiar with the with
command, but here are a few use cases that make sense with OpenSees.
First is writing bespoke analysis results files.
#
# Define your model and analysis
#
with open('myResults.csv','w') as output:
for i in range(Nsteps):
ops.analyze(1,dt)
output.write(f'{ops.getTime()},{ops.nodeDisp(2,1)}\n')
Along the same lines, the second use is calling the OpenSees Tcl to Python converter.
exec(open('toOpenSeesPy.py').read())
with open('beam.py','w') as outfile:
outfile.write('import openseespy.opensees as ops\n\n')
toOpenSeesPy('beam.tcl',outfile,'ops')
Yeah, I know, I should stop using exec
–open
–read
, a convoluted equivalent to Tcl’s source
command, and learn how to better use the import
command.
The third use is reading the maximum absolute response from the file generated by an envelope recorder, whose first line is max, second line is min, and third line (index 2) is max abs.
#
# Define your model and analysis
#
ops.recorder('EnvelopeNode','-file','node.out','-node',2,'-dof',1,'disp')
ops.analyze(Nsteps,dt)
umax = 0
with open('node.out','r') as result:
contents = result.readlines()
umax = contents[2]
If you have come across other crafty uses of the with
command in OpenSees, please share in the Comments section below.
I’ve been experimenting with using the with block to introduce a single scoped instance of a material or section object for testing purposes. Inside the block you can directly invoke many of the C++ methods for the underlying object (e.g., setTrialStrain, getTangent, commit, etc). Everything that happens inside the block is on a clean slate and wont be observed by any elements who were assigned the material. Its like the “testing” model builders, but it doesnt introduce or alter any global state. I’m still not sure if this will be convenient for most users, but if people like it I’d love to merge it upstream. This page has some examples of its use; if you find any upstream potential, it’d be great to get some feedback! I’ve also been able to use this mechanism to send UniaxialMaterial –like classes written in pure Python down to C++ section objects.
LikeLike