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} {
    py get_fibers.py model.json record-${ds}.txt -e 4020,3020 -d 60 -s $ds
}

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
s = section.FiberSection(
    areas = [
        patch.circ(extRad=20, intRad=18),
        layer.line(vertices=[[-14, -10], [14, 10]]),
        patch.rect(vertices=[[-15, -10], [15, 10]])
    ]
)
render.section(s);

# from SectionLib import sees2gmsh, plot
# plot(sees2gmsh(s, (10,10)))

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:

  • Octagon(radius) Constructs an octagon.
  • Octagon(extRad, intRad) Constructs an octagonal annulus
  • Octagon(extRad, extRad) (ie when both arguments are equal) Constructs an octagonal boundary line.
from opensees.section import ConfinedOctagon as Octagon
render.section(Octagon(20));

render.section(Octagon(20, 18));

render.section(Octagon(20, 20));

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

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
ft, inch
(12.000000000000002, 1.0)
Dcol = 7*ft
Rcol = Dcol/2
cover = 2*inch
DS = {
  # Any outermost cover fiber
  "dsr1" : {
      "regions": [
          Octagon(Rcol, Rcol)
      ]
  },
  "dsr2" : {
      "regions": [
          section.FiberSection(areas=[
              patch.circ(intRad=Rcol-cover-2, extRad=Rcol-cover)
          ])
      ],
      "material": "*steel*"
  },
  "dsr3" : {
      "regions": [
      #             external radius      internal radius
          Octagon(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
model_file = "modelDetails.json"
elements = [4020]
with open(model_file, "r") as f:
    model = json.load(f)
ds1_fibers = np.array([
    f["coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr1"])
])

ds2_fibers = np.array([
    f["coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr2"])
])

ds3_fibers = np.array([
    f["coord"] for e,s,f in iter_elem_fibers(model, elements, filt=DS["dsr3"])
])

3) Visualizing {#3-visualizing}

Patches can be superimposed for plotting purposes by adding them to a Section object like the one returned by the Octagon function. The add_patches method accepts a list of Patch objects; this list is constructed in the following cell by concatenating (+ operator) the patches attributes of each of the previously defined damage regions.

sect = Octagon(Dcol/2)
sect.add_patches(
    DS["dsr1"]["regions"][0].layers +
    DS["dsr2"]["regions"][0].patches +
    DS["dsr3"]["regions"][0].patches
)
ax = render.section(sect)

# Create grid of points
import numpy as np
ax = render.section(sect)
# ax.scatter(*list(zip(*ds1_fibers)), color="blue",  s=0.5)
ax.scatter(*list(zip(*ds2_fibers)), color="black", s=0.5)
ax.scatter(*list(zip(*ds3_fibers)), color="red",   s=0.5);

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 = [
    f["coord"] for _,__,f in iter_elem_fibers(model, [4020])
]

ax = render.section(sect)
ax.scatter(*list(zip(*all_fibers)), color="red", s=0.5);


Back to top