---
author:
- Debugging, testing, and troubleshooting
date: "by [Eugeniy E. Mikhailov](http://physics.wm.edu/~evmik/) and
  [Greg Bentsen](https://physics.wm.edu/~gbentsen/)"
title: Coding Lab 4
---

## Logistics and Agenda

Homework 2 due Monday Sept 14 at 11:59pm

\

Agenda

-   This week:  VSCode IDE: editing, debugging, project management
-   Next week:  AI tools, data reduction & fitting

\

Today

-   Debugging best practices (10 min)
-   Parsing error messages (10 min)
-   Coding time (30 min)

## Homework logistics:

-   You may **run unit tests in Gradescope** to confirm correct
    execution
-   You may **resubmit as many times as you like** until the deadline
-   Split your code into **implementation** and **tests**
    -   Implementation files (e.g. `p6.py`) will be graded by the
        autograder
    -   Tests / figures should be run separately and results included in
        the report

::: columns
::: {.column width="45%"}
Implementation file

![](./pics/implementation_file.png){width="60%"}
:::

::: {.column width="45%"}
Test file

![](./pics/test_file.png){width="60%"}
:::
:::

## Debugging, testing, and troubleshooting

For better or for worse: **most of your time will be spent debugging,
testing, and troubleshooting your code.**

This is especially true now that AI tools have become available.

\

::: incremental
**Debugging is like detective work**

-   It pays to have good hunches.
-   You must systematically **evaluate** and **eliminate** these hunches
    based on evidence.

\

**It also pays to "think like a scientist"**

-   Be skeptical of everything (especially AI-generated code).
-   Regularly **test, verify, and validate** using controlled
    experiments.
:::

## Testing, troubleshooting and the scientific method

::: incremental
**It pays to "think like a scientist"**

::: columns
::: {.column width="45%"}
1.  Make observations
2.  Form hypotheses
3.  Design an experiment to test your hypotheses
4.  Draw conclusions
:::

::: {.column width="45%"}
1.  "This function is returning 0 when it should be returning 3.14"
2.  "Perhaps my loop is not doing any iterations"
3.  "Include an increment variable `count` that counts how many times
    the loop runs"
4.  "I see that `count = 5` so my loop is iterating correctly. The
    problem must lie elsewhere"
:::
:::
:::

## Debugging, testing, and troubleshooting

::: incremental
**Useful questions to ask before errors occur:**

-   Is my code giving me the result I expect?
-   Do my results match with simple known cases?
-   Does my code agree with existing implementations?
-   Does my code break if I give it edge cases?

\

**Useful questions to ask when errors occur:**

-   Pinpoint the error: where exactly does my code "go off the rails"?
-   Reproduce the error: can I make the error happen on purpose?
-   Modularity: can I isolate the problematic behavior to a single line
    of code? Or a single function?
:::

## Practical advice

::: incremental
-   Benchmark your results against known, simple / analytic results
    ("sanity checks")
-   Use the debugger to step through the code line by line
-   Systematically check internal varibles against your expectations
    -   Use watch or print statements
-   Write pseudocode before, during, and after
-   Check edge cases
-   Understand error messages, even when they look complicated
    -   Do not just blindly feed them to a chat bot (although sometimes
        this can be useful)
-   When possible, exploit non-trivial checks
    -   For example, conservation of energy, momentum, etc
:::

## Debugging practice

Practice using 2D arrays and the debugger to parse error messages

``` {.python .numberLines}
import numpy as np
from plot_array import *

# Define array
temperature = np.array([
    [20.1, 20.4, 20.8, 21.0],
    [19.8, 20.2, 20.6, 20.9],
    [19.5, 19.9, 20.3, 20.7]
])

# Plot array
plot_array(temperature, "temps.png")


# -----------------------------------------------------------------

# Array indexing
val_00 = temperature[0,0]
val_23 = temperature[2,3]
# val_32 = temperature[3,2]

col_0 = temperature[:,0]
col_1 = temperature[:,1]
row_1 = temperature[1,:]

col_m1 = temperature[-1,:]



# -----------------------------------------------------------------

# Combing rows and columns?
# combined = col_0 + row_1

combined = col_0 + col_1



# -----------------------------------------------------------------

# Find all grid points hotter than 20.5 degrees
hot_points = temperature > 20.5

plot_array(hot_points, "hot_points.png")



# -----------------------------------------------------------------

# Computing averages across rows and columns
column_means = np.mean(temperature, axis=1)
print("Column means:", column_means)



# -----------------------------------------------------------------

# Compute approximate derivative in x direction
dx = 0.5
dTdx = np.zeros_like(temperature)

for i in range(temperature.shape[0]):
    for j in range(1, temperature.shape[1]-1):
        dTdx[i, j] = (temperature[i, j + 1] - temperature[i, j - 1]) / (2 * dx)

print("dT/dx:")
print(dTdx)
```
