Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Optimizing a bridge structure

Installation of the truss package

For this session, you will need the Python truss package. The following cell will install it automatically.

# FOR JUPYTER LAB
%matplotlib notebook
# FOR JUPYTER NOTEBOOK AND HUB
# % matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import sys
import os
import zipfile
import urllib.request
import shutil
from scipy import optimize


url = "https://github.com/lcharleux/truss/archive/master.zip"
file_name = "truss-master.zip"

with urllib.request.urlopen(url) as response, open(file_name, "wb") as out_file:
    shutil.copyfileobj(response, out_file)
    with zipfile.ZipFile(file_name) as zf:
        zf.extractall()

os.remove(file_name)

sys.path.append("truss-master")
try:
    import truss

    print("Truss is correctly installed")
except:
    print("Truss is NOT correctly installed !")
Truss is correctly installed

A short truss tutorial is available here:

http://truss.readthedocs.io/en/latest/tutorial.html

Building the bridge structure

In this session, we will modelled a bridge structure using truss and optimize it using various criteria. The basic structure is introduced below. It is made of steel bars and loaded with one vertical force on GG. The bridge is symmetrical so only the left half is modelled.

E = 210.0e9  # Young Modulus [Pa]
rho = 7800.0  # Density       [kg/m**3]
A = 5.0e-2  # Cross section [m**2]
sigmay = 400.0e6  # Yield Stress  [Pa]

# Model definition
model = truss.core.Model()  # Model definition

# NODES
nA = model.add_node((0.0, 0.0), label="A")
nC = model.add_node((3.0, 0.0), label="C")
nD = model.add_node((3.0, 3.0), label="D")
nE = model.add_node((6.0, 0.0), label="E")
nF = model.add_node((6.0, 3.0), label="F")
nG = model.add_node((9.0, 0.0), label="G")
nH = model.add_node((9.0, 3.0), label="H")

# BOUNDARY CONDITIONS
nA.block[1] = True
nG.block[0] = True
nH.block[0] = True

# BARS
AC = model.add_bar(nA, nC, modulus=E, density=rho, section=A, yield_stress=sigmay)
CD = model.add_bar(nC, nD, modulus=E, density=rho, section=A, yield_stress=sigmay)
AD = model.add_bar(nA, nD, modulus=E, density=rho, section=A, yield_stress=sigmay)
CE = model.add_bar(nC, nE, modulus=E, density=rho, section=A, yield_stress=sigmay)
DF = model.add_bar(nD, nF, modulus=E, density=rho, section=A, yield_stress=sigmay)
DE = model.add_bar(nD, nE, modulus=E, density=rho, section=A, yield_stress=sigmay)
EF = model.add_bar(nE, nF, modulus=E, density=rho, section=A, yield_stress=sigmay)
EG = model.add_bar(nE, nG, modulus=E, density=rho, section=A, yield_stress=sigmay)
FH = model.add_bar(nF, nH, modulus=E, density=rho, section=A, yield_stress=sigmay)
FG = model.add_bar(nF, nG, modulus=E, density=rho, section=A, yield_stress=sigmay)
GH = model.add_bar(nG, nH, modulus=E, density=rho, section=A, yield_stress=sigmay)

# STRUCTURAL LOADING
nG.force = np.array([0.0, -1.0e6])


model.solve()


xlim, ylim = model.bbox(deformed=False)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.set_aspect("equal")
# ax.axis("off")
model.draw(
    ax, deformed=False, field="stress", label=True, force_scale=1.0e-6, forces=True
)
plt.xlim(xlim)
plt.ylim(ylim)
plt.grid()
plt.xlabel("Axe $x$")
plt.ylabel("Axe $y$")
Loading...
Loading...

Read Data

Detailed results at the nodes

model.data(at="nodes")
Loading...

Detailed results on the bars

model.data(at="bars")
Loading...

Dead (or structural) mass

m0 = model.mass()
m0 * 1.0e-3  # Mass in tons !
np.float64(14.323889603929565)

Model modification

Modifing section

# change section of one bar
FG.section = 0.0333

# solve with updated sections
model.solve()

model.data(at="bars")
Loading...

Changing all section (or other parameters)

# loop over bars
for bar in model.bars:
    # get the normal force of the bar
    N = bar.tension

    # change the section
    bar.section = 0.2


# solve with updated parameters
model.solve()

Questions

Question 1: Verify that the yield stress is not exceeded anywhere, do you think this structure has an optimimum weight ? You can use the state/failure data available on the whole model.

# Example:
model.data(at="bars").state.failure.values

# ...
array([np.False_, np.False_, np.False_, np.False_, np.False_, np.False_, np.False_, np.False_, np.False_, np.False_, np.False_], dtype=object)

Question 2: Modify all the cross sections at the same time in order to minimize weight while keeping acceptable stress level.

Question 3: We want to modify the position along the y\vec y axis of the points DD, FF and HH in order to minimize the vertical displacement of the node GG times the mass of the structure α\alpha:

α=uy(G)m\alpha = |u_y(G)| m

Where uy(G)u_y(G) is the displacement of the node GG along the y\vec y axis and mm the mass of the whole structure.

Do not further modify the sections determined in question 4. Comment the solution.

Question 4: Same question with displacements also along x\vec x of CC, DD, EE and FF. Is it better ?

Question 5: You can now try to perform topological optimization by removing/merging well chosen beams and nodes. In order to make the structure even more efficient.

Question 6: You are now asked to optimize the cross section along with the position of CC, DD, EE and FF in order to reach the yield stress in each individual beam.