Two questions that sound like one
The previous guide argued that you should not roll your own numerical core — that you should stand on tuned libraries like BLAS and LAPACK rather than hand-write the inner loops. But trusting a library is only the floor. The moment you assemble those pieces into a simulation of something real — a heat-diffusing rod, a bending beam, a fluid in a pipe — a deeper question appears: is the answer on my screen correct? This guide is about pulling that one fuzzy question apart into two sharp ones, because they fail differently, you debug them differently, and confusing them is how good-looking simulations quietly lie.
The two questions have names that the whole field shares. Verification asks: *am I solving the equations right?* That is, does my code faithfully produce the solution of the mathematical model I claim to be solving — no bugs, no scheme that secretly converges to the wrong thing. Validation asks: *am I solving the right equations?* That is, does that mathematical model actually describe the physical reality I care about. The slogan, worth memorizing word for word, is: verification is solving the equations right; validation is solving the right equations.
A leaky pipe: where each kind of error enters
Picture the journey from reality to a number on your screen as a pipe with three joints, and an error can leak in at each one. First, reality is squeezed into a mathematical model — you decide to treat air as a continuous fluid, ignore friction, assume the rod is perfectly uniform. The gap between reality and that idealized model is modeling error, and it is exactly what validation hunts. Second, the model — usually a differential equation you cannot solve by hand — is replaced by a discrete approximation: a grid, a finite-difference stencil, a finite-element mesh. The gap there is discretization error, which shrinks as you refine the grid. Third, that discrete problem is solved in floating-point arithmetic by your code, introducing round-off and, if you are unlucky, plain bugs.
Now the division of labour is clean. Verification lives at joints two and three: it asks whether your code, as the grid is refined and round-off is controlled, actually converges to the true solution of the discrete-then-continuous model — it polices discretization error and bugs. Validation lives at joint one: it asks whether that model, even solved perfectly, matches reality — it polices modeling error. The deep trap is that these two errors can cancel. A buggy code on a coarse grid can accidentally match an experiment because two wrongs happened to add to a right. That agreement is worthless, and only separating verification from validation exposes it.
How you actually verify: make the answer known
Verification has a beautiful concrete method, because it is pure math: to check that your code solves the equations right, compare its output against a solution you already know exactly. The cleanest source of such a known answer is the method of manufactured solutions, the subject of the very next guide. The idea inverts the usual workflow. Instead of starting from an equation and struggling to find its solution, you pick a smooth solution out of thin air — say u(x) = sin(x) — substitute it into your differential operator, and let the algebra tell you what source term and boundary values would make that your exact solution. Now you have a problem whose answer you know to the last digit, and you can feed it to your code.
But matching a known answer at one grid resolution is not enough — round-off and luck can fake it. The gold standard of verification is a convergence study: solve the manufactured problem on a sequence of grids of spacing h, h/2, h/4, and watch how the error shrinks. Your scheme came with a promised order of accuracy — a first-order method should have error O(h), a second-order method O(h^2). If, when you halve h, the error drops by about 2 for a first-order method or about 4 for a second-order method, the observed order matches the theoretical order, and that is the strongest evidence short of a proof that your code is bug-free. If the error refuses to fall at the promised rate, you have a bug — even if every individual answer looked plausible.
verify by manufactured solution + convergence study
1. pick exact u*(x) e.g. u*(x) = sin(x)
2. f(x) := L[u*](x) plug u* into your operator L, read off the source
3. for h in {h, h/2, h/4}:
u_h := solve L[u]=f on grid of spacing h
e_h := max | u_h - u* | (the error you CAN compute)
4. observed order p ~ log2( e_h / e_{h/2} )
5. compare p to the scheme's promised order
matches -> strong evidence the code is correct
too low -> there is a bug, no matter how 'reasonable' u_h lookedHow you validate, and why it can never be 'proved'
Validation is humbler and harder, because there is no exact answer to compare against — reality does not hand you a formula. Instead you compare your verified simulation against measurements: a wind-tunnel pressure, a thermocouple reading, a clinically observed dose. A close-related practice is the benchmark problem — a standard test case (lid-driven cavity flow, a flow past a cylinder) for which a trusted reference answer exists from careful experiments or from another well-verified code, so a new code can be checked against the community's accumulated truth.
Here is the honest, slightly uncomfortable truth about validation: it can never be completed, only ever supported or refuted. Agreement with one experiment validates your model for that regime only. A model of airflow validated at low speed may be utterly wrong near the speed of sound; a model fit to yesterday's data may fail tomorrow. This is not a flaw to be fixed — it is the nature of modeling. Validation buys you justified confidence within a tested envelope, never a guarantee outside it. And some questions sit permanently beyond reach: whether smooth solutions of the 3D Navier-Stokes equations always stay smooth is a famous open problem in mathematics, so no amount of turbulence simulation can be validated against a regularity we ourselves do not yet possess.
Making it a habit: tests that stay green
Verification and validation are not one-time ceremonies you perform before a paper and forget. Code changes; someone optimizes a loop, swaps a solver, refactors a boundary condition — and silently breaks the convergence that was working last week. The defence is regression testing: turn your manufactured-solution convergence study and your benchmark comparisons into automated tests that run on every change. If a 'speed-up' quietly drops your method from second order to first, a green-then-red test catches it the same afternoon, instead of in a reviewer's email six months later.
Two practical cautions before you trust any green checkmark. First, a verification test must be sensitive: assert the observed order of accuracy, not merely that 'the error is small', because a broken second-order scheme can still produce small errors that simply stop improving. Second, keep the two activities labelled in your own head and in your test suite — a passing verification test says nothing about whether your physics is right, and a successful validation says nothing about whether your code has bugs in an untested regime. They are separate ledgers, and the next three guides in this rung sharpen each in turn: convergence studies and manufactured solutions, then reproducibility, then honest error bars.