Moment Curvature Analysis#

This example demonstrates how to perform a moment curvature analysis using concreteproperties. We start by importing the necessary modules.

[1]:
import numpy as np
from sectionproperties.pre.library import circular_section, rectangular_section

import concreteproperties.stress_strain_profile as ssp
from concreteproperties import (
    Concrete,
    ConcreteSection,
    SteelBar,
    add_bar_rectangular_array,
)
from concreteproperties.results import MomentCurvatureResults

Assign Materials#

Multiple material types will be used in this example to highlight different moment curvature results.

[2]:
conc_linear = Concrete(
    name="Linear Concrete",
    density=2.4e-6,
    stress_strain_profile=ssp.ConcreteLinear(
        elastic_modulus=35e3, ultimate_strain=0.0035
    ),
    ultimate_stress_strain_profile=ssp.BilinearStressStrain(
        compressive_strength=40,
        compressive_strain=0.00175,
        ultimate_strain=0.0035,
    ),
    flexural_tensile_strength=3.5,
    colour="lightgrey",
)

conc_linear_no_tension = Concrete(
    name="Linear Concrete (No T)",
    density=2.4e-6,
    stress_strain_profile=ssp.ConcreteLinearNoTension(
        elastic_modulus=35e3, ultimate_strain=0.0035
    ),
    ultimate_stress_strain_profile=ssp.BilinearStressStrain(
        compressive_strength=40,
        compressive_strain=0.00175,
        ultimate_strain=0.0035,
    ),
    flexural_tensile_strength=3.5,
    colour="lightgrey",
)


conc_nonlinear = Concrete(
    name="Non-Linear Concrete",
    density=2.4e-6,
    stress_strain_profile=ssp.EurocodeNonLinear(
        elastic_modulus=35e3,
        ultimate_strain=0.0035,
        compressive_strength=40,
        compressive_strain=0.0023,
        tensile_strength=3.5,
        tension_softening_stiffness=10e3,
    ),
    ultimate_stress_strain_profile=ssp.BilinearStressStrain(
        compressive_strength=40,
        compressive_strain=0.00175,
        ultimate_strain=0.0035,
    ),
    flexural_tensile_strength=3.5,
    colour="lightgrey",
)

conc_material_list = [
    conc_linear,
    conc_linear_no_tension,
    conc_nonlinear,
]

steel = SteelBar(
    name="Steel - Elastic-Plastic",
    density=7.85e-6,
    stress_strain_profile=ssp.SteelElasticPlastic(
        yield_strength=500,
        elastic_modulus=200e3,
        fracture_strain=0.05,
    ),
    colour="grey",
)

Plot Stress-Strain Profiles#

Let’s use the plot_stress_strain() method to compare the various service stress-strain profiles:

[3]:
for conc in conc_material_list:
    conc.stress_strain_profile.plot_stress_strain(title=conc.name)
../_images/examples_moment_curvature_6_0.svg
../_images/examples_moment_curvature_6_1.svg
../_images/examples_moment_curvature_6_2.svg
[4]:
steel.stress_strain_profile.plot_stress_strain(title=steel.name)
../_images/examples_moment_curvature_7_0.svg
[4]:
<Axes: title={'center': 'Steel - Elastic-Plastic'}, xlabel='Strain', ylabel='Stress'>

Create Reinforced Concrete Geometry#

The section being analysed in this example is a 350D x 600W concrete column with a 125 mm circular void at its centre. The column is reinforced with 14N24 bars. As we will be using conducting multiple analyses with different material properties, we will assign the concrete material later.

[5]:
col = rectangular_section(d=350, b=600)
void = circular_section(d=125, n=12).align_center(align_to=col)
col = col - void  # subtract void from column

# add bars to column
geom = add_bar_rectangular_array(
    geometry=col,
    area=450,
    material=steel,
    n_x=6,
    x_s=492 / 5,
    n_y=3,
    y_s=121,
    anchor=(54, 54),
    exterior_only=True,
)

geom.plot_geometry(labels=[], cp=False, legend=False)
../_images/examples_moment_curvature_9_0.svg
[5]:
<Axes: title={'center': 'Cross-Section Geometry'}>

Varying Concrete Properties#

In this example we will first study the effect the concrete stress-strain profile has on the moment curvature diagram.

Moment Curvature Analysis#

The below code loops through each concrete material, assigning it to the concrete column geometry and performs a moment curvature analysis.

[6]:
# initialise list to store results and list to store labels
moment_curvature_results = []
labels = []

# loop through each concrete material
for idx, conc in enumerate(conc_material_list):
    # assign concrete material to first geometry in CompoundGeometry object
    geom.geoms[0].material = conc

    # create ConcreteSection object
    conc_sec = ConcreteSection(geom)

    # plot section first time only
    if idx == 0:
        conc_sec.plot_section()

    # perform moment curvature analysis and store results
    # bending about major axis so theta = pi/2
    res = conc_sec.moment_curvature_analysis(
        theta=np.pi / 2, kappa_inc=2.5e-7, progress_bar=False
    )
    moment_curvature_results.append(res)

    # create plot label
    labels.append(conc.name)
