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:
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
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$")
Text(0, 0.5, 'Axe $y$')
Read Data#
Detailed results at the nodes#
model.data(at="nodes")
label | coords | disp | force | block | |||||
---|---|---|---|---|---|---|---|---|---|
o | x | y | ux | uy | Fx | Fy | bx | by | |
0 | A | 0.0 | 0.0 | -0.001143 | 0.0 | 0.0 | 1000000.0 | False | True |
1 | C | 3.0 | 0.0 | -0.000857 | -0.00338 | 0.0 | 0.0 | False | False |
2 | D | 3.0 | 3.0 | 0.001429 | -0.00338 | 0.0 | 0.0 | False | False |
3 | E | 6.0 | 0.0 | -0.000571 | -0.006188 | 0.0 | 0.0 | False | False |
4 | F | 6.0 | 3.0 | 0.000857 | -0.006473 | 0.0 | 0.0 | False | False |
5 | G | 9.0 | 0.0 | 0.0 | -0.008139 | 3000000.0 | -1000000.0 | True | False |
6 | H | 9.0 | 3.0 | 0.0 | -0.008139 | -3000000.0 | 0.0 | True | False |
Detailed results on the bars#
model.data(at="bars")
conn | props | state | geometry | props | direction | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
c1 | c2 | section | density | tension | elongation | strain | stress | failure | volume | length | mass | dx | dy | |
0 | A | C | 0.05 | 7800.0 | 1000000.0 | 0.000286 | 0.000095 | 20000000.0 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
1 | C | D | 0.05 | 7800.0 | 0.0 | 0.0 | 0.0 | 0.0 | False | 0.15 | 3.0 | 1170.0 | 0.0 | 1.0 |
2 | A | D | 0.05 | 7800.0 | -1414213.562373 | -0.000571 | -0.000135 | -28284271.247462 | False | 0.212132 | 4.242641 | 1654.629868 | 0.707107 | 0.707107 |
3 | C | E | 0.05 | 7800.0 | 1000000.0 | 0.000286 | 0.000095 | 20000000.0 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
4 | D | F | 0.05 | 7800.0 | -2000000.0 | -0.000571 | -0.00019 | -40000000.000001 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
5 | D | E | 0.05 | 7800.0 | 1414213.562373 | 0.000571 | 0.000135 | 28284271.247462 | False | 0.212132 | 4.242641 | 1654.629868 | 0.707107 | -0.707107 |
6 | E | F | 0.05 | 7800.0 | -1000000.0 | -0.000286 | -0.000095 | -20000000.0 | False | 0.15 | 3.0 | 1170.0 | 0.0 | 1.0 |
7 | E | G | 0.05 | 7800.0 | 2000000.0 | 0.000571 | 0.00019 | 40000000.000001 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
8 | F | H | 0.05 | 7800.0 | -3000000.0 | -0.000857 | -0.000286 | -60000000.000001 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
9 | F | G | 0.05 | 7800.0 | 1414213.562373 | 0.000571 | 0.000135 | 28284271.247462 | False | 0.212132 | 4.242641 | 1654.629868 | 0.707107 | -0.707107 |
10 | G | H | 0.05 | 7800.0 | 0.0 | 0.0 | 0.0 | 0.0 | False | 0.15 | 3.0 | 1170.0 | 0.0 | 1.0 |
Dead (or structural) mass#
m0 = model.mass()
m0 * 1.0e-3 # Mass in tons !
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")
conn | props | state | geometry | props | direction | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
c1 | c2 | section | density | tension | elongation | strain | stress | failure | volume | length | mass | dx | dy | |
0 | A | C | 0.05 | 7800.0 | 1000000.0 | 0.000286 | 0.000095 | 20000000.0 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
1 | C | D | 0.05 | 7800.0 | 0.0 | 0.0 | 0.0 | 0.0 | False | 0.15 | 3.0 | 1170.0 | 0.0 | 1.0 |
2 | A | D | 0.05 | 7800.0 | -1414213.562373 | -0.000571 | -0.000135 | -28284271.247462 | False | 0.212132 | 4.242641 | 1654.629868 | 0.707107 | 0.707107 |
3 | C | E | 0.05 | 7800.0 | 1000000.0 | 0.000286 | 0.000095 | 20000000.0 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
4 | D | F | 0.05 | 7800.0 | -2000000.0 | -0.000571 | -0.00019 | -40000000.0 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
5 | D | E | 0.05 | 7800.0 | 1414213.562373 | 0.000571 | 0.000135 | 28284271.247462 | False | 0.212132 | 4.242641 | 1654.629868 | 0.707107 | -0.707107 |
6 | E | F | 0.05 | 7800.0 | -1000000.0 | -0.000286 | -0.000095 | -20000000.0 | False | 0.15 | 3.0 | 1170.0 | 0.0 | 1.0 |
7 | E | G | 0.05 | 7800.0 | 2000000.0 | 0.000571 | 0.00019 | 40000000.000001 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
8 | F | H | 0.05 | 7800.0 | -3000000.0 | -0.000857 | -0.000286 | -60000000.000001 | False | 0.15 | 3.0 | 1170.0 | 1.0 | 0.0 |
9 | F | G | 0.0333 | 7800.0 | 1414213.562373 | 0.000858 | 0.000202 | 42468875.74694 | False | 0.14128 | 4.242641 | 1101.983492 | 0.707107 | -0.707107 |
10 | G | H | 0.05 | 7800.0 | 0.0 | 0.0 | 0.0 | 0.0 | False | 0.15 | 3.0 | 1170.0 | 0.0 | 1.0 |
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([False, False, False, False, False, False, False, False, False,
False, 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
Where
Do not further modify the sections determined in question 4. Comment the solution.
Question 4: Same question with displacements also along
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