π Introduction to Loops with Integrals#
Utility of loops#
Branching causes specific blocks of code to be executed only under certain conditions. The conditions are articulated as logical expressions.
How do you write loops?#
The simplest version of loop is a βfor loopβ.
for looping_variable in sequence:
code_block
# List of engineering disciplines offered at Drexel University
engineering_disciplines = ['Biomedical Engineering', 'Chemical Engineering', 'Civil Engineering', 'Electrical Engineering', 'Mechanical Engineering', 'Computer Engineering']
# Simple for loop to print each discipline
for discipline in engineering_disciplines:
print(f"Drexel University offers a program in {discipline}.")
Drexel University offers a program in Biomedical Engineering.
Drexel University offers a program in Chemical Engineering.
Drexel University offers a program in Civil Engineering.
Drexel University offers a program in Electrical Engineering.
Drexel University offers a program in Mechanical Engineering.
Drexel University offers a program in Computer Engineering.
For Loops with Branching#
# Sample voltage measurements
voltage_measurements = [0.5, 3.3, 5.5, 10.2, 12.0, 15.5, 3.3, 12.0, 2.8, 11.1]
# Safe operating levels
lower_threshold = 3.3
upper_threshold = 12.0
# Initialize lists to hold filtered results
safe_voltages = []
threshold_voltages = []
for voltage in voltage_measurements:
# Check if voltage is within safe operating levels
if lower_threshold < voltage < upper_threshold:
safe_voltages.append(voltage)
# Check if voltage is exactly at the threshold values
elif voltage == lower_threshold or voltage == upper_threshold:
threshold_voltages.append(voltage)
print("Safe operating voltage measurements:", safe_voltages)
print("Voltage measurements at threshold levels:", threshold_voltages)
Safe operating voltage measurements: [5.5, 10.2, 11.1]
Voltage measurements at threshold levels: [3.3, 12.0, 3.3, 12.0]
Loops with Flow Control#
Sometimes it is important to add conditional flow control to the loops. This can be done with continue, pass, and break statements.
Incorporating continue
, pass
, and break
into the previous example can demonstrate their utility in controlling the flow of a for loop. These statements are useful in Python for managing loop execution under specific conditions:
continue
skips the rest of the code inside the loop for the current iteration and proceeds to the next iteration.pass
does nothing; it acts as a placeholder for future code.break
exits the loop entirely, skipping any remaining iterations.
Modified Example with continue
, pass
, and break
#
# Sample voltage measurements
voltage_measurements = [0.5, 3.3, 5.5, 10.2, -1, 12.0, 15.5, 3.3, 12.0, 2.8, 11.1, -1]
# Safe operating levels
lower_threshold = 3.3
upper_threshold = 12.0
# Initialize lists to hold filtered results
safe_voltages = []
threshold_voltages = []
critical_voltages = []
for voltage in voltage_measurements:
# Check for critical condition (e.g., negative voltage)
if voltage < 0:
print(f"Critical voltage detected: {voltage}V. Investigation required.")
critical_voltages.append(voltage)
break # Exit loop at first sign of critical condition
if voltage == lower_threshold or voltage == upper_threshold:
threshold_voltages.append(voltage)
continue # Skip to the next iteration
if lower_threshold < voltage < upper_threshold:
safe_voltages.append(voltage)
else:
# Placeholder for future condition handling
pass # Do nothing for now
print("Safe operating voltage measurements:", safe_voltages)
print("Voltage measurements at threshold levels:", threshold_voltages)
print("Critical voltage measurements:", critical_voltages)
Critical voltage detected: -1V. Investigation required.
Safe operating voltage measurements: [5.5, 10.2]
Voltage measurements at threshold levels: [3.3]
Critical voltage measurements: [-1]
Explanation#
Critical Condition with
break
: We added a condition at the beginning of the loop to check for critical system failures, exemplified here by negative voltages. If such a condition is detected, a message is printed, the voltage is added tocritical_voltages
, andbreak
is used to exit the loop immediately. This could represent a situation where processing needs to stop because of a significant error or anomaly.Threshold Check with
continue
: After handling the critical condition, we check if the voltage is at either threshold value. If so, we add it tothreshold_voltages
and then usecontinue
to skip the remaining code in the loop, moving directly to the next iteration. This ensures that threshold voltages are not also classified as safe voltages.Placeholder with
pass
: In theelse
clause, where we might handle voltages outside the safe operating range but not critical, we usepass
as a placeholder. This could be where youβd implement additional logic, such as logging these measurements for further analysis. For now, it does nothing but serves as a placeholder for future code.
Loops with Enumerate#
The enumerate
function is a built-in function that returns an iterator of tuples containing indices and values from an iterable. It is often used in loops to keep track of the index of the current item.
# List of signal strength measurements
signal_strengths = [0.1, 0.5, 1.5, 2.5, 1.2, 0.4, 0.9, 2.2, 1.8, 0.2, 0.5]
# Threshold for considering a measurement as a peak
threshold = 2.0
# Loop through the list with enumerate to track index and value
for index, strength in enumerate(signal_strengths):
if strength > threshold:
print(f"Signal peak detected at position {index} with strength {strength}")
Signal peak detected at position 3 with strength 2.5
Signal peak detected at position 7 with strength 2.2
Explanation#
Enumerate Function:
enumerate(signal_strengths)
takes thesignal_strengths
list and returns an enumerate object. This object generates pairs containing the index of each element and the elementβs value itself (index, strength
).Loop with Index and Value: Inside the loop,
index
represents the position of the measurement in the list, andstrength
is the measurement value. This allows us to easily refer to both the measurementβs value and its position.Conditional Check: The
if
statement checks if the current signal strength (strength
) exceeds the definedthreshold
. If it does, it prints a message indicating that a signal peak was detected, including the position (index
) and the strength of the signal.
Loops on Dictionaries#
# Dictionary of construction materials and their properties
construction_materials = {
'concrete': {'density': 2400, 'compressive_strength': 30, 'cost_per_unit': 70},
'steel': {'density': 7850, 'compressive_strength': 250, 'cost_per_unit': 250},
'wood': {'density': 700, 'compressive_strength': 40, 'cost_per_unit': 50},
'brick': {'density': 2000, 'compressive_strength': 20, 'cost_per_unit': 40}
}
# Loop through the dictionary to analyze materials
for material, properties in construction_materials.items():
print(f"Analyzing {material}:")
for property, value in properties.items():
print(f" {property}: {value}")
# Identifying materials with compressive strength above a threshold
strength_threshold = 50
print("\nMaterials with compressive strength above 50 MPa:")
for material, properties in construction_materials.items():
if properties['compressive_strength'] > strength_threshold:
print(f"- {material}")
Analyzing concrete:
density: 2400
compressive_strength: 30
cost_per_unit: 70
Analyzing steel:
density: 7850
compressive_strength: 250
cost_per_unit: 250
Analyzing wood:
density: 700
compressive_strength: 40
cost_per_unit: 50
Analyzing brick:
density: 2000
compressive_strength: 20
cost_per_unit: 40
Materials with compressive strength above 50 MPa:
- steel
Explanation#
Looping Through Dictionary: The
for material, properties in construction_materials.items():
loop iterates over theconstruction_materials
dictionary.material
is the key (e.g., βconcreteβ, βsteelβ), andproperties
is the value, which is another dictionary containing the properties of each material.Nested Loop for Properties: Inside the first loop, another loop iterates through the properties of each material. This nested loop allows for printing out all properties of each material in a readable format.
Conditional Analysis: After printing the details of each material, another loop filters materials based on their compressive strength, identifying those with values above a certain threshold (in this case, 50 MPa). This demonstrates how to apply conditions to selectively process or analyze data within a dictionary.
Loops with Zips#
# Molar masses of compounds in g/mol (for simplicity, assume uniform across mixtures)
molar_masses = [18.01528, 44.01, 28.0134] # Water (H2O), Carbon Dioxide (CO2), Nitrogen (N2)
# Mass fractions of each compound in three different mixtures
mixture_1_fractions = [0.8, 0.1, 0.1]
mixture_2_fractions = [0.3, 0.6, 0.1]
mixture_3_fractions = [0, 0.4, 0.6]
# List of all mixture fractions for iteration
mixtures_fractions = [mixture_1_fractions, mixture_2_fractions, mixture_3_fractions]
# Calculate and print the average molar mass for each mixture
for mixture in mixtures_fractions:
average_molar_mass = sum(m * f for m, f in zip(molar_masses, mixture))
print(f"Average molar mass of mixture: {average_molar_mass:.2f} g/mol")
Average molar mass of mixture: 21.61 g/mol
Average molar mass of mixture: 34.61 g/mol
Average molar mass of mixture: 34.41 g/mol
Explanation#
Zip Function:
zip(molar_masses, mixture)
pairs each molar mass with its corresponding mass fraction in the mixture. This is crucial for performing calculations that depend on corresponding elements from multiple lists.Loop Over Mixtures: The outer loop
for mixture in mixtures_fractions:
iterates over each list of mass fractions (each representing a different mixture).List Comprehension with Zip: Inside the loop, a list comprehension calculates the product of the molar mass and the mass fraction for each compound in the current mixture.
sum(...)
then adds these products together to get the average molar mass of the mixture.Print Results: For each mixture, the calculated average molar mass is printed, formatted to two decimal places.
While Loops#
While loops are used to execute a block of code repeatedly as long as a specified condition is true. This is useful when the number of iterations is not known beforehand and depends on certain conditions being met.
You must be careful for a while loop to not run indefinitely. This can happen if the condition never becomes false. This is called an infinite loop and can cause the program to become unresponsive.
while logical_expression:
# code_block is repeated until logical expression is false
code_block
Example: Estimating the Square Root using Newtonβs Method#
Newtonβs method, also known as the Newton-Raphson method, is an efficient, iterative approach for finding approximations to the roots (or zeroes) of a real-valued function. This example demonstrates how a while loop can be used to implement Newtonβs method for estimating the square root of a number, a basic yet practical application in engineering for tasks such as stress analysis, signal processing, and control systems design.
Newtonβs Method for Square Roots#
The Newton-Raphson formula to find the square root of a number x
can be simplified as:
where estimate
is the current approximation of the square root of x
, and new_estimate
is the improved approximation.
def estimate_sqrt(target, tolerance=1e-6):
"""
Estimates the square root of a given number using Newton's method.
Parameters:
- target: The number to estimate the square root of.
- tolerance: The tolerance for the difference between successive estimates.
Returns:
- float: The estimated square root of the target.
"""
estimate = target / 2.0 # Initial estimate
while True:
new_estimate = 0.5 * (estimate + target / estimate)
# Check if the difference between successive estimates is within the tolerance
if abs(new_estimate - estimate) < tolerance:
break
estimate = new_estimate
return estimate
# Example usage
number = 25
sqrt_estimate = estimate_sqrt(number)
print(f"Estimated square root of {number}: {sqrt_estimate:.6f}")
Estimated square root of 25: 5.000000
Explanation#
Initial Estimate: The initial guess for the square root is half the target value, a common starting point for positive numbers.
While Loop: The loop continues iterating until the difference between successive estimates of the square root is smaller than a specified tolerance, indicating convergence.
Break Condition: The loop exits (
break
) when the change between the current and new estimate is within the desired tolerance, signifying that further iterations would not significantly improve the approximation.Return Value: Once the loop exits, the function returns the last calculated estimate as the square root of the target number.
Useful for User Interactions#
useful when you have a system waiting for a user response β for example, a game waiting for a player to make a move, or a chatbot waiting for a user to input a message. Commonly called callbacks.
import ipywidgets as widgets
from IPython.display import display, clear_output
button = widgets.Button(description="Add")
output = widgets.Output()
display(button, output)
current_value = 0
target_value = 10
def on_button_clicked(b):
global current_value # Access the global variable
with output:
clear_output(wait=True) # Clear the previous output
if current_value < target_value:
current_value += 1 # Increment the current value
print(f"Current Value: {current_value}")
else:
print("Target reached!")
button.on_click(on_button_clicked)
While Loops with Flow Control Statements#
Real Example: Water Treatment Chemical Dosage Optimization#
Scenario: In a water treatment process, the optimal chemical dosage for treating a batch of water depends on various factors like water quality parameters (e.g., pH, turbidity) and chemical concentration. The goal is to iteratively adjust the chemical dosage based on the water quality outcome, aiming for a target quality level with minimal chemical usage.
The process involves incrementally adjusting the chemical dosage and observing the resulting water quality. If the water quality meets the target criteria, the process stops. If not, the dosage is adjusted based on the observed quality.
Simplified Logic for Dosage Optimization#
Objective: Find the optimal dosage of a treatment chemical to achieve a target turbidity level in water.
Assumptions:
Initial chemical dosage is set based on standard practice.
Turbidity level is measured after each treatment iteration.
The process is limited to a maximum number of iterations to prevent excessive chemical use.
Pseudo-Logic:
Initialize variables: initial dosage, target turbidity, maximum iterations.
Iterate with adjustments until the target turbidity is reached or the maximum iterations are exceeded.
Adjust dosage based on the difference between current and target turbidity levels.
Incorporate
break
for success,continue
for minor adjustments, and error handling for unexpected measurements.
import numpy as np # For random number generation
import random # To simulate changes in turbidity
def optimize_chemical_dosage(initial_dosage, target_turbidity, max_iterations=10):
dosage = initial_dosage
iteration = 0
while iteration < max_iterations:
iteration += 1
# Simulate measuring turbidity after applying the current dosage
current_turbidity = target_turbidity + (random.random() - 0.5) * 2 # Random fluctuation
print(f"Iteration {iteration}: Current Turbidity = {current_turbidity:.2f}, Dosage = {dosage:.2f}")
# Check if target turbidity is achieved
if abs(current_turbidity - target_turbidity) <= 0.1: # Tolerance level
print("Target turbidity level achieved.")
break
# Adjust dosage based on the difference from target
elif current_turbidity > target_turbidity:
dosage += 0.1 # Increase dosage
elif current_turbidity < target_turbidity:
dosage -= 0.1 # Reduce dosage if above target to save chemical
if dosage < 0: # Error handling for negative dosage
print("Error: Dosage calculation went below zero.")
break
# Check for last iteration without success
if iteration == max_iterations:
print("Maximum iterations reached without achieving target turbidity.")
return dosage
random.seed(0) # Set seed for reproducibility
# Example usage
initial_dosage = 1.0 # Initial chemical dosage in some units
target_turbidity = 1.0 # Target turbidity level
final_dosage = optimize_chemical_dosage(initial_dosage, target_turbidity)
print(f"Final optimized chemical dosage: {final_dosage:.2f}")
Iteration 1: Current Turbidity = 1.69, Dosage = 1.00
Iteration 2: Current Turbidity = 1.52, Dosage = 1.10
Iteration 3: Current Turbidity = 0.84, Dosage = 1.20
Iteration 4: Current Turbidity = 0.52, Dosage = 1.10
Iteration 5: Current Turbidity = 1.02, Dosage = 1.00
Target turbidity level achieved.
Final optimized chemical dosage: 1.00
Explanation#
Simulation: The change in turbidity after each treatment is simulated with a random fluctuation around the target to mimic real-world uncertainty.
Dosage Adjustment: Dosage is adjusted iteratively based on whether the current turbidity is above or below the target.
Flow Control:
break
exits the loop once the target is met or an error (negative dosage) occurs. The loop also stops if the maximum iterations are reached, indicating a potential problem with the process or the assumptions.Error Handling: Checks for negative dosage values to prevent illogical treatment scenarios.
Using loops in integration#
Many engineering applications require integration, which can be understood as calculating the area under a curve. For example, consider the following:
estimating the force of water against a bridge or dam
determining the amount of time a reactor should operate for a given chemical to be produced
processing audio or electrical signals into meaningful input
determining the force required to move an object a given distance
For example, to deposit materials on graphene, one could observe the progress of experiments over time to find the amount of mass deposited to optimize the conditions for deposition.
The Riemann integral is the simplest method of approximating the area under a curve. One simply
divides the area under the curve into rectangles of equal width \(h\) and height \(f(x_i)\),
calculates the area for each rectangle using \(A_i = hf(x_i)\), and
sums the areas of each rectangle between some smaller value of \(x\) called \(a\) and a larger value of \(x\) called \(b\).
Mathematically, this process is expressed as