Damage Monitoring Tools
The damage monitoring toolkit consists the files SectionLib.py
and get_fibers.py
, and the Python package opensees
. Currently these files have to be copied to the location from where they are executed, and the opensees
package should be installed by running the following command:
pip install opensees
The toolkit can be used from either Tcl, Python, or directly at the command line.
The following example shows how the get_fibers.py
module may be invoked from Tcl:
proc py {args} {
eval "[exec python.exe {*}$args]"
}
foreach ds {dsr1 dsr2 dsr3} {
${ds}.txt -e 4020,3020 -d 60 -s $ds
py get_fibers.py model.json record-}
Note: This currently requires the
get_fibers.py
file to be visible from the current working directory of the Tcl interpreter.
1) Geometry building {#1-geometry-building}
Damage regions are built from the same plane geometry primitives that are offered by OpenSees (e.g. the patch
and layer
commands).
Additionally, the function section
from the module opensees.render.mpl
can be used to visualize components.
from opensees import patch, layer, section
import opensees.render.mpl as render
= section.FiberSection(
s = [
areas =20, intRad=18),
patch.circ(extRad=[[-14, -10], [14, 10]]),
layer.line(vertices=[[-15, -10], [15, 10]])
patch.rect(vertices
]
); render.section(s)
Print section properties:
print(s.area)
print(s.ixc)
print(s.iyc)
# print(s.ixc)
838.7610416728243
63215.74854278119
88215.74854278119
Additionally, the SectionLib
module provides convenient wrappers for building complex sections.
The Octagon
function from this library can be called in 3 ways:
ConfinedPolygon(radius)
Constructs an octagon.PolygonRing(extRad, intRad, n)
Constructs ann
-gon annulus
from opensees.section import ConfinedPolygon
8, 20)); render.section(section.ConfinedPolygon(
8, 20, 18)); render.section(section.PolygonRing(
8, 20, 20)); render.section(section.ConfinedPolygon(
2) Define damage state regions; the get_fibers
module {#2-define-damage-state-regions-the-get_fibers-module}
from get_fibers import iter_elem_fibers, damage_states
The get_fibers
module provides the helper function iter_elem_fibers
for iterating over a filtered collection of fibers. Fibers are filtered out by supplying a damage state dictionary with a required "regions"
field, and optional "material"
field.
from opensees.units.english import ft, inch
= 7*ft
Dcol = Dcol/2
Rcol = 2*inch cover
= damage_states(Dcol)
DS # DS = {
# # Any outermost cover fiber
# "dsr1" : {
# "regions": [
# section.PolygonRing(8, Rcol, Rcol-1.0)
# ]
# },
# "dsr2" : {
# "regions": [
# section.FiberSection(areas=[
# patch.circ(intRad=Rcol-cover-2, extRad=Rcol-cover)
# ])
# ],
# "material": "*steel*"
# },
# "dsr3" : {
# "regions": [
# # external radius internal radius
# section.PolygonRing(8, Rcol-cover*(1-0.75), Rcol-cover*(1-0.5))
# ],
# "material": "*concr*"
# },
# }
3) Iterating over fibers {#3-iterating-over-fibers}
import json
import numpy as np
= "modelDetails.json"
model_file = [4010] elements
with open(model_file, "r") as f:
= json.load(f) model
If the third argument to iter_elem_fibers
is omitted, all fibers are returned (Underscores are used in the following cell to name unused variables).
= [
all_fibers "coord"] for _,__,f in iter_elem_fibers(model, elements)
f[
]
= np.array([
ds1_fibers "coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr1"], sections=[0])
f[
])
= np.array([
ds2_fibers "coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr2"], sections=[0])
f[
])
= np.array([
ds3_fibers "coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr3"], sections=[0])
f[
])
= np.array([
ds4_fibers "coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr3"], sections=[0])
f[ ])
3) Visualizing {#3-visualizing}
= section.ConfinedPolygon(8, Dcol/2)
sect = render.section(sect)
ax "dsr1"]["regions"][0], facecolor="b", ax=ax)
render.section(DS["dsr2"]["regions"][0], facecolor="pink", ax=ax)
render.section(DS["dsr3"]["regions"][0], facecolor="y", ax=ax)
render.section(DS["dsr4"]["regions"][0], facecolor="g", ax=ax);
render.section(DS["dsr5"]["regions"][0], facecolor="r", ax=ax);
render.section(DS[# ax.set_xlim([0, Rcol+1])
# ax.set_ylim([-1, Rcol+1])
# Create grid of points
import numpy as np
# Create plot axis and add sections to it
= render.section(sect)
ax "dsr1"]["regions"][0], facecolor="b", ax=ax)
render.section(DS["dsr2"]["regions"][0], facecolor="pink", ax=ax)
render.section(DS["dsr3"]["regions"][0], facecolor="y", ax=ax)
render.section(DS["dsr4"]["regions"][0], facecolor="g", ax=ax);
render.section(DS["dsr5"]["regions"][0], facecolor="r", ax=ax);
render.section(DS[
# add filtered fibers to plot
*list(zip(*all_fibers)), color="grey", alpha=0.3, s=0.5);
ax.scatter(*list(zip(*ds1_fibers)), marker=".", color="blue")
ax.scatter(*list(zip(*ds2_fibers)), color="r", marker="o")#, s=0.8)
ax.scatter(*list(zip(*ds3_fibers)), color="r", marker="x")#, s=1)
ax.scatter(*list(zip(*ds4_fibers)), color="r", marker="+")#, s=1)
ax.scatter(
# Set plot limits
0, Rcol+1])
ax.set_xlim([ -1, Rcol+1])
ax.set_ylim(["on"); ax.axis(
= render.section(sect)
ax *list(zip(*all_fibers)), color="red", s=0.5); ax.scatter(
Fiber Response Animation
fiberStrains.py -a -dsr dsr -sec sec ...
a is analysis type and can be any one of: [po cyclic]
dsr can be any set of: [dsr1 dsr2 dsr3 dsr4 dsr5 dsr6 all]
sec can be any one of: [1 np], where np is integer representing last integration point.
Options
-vmin <float>
-vmax <float>
vmin and vmax are customized colorbar limits, if defaults must be adjusted.