Shape: (2, 3)
Midterm Post-Test
CU Boulder ATOC
2026-01-01
Let’s talk about what tripped people up.
“What is today’s date?”
Using two nested
forloops over row and column indices, print each entry oftemp_matrixin the formattemp_matrix[ii, jj] = valuefor all validiiandjj, in row-major order.(Do not use
flatten(),ravel(),np.nditer, or vectorized printing.)
Many of you wrote something like:
What this does:
15.2, 18.7, 22.1, …ii and jj to format the output!The question asked for: temp_matrix[ii, jj] = value
You need the indices, not just the values.
temp_matrix.shape gives (2, 3) — unpack into n_rows and n_colsfor ii in range(n_rows) walks through rows: 0, 1for jj in range(n_cols) walks through columns: 0, 1, 2temp_matrix[ii, jj] grabs the element at row ii, column jjLooping over indices (when you need ii, jj):
Looping over values (when you just need the numbers):
Know the difference. The question tells you which one to use.
range(shape) + array[ii, jj]for val in arrayGiven:
Write nested loops to print every element where wind speed exceeds 5.0:
wind_data[0, 0] = 5.2 --> WINDY
wind_data[0, 2] = 8.7 --> WINDY
...
Solution:
wind_data[0, 0] = 5.2 --> WINDY
wind_data[0, 2] = 8.7 --> WINDY
wind_data[1, 0] = 6.1 --> WINDY
wind_data[1, 2] = 7.3 --> WINDY
wind_data[2, 2] = 9.1 --> WINDY
In the Lorenz63 class, the
integrate()method uses a loop to advance the model forward in time. Explain in 1-2 sentences why we need a loop for time integration.
The common (wrong) answer:
“Because we have many time steps and need to repeat the calculation.”
This is too vague. You could say the same thing about converting 1000 temperatures from Celsius to Fahrenheit — but that doesn’t need a loop (use NumPy!).
What makes time integration different?
Each step depends on the previous step. To compute \(y_{n+1}\), we need \(y_n\), which itself came from \(y_{n-1}\). This is a sequential dependency — we cannot compute step 100 without first computing steps 1 through 99.
Independent — no loop needed:
| Operation | Independent? | Loop needed? |
|---|---|---|
| Convert 1000 temps C → F | Yes | No — vectorize! |
| Compute mean of each row | Yes | No — axis=1 |
| Euler time stepping | No — \(y_{n+1}\) needs \(y_n\) | Yes |
| Running sum / cumulative | No — each sum needs the previous | Yes |
The rule: If step \(n+1\) depends on the result of step \(n\), you must use a loop.
Independent (vectorize!):
x₀ → f(x₀) Each computation stands alone.
x₁ → f(x₁) You can do them all at once.
x₂ → f(x₂) NumPy handles this in C.
x₃ → f(x₃)
Sequential (loop required):
y₀ ──▶ y₁ ──▶ y₂ ──▶ y₃ ──▶ ...
Euler Euler Euler Euler
Each arrow REQUIRES the previous value to exist.
You can't skip ahead. This is a sequential chain.
This is the defining feature of time integration, and it’s why we can’t just vectorize the whole thing in one NumPy call.
| Concept | What went wrong | What to remember |
|---|---|---|
| The date | You forgot it existed | the date |
| Nested loops | Iterated over values instead of indices | for ii in range(n_rows): for jj in range(n_cols): array[ii, jj] |
| Why loops for integration | Answers were too vague | \(y_{n+1}\) depends on \(y_n\), sequential dependencies require a loop |

ATOC 4815/5815 - Midterm Post-Test