Module: Modules_File_I
Assignment Type: Problem-Solving Exercise
Estimated Time: 2–4 hours
Submission Format: Google Colab notebook link (shared with comment access) or a written report (PDF or DOCX) that includes all code, outputs, and written responses
Real engineering and scientific data is rarely perfect. Instruments introduce measurement error, and theoretical models make simplifying assumptions that may or may not hold under real conditions. In this exercise, you will act as a data analyst examining experimentally collected gas-behavior data to evaluate two models of gas behavior:
1. The Ideal Gas Law: PV = nRT (simplified model)
2. The Van der Waals Equation: (P + a·n²/V²)(V − n·b) = nRT (corrected model)
You will use Python's standard library modules and file I/O tools — exactly the skills covered in this module — to load, process, analyze, and report on the data. This workflow mirrors what engineers and scientists do daily: load data from instruments, apply a model, visualize agreement (or disagreement), and draw defensible conclusions.
This assignment directly practices:
math, csv, os, datetime, sys, pathlib)with statement for safe file handlingBy the end of this assignment, you will be able to:
1. Construct a Python script that reads experimental data from a CSV file and writes processed results to a new CSV file using csv.DictReader, csv.DictWriter, and the with statement.
2. Apply standard library modules (math, os, datetime, pathlib) to perform engineering calculations and manage file paths in a cross-platform manner.
3. Analyze the deviation between experimentally observed pressure values and values predicted by both the Ideal Gas Law and the Van der Waals equation by calculating and interpreting percent error.
4. Evaluate the relative accuracy of the Ideal Gas Law versus the Van der Waals equation for a real gas by interpreting visual plots and numerical error metrics, and construct a written argument that accounts for measurement uncertainty.
The Ideal Gas Law assumes gas molecules have no volume and exert no intermolecular forces:
`
P = nRT / V
`
Where:
The Van der Waals equation corrects the Ideal Gas Law for two physical realities:
`
P = nRT / (V - nb) - a n² / V²
`
Where a and b are gas-specific constants. For this assignment, you are analyzing carbon dioxide (CO₂):
| Constant | Value | Units |
|---|---|---|
| a | 0.3658 | Pa·m⁶·mol⁻² |
| b | 4.286 × 10⁻⁵ | m³·mol⁻¹ |
> Note: These constants have known accepted (theoretical/literature) values. Your job is to use these accepted values to generate predicted pressures and compare them to the measured data.
Percent error quantifies how far a model's prediction is from the measured value:
`
percent_error = ((predicted - measured) / measured) * 100
`
A value near zero indicates good agreement. A positive value means the model over-predicts; a negative value means it under-predicts.
No instrument reads perfectly. Assume the pressure sensor used to collect this data has a manufacturer-specified accuracy of ±1.5% of the measured value. This means any percent error within ±1.5% may be attributable to instrument error alone, not model error. You must address this in your conclusions.
Copy the data below into a plain text file named co2_experimental_data.csv and upload it to your Colab session, or create the file programmatically in Colab using the code provided in the starter notebook.
The dataset contains measurements taken on CO₂ at varying temperatures and volumes. The number of moles n = 1.000 mol is held constant across all trials.
`
trial_id,temperature_K,volume_m3,n_mol,measured_pressure_Pa
1,300.0,0.002500,1.000,997200
2,300.0,0.003000,1.000,829500
3,300.0,0.004000,1.000,621800
4,300.0,0.005000,1.000,497100
5,325.0,0.002500,1.000,1079600
6,325.0,0.003000,1.000,898200
7,325.0,0.004000,1.000,673100
8,325.0,0.005000,1.000,538500
9,350.0,0.002500,1.000,1161400
10,350.0,0.003000,1.000,967100
11,350.0,0.004000,1.000,724700
12,350.0,0.005000,1.000,579600
13,375.0,0.002500,1.000,1243700
14,375.0,0.003000,1.000,1036100
15,375.0,0.004000,1.000,776600
16,375.0,0.005000,1.000,620900
17,400.0,0.002500,1.000,1325600
18,400.0,0.003000,1.000,1105300
19,400.0,0.004000,1.000,828700
20,400.0,0.005000,1.000,662400
`
A starter notebook with scaffolding code is provided below. Copy this into a new Colab notebook. Sections marked # TODO require you to write the code. Sections marked # PROVIDED are complete and should not be modified.
`python
import math
import csv
import os
import sys
from datetime import datetime
from pathlib import Path
import matplotlib.pyplot as plt # available in Colab by default
R = 8.314 # Universal gas constant, J·mol⁻¹·K⁻¹
A_VDW = 0.3658 # Van der Waals constant a for CO₂, Pa·m⁶·mol⁻²
B_VDW = 4.286e-5 # Van der Waals constant b for CO₂, m³·mol⁻¹
SENSOR_ERROR_PCT = 1.5 # Instrument accuracy ±1.5%
INPUT_FILE = Path("co2_experimental_data.csv")
OUTPUT_FILE = Path("co2_analysis_results.csv")
raw_data = """trial_id,temperature_K,volume_m3,n_mol,measured_pressure_Pa
1,300.0,0.002500,1.000,997200
2,300.0,0.003000,1.000,829500
3,300.0,0.004000,1.000,621800
4,300.0,0.005000,1.000,497100
5,325.0,0.002500,1.000,1079600
6,325.0,0.003000,1.000,898200
7,325.0,0.004000,1.000,673100
8,325.0,0.005000,1.000,538500
9,350.0,0.002500,1.000,1161400
10,350.0,0.003000,1.000,967100
11,350.0,0.004000,1.000,724700
12,350.0,0.005000,1.000,579600
13,375.0,0.002500,1.000,1243700
14,375.0,0.003000,1.000,1036100
15,375.0,0.004000,1.000,776600
16,375.0,0.005000,1.000,620900
17,400.0,0.002500,1.000,1325600
18,400.0,0.003000,1.000,1105300
19,400.0,0.004000,1.000,828700
20,400.0,0.005000,1.000,662400"""
with open(INPUT_FILE, 'w', newline='') as f:
f.write(raw_data)
print(f"Input file created: {INPUT_FILE}")
print(f"File exists: {INPUT_FILE.exists()}")
print(f"Working directory: {os.getcwd()}")
print(f"Python version: {sys.version}")
def ideal_gas_pressure(n, R, T, V):
"""
PROVIDED: Calculate pressure using the Ideal Gas Law.
Returns pressure in Pa.
"""
return (n R T) / V
def vdw_pressure(n, R, T, V, a, b):
"""
TODO: Calculate pressure using the Van der Waals equation.
The Van der Waals equation solved for P is:
P = nRT / (V - nb) - a n2 / V2
Parameters
----------
n : float — moles of gas
R : float — gas constant (8.314 J/mol/K)
T : float — temperature in Kelvin
V : float — volume in m³
a : float — Van der Waals constant a
b : float — Van der Waals constant b
Returns
-------
float — predicted pressure in Pa
"""
# TODO: Replace 'pass' with your implementation.
pass
def percent_error(predicted, measured):
"""
TODO: Calculate percent error between predicted and measured values.
Formula: ((predicted - measured) / measured) * 100
Parameters
----------
predicted : float
measured : float
Returns
-------
float — percent error (positive = over-prediction)
"""
# TODO: Replace 'pass' with your implementation.
pass
results = [] # This list will hold one dictionary per trial.
results containing all original#
fieldnames = [] # TODO: Replace [] with your list of field names.
results.trial_ids = [r['trial_id'] for r in results]
measured = [r['measured_pressure_Pa'] for r in results]
p_ideal_list = [r['p_ideal_Pa'] for r in results]
p_vdw_list = [r['p_vdw_Pa'] for r in results]
pct_ideal_list = [r['pct_err_ideal'] for r in results]
pct_vdw_list = [r['pct_err_vdw'] for r in results]
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(trial_ids, measured, 'ko-', label='Measured', linewidth=2)
ax.plot(trial_ids, p_ideal_list, 'b^--', label='Ideal Gas Law')
ax.plot(trial_ids, p_vdw_list, 'rs--', label='Van der Waals')
ax.set_xlabel('Trial ID')
ax.set_ylabel('Pressure (Pa)')
ax.set_title('Predicted vs Measured Pressure — CO₂')
ax.legend()
ax.grid(True)
plt.tight_layout()
plt.savefig('pressure_comparison.png', dpi=150)
plt.show()
print("Plot 1 saved.")
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(trial_ids, pct_ideal_list, 'b^--', label='Ideal Gas Law % Error')
ax.plot(trial_ids, pct_vdw_list, 'rs--', label='Van der Waals % Error')
ax.axhline(y= SENSOR_ERROR_PCT, color='gray', linestyle=':', label='+1.5% sensor limit')
ax.axhline(y=-SENSOR_ERROR_PCT, color='gray', linestyle=':', label='−1.5% sensor limit')
ax.axhline(y=0, color='black', linewidth=0.8)
ax.set_xlabel('Trial ID')
ax.set_ylabel('Percent Error (%)')
ax.set_title('Model Percent Error vs Sensor Accuracy Band — CO₂')
ax.legend()
ax.grid(True)
plt.tight_layout()
plt.savefig('percent_error_comparison.png', dpi=150)
plt.show()
print("Plot 2 saved.")