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.
-
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?
-
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.
-
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.
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.
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.
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 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!