A Python library for concrete slab bridge simulation


License
MIT
Install
pip install bridge-sim==0.0.8.9

Documentation

A Python library for concrete slab bridge simulation

https://img.shields.io/circleci/build/github/jerbaroo/bridge-sim.svg https://img.shields.io/docker/pulls/jerbaroo/bridge-sim.svg https://img.shields.io/codeclimate/maintainability/jerbaroo/bridge-sim.svg https://img.shields.io/github/license/jerbaroo/bridge-sim.svg

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.

./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 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.

Docker

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.

Lisa

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.

Development

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

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 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()

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,
            )
        ],
        # 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()

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

# 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()