# You must make sure to run all cells in sequence using shift + enter or you might encounter errors
from pykubegrader.initialize import initialize_assignment
responses = initialize_assignment("1_lab_building_bridge", "week_8", "lab", assignment_points = 126.0, assignment_tag = 'week8-lab')
# Initialize Otter
import otter
grader = otter.Notebook("1_lab_building_bridge.ipynb")
๐๏ธ Mission: Bridge Safety Analysis โ The Engineerโs Challenge! ๐#
๐ Introduction: Welcome to the Team!#
Congratulations, Engineer! ๐ Youโve just been hired as the lead structural engineer at SteelWorks Inc. Your first mission? Analyze the safety of the Golden Gate Bridge under different loading conditionsโor risk total catastrophe! ๐ฑ
Our bridge must withstand traffic loads, fierce winds, and the occasional flock of overly enthusiastic pigeons. ๐ฆ๐จ As a skilled Python programmer, youโll use Object-Oriented Programming (OOP), scientific computing, and graphing techniques to ensure that our bridge doesnโt collapse into the ocean! ๐
๐ ๏ธ Engineering Context: Why This Matters?#
Every year, bridges are designed, tested, and maintained to ensure safety for millions of people. A poorly designed bridge can lead to catastrophic failuresโremember the Tacoma Narrows Bridge disaster? ๐ช๏ธ๐ Oops.
By analyzing real-world deflection curves, stress distributions, and wind loads, you will: ๐ก Learn fundamental mechanics principles using computational tools. ๐ก Develop engineering intuition on load-bearing structures. ๐ก Prepare for your future as an engineering superhero! ๐ฆธโโ๏ธโก
๐ฏ Your Challenge: Save the Bridge!#
You will design a Python simulation that includes: ๐ Beam Deflection Analysis: How much will our bridge bend under load? ๐ Stress & Safety Factor Checks: Will our materials withstand the forces? ๐ Wind Load Effects: What happens when strong winds hit the bridge? ๐ฌ๏ธ ๐ Graphical Reports: Visualize stress, deflection, and safety margins.
๐ง Engineering Formulas Used#
Weโll use some key engineering equations in our Python models:
๐ Beam Deflection Equation (Traffic Load)#
๐ช Bending Stress in the Beam#
๐ฌ๏ธ Wind Load Contribution#
๐ Graphing & Visualization#
Youโll use Matplotlib to create stunning plots for:
๐ Bridge deflection curves to see how much it bends.
๐ Stress distribution plots to analyze failure points.
๐ Wind load impact graphs to visualize dangerous weather effects.\
๐พ Coding Concepts Youโll Apply#
๐น Object-Oriented Programming (OOP) โ Classes, Inheritance, Encapsulation.
๐น Encapsulation with @property
methods โ Dynamic safety factor updates.
Step 1: Abstract Base Class for Bridge Components#
We enforce structure using an abstract class for bridge components. Remember, this is a great way to protect you from yourself! Moreover, as an engineer, you need to make sure that you do not miss the safety factor! Therefore we are going to use getter and setter methods to ensure that we donโt accidentally mess with, or include a safety factor that is less than 1.0!
Recall a safety factor is a factor of safety that is used to ensure that the bridge is safe. It is defined as the ratio of the yield strength to the stress in the bridge.
# import the necessary libraries
# from abc import ABC, abstractmethod
# import numpy as np
# import matplotlib.pyplot as plt
...
# Define the BridgeComponent class make sure that it inherits from ABC
...
"""Abstract base class for all bridge components.
This class defines the common interface and properties that all bridge components must implement.
It enforces safety requirements through validation of safety factors.
Attributes:
material (str): The material the component is made of
length (float): Length of the component in meters
yield_strength (float): The yield strength of the material in Pa
_safety_factor (float): Safety factor that must be > 1.0
"""
# Define the __init__ method
# This is the constructor for the class look at the docstring to understand the arguments
...
"""Initialize a bridge component.
Args:
material (str): Material name/type
length (float): Component length in meters
elastic_modulus (float): Material elastic modulus in Pa
yield_strength (float): Material yield strength in Pa
safety_factor (float): Safety factor > 1.0
"""
# Assign the atributes to the instance of the class, for the safety factor we should use a private variable commonly denoted by a single underscore in front of the variable name
...
# Define the safety_factor using the @property decorator
# This should return the value for the safety factor
...
# Define the setter for the safety factor
# This should set the value for the safety factor
# the syntax is @property_name.setter
# make sure that the setter checks if the value is greater than 1.0
# if it is less than 1.0, it should raise a ValueError("Safety factor must be greater than 1.0")
...
# Define the compute_stress method
# This should be an abstract method that must be implemented by the subclasses
# for now, we will just pass the method
...
# Define the is_safe method
# This should check if the stress input is less than the yield strength divided by the safety factor, save the result in a variable called safe_limit
# then return the result of the comparison between the stress and the safe_limit
# the safe_limit can be a local variable or a property of the class
...
grader.check("q1-bridge-component")
Question 1 (Points: 12.0): Step 2: Beam and Cable Components#
Bridges are built up of beams and cables, so we need to define the components that make up the bridge. A beam and a cable are both bridge components, so it makes sense to inherit from the BridgeComponent class.
We define Beam
and Cable
, each with a compute_stress function.
# define the Beam class, make sure that it inherits from BridgeComponent
...
"""Represents a bridge beam that undergoes bending stress.
A beam is a structural element that primarily resists loads applied laterally to its axis.
It experiences bending stress due to these loads.
Args:
material (str): Material name of the beam
length (float): Length of the beam in meters
elastic_modulus (float): Elastic modulus of the material in Pa
yield_strength (float): Yield strength of the material in Pa
safety_factor (float): Safety factor to apply to yield strength
moment_of_inertia (float): Second moment of area in m^4
neutral_axis_distance (float): Distance from neutral axis to outer fiber in m
uniform_load (float): Uniformly distributed load in N/m
"""
# define the __init__ method, make sure that it calls the __init__ method of the BridgeComponent class, use super() to do this, it should take the arguments from the docstring
...
# This is where you should call the __init__ method of the BridgeComponent class, use super() to do this, it should take the arguments from the docstring
...
# This is where you should define the instance variables for the moment of inertia, neutral axis distance, and uniform load
...
# define the compute_stress method
# This should compute the maximum bending stress in the beam
...
"""Computes maximum bending stress in the beam.
Calculates the maximum bending stress at the mid-span of the beam using
the flexure formula ฯ = My/I, where M is the bending moment, y is the distance
from neutral axis, and I is the moment of inertia.
Returns:
float: Maximum bending stress in Pa
"""
# Compute the mid-span of the beam the length divided by 2
...
# Compute the bending moment at the mid-span of the beam using the uniform load and the length of the beam
# the formula is M = qx(L-x)/2, where q is the uniform load, x is the mid-span of the beam, and L is the length of the beam
...
# Compute the maximum bending stress at the mid-span of the beam using the bending moment, the neutral axis distance, and the moment of inertia
# the formula is ฯ = My/I, where M is the bending moment, y is the neutral axis distance, and I is the moment of inertia
...
# define the plot_deflection method
# This should plot the deflection curve of the beam using LaTeX equations
...
"""Plots the deflection curve of the beam using LaTeX equations.
Creates a matplotlib figure showing the beam's deflection along its length.
The deflection is calculated using the elastic curve equation for a uniformly
loaded beam. The plot includes axis labels, title with the equation, and grid.
Returns:
None
"""
# Compute the deflection of the beam using the elastic curve equation for a uniformly loaded beam
# set x to be a linspaced array from 0 to the length of the beam with 100 points, use np.linspace
# set y to be the deflection of the beam using the elastic curve equation for a uniformly loaded beam
# the formula is y = (qx(L-x)/24EI) * (L^2 - x^2), where q is the uniform load, x is the position along the beam, L is the length of the beam, E is the elastic modulus, and I is the moment of inertia
...
# plot the deflection of the beam using the elastic curve equation for a uniformly loaded beam
# make a figure using the plt.figure() function, and assign it to the variable fig
# make an axis using the fig.add_subplot() function, and assign it to the variable ax
# plot the deflection of the beam using the ax.plot() function
# set the xlabel of the axis to be "Position along bridge (m)"
# set the ylabel of the axis to be "Deflection (m)"
# set the title of the axis to be the LaTeX equation for the deflection of the beam the string should be r"Bridge Deflection: $y(x) = \frac{q x (L-x)}{24EI} (L^2 - x^2)$"
# call the legend of the axis using the ax.legend() function
# call the grid of the axis using the ax.grid() function
# call the show of the figure using the plt.show() function
...
# define the Cable class, make sure that it inherits from BridgeComponent
...
"""Represents a bridge cable under tension.
A cable is a structural element that carries only tensile forces.
It is commonly used in suspension and cable-stayed bridges.
Args:
material (str): Material name of the cable
length (float): Length of the cable in meters
elastic_modulus (float): Elastic modulus of the material in Pa
yield_strength (float): Yield strength of the material in Pa
safety_factor (float): Safety factor to apply to yield strength
tension_force (float): Axial tension force in the cable in N
cross_section_area (float): Cross-sectional area of the cable in m^2
"""
# define the __init__ method, make sure that it calls the __init__ method of the BridgeComponent class, use super() to do this, it should take the arguments from the docstring
...
# This is where you should call the __init__ method of the BridgeComponent class, use super() to do this, it should take the arguments from the docstring
...
# This is where you should define the instance variables for the tension force and the cross-sectional area
...
# define the compute_stress method
# This should compute the tensile stress in the cable using the formula ฯ = F/A, where F is the tension force and A is the cross-sectional area
...
grader.check("q2-beam-cable")
Question 2 (Points: 30.0): Step 4: Bridge Class Using Composition#
Now, we define a bridge object that contains beams and cables.
...
"""A class representing a bridge structure composed of multiple components.
This class manages a collection of bridge components like beams and cables,
and provides methods to add components and check their structural safety.
Attributes:
name (str): The name identifier for the bridge
length (float): The total length of the bridge in meters
components (list): List of BridgeComponent objects that make up the bridge
"""
# define the __init__ method, make sure that it takes the arguments from the docstring
...
"""Initialize a new Bridge instance.
Args:
name (str): The name identifier for the bridge
length (float): The total length of the bridge in meters
elastic_modulus (float): Young's modulus of the bridge material in Pascals
"""
# This is where you should define the instance variables for the name, length, elastic modulus, and components
# add an empty list to the instance variables for the components
...
# define the add_component method
# This should add a bridge component to the bridge structure
...
"""Adds a bridge component to the bridge structure.
Args:
component (BridgeComponent): A bridge component object (beam, cable, etc.)
"""
# add the component to the components list
...
# define the check_safety method
# This should perform a safety analysis on all bridge components
...
"""Performs a safety analysis on all bridge components.
Calculates stress for each component and checks if it's within safe limits.
Prints a detailed safety report including stress values and safety status
for each component, followed by an overall bridge safety verdict.
Returns:
None
"""
# initialize a boolean variable called bridge_safe to be True
...
# print the name of the bridge using the print() function
# the string should be f"\n๐ Safety Analysis for <name> Bridge:"
# recall \n is a newline character and f is used for formatted strings, <name> should be the name of the bridge
...
# loop through the components list, and assign the current component to the variable component
...
# compute the stress of the current component using the compute_stress method
...
# check if the stress is safe using the is_safe method
# here we are using polymorphism to call the is_safe method of the current component
...
# get the type of the current component using the __class__.__name__ attribute
# this is a way to get the type of the current component using Python's magic methods
# __class__ returns the class object of the instance
# __name__ returns the string name of the class
...
# print the type of the current component, the stress, and the safety status
print(f" - {component_type}: Stress = {stress:.2f} Pa | Safe: {'โ
' if safe else 'โ ๏ธ'}")
# if the stress is not safe, set the bridge_safe variable to False
...
# print the final verdict
print("\nFinal Verdict:", "โ
Bridge is SAFE" if bridge_safe else "โ ๏ธ WARNING: Bridge is UNSAFE")
grader.check("Bridge-Class-Composition")
Question 3 (Points: 16.0): Step 3: Wind and Load Analysis#
We extend the bridge to handle wind effects.
# define the WindLoadedBridge class, make sure that it inherits from Bridge
...
"""A bridge class that accounts for wind loading effects.
This class extends the base Bridge class to include wind force calculations
and analysis. It provides methods to analyze and visualize the combined effects
of traffic and wind loads on the bridge structure.
Args:
name (str): Name of the bridge
length (float): Length of the bridge in meters
wind_load (float): Wind load force per unit length (N/m)
Attributes:
bridge (Bridge): Reference to the base bridge object
wind_load (float): Wind load magnitude
"""
# define the __init__ method, make sure that it calls the __init__ method of the Bridge class, use super() to do this, it should take the arguments from the docstring
...
# This is where you should call the __init__ method of the Bridge class, use super() to do this, it should take the arguments from the docstring
...
def plot_bending_moment(self):
"""Plots the bending moment distribution with LaTeX equations.
Creates a matplotlib figure showing three curves:
1. Bending moment due to traffic load
2. Bending moment due to wind load
3. Total combined bending moment
The plot includes LaTeX formatted equations in the legend explaining
the moment calculations. Grid lines and proper axis labels are included
for clarity.
"""
# Compute the bending moment due to traffic load
# set x to be a linspaced array from 0 to the length of the bridge with 100 points, use np.linspace
# set M_traffic to be the bending moment due to traffic load using the formula M = qx(L-x)/2, where q is the traffic load, x is the position along the bridge, and L is the length of the bridge, we will assume the traffic load is 5000 N/m
...
# Compute the bending moment due to wind load the expression is M_wind = wind load * x * (bridge length - x)
...
# Compute the total bending moment the expression is M_total = M_traffic + M_wind
...
# Plot the bending moment distribution
# make a figure using the plt.figure() function, and assign it to the variable fig
# make an axis using the fig.add_subplot(111) function, and assign it to the variable ax
...
# on the same axis, plot the bending moment due to traffic load, the bending moment due to wind load, and the total bending moment
# use the ax.plot() function to plot the bending moment due to traffic load, the bending moment due to wind load, and the total bending moment
# set the label of the bending moment due to traffic load to be r"Traffic Load: $M(x) = \frac{q x (L-x)}{2}$"
# set the label of the bending moment due to wind load to be r"Wind Load: $M_{wind}(x) = W x (L - x)$", set the linestyle to be dashed
# set the label of the total bending moment to be r"Total Moment: $M_{total} = M + M_{wind}$"
...
# set the xlabel of the axis to be "Position along bridge (m)"
# set the ylabel of the axis to be "Bending Moment (Nยทm)"
# set the title of the axis to be "Effect of Wind Load on Bending Moment"
# call the legend of the axis using the ax.legend() function
# call the grid of the axis using the ax.grid() function
# call the show of the figure using the plt.show() function
...
grader.check("WindLoadedBridge-Class")
Question 4 (Points: 21.0): Step 5: Running the Full Analysis#
Create and Evaluate a Bridge#
# Create a bridge
# create a bridge object with the name "Golden Gate", length 100 meters, and elastic modulus 2.1e11 Pa
# length is 100 meters,
...
# Add a beam component
# create a beam, `beam` object with the material "Steel", length 100 meters, elastic modulus 4e8 Pa, yield strength 250e6 Pa, safety factor 1.5, moment of inertia 5e-3 m^4, neutral axis distance 0.5, and uniform load 5000 N/m
# material is "Steel", length is 100 meters, yield strength is 250e6 Pa, safety factor is 1.5, moment of inertia is 5e-3 m^4, neutral axis distance is 0.5, and uniform load is 5000 N/m
...
# Add a cable component
# create a cable, `cable` object with the material "High-strength Steel", length 150 meters, elastic modulus 210e11 Pa, yield strength 400e6 Pa, safety factor 2.0, tension force 1e6 N, and cross-sectional area 0.01 m^2
# material is "High-strength Steel", length is 150 meters, yield strength is 400e6 Pa, safety factor is 2.0, tension force is 1e6 N, and cross-sectional area is 0.01 m^2
...
# Add components to the bridge
# add the beam and the cable to the bridge
...
# Perform safety check
...
# Plot deflection
...
# Analyze wind load
# create a wind loaded bridge, `wind_bridge` object with the bridge `golden_gate` and wind load 3000 N/m
# name is "Golden Gate", length is 100 meters and wind load is 3000 N/m
...
# plot the bending moment of the wind loaded bridge using the plot_bending_moment method
...
grader.check("GoldenGateBridge-Class")
Question 5 (Points: 21.0): Interactive Visualization#
As an engineer you might want to see how adjusting one parameter influences all the other design parameters. Python provides powerful tools for interactive calculations and visualization.
# Import necessary modules for interactive widgets and display
# import ipywidgets as widgets
# import from IPython.display import display
...
# Adjusted style for better spacing
style = {'description_width': '200px'}
layout = widgets.Layout(width='70%')
# Widgets for Beam parameters
beam_length_slider = widgets.FloatSlider(
value=100,
min=10,
max=300,
step=10,
description='Beam Length (m):',
continuous_update=False,
style=style,
layout=layout
)
# Widgets for Beam parameters
beam_yield_strength_slider = widgets.FloatSlider(
value=250e6,
min=100e6,
max=500e6,
step=10e6,
description='Yield Strength (Pa):',
continuous_update=False,
style=style,
layout=layout
)
# Add a widget for the beam safety factor, follow the same pattern as the beam yield strength slider
# set the default value to be 1.5, the minimum to be 1.0, the maximum to be 3.0, the step to be 0.1, the description to be "Safety Factor:", and the continuous_update to be False, style and layout should be the same as the beam yield strength slider
...
# Add a widget for the beam moment of inertia, follow the same pattern as the beam yield strength slider
# set the default value to be 5e-3, the minimum to be 1e-4, the maximum to be 1e-2, the step to be 1e-4, the description to be "Moment of Inertia (m^4):", and the continuous_update to be False, style and layout should be the same as the beam yield strength slider
...
# we have provided the rest of the widgets for the beam parameters
beam_uniform_load_slider = widgets.FloatSlider(
value=5000,
min=1000,
max=20000,
step=500,
description='Uniform Load (N/m):',
continuous_update=False,
style=style,
layout=layout
)
# Widgets for Cable parameters
cable_length_slider = widgets.FloatSlider(
value=150,
min=50,
max=300,
step=10,
description='Cable Length (m):',
continuous_update=False,
style=style,
layout=layout
)
cable_yield_strength_slider = widgets.FloatSlider(
value=400e6,
min=200e6,
max=800e6,
step=20e6,
description='Cable Yield Strength (Pa):',
continuous_update=False,
style=style,
layout=layout
)
cable_safety_factor_slider = widgets.FloatSlider(
value=2.0,
min=1.0,
max=3.0,
step=0.1,
description='Cable Safety Factor:',
continuous_update=False,
style=style,
layout=layout
)
cable_tension_force_slider = widgets.FloatSlider(
value=1e6,
min=5e5,
max=2e6,
step=1e5,
description='Tension Force (N):',
continuous_update=False,
style=style,
layout=layout
)
cable_cross_section_area_slider = widgets.FloatSlider(
value=0.01,
min=0.005,
max=0.05,
step=0.005,
description='Cross Section Area (m^2):',
continuous_update=False,
style=style,
layout=layout
)
# Widget for Wind Load
wind_load_slider = widgets.FloatSlider(
value=3000,
min=1000,
max=10000,
step=500,
description='Wind Load (N/m):',
continuous_update=False,
style=style,
layout=layout
)
# Function to update the bridge model and plots, this should be called update_bridge, it should take the arguments from the widgets
# beam_length, beam_yield_strength, beam_safety_factor, beam_moment_of_inertia, beam_uniform_load,
# cable_length, cable_yield_strength, cable_safety_factor, cable_tension_force, cable_cross_section_area,
# wind_load
...
# create a bridge object with the name "Golden Gate", length 100 meters, and elastic modulus 2.1e11 Pa
# length is 100 meters
...
# Create beam with updated parameters
# material is "Steel", length is beam_length, elastic modulus is 4e8 Pa, yield strength is beam_yield_strength, safety factor is beam_safety_factor, moment of inertia is beam_moment_of_inertia, neutral axis distance is 0.5, and uniform load is beam_uniform_load
...
# Create cable with updated parameters
# material is "High-strength Steel", length is cable_length, elastic modulus is 2.1e11 Pa, yield strength is cable_yield_strength, safety factor is cable_safety_factor, tension force is cable_tension_force, and cross-sectional area is cable_cross_section_area
...
# Add components to the bridge
# add the beam and the cable to the bridge
...
# Perform safety check
# print the safety check results
print("Safety Check Results:")
# call the check_safety method
...
# Plot deflection
print("Beam Deflection:")
...
# Analyze wind load
print("Wind Load Analysis:")
# wind_bridge is a WindLoadedBridge object with the bridge golden_gate and wind_load
# name is "Golden Gate", length is 100 meters and wind load is wind_load
...
# plot the bending moment of the wind loaded bridge using the plot_bending_moment method
...
# Interactive display, widgets should be the same as the ones defined above
interactive_plot = widgets.interactive(
update_bridge,
beam_length=beam_length_slider,
beam_yield_strength=beam_yield_strength_slider,
beam_safety_factor=beam_safety_factor_slider,
beam_moment_of_inertia=beam_moment_of_inertia_slider,
beam_uniform_load=beam_uniform_load_slider,
cable_length=cable_length_slider,
cable_yield_strength=cable_yield_strength_slider,
cable_safety_factor=cable_safety_factor_slider,
cable_tension_force=cable_tension_force_slider,
cable_cross_section_area=cable_cross_section_area_slider,
wind_load=wind_load_slider
)
plt.ion()
# display the interactive plot
display(interactive_plot)
grader.check("InteractiveVisualization-Class")
Submitting Assignment#
Please run the following block of code using shift + enter
to submit your assignment, you should see your score.
from pykubegrader.submit.submit_assignment import submit_assignment
submit_assignment("week8-lab", "1_lab_building_bridge")