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][license]] before use.
[[./data/images/animation.png]] ** Installation 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. *** PyPI First make sure you are using Python 3.8+. You will also need [[https://opensees.berkeley.edu/][OpenSees]] to run FE simulations which you can download [[https://opensees.berkeley.edu/OpenSees/user/download.php][here]]. If you are installing OpenSees on Linux then the top answer [[https://www.researchgate.net/post/How_to_install_opensees_in_UBUNTU][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 [[https://python-poetry.org/docs/][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 [[#examples][below]]. *** Docker Make sure you have [[https://docs.docker.com/get-docker/][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 [[#examples][below]]. **** Lisa
These instructions may be useful if you are running simulations on the [[https://userinfo.surfsara.nl/systems/lisa][SURF SARA Lisa]] cluster or another system that supports [[https://sylabs.io/docs/#singularity][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 [[docker/run-lisa.sh][run-lisa.sh]] for an example of such a script and see the Lisa [[https://userinfo.surfsara.nl/systems/lisa/user-guide/creating-and-running-jobs][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 [[docker/sim.sh][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=.
*** Development First make sure you are using Python 3.8+ and [[https://python-poetry.org/docs/][install Poetry]]. You will also need [[https://opensees.berkeley.edu/][OpenSees]] to run FE simulations which you can download [[https://opensees.berkeley.edu/OpenSees/user/download.php][here]]. If you are installing OpenSees on Linux then the top answer [[https://www.researchgate.net/post/How_to_install_opensees_in_UBUNTU][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
* Installation notes 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. Introduction 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.
** Examples 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=. *** Example 1: applying a point load 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()
*** Example 2: defining a vehicle 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=[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()
*** Example 3: pier settlement 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()
*** Example 4: multiple response types 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()
*** Example 5: defining a bridge 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, ) ],
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()
*** Example 6: generating traffic 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" )
*** Example 7: animating traffic flow 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, )
*** Example 8: contour plot of temperature effect 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()
*** Example 9: time series of temperature effect 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
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, )
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()