diff options
| author | Christian Kolset <christian.kolset@gmail.com> | 2025-04-29 15:17:05 -0600 |
|---|---|---|
| committer | Christian Kolset <christian.kolset@gmail.com> | 2025-04-29 15:17:05 -0600 |
| commit | ff4b21339f32625e169a0dd54c5cc4dc50e0ecd6 (patch) | |
| tree | 03786ae7b5ec74431a36dcc7ce08a74b9af128dd /tutorials/module_1 | |
| parent | f1cc185b2571715b3077c9ea8ed601940a8f4932 (diff) | |
Added error tutorial
Diffstat (limited to 'tutorials/module_1')
| -rw-r--r-- | tutorials/module_1/errorPlots.py | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/tutorials/module_1/errorPlots.py b/tutorials/module_1/errorPlots.py new file mode 100644 index 0000000..8351fc8 --- /dev/null +++ b/tutorials/module_1/errorPlots.py @@ -0,0 +1,144 @@ +# Import required packages +import numpy as np +import matplotlib.pyplot as plt + +# --------------------------------------------------------------------------- +# PART 1: Visualizing Truncation Error and Approximate Integral +# --------------------------------------------------------------------------- + +# Generate true curve: y = sin(x) +x_fine = np.linspace(0, np.pi/2, 400) +y_fine = np.sin(x_fine) + +# Linear approximation (straight line between 0 and pi/2) +x_line = np.array([0, np.pi/2]) +y_line = np.sin(x_line) + +# Plot true curve and linear approximation +plt.figure(figsize=(8, 6)) + +plt.plot(x_fine, y_fine, label='True function: $y = \sin(x)$', color='black', linewidth=3) +plt.plot(x_line, y_line, label='Linear approximation', color='red', linestyle='--', linewidth=2) + +# Shade area between true curve and linear approximation (truncation error) +plt.fill_between(x_fine, y_fine, np.interp(x_fine, x_line, y_line), + where=(y_fine > np.interp(x_fine, x_line, y_line)), + interpolate=True, color='gray', alpha=0.5, label='Truncation Error') + +# Shade approximate integral (area under linear approximation) +plt.fill_between(x_fine, 0, np.interp(x_fine, x_line, y_line), + color='lightblue', alpha=0.5, label='Approximate Integral') + +# Remove ticks +plt.xticks([]) +plt.yticks([]) +plt.grid(False) + +# Labels and title +plt.xlabel('x', fontsize=20) +plt.ylabel('y', fontsize=20) +plt.title('Truncation Error', fontsize=22) +plt.legend(fontsize=16, loc='lower right') +plt.tight_layout() +plt.show() + +# --------------------------------------------------------------------------- +# PART 2: Error Plot for Truncation, Round-off, and Total Errors +# --------------------------------------------------------------------------- + +# Set up for log-log error plot +h = np.logspace(-16, -1, 400) +truncation_error = 1e-1 * h +roundoff_error = 1e-16 / h +total_error = truncation_error + roundoff_error + +# Find minimum total error point +min_idx = np.argmin(total_error) +min_h = h[min_idx] +arrow_target_h = 2.5 * min_h +arrow_target_err = total_error[np.argmin(np.abs(h - arrow_target_h))] + +# Plot errors +plt.figure(figsize=(10, 7)) + +plt.loglog(h, truncation_error, label='Truncation error', linewidth=3, color='blue') +plt.loglog(h, roundoff_error, label='Round-off error', linewidth=3, color='orange') +plt.loglog(h, total_error, label='Total error', linewidth=4, color='black') + +# Annotation +plt.annotate('Point of\n diminishing\n returns', + xy=(arrow_target_h, arrow_target_err), xycoords='data', + xytext=(arrow_target_h, 15 * arrow_target_err), textcoords='data', + arrowprops=dict(arrowstyle='->', lw=2), + fontsize=20, ha='center') + +# Remove ticks and grid +plt.xticks([]) +plt.yticks([]) +plt.grid(False) + +# Labels and legend +plt.xlabel('Log step size', fontsize=22) +plt.ylabel('Log error', fontsize=22) +plt.legend(fontsize=20, loc='upper right') +plt.tight_layout() +plt.show() + + +# --------------------------------------------------------------------------- +# PART 3: Error Plot for Truncation with more steps +# --------------------------------------------------------------------------- + +# Fix legend duplication and improve clarity +import numpy as np +import matplotlib.pyplot as plt + +# Generate true curve: y = sin(x) over 0 to π +x_fine = np.linspace(0, np.pi, 800) +y_fine = np.sin(x_fine) + +# Choose multiple linear segments +n_steps = 3 # number of straight line segments +x_steps = np.linspace(0, np.pi, n_steps + 1) +y_steps = np.sin(x_steps) + +# Plot true curve +plt.figure(figsize=(8, 6)) +plt.plot(x_fine, y_fine, label='True function: $y = \\sin(x)$', color='black', linewidth=3) + +# Plot piecewise linear approximation +plt.plot(x_steps, y_steps, label='Linear approximation', color='red', linestyle='--', linewidth=2) + +# Track whether we've added the truncation label already +truncation_label_added = False + +# Shade truncation error (avoid duplicate legend entry) +for i in range(n_steps): + x_segment = np.linspace(x_steps[i], x_steps[i+1], 100) + y_segment_line = np.interp(x_segment, [x_steps[i], x_steps[i+1]], [y_steps[i], y_steps[i+1]]) + y_segment_true = np.sin(x_segment) + + label = 'Truncation error' if not truncation_label_added else None + plt.fill_between(x_segment, y_segment_true, y_segment_line, + where=(y_segment_true > y_segment_line), + interpolate=True, color='gray', alpha=0.5, label=label) + truncation_label_added = True + +# Shade approximate integral under the piecewise linear approximation +plt.fill_between(x_fine, 0, np.interp(x_fine, x_steps, y_steps), + color='lightblue', alpha=0.5, label='Approximate integral') + +# Remove ticks +plt.xticks([]) +plt.yticks([]) +plt.grid(False) + +# Labels and title +plt.xlabel('x', fontsize=20) +plt.ylabel('y', fontsize=20) +plt.title('Truncation Error', fontsize=24) +plt.legend(fontsize=16, loc='lower right') +plt.tight_layout() +plt.show() + + |
