OpenSees Cloud

OpenSees AMI

How to Record Fiber Response

Original Post - 25 Jul 2021 - Michael H. Scott

Visit Structural Analysis Is Simple on Substack.


Recording the response of a single fiber in a fiber section is a common ask. You will need to use an Element recorder, but what you can record in each fiber is defined in the UniaxialMaterial::setResponse() method. The most common option is stressStrain, which gives the fiber stress-strain response history.

After setResponse() drills down to the section level, there are three options to specify the fiber whose response you would like to record.

  1. Fiber index - Let’s get this option out of the way. You can specify the index (from the internal array of material pointers; 0,…,Nf-1) of the fiber you want to record.
    ...,'fiber',fiberIndex,'stressStrain')
    

    Although I’m pretty sure I coded this option, I don’t know how anyone would know the index of a particular fiber. Perhaps this was a useful option for debugging?

  2. Fiber closest to a section coordinate - You can ask the recorder to find the fiber closest to section coordinates that you specify.
    ...,'fiber',y,z,'stressStrain')
    

    The section y-z axes are shown below.

Section axes

  1. Fiber with a specified material tag closest to a section coordinate - Just like option 2, but restricts the search to only fibers with the specified material tag. This option is useful for sections with overlapping fibers, e.g., steel and concrete fibers in a reinforced concrete section, where you want to be sure you get the correct fiber.
    ...,'fiber',y,z,matTag,'stressStrain')
    

The same three options are available for FiberSection2d and 3d as well as NDFiberSection2d and 3d.

What comes before 'fiber' depends on the element. For zero length section elements, which are convenient for moment-curvature and axial-moment interaction analysis, you input 'section', 'fiber', and then one of the three options shown above.

ops.recorder('Element','-ele',1,'-file','fiber.out','section','fiber',...)

For the beam-column elements (displacement-based, force-based, and mixed), you can specify a section (integration point) number (1,…,Np; in sequence from node I to node J) and then give the fiber arguments.

ops.recorder('Element','-ele',1,'-file','fiber.out','section',secNum,'fiber',...)

A lesser known, but more direct, option is to find the section closest to a specified x-coordinate (0 to L from node I to node J) along a beam-column element.

ops.recorder('Element','-ele',1,'-file','fiber.out','sectionX',x,'fiber',...)

For the sake of demonstration, we’ll do moment-curvature analysis of an RC section with a single layer of longitudinal steel reinforcement.

Reinforced concrete section

Using a zeroLengthSection element with displacement control on the nodal rotation, we know the curvature is the nodal rotation and the moment is the load factor. The model uses basic material models–Concrete01 with standard inputs for compressive and spalling strains, and EPP Steel01–for the fibers.

import openseespy.opensees as ops

kip = 1.0
inch = 1.0

ft = 12*inch
ksi = kip/inch**2

fc = 4*ksi
fy = 60*ksi
E = 29000*ksi

Abar = 0.79*inch**2

h = 24*inch
b = 16*inch

ops.wipe()
ops.model('basic','-ndm',2,'-ndf',3)

ops.node(1,0,0); ops.fix(1,1,1,1)
ops.node(2,0,0); ops.fix(2,0,1,0)

ops.uniaxialMaterial('Concrete01',1,fc,0.002,0,0.006)
ops.uniaxialMaterial('Steel01',2,fy,E,0)

ops.section('Fiber',1)
ops.patch('rect',1,20,1,-h/2,-b/2,h/2,b/2)
ops.layer('straight',2,3,Abar,-h/2+2.5*inch,b/2-2.5*inch,-h/2+2.5*inch,-b/2+2.5*inch)

ops.element('zeroLengthSection',1,1,2,1)

ops.timeSeries('Linear',1)
ops.pattern('Plain',1,1)
ops.load(2,0,0,1)

Ky = 0.003/(h/2) # ballpark estimate of yield curvature
ops.integrator('DisplacementControl',2,3,Ky/100)

ops.analysis('Static')

epsc = 0
while epsc > -0.003:
    ops.analyze(1)
    epsc = ops.nodeDisp(2,1) - h/2*ops.nodeDisp(2,3)

ops.wipe()

The analysis stops when the strain at the compression face reaches 0.003. Note that the strain in the extreme compression fiber will be a little less than 0.003 because the strain is sampled at the center of the fiber.

The resulting moment-curvature response is shown below.

RC seciton moment-curvature

With the Whitney stress block (WSB) approximation, the nominal moment strength should be 239.3 kip-ft. The load factor reported by OpenSees is 239.5 kip-ft. For reinforced concrete, that is exact. You can also use the displacements of node 2 to determine the depth to the neutral axis, which also matches the WSB approximation.

Now, let’s define three fiber recorders: A - fiber closest to compression face (y=h/2); B - fiber closest to tension face (y=-h/2); and C - steel fiber closest to tension face.

RC section fiber discretization

For 2D problems, bending is about the z-axis, so only the y-coordinate matters when specifying the fiber location. The recorder ignores the z-coordinate, but you still have to input something in its place–0 is perfectly fine.

# Compression fiber
ops.recorder('Element','-ele',1,'-file','fiberA.out','section','fiber',h/2,0,'stressStrain')
# Tension fiber
ops.recorder('Element','-ele',1,'-file','fiberB.out','section','fiber',-h/2,0,'stressStrain')
# Tension fiber - steel
ops.recorder('Element','-ele',1,'-file','fiberC.out','section','fiber',-h/2,0,2,'stressStrain')

The stress-strain response from each fiber is shown below

Fiber stress-strain

Fiber A shows the concrete stress-strain response in compression; fiber B shows the concrete tension response (zero stress); and fiber C shows the EPP response of the reinforcing steel. All makes sense!