This document provides installation instructions and usage examples.
API documentation is available at https://jerbaroo.github.io/bridge-sim
Table of Contents
If you are interested in using this library, please open an issue to ask any questions (one issue per question)! I welcome all feedback, so don’t hesitate to communicate any thoughts. Please star the project if you like it. Read the license before use.
Three installation methods are provided. You can install bridge-sim
from PyPI using your preferred Python package manager. We also provide a Docker image with bridge-sim
and all dependencies already installed. And finally you can clone this repository if you intend on contributing to the bridge-sim
project.
First make sure you are using Python 3.8+. You will also need OpenSees to run FE simulations which you can download here. If you are installing OpenSees on Linux then the top answer here may be of some help.
Using pip: inside your Python virtual environment run this command pip install bridge-sim
.
If you are starting a project from scratch I recommend the Poetry package manager. Initialize a project named foobar with poetry new foobar && cd foobar
, then add bridge-sim
as a dependency with poetry add bridge-sim
.
Now that you have bridge-sim
installed you probably want to run some code, for that see the examples section below.
Make sure you have Docker installed. Then in a terminal run the following to jump into a Docker image that already has all dependencies installed:
$ docker run -it jerbaroo/bridge-sim:v0.0.8.9
You are now in the /bridge-sim
directory of the Docker container. You can run the provided example file example.py
with poetry run python example.py
. This will generate a file /root/docker-1.png
.
To copy docker-1.png
to your host system run the following commands in another terminal. The first command lists all running Docker containers. Copy the container ID and then use the docker cp
command to copy docker-1.png
to your host system.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d297a50ff165 jerbaroo/bridge-sim:v0.0.8.9 "/bin/bash" 37 seconds ago Up 37 seconds vigorous_leavitt
$ docker cp d297a50ff165:/root/docker-1.png docker-1.png
The Docker image that you enter with docker run
has OpenSees installed at /root/bin/OpenSees
. The bridge-sim
source code along with all installed Python dependencies are in /bridge-sim
. We have shown how to run the provided example.py
file but you could modify this file and run a different example, some examples are provided below.
These instructions may be useful if you are running simulations on the SURF SARA Lisa cluster or another system that supports Singularity.
Once you have SSHed into the Lisa cluster you can build a Singularity image of bridge_sim
on Lisa with singularity pull docker://jerbaroo/bridge-sim:v0.0.8.9
. If the pull
command fails or the generated .sif
file is corrupted then try deleting the .sif
file and run the pull
command again.
To run a simulation you need a script to interact with the scheduler. See run-lisa.sh for an example of such a script and see the Lisa user guide for further instructions. The way I use the run-lisa.sh
script, is I configure scheduling parameters in the run-lisa.sh
script but define my actual job in a second script sim.sh.
To view jobs in the queue I run squeue | grep brjeremy
, where brjeremy
is my username. Job output is saved in a slurm-XXXXX.out
file where XXXXX
is the job ID. I always delete the output from old jobs, so to delete the old output and run a new job I type rm slurm*.out; sbatch run-lisa.sh
. Then the output can be viewed with cat slurm-XXXXX.out
. To cancel a job run scancel XXXXX
.
First make sure you are using Python 3.8+ and install Poetry. You will also need OpenSees to run FE simulations which you can download here. If you are installing OpenSees on Linux then the top answer here may be of some help.
Now clone this repository, change into the directory and once in the bridge-sim
directory install project dependencies:
$ git clone https://github.com/jerbaroo/bridge-sim
$ cd bridge-sim
$ poetry install
After installation you can find your poetry created virtual environment by using poetry show -v
. You might need to add the path to the python executable manually in your IDE.
A brief introduction to some of the Python classes provided. A Bridge
describes the material properties, geometry and boundary conditions of a bridge. A FEMRunner
is capable of transforming a Bridge
along with some additional simulation parameters into a model file, running that file, and returning the responses from simulation. This project currently provides one instance of FEMRunner
which is called OSRunner
and is capable of running simulations with OpenSees. A Config
contains some additional global configuration but is also used as a container for a Bridge
and FEMRunner
. This is useful because all three of these objects are required in many situations and combining them into one object makes life a bit easier than passing these three objects around separately.
If you have managed to install the software then the next step is to run an example such as example.py
. You will need to make sure that OpenSees is on your PATH, if you have followed the Docker installation instructions then this is already done for you. The file example.py
can be run with poetry run python example.py
.
Narrow example bridge with a single point load applied.
import matplotlib.pyplot as plt
from bridge_sim import bridges, configs, model, plot, sim
config = configs.opensees_default(bridges.bridge_narrow)
point_loads = [model.PointLoad(x=5, z=0, load=100)]
responses = sim.responses.load(config, model.RT.YTrans, point_loads)
plot.contour_responses(config, responses, point_loads)
plot.top_view_bridge(config.bridge, piers=True)
plt.tight_layout()
plt.show()
Narrow example bridge with a 5-axled vehicle on it, each wheel is a point load.
import matplotlib.pyplot as plt
from bridge_sim import bridges, configs, model, plot, sim
config = configs.opensees_default(bridges.bridge_narrow, shorten_paths=True)
point_loads = model.Vehicle(
# Load intensity of each axle.
load=[5000, 4000, 4000, 5000, 7000],
# Distance between each pair of axles.
axle_distances=[2, 2, 2, 1],
# Width of each axle, distance between point loads.
axle_width=2.5,
# Speed of the vehicles.
kmph=20,
).point_load_pw(config=config, time=3.5, list=True)
responses = sim.responses.load(config, model.RT.YTrans, point_loads)
plot.contour_responses(config, responses, point_loads)
plot.top_view_bridge(config.bridge, piers=True)
plt.tight_layout()
plt.show()
Wide example bridge with two supporting piers, one pier settled by 1.2 m.
import matplotlib.pyplot as plt
from bridge_sim import bridges, configs, sim, model, plot
config = configs.opensees_default(bridges.bridge_wide)
responses = sim.responses.load(
config,
model.RT.YTrans,
pier_settlement=[model.PierSettlement(0, 1.2)]
)
plot.contour_responses(config, responses)
plot.top_view_bridge(config.bridge, piers=True)
plt.tight_layout()
plt.show()
Like the previous pier settlement example but plotting multiple response types.
import matplotlib.pyplot as plt
from bridge_sim import bridges, configs, model, plot, sim
config = configs.opensees_default(bridges.bridge_wide)
plt.figure(figsize=(12, 8))
for subplot, response_type in enumerate([
model.RT.YTrans, model.RT.ZTrans,
model.RT.StrainXXB, model.RT.StrainZZB,
]):
responses = sim.responses.load(
config,
response_type,
pier_settlement=[model.PierSettlement(0, 1.2)],
)
plt.subplot(2, 2, subplot + 1)
plot.contour_responses(config, responses, interp=(200, 60))
plot.top_view_bridge(config.bridge, piers=True)
plt.title(response_type.name())
plt.tight_layout()
plt.show()
Like the first point-load example but with a custom square bridge.
import matplotlib.pyplot as plt
from bridge_sim import bridges, configs, model, plot, sim
from bridge_sim.bridges import Bridge, Lane, MaterialDeck, MaterialSupport, Support
def new_bridge():
return Bridge(
name="square", # Name used to identify saved/loaded data.
msl=0.5, # Maximum shell length.
length=10, # Length of this bridge.
width=10, # Width of this bridge.
supports=[
Support(
x=5, # X position of center of the support.
z=0, # Z position of center of the support.
length=2, # Length between support columns (X direction).
height=2, # Height from top to bottom of support.
width_top=2, # Width of support column at top (Z direction).
width_bottom=1, # Width of support column at bottom (Z direction).
materials=[ # List of materials for the support columns.
MaterialSupport(
density=0.7,
thickness=0.7,
youngs=40000,
poissons=0.2,
start_frac_len=0,
)
],
fix_z_translation=True,
fix_x_translation=True,
)
],
# List of materials for the bridge deck.
materials=[MaterialDeck(thickness=0.7, youngs=40000, poissons=0.2,)],
# List of lanes where traffic can drive on the bridge.
lanes=[Lane(-1, 1, True)],
)
config = configs.opensees_default(new_bridge)
point_loads = [model.PointLoad(x=8, z=0, load=100)]
responses = sim.responses.load(config, model.RT.YTrans, point_loads)
plot.contour_responses(config, responses, point_loads)
plot.top_view_bridge(config.bridge, piers=True, lanes=True)
plt.tight_layout()
plt.show()
Generate 10 seconds of traffic and animate it moving over bridge 705.
from bridge_sim import bridges, configs, plot, traffic
config = configs.opensees_default(bridges.bridge_705(0.5))
time = 10
config.sensor_freq = 1 / 10
traffic_scenario = traffic.normal_traffic(config)
traffic_sequence = traffic_scenario.traffic_sequence(config, time)
traffic = traffic_sequence.traffic()
plot.animate.animate_traffic(
config=config,
traffic_sequence=traffic_sequence,
traffic=traffic,
save="animation.mp4"
)
First generating traffic. Then animating the responses of the bridge to that traffic, to pier settlement, to temperature effect and to shrinkage.
NOTE: This example will a long time to run because responses are calculated based on superposition of many “unit” load simulations that must be run.
from bridge_sim import bridges, configs, model, plot, temperature, traffic
config = configs.opensees_default(bridges.bridge_705(10), il_num_loads=100)
time = 10
config.sensor_freq = 1 / 10
traffic_scenario = traffic.normal_traffic(config)
traffic_sequence = traffic_scenario.traffic_sequence(config, time)
weather = temperature.load("holly-springs-19")
weather["temp"] = temperature.resize(weather["temp"], tmin=-5, tmax=35)
plot.animate.animate_responses(
config=config,
traffic_sequence=traffic_sequence,
response_type=model.ResponseType.YTrans,
units="mm",
save="traffic-responses.mp4",
pier_settlement=[
(model.PierSettlement(4, 1.2), model.PierSettlement(4, 2))],
weather=weather,
start_date="01/05/2019 00:00",
end_date="01/05/2019 23:59",
install_day=30,
start_day=365,
end_day=366,
with_creep=True,
)
Contour plot of temperature when the bottom and top temperatures of the bridge are 20 and 22 degrees celcius respectively.
import matplotlib.pyplot as plt
import numpy as np
from bridge_sim import bridges, configs, model, sim, plot, temperature
config = configs.opensees_default(bridges.bridge_705(msl=10))
bridge = config.bridge
response_type = model.RT.StrainXXB
points = [
model.Point(x=x, y=0, z=z)
for x in np.linspace(bridge.x_min, bridge.x_max, num=int(bridge.length * 2))
for z in np.linspace(bridge.z_min, bridge.z_max, num=int(bridge.width * 2))
]
temp_effect = temperature.effect(
config=config, response_type=response_type, points=points, temps_bt=[[20], [22]]
).T[0] # Only considering a single temperature profile.
responses = sim.model.Responses( # Converting to "Responses" for plotting.
response_type=response_type,
responses=[(temp_effect[p], points[p]) for p in range(len(points))],
).without_nan_inf()
plot.contour_responses(config, responses)
plot.top_view_bridge(config.bridge, piers=True)
plt.tight_layout()
plt.show()
Generating traffic, then calculating time series of responses to that traffic over a wide example bridge. Then also calculating the responses to temperature.
NOTE: This example will a long time to run because responses are calculated based on superposition of many “unit” load simulations that must be run.
import matplotlib.pyplot as plt
from bridge_sim import bridges, configs, model, sim, temperature, traffic
config = configs.opensees_default(bridges.bridge_705(10), il_num_loads=100)
points = [model.Point(x=10), model.Point(x=20)]
response_type = model.RT.YTrans
# First generate some traffic data.
traffic_sequence = traffic.normal_traffic(config).traffic_sequence(config, 10)
traffic_array = traffic_sequence.traffic_array()
responses_to_traffic = sim.responses.to_traffic_array(
config=config,
traffic_array=traffic_array,
response_type=response_type,
points=points,
)
# And responses to temperature.
weather = temperature.load("holly-springs-19")
weather["temp"] = temperature.resize(weather["temp"], tmin=-5, tmax=31)
temp_responses = sim.responses.to_temperature(
config=config,
points=points,
responses_array=responses_to_traffic,
response_type=response_type,
weather=weather,
start_date="01/05/2019 00:00",
end_date="02/05/2019 00:00",
)
plt.plot((responses_to_traffic + temp_responses).T)
plt.show()