Chapter 15 — Teaching Notes
One-line purpose. Deliver the book's emotional payoff for Python-native students — call Fortran from
Python, and measure the speedup — while drilling the one technical idea that makes or breaks it: memory
layout at the boundary (order='F').
Key ideas to emphasize
- The two-language workflow is a division of labor, not a competition. Hammer the threshold concept: whole-program speed is set by the hot loop's language. Once students see that, the tired "Python vs Fortran" debate evaporates — you write the 10% that runs a billion times in Fortran and the rest in Python.
order='F'is the whole chapter's technical crux. f2py preserves indexing but copies a C-contiguous array on every call. This is the single most common way a "Fortran-accelerated" program ends up no faster than before. Make them feel it: same kernel, one keyword, order-of-magnitude difference.intentdoes double duty. The habit from Ch. 6 (intent on every argument) is now the metadata f2py reads to build the Python signature. Reward students who already internalized it.- Honesty about the speedup. The number is 10–100×, an order of magnitude, and it is theirs to measure
— not a promise. Model the
assert np.allclosediscipline: a speedup that changes the answer is a bug. - ctypes/cffi need
bind(c). This is where Ch. 14 pays off — the C ABI is the universal adapter, and f2py's convenience is precisely that it builds the C mask for you.
Misconceptions to preempt
- "f2py transposes my array because Fortran is column-major." (No — it preserves indexing and reconciles
layout by copying.
a[i,j]→u(i+1,j+1).) - "If NumPy is fast, I never need Fortran." (True until a loop-carried dependency blocks vectorization — the heat time loop. Then pure Python falls off a cliff and Fortran is the answer.)
- "The speedup is a fixed number like 50×." (It depends on hardware, compiler, flags, and size; only the order of magnitude is robust.)
- "
intent(inout)andintent(in)behave the same at the boundary." (No —intent(in)may copy silently;intent(inout)raises on a non-F-contiguous array, because it cannot write back through a copy.) - "1-D arrays have the order='F' problem too." (No — a 1-D array is both C- and F-contiguous.)
A live demonstration (8 minutes)
Build code/example-02-heat-step.f90 live: f2py -c -m heatlib example-02-heat-step.f90. In an interpreter,
create the 4×4 field twice — once np.zeros((4,4)) (C-contiguous) and once with order='F' — call step
on each, and show (a) the answers are identical (f2py preserves indexing) and (b) np.isfortran(...) differs.
Then, if time, wrap a big-array version and %timeit both to expose the per-call copy. The wordless punch:
same code, same answer, one keyword, very different speed. (If f2py's build fails on your Python, that itself
is the teachable moment about the Meson backend — pip install meson ninja, --backend meson.)
Class-time budget (~55 min)
- 8 min: the two-language workflow and the threshold concept (§15.1).
- 12 min: f2py mechanics — the
-c -mbuild, intent→signature, module namespacing (§15.2), with the live demo start. - 15 min: dtype and
order='F'— the crux; the copy,intent(inout), the Find-the-Bug (§15.3). - 8 min: ctypes/cffi and why they need
bind(c)(§15.4). - 12 min: the payoff — port, wrap, benchmark honestly; run
benchmark.pyif the room can (§15.5) + the Project Checkpoint.
Prerequisites to review
- Ch. 5 §5.6 column-major order (first index fastest) — the direct parent of
order='F'. Five minutes re-drawing the memory layout diagram pays for itself. - Ch. 6
intentand the canonicalstep(field, alpha, dt)— the kernel we wrap. - Ch. 14
iso_c_binding/bind(c)— needed for §15.4. If Ch. 14 is fresh, students are ready. - Practical: confirm students have NumPy and gfortran, and can run
f2py --version, before class — the build environment (especially the Meson transition) is where live sessions stall.
Connections
Back: Ch. 5 (layout), Ch. 6 (intent/step), Ch. 14 (bind(c)). Forward: Ch. 16 (fpm and the ecosystem, next),
Ch. 24 (the real stencil drops into the same step interface), Ch. 28 (rigorous benchmarking), Ch. 31
(Amdahl caps the payoff — Exercise 15.21), Ch. 33 (parallelize the wrapped kernel — CS-02 extension). This is
the anchor climax the whole book foreshadowed since Ch. 1.