Self-Assessment Quiz: Anatomy of a Real Scientific Code
Twenty questions to confirm you can read a large code's layout, name its roles, choose and read a build system, navigate it, and reason about where its state and time live. Aim for 16 or more. Answers and a topic map are at the end — try the whole quiz first.
Question 1
In a well-organized scientific-code source tree, the utility modules (kinds, constants) live:
- A. At the top, above the driver
- B. At the bottom, because everything may use them and they use almost nothing
- C. Wherever the author happened to put them; the location is arbitrary
- D. In the test/ directory
Question 2
The driver in a large code is best described as the unit that:
- A. Does the heaviest numerical work
- B. Orchestrates the run — setup, main loop, output — while delegating every real task to modules below it
- C. Defines the precision kind dp
- D. Holds the physical constants
Question 3
A physics module typically contains:
- A. The main time-stepping loop
- B. One physical process (e.g. diffusion) as procedures, ideally pure functions of their inputs
- C. File open/read/write routines
- D. The program statement
Question 4
"Depend downward, never sideways or up" means:
- A. Each module uses only modules in layers below it
- B. Modules should be listed alphabetically
- C. The driver should be compiled first
- D. Every module must use every other module
Question 5
The single most useful mental model of a large code, and the one that "cannot lie," is:
- A. The alphabetical file listing
- B. The module map — the use dependency graph, enforced by the compiler
- C. The line count
- D. The author list
Question 6
Which build system scans your use statements and derives the compile order automatically?
- A. Make
- B. A hand-written shell script
- C. fpm
- D. None; compile order is always manual
Question 7
CMake's role in a large multi-language scientific code is to: - A. Run the simulation - B. Describe the project so it can generate the actual build files for any platform, and find libraries - C. Replace the Fortran compiler - D. Store the output data
Question 8
A build configuration includes all of the following EXCEPT: - A. The compiler and its version - B. The optimization and debugging flags - C. The versions of external libraries linked in - D. The wall-clock time the last run took
Question 9
Recording the build configuration matters because: - A. It makes the executable smaller - B. The same source built two ways can give different numerical results, so a reproducible result must say which build - C. It is required by the Fortran standard - D. It speeds up compilation
Question 10
The entry point of a Fortran program is:
- A. The first file alphabetically
- B. Its single program unit, where execution begins
- C. The largest module
- D. The README.md
Question 11
To find every module a code defines, you would grep for:
- A. program
- B. module (module definitions)
- C. end
- D. implicit none
Question 12
When navigating a large code, the professional's approach is to: - A. Read every file top to bottom until it makes sense - B. Hold the architecture in your head and query the rest with grep and tags, reading only what your task needs - C. Rewrite it from scratch to understand it - D. Start at the last file and work backward
Question 13
A plain grep for the name step can mislead you because:
- A. grep is too slow
- B. Fortran is case-insensitive (Step, STEP) and names can be renamed on import, so text hits are not always the right symbol
- C. grep cannot search .f90 files
- D. step is a reserved word
Question 14
State that is easiest to reason about when reading a routine is:
- A. A COMMON block
- B. A module variable read by many routines
- C. State passed explicitly as arguments with intent, visible in the signature
- D. State hidden in a saved local variable
Question 15
A routine that reads a module variable not in its argument list is harder to understand because: - A. It runs slower - B. It has a hidden input — you must search the whole module for who assigns the variable to know its value - C. Module variables cannot be real - D. The compiler forbids it
Question 16
In example-02, via_global() returns two different values from identical calls because:
- A. The function is impure by a bug
- B. Between the calls, another line changed the module state the function silently depends on
- C. Floating-point rounding differs
- D. The compiler optimized it away
Question 17
In almost every explicit PDE solver, the runtime is dominated by: - A. Reading the config file - B. The innermost stencil loop, evaluated over every interior cell every timestep - C. Writing the final output - D. Allocating the field once
Question 18
Before optimizing an unfamiliar solver, the correct order of operations is:
- A. Optimize the first expensive-looking loop immediately
- B. Navigate to the hot loop, then profile to confirm where time goes, then optimize, then re-measure
- C. Rewrite it in C
- D. Add more print statements everywhere
Question 19
Reorganizing the solver into src/ + app/ + test/, the program heat driver goes in:
- A. src/
- B. app/ (each program there becomes an executable)
- C. test/
- D. the project root
Question 20
The reorganized solver's dependency graph is a tree with kinds at the root of dependence. A valid
compile order is therefore:
- A. heat, heat_io, heat_solver, heat_types, timers, kinds
- B. kinds, timers, heat_types, heat_solver, heat_io, heat
- C. any order
- D. heat_io, kinds, heat, heat_solver, timers, heat_types
Answer Key
| Q | Ans | Why |
|---|---|---|
| 1 | B | Utilities are the foundation: everyone uses them, they use nothing, so they sit at the bottom. |
| 2 | B | The driver orchestrates and delegates; it performs no science itself. |
| 3 | B | A physics module encodes one process, ideally as pure functions of its inputs. |
| 4 | A | Layered dependence: each module uses only layers below, keeping the graph acyclic. |
| 5 | B | The use graph is compiler-enforced, so it is the code's true, un-lying table of contents. |
| 6 | C | fpm reads use statements and derives compile order automatically. |
| 7 | B | CMake describes the project and generates platform build files; it also finds libraries. |
| 8 | D | Runtime is a result, not part of how the source was built. |
| 9 | B | Different builds can give different numbers, so reproducibility requires recording the build. |
| 10 | B | Execution begins in the single program unit. |
| 11 | B | Grepping module lists the module definitions (the nodes of the map). |
| 12 | B | You query a large code by architecture; you do not read it whole. |
| 13 | B | Case-insensitivity and renamed imports make text hits unreliable; tags/LSP resolve symbols. |
| 14 | C | Argument-passed state is visible in the signature and readable in isolation. |
| 15 | B | A module variable is a hidden input; you must find every assignment to know its value. |
| 16 | B | A distant line mutated the shared module state the function depends on. |
| 17 | B | The inner stencil loop is the classic hot spot — the 80/20 rule bites hard. |
| 18 | B | Navigate, then measure, then change, then re-measure. Never guess the hot spot. |
| 19 | B | fpm makes each program in app/ an executable; the library modules go in src/. |
| 20 | B | kinds first (uses nothing), driver last (uses everything) — a topological sort. |
Topics to review by question
- Q1–5 → §36.1 (source tree) and §36.2 (the five roles, layering).
- Q6–9 → §36.3 (build systems and build configuration).
- Q10–13 → §36.4 (entry point, module map, grep vs tags).
- Q14–18 → §36.5 (where state lives, data flow, where the time goes).
- Q19–20 → the Project Checkpoint (reorganizing into
src//app//test/; compile order).
Scored below 16? Reread the flagged sections. This chapter is the map for all of Part IX, and the capstone in Chapter 38 assumes you can find your way around a real code.