../_images/examples_moment_curvature_11_0.svg

Plotting Results#

We can plot the moment curvature results on a single plot by using the MomentCurvatureResults.plot_multiple_results() method. Note that individual plots can also be generated by using the plot_results() method.

[7]:
MomentCurvatureResults.plot_multiple_results(
    moment_curvature_results=moment_curvature_results, labels=labels, fmt="-"
)
../_images/examples_moment_curvature_13_0.svg
[7]:
<Axes: title={'center': 'Moment-Curvature'}, xlabel='Curvature', ylabel='Moment'>

In the above plot, the linear concrete exhibits a much stiffer response when compared to the other two plots. This is because there is no cracking behaviour modelled into the linear concrete stress-strain profile and the concrete fails in compression just after the steel reaches its yield stress. The concrete stresses continue to increase after yielding of the steel until compression failure. This can be confirmed by examining the failure_geometry attribute.

[8]:
print(moment_curvature_results[0].failure_geometry.material.name)
Linear Concrete

Let’s examine the moment curvature diagrams that do model cracking behaviour further.

[9]:
MomentCurvatureResults.plot_multiple_results(
    moment_curvature_results=moment_curvature_results[1:], labels=labels[1:], fmt="-"
)
../_images/examples_moment_curvature_17_0.svg
[9]:
<Axes: title={'center': 'Moment-Curvature'}, xlabel='Curvature', ylabel='Moment'>

Both plots show similar behaviour with a couple of interesting differences:

  1. The non-linear concrete material is able to capture the initial uncracked behaviour and the softening that occurs after cracking. After cracking, the cracked responses are markedly similar.

  2. The post yield behaviour for the non-linear material is softer than that of the linear material. This is because the concrete stress for the linear material can continue to increase as the curvature increases, as stresses are extrapolated in the ConcreteLinearNoTension stress-strain profile and there is no softening of the concrete stress. On the other hand, the non-linear concrete material does model this ‘softening’ and the resultant moment is thus lower.

Compare Cracking Moments#

Finally, we will compare the cracking moment obtained in an elastic analysis with that from the moment curvature analysis. First we compute the cracking moment using the calculate_cracked_properties() method.

[10]:
print(
    f"M_cr = {conc_sec.calculate_cracked_properties(theta=np.pi / 2).m_cr / 1e6:.2f} kN.m"
)
M_cr = 84.77 kN.m

Now let’s examine the non-linear concrete response in the initial elastic region.

[11]:
import matplotlib.pyplot as plt


fix, ax = plt.subplots()
kappa = np.array(moment_curvature_results[-1].kappa)
moment = np.array(moment_curvature_results[-1].m_xy) / 1e6
ax.plot(kappa[:12], moment[:12], "x-")
plt.show()
../_images/examples_moment_curvature_22_0.svg

It’s clear in the above plot that the softening due to initial cracking occurs between 75 kN.m and 125 kN.m, which aligns well with the elastic result. To investigate this further, we could reduce the resolution of the moment-curvature plot in this region.

Finetuning Analysis Parameters#

There are a number of analysis parameters that can be finetuned to control the moment curvature analysis. These will be explored in this example.

We start by creating a simple geometry with relatively simple material properties (linear concrete with no tension & elastic-plastic steel).

[12]:
concrete = Concrete(
    name="Concrete (No Tension)",
    density=2.4e-6,
    stress_strain_profile=ssp.ConcreteLinearNoTension(
        elastic_modulus=35e3,
        ultimate_strain=0.003,
        compressive_strength=40,
    ),
    ultimate_stress_strain_profile=ssp.BilinearStressStrain(
        compressive_strength=40,
        compressive_strain=0.00175,
        ultimate_strain=0.0035,
    ),
    flexural_tensile_strength=3.5,
    colour="lightgrey",
)

geom = rectangular_section(d=600, b=400, material=concrete)

geom = add_bar_rectangular_array(
    geometry=geom,
    area=450,
    material=steel,
    n_x=3,
    x_s=158,
    n_y=3,
    y_s=258,
    anchor=(42, 42),
    exterior_only=True,
)

conc_sec = ConcreteSection(geom)
conc_sec.plot_section()
../_images/examples_moment_curvature_25_0.svg
[12]:
<Axes: title={'center': 'Reinforced Concrete Section'}>

Default Analysis Parameters#

[13]:
res1 = conc_sec.moment_curvature_analysis(progress_bar=False)
[14]:
res1.plot_results(fmt="x-")
print(f"Number of calculations = {len(res1.kappa)}")
print(f"Failure curvature = {res1.kappa[-1]:.4e}")
../_images/examples_moment_curvature_28_0.svg
Number of calculations = 33
Failure curvature = 4.9206e-05

In the above plot we waste a lot of time calculating the initial linear behaviour and can not be super confident that we have captured the yielding behaviour well. However, we don’t spend too much time in the yielded plateau region as the curvature increment is adaptively increased.

Initial Curvature Increment#

In this example we change the initial curvature increment from 1e-7 (default) to 5e-6.

[15]:
res2 = conc_sec.moment_curvature_analysis(kappa_inc=5e-6, progress_bar=False)
[16]:
res2.plot_results(fmt="x-")
print(f"Number of calculations = {len(res2.kappa)}")
print(f"Failure curvature = {res2.kappa[-1]:.4e}")
../_images/examples_moment_curvature_32_0.svg
Number of calculations = 13
Failure curvature = 4.9206e-05

We now save a lot of time in the initial linear region compared to the previous plot however the yielding behaviour is not super well described.

Further Refinement#

In this example we change the following parameters:

  • kappa_inc=1e-6 - a balance between the previous two examples

  • kappa_mult=1.25 - smoother changes in curvature increment (default = 2)

  • delta_m_min=0.1 - only increase the curvature increment if the change in moment is less than 10% (default = 15%)

  • kappa_inc_max=2e-5 - allow larger curvature increments, can be useful in the plateau region (default = 5e-6)

[17]:
res3 = conc_sec.moment_curvature_analysis(
    kappa_inc=1e-6,
    kappa_mult=1.25,
    delta_m_min=0.1,
    kappa_inc_max=2e-5,
    progress_bar=False,
)
[18]:
res3.plot_results(fmt="x-")
print(f"Number of calculations = {len(res3.kappa)}")
print(f"Failure curvature = {res3.kappa[-1]:.4e}")
../_images/examples_moment_curvature_36_0.svg
Number of calculations = 28
Failure curvature = 4.9206e-05

Summary#

Note that all failure curvatures are the same, regardless of the analysis parameters the failure point is always included in the results.

Let’s compare the most granular result (res3) with the result with the fastest computation time (res2).

[19]:
MomentCurvatureResults.plot_multiple_results(
    moment_curvature_results=[res2, res3],
    labels=["Coarse", "Refined"],
    fmt="-",
)
../_images/examples_moment_curvature_38_0.svg
[19]:
<Axes: title={'center': 'Moment-Curvature'}, xlabel='Curvature', ylabel='Moment'>

Note that the behaviour is largely similar, however the refined parameters do a better job of capturing the yielding behaviour.

Non-Zero Axial Force#

Moment-curvature diagrams can be generated with non-zero axial forces. A simple column is used to illustrate this.

[20]:
concrete = Concrete(
    name="Concrete (No Tension)",
    density=2.4e-6,
    stress_strain_profile=ssp.ConcreteLinearNoTension(
        elastic_modulus=35e3,
        ultimate_strain=0.003,
        compressive_strength=31,
    ),
    ultimate_stress_strain_profile=ssp.BilinearStressStrain(
        compressive_strength=31,
        compressive_strain=0.00175,
        ultimate_strain=0.0035,
    ),
    flexural_tensile_strength=3.5,
    colour="lightgrey",
)

steel = SteelBar(
    name="Steel - Elastic-Plastic",
    density=7.85e-6,
    stress_strain_profile=ssp.SteelElasticPlastic(
        yield_strength=320,
        elastic_modulus=200e3,
        fracture_strain=0.05,
    ),
    colour="grey",
)

geom = rectangular_section(d=600, b=600, material=concrete)
geom = add_bar_rectangular_array(
    geometry=geom,
    area=610,
    material=steel,
    n_x=3,
    x_s=236,
    n_y=3,
    y_s=236,
    anchor=(64, 64),
    exterior_only=True,
)

conc_sec = ConcreteSection(geom)
conc_sec.plot_section()
../_images/examples_moment_curvature_42_0.svg
[20]:
<Axes: title={'center': 'Reinforced Concrete Section'}>

We perform four moment-curvature analyses with varying levels of axial force.

[21]:
res_n0 = conc_sec.moment_curvature_analysis(n=0, kappa_inc=1e-6, progress_bar=False)
res_n1 = conc_sec.moment_curvature_analysis(
    n=0.2 * 600 * 600 * 31, kappa_inc=1e-6, progress_bar=False
)
res_nt = conc_sec.moment_curvature_analysis(
    n=-1000e3, kappa_inc=1e-6, progress_bar=False
)
[22]:
MomentCurvatureResults.plot_multiple_results(
    moment_curvature_results=[res_n0, res_n1, res_nt],
    labels=["$N=0$ kN", "$N=0.2f'cA_g$", "$N=-1000$ kN"],
    fmt="-",
)
../_images/examples_moment_curvature_45_0.svg
[22]:
<Axes: title={'center': 'Moment-Curvature'}, xlabel='Curvature', ylabel='Moment'>

The above plot clearly illustrates the influence axial force has on the moment-curvature response of a column.