Table of Contents
- When Is Flow Incompressible? The Mach Number Rule
- Governing Equations: Continuity and Navier-Stokes
- Pressure-Velocity Coupling: SIMPLE, PISO, PIMPLE
- Laminar vs Turbulent Incompressible Flow
- Boundary Layer: No-Slip, Viscous Sublayer, Log-Law
- Engineering Applications
- Solver Comparison: OpenFOAM & Fluent
- Articles in This Section
When Is Flow Incompressible? The Mach Number Rule
A flow is treated as incompressible when density variations throughout the flow field are small enough to be neglected. In practice, the key parameter is the Mach number:
The widely accepted engineering rule is: if Ma < 0.3, treat the flow as incompressible. At Ma = 0.3, the maximum density change relative to the stagnation density is about 4.5% — small enough for most engineering purposes. Below Ma = 0.1 (typical of HVAC ducts, building ventilation, low-speed water systems), the error from ignoring compressibility is under 0.5%.
Why does density stay nearly constant at low Mach numbers? The pressure fluctuations driving the flow scale as \(\rho U^2\), while the acoustic pressure scale is \(\rho c^2\). Their ratio is \(Ma^2\) — so at Ma = 0.3, pressure fluctuations cause only about 9% density change from the isentropic relation. Below that threshold, density is effectively a constant material property.
The "Ma < 0.3" rule is everywhere, but why exactly 0.3? Is it a strict physics cutoff or more of a practical guideline?
It's definitely a practical guideline, not a sharp physics cutoff. The reasoning goes like this: for isentropic flow, the density ratio between a moving fluid and the stagnation point is \(\rho/\rho_0 = (1 + (\gamma-1)/2 \cdot Ma^2)^{-1/(\gamma-1)}\). Plug in Ma = 0.3 and you get about a 4.5% density variation — which most engineers are happy to ignore. The real test is whether your quantity of interest — force coefficients, pressure drop, flow rates — changes significantly when you switch from incompressible to compressible solver. For a ventilation fan spinning slowly, there's zero practical difference. For a turbofan blade tip moving at Ma = 0.7, you absolutely need compressibility. The 0.3 threshold is where errors become noticeable but not yet disastrous; it's been validated on so many benchmark cases that it became the standard rule of thumb.
What about water — does Mach number even apply to liquids? Water seems obviously incompressible regardless.
Great point. The speed of sound in water is about 1,480 m/s — water flowing at 10 m/s has Ma ≈ 0.007, so for steady liquid flows the incompressible assumption is essentially exact. Water is so stiff elastically that it takes enormous pressures to measurably change its density. The exception is water hammer — rapid valve closure creates pressure waves that propagate at the acoustic speed through the pipe system, and there you genuinely need the compressible water hammer equations. Similarly, cavitation involves phase change and density jumps, so the simple incompressible model breaks down in those regions too. But for 99% of water hydraulics, pipe networks, and pump analysis, incompressible Navier-Stokes is perfectly correct.
Typical Mach Numbers for Common Applications
| Application | Typical Velocity | Ma (air, 20°C) | Treatment |
|---|---|---|---|
| HVAC duct airflow | 2–8 m/s | 0.006–0.023 | Incompressible |
| Road vehicle aerodynamics (highway) | 30 m/s (108 km/h) | 0.088 | Incompressible |
| Racing car aerodynamics | 80 m/s (288 km/h) | 0.234 | Incompressible (marginal) |
| Commercial aircraft cruise | 250 m/s | 0.85 | Compressible (transonic) |
| Water in a pipe (pump system) | 2–5 m/s | 0.001–0.003 | Incompressible |
| Blood flow in aorta | ~0.5 m/s | ~0.001 | Incompressible |
Governing Equations: Continuity and Navier-Stokes
For an incompressible, Newtonian fluid with constant viscosity, the governing equations are the incompressible Navier-Stokes equations. These consist of two coupled equations:
Continuity Equation (Mass Conservation)
This states that the velocity field must be divergence-free: there are no sources or sinks of mass. Every parcel of fluid that flows into a control volume must flow out. This constraint is what makes incompressible flow numerically challenging — pressure has no governing equation of its own; it instead acts as a Lagrange multiplier that enforces this divergence-free constraint.
Momentum Equation (Newton's Second Law)
Where \(\mathbf{u}\) is the velocity vector [m/s], \(p\) is pressure [Pa], \(\rho\) is the constant fluid density [kg/m³], \(\nu = \mu/\rho\) is kinematic viscosity [m²/s], and \(\mathbf{g}\) is the gravitational acceleration vector [m/s²]. The left-hand side contains the local acceleration \(\partial\mathbf{u}/\partial t\) and the convective (nonlinear) acceleration \((\mathbf{u}\cdot\nabla)\mathbf{u}\). The right-hand side contains the pressure gradient force, the viscous diffusion term, and body forces.
Dimensionless Form and the Reynolds Number
Scaling velocities by a reference \(U_\infty\), lengths by \(L\), and pressure by \(\rho U_\infty^2\) gives the dimensionless Navier-Stokes equations, where the single dimensionless parameter governing the entire flow regime is the Reynolds number:
At low Re, viscous forces dominate and flow is laminar. As Re increases, inertial forces grow relative to viscous damping; eventually the flow transitions to turbulence. For flow in a circular pipe, the critical Reynolds number for transition is approximately Re ≈ 2,300. For flow over a flat plate, transition begins around Re ≈ 5×10⁵.
I understand the momentum equation conceptually, but why does pressure appear as \(p/\rho\) instead of just \(p\)? Is there a trick here?
Yes, it's just a convenient notation that groups the modified pressure. Since density \(\rho\) is constant in incompressible flow, you can define a "kinematic pressure" \(P = p/\rho\) [m²/s²] and rewrite the equation without \(\rho\) explicitly in the pressure gradient term. This is particularly useful in OpenFOAM — when you look at the output file p, you're actually reading kinematic pressure, not absolute pressure in Pascals. If you want the actual pressure in Pa, you multiply by density. It also clarifies that for incompressible flow, only pressure differences matter (the absolute level is arbitrary), which is why you need at least one pressure reference point in your boundary conditions — otherwise the pressure system is singular and your solver won't converge.
You said pressure acts as a Lagrange multiplier. Can you explain that more concretely? I'm used to thinking of pressure as a real physical force.
Pressure is absolutely a real physical force — it acts on every fluid surface. But in the incompressible limit, what determines its value is the mathematical requirement that the velocity field must stay divergence-free at every instant. Think of it this way: if you have a pipe that narrows, the flow must accelerate. The pressure gradient is what provides exactly the right amount of force to make that happen while also ensuring continuity. The pressure "adjusts itself" to whatever value is needed to prevent mass accumulation anywhere in the domain. In compressible flow, there's no such constraint — pressure is determined by the equation of state (\(p = \rho R T\)) and can evolve independently. In incompressible flow, density is fixed, so the equation of state drops out, and pressure is left doing double duty: both applying force and enforcing the constraint. That's the mathematical sense in which it acts as a Lagrange multiplier, and it's precisely why incompressible solvers need special pressure-velocity coupling algorithms.
Pressure-Velocity Coupling: SIMPLE, PISO, PIMPLE
The core numerical challenge in incompressible CFD is that the continuity equation \(\nabla\cdot\mathbf{u}=0\) contains no pressure — yet pressure couples all velocity components. There is no explicit equation for pressure. The standard approach is operator splitting: decouple the equations, solve them sequentially, and iterate to convergence. Three major algorithms dominate practice:
SIMPLE (Semi-Implicit Method for Pressure-Linked Equations)
Proposed by Patankar and Spalding (1972), SIMPLE is the foundation algorithm for steady-state incompressible flow. The procedure per outer iteration is:
- Guess or use current pressure field \(p^*\)
- Solve momentum equations with \(p^*\) to get intermediate velocity \(\mathbf{u}^*\) (which violates continuity)
- Derive a pressure correction equation from the continuity constraint, solve for \(p'\)
- Update: \(p = p^* + \alpha_p\, p'\) and \(\mathbf{u} = \mathbf{u}^* + \mathbf{u}'\) using under-relaxation factor \(\alpha_p \in (0, 1)\)
- Repeat until residuals are sufficiently small
The pressure correction equation has the form of a Poisson equation: \(\nabla\cdot(A_p^{-1}\nabla p') = \nabla\cdot\mathbf{u}^*\), where \(A_p\) is the central diagonal of the momentum matrix. SIMPLE requires aggressive under-relaxation (typically \(\alpha_u = 0.7\), \(\alpha_p = 0.3\)) to stabilize the outer iterations — it is robust but converges slowly for highly coupled or transient problems.
PISO (Pressure Implicit with Splitting of Operators)
Proposed by Issa (1986) for transient flows. PISO performs multiple pressure correction steps within each time step (typically 2–3 corrector steps) to satisfy continuity more accurately at each instant. Unlike SIMPLE, PISO does not use under-relaxation — the time step size controls stability. PISO is explicit in the sense that it advances from one time level to the next without iterating to steady state; it is appropriate when time accuracy matters.
PIMPLE (PISO + SIMPLE)
A hybrid algorithm implemented in OpenFOAM that wraps PISO loops inside outer SIMPLE-like iterations. This allows larger time steps (beyond the Courant-number limit for pure PISO) while maintaining reasonable accuracy. The key parameters are nOuterCorrectors (outer SIMPLE iterations, typically 1–3 for most cases, up to 50 for strongly coupled problems), nCorrectors (PISO pressure correctors, typically 2–3), and nNonOrthogonalCorrectors (extra passes for non-orthogonal meshes, typically 1–2).
So when do I use SIMPLE vs PISO vs PIMPLE in OpenFOAM? I always see different tutorials using different ones and I'm not sure when to choose which.
The practical rule is: SIMPLE for steady state, PISO for time-accurate transient, PIMPLE when you need transient but want larger time steps. For a room air conditioning study where you just want the final steady airflow pattern — use simpleFoam (SIMPLE). No need for time accuracy; you iterate to convergence as fast as possible. For a vortex shedding problem behind a cylinder where you need to capture the shedding frequency accurately — use icoFoam or pimpleFoam with small time steps so the Courant number stays below 1 (PISO regime). For a complex transient HVAC startup with a big domain where small time steps would take forever — use pimpleFoam with nOuterCorrectors = 2 or 3 and push the Courant number to 5 or 10. You trade some temporal accuracy for feasibility. The most common mistake beginners make is using PIMPLE with nOuterCorrectors = 1 (which makes it pure PISO) but a Courant number of 20 — that's unstable because PISO isn't designed for that.
What is under-relaxation actually doing physically in SIMPLE? I know I'm supposed to set it to 0.7 for velocity, but I don't understand why reducing the update helps.
Under-relaxation damps the oscillations that come from the chicken-and-egg coupling between pressure and velocity. When you solve momentum with the current pressure guess, you get a velocity that doesn't satisfy continuity. When you correct pressure to enforce continuity, you change the driving force for momentum, so your velocity guess is now inconsistent with the new pressure. If you apply the full correction each time, these updates can overshoot and oscillate wildly — pressure swings high, drives velocity the wrong way, then pressure overcorrects, and so on. Under-relaxation says: "only move 30% of the way toward the corrected value this iteration." It's like a damped feedback loop rather than a bang-bang controller. Too much relaxation (low \(\alpha\)) means slow convergence; too little (high \(\alpha\)) means instability. The 0.7 / 0.3 split for velocity / pressure is a historical starting point that works well for most steady flows; for highly turbulent or buoyancy-driven flows you often need to reduce both further.
Comparison Table
| Algorithm | Best For | Time Accuracy | Courant Limit | OpenFOAM Solver |
|---|---|---|---|---|
| SIMPLE | Steady state | None (iterative) | N/A (no physical time) | simpleFoam |
| PISO | Transient, time-accurate | 2nd order | Co < 1 | icoFoam (laminar) |
| PIMPLE | Transient, large Δt | Variable | Co up to ~10–50 | pimpleFoam |
Laminar vs Turbulent Incompressible Flow
Whether a flow is laminar or turbulent profoundly affects the velocity profile, pressure drop, heat transfer, and mixing — and determines what equations you must actually solve.
Laminar flow (Re below the critical threshold) has smooth, orderly streamlines. Each fluid layer slides past adjacent layers without significant mixing across streamlines. The velocity profile in a pipe is parabolic (Hagen-Poiseuille), and the pressure drop scales linearly with velocity: \(\Delta p \propto U\). Laminar flow can be solved exactly with the steady Navier-Stokes equations — no turbulence model is needed.
Turbulent flow (Re well above the critical threshold) has chaotic, three-dimensional velocity fluctuations superimposed on the mean flow. These fluctuations are responsible for dramatically enhanced mixing and momentum transfer across streamlines. The pressure drop scales roughly as \(\Delta p \propto U^{1.75}\) to \(U^2\) depending on Re. Solving turbulent flow requires either:
- RANS (Reynolds-Averaged Navier-Stokes): solve for the time-averaged flow field; model the effect of turbulent fluctuations with a turbulence closure model (k-ε, k-ω SST, etc.)
- LES (Large Eddy Simulation): resolve large turbulent eddies directly, model only sub-grid-scale eddies; much more accurate but orders of magnitude more expensive
- DNS (Direct Numerical Simulation): resolve all scales of turbulence; only feasible for low Re research cases in simple geometries
Why can't I just use a very fine mesh and solve turbulent flow directly without a turbulence model? Isn't that what DNS is?
That's exactly what DNS is — but the required mesh resolution is brutal. The smallest turbulent eddies (Kolmogorov microscale) scale as \(\eta \sim Re^{-3/4} L\), so the number of grid points scales as \(Re^{9/4}\). For a pipe flow at Re = 10,000, you'd need roughly \(10,000^{9/4} \approx 10^9\) grid points, and you'd need to march in time with steps small enough to resolve the fastest turbulent oscillations. That's around \(10^{10}\) time steps for a flow-through event. On the world's fastest supercomputers today, DNS at Re = 10,000 in a pipe takes weeks. Your HVAC model at Re = 100,000? Completely infeasible as DNS with any foreseeable hardware. RANS reduces this to maybe a million cells solved in minutes on a laptop, by replacing the chaotic fluctuations with modeled turbulent stresses. That's the trade-off: extreme computational cost for accuracy vs. turbulence models with their uncertainties but tractable cost.
Which turbulence model should I use for an incompressible flow around a building?
For wind engineering around buildings, the standard industry choice is k-ω SST (Shear Stress Transport). Here's why: building flows have large separated regions on the leeward faces and roof, recirculation zones in street canyons, and sharp-edge-triggered separation at corners. The k-ε model (standard or realizable) handles free-stream turbulence well but predicts separation point incorrectly and tends to underpredict separated regions. SST blends k-ω near walls (which it handles excellently with low-Re correction) and k-ε in the free stream, and activates a limiter that prevents over-prediction of turbulent shear stress in adverse pressure gradient regions — exactly where buildings make things hard. If you need really accurate pedestrian-level wind comfort data, consider SAS (Scale-Adaptive Simulation) or LES, but for design-level studies and wind load estimation, SST with a good mesh (y⁺ ≈ 1 or a wall function approach with y⁺ 30–300) is the practical standard.
Boundary Layer: No-Slip, Viscous Sublayer, and the Log-Law Region
When a fluid flows over a solid surface, the no-slip condition requires the fluid velocity to equal the wall velocity exactly at the surface:
For a stationary wall, this means \(\mathbf{u} = 0\) at the surface. This creates a thin region adjacent to the wall — the boundary layer — where velocity transitions from zero at the wall to the free-stream value. The structure of a turbulent boundary layer is described by the universal law of the wall, expressed in wall units:
Where \(u_\tau\) is the friction velocity and \(\tau_w\) is the wall shear stress. The boundary layer is divided into three distinct regions:
- Viscous sublayer (\(y^+ < 5\)): viscous stresses dominate, turbulence is damped to near-zero. Velocity profile is linear: \(u^+ = y^+\)
- Buffer layer (\(5 < y^+ < 30\)): transition zone where both viscous and turbulent stresses are significant; no simple analytical formula applies
- Log-law region (\(30 < y^+ < 300\)): turbulent inertial sublayer where the velocity follows the logarithmic law: \(u^+ = \frac{1}{\kappa}\ln(y^+) + B\), with von Kármán constant \(\kappa \approx 0.41\) and constant \(B \approx 5.0\)
What does y+ actually mean in practice for my CFD mesh? My instructor told me to keep it below 1 but the tutorial says 30–300 is fine. Who's right?
Both are right — they're describing two different wall treatment approaches, and you need to be consistent with your turbulence model setup. If you're using a low-Reynolds-number turbulence model (like k-ω SST with the "low-Re correction" option, or the Spalart-Allmaras model in its standard form) that resolves the viscous sublayer directly, then you need \(y^+ \lesssim 1\) for your first wall cell. The model equations are valid all the way to the wall and require resolution of the viscous sublayer. If you're using wall functions (which model everything between the wall and the log-law region without resolving it), then you need \(y^+ \approx 30\mbox{–}300\) so that your first cell sits squarely in the log-law region where the wall function formula is valid. The dangerous zone is \(y^+ \approx 5\mbox{–}30\) — if you end up there, your first cell is in the buffer layer, neither the viscous sublayer formula nor the log-law is accurate, and your wall shear stress (and hence heat transfer) prediction will be poor. Pick one approach and stick to it throughout the mesh.
How do I estimate what first-cell height I need to achieve a target y+ before I even run the simulation?
Use a flat-plate friction estimate — it's rough but good enough to set up the mesh before your first run. The steps are: (1) estimate the wall shear stress using a skin friction correlation, for example the flat-plate Schlichting formula \(C_f \approx 0.026\,Re_L^{-1/7}\) for turbulent flow; (2) compute the friction velocity \(u_\tau = \sqrt{C_f/2} \cdot U_\infty\); (3) compute the first-cell height from the target \(y^+\): \(\Delta y = y^+\,\nu/u_\tau\). For example, for air at 10 m/s over a 1 m plate: \(Re = 10/1.5\times10^{-5} \approx 667,000\), \(C_f \approx 0.026 \times 667000^{-1/7} \approx 0.0039\), \(u_\tau \approx \sqrt{0.0039/2} \times 10 \approx 0.14\) m/s, and for \(y^+ = 1\): \(\Delta y = 1 \times 1.5\times10^{-5}/0.14 \approx 0.11\) mm. After you run, check the y+ distribution on walls and iterate the mesh if needed. There are online y+ calculators that automate this — just make sure you understand the input parameters rather than blindly trusting the numbers.
Engineering Applications of Incompressible Flow Analysis
Incompressible CFD covers an enormous range of engineering problems:
HVAC and Building Ventilation
Heating, ventilation, and air conditioning systems operate entirely in the incompressible regime. CFD is used to optimize air distribution from diffusers, identify dead zones with poor ventilation, assess thermal comfort (operative temperature, draft risk), and comply with local air quality standards. Building codes in many countries now accept CFD evidence for natural ventilation design. Typical flows: Re = 10³–10⁶, geometries include complex room shapes, furniture, diffusers, and perforated ceilings.
Water Distribution and Hydraulic Systems
Pipe networks, pump systems, valves, and water treatment plants involve incompressible liquid flows. CFD predicts pressure losses, flow distribution across parallel branches, cavitation risk at pump inlets, sedimentation in reservoirs, and mixing of chemical additives. Combined with structural analysis, CFD results also inform water hammer risk assessment during valve operations.
Low-Speed Aerodynamics
Road vehicles (cars, trucks, trains) at highway speeds have Ma ≈ 0.05–0.25, well within incompressible territory. CFD optimizes drag coefficient (Cd), assesses cooling airflow to brakes and radiators, evaluates crosswind stability, and studies under-body flow. Similarly, small wind turbines, propellers of ships and submarines, and sports aerodynamics (cycling, swimming) are all incompressible problems.
Biomedical and Cardiovascular Flows
Blood in major vessels (aorta, coronary arteries) is an incompressible non-Newtonian fluid at very low Reynolds numbers (Re = 1,000–5,000 in the aorta, much lower in smaller vessels). CFD is used to study arterial wall shear stress (linked to atherosclerosis initiation), blood flow through prosthetic heart valves, cerebrospinal fluid dynamics, and drug delivery in airways. Non-Newtonian models (Carreau, Casson) replace the constant-viscosity Newtonian assumption for blood at low shear rates.
For a car aerodynamics project, what's the most important thing to get right in the simulation setup to get accurate drag?
Three things matter most. First, the mesh in the wake region: drag has large contributions from pressure recovery (or lack of it) in the separated wake behind the car. You need sufficient cell density in the wake to capture the size and structure of the recirculation region — not just around the car surface. A mesh that looks fine on the car body but has huge cells 1 metre downstream will give poor drag. Second, turbulence model choice: standard k-ε overestimates the turbulent kinetic energy in the stagnation region on the front hood and underestimates separation on the rear. k-ω SST with curvature correction, or Realizable k-ε, gives significantly better Cd predictions. For road car aerodynamics, industry uses DES or SAS increasingly for accurate time-averaged drag. Third, moving ground and rotating wheels: if you model the car with a stationary floor and stationary wheel surfaces, you're modeling something physically different from a car on a road. The ground boundary layer builds up under the car floor, pushing air outward, and stationary wheels dramatically underpredict wheel wake drag. Even for steady simulations, a moving floor BC and spinning wheel surfaces (using MRF or AMI patches) are essential for drag accuracy within ±5% of wind tunnel.
Solver Comparison: OpenFOAM and Fluent
OpenFOAM Incompressible Solvers
| Solver | Algorithm | Turbulence | Best Use Case |
|---|---|---|---|
simpleFoam | SIMPLE | RANS (all models) | Steady turbulent incompressible flow; the workhorse for industrial CFD |
icoFoam | PISO | Laminar only | Transient laminar incompressible; educational and benchmark use; Co < 1 |
pisoFoam | PISO | RANS/LES | Transient turbulent flow with strict time accuracy; Co < 1 |
pimpleFoam | PIMPLE | RANS/LES/DES | Transient flow with larger time steps; most general transient solver |
buoyantSimpleFoam | SIMPLE | RANS | Steady buoyancy-driven flows (natural convection, HVAC with thermal gradients) |
SRFSimpleFoam | SIMPLE | RANS | Single rotating frame — fans, impellers in steady-state rotating frame |
ANSYS Fluent: Pressure-Based Solver
Fluent uses a pressure-based solver architecture for incompressible and low-Mach-number flows. The default algorithm is SIMPLE, with SIMPLEC (SIMPLE Consistent, higher accuracy pressure correction) and PISO available. Key settings for incompressible flows in Fluent:
- Solver type: Pressure-Based (vs. density-based for compressible flows)
- Velocity formulation: Absolute (default) or Relative for rotating frames
- Pressure-velocity coupling: SIMPLE, SIMPLEC, or PISO
- Spatial discretization: Second-order upwind for momentum and turbulence quantities; PRESTO or Body Force Weighted for pressure with strong buoyancy
Is OpenFOAM actually used in industry, or is it mainly an academic tool? I see companies always listing Fluent and Star-CCM+.
OpenFOAM is genuinely used in industry, perhaps more than most students realize. The automotive sector uses it extensively — BMW, Volkswagen, Toyota have large internal CFD teams running OpenFOAM for aerodynamics and thermal management, partly because the licensing cost scales from zero (for ESI OpenCFD version) and partly because it's fully customizable at the source level. Aerospace uses it for research-grade computations. Wind energy companies use it for large-domain wind farm simulations where the commercial license cost for thousands of CPU cores would be prohibitive. The main reason Fluent and Star-CCM+ dominate in smaller companies and consultancies is the GUI — setting up a case in Fluent's point-and-click interface takes 2 hours; doing the same in OpenFOAM with text-based dictionaries takes 2 days for a newcomer. Once you know OpenFOAM well, the speed difference shrinks significantly. The honest answer is: for specialized or large-scale work, OpenFOAM is excellent and widely used; for consultancy work where client deliverables need to be generated quickly by various skill levels, commercial tools with their GUIs win.
My simpleFoam simulation converges to residuals of 10⁻³ and then stalls — it won't go lower. Is that a problem?
That depends entirely on what "stalls" means. If residuals reach 10⁻³ and level off flat — never going higher, never going lower — that often means the flow is physically unsteady (vortex shedding, oscillating separation) but you're trying to solve it with a steady-state solver. simpleFoam is looking for a steady solution that doesn't exist; the "converged" 10⁻³ result is a time-averaged nonsense. You should check whether the residuals oscillate slightly (a sign of unsteadiness) and whether key monitor quantities like drag or pressure drop are still changing iteration-to-iteration. If so, switch to pimpleFoam and run as transient, or use a time-averaging approach. If residuals genuinely stall because they drop smoothly to 10⁻³ and sit there stably, with monitor quantities flat, that's often acceptable — especially for turbulence quantities like k and ε which frequently don't converge below 10⁻³ in complex geometries. The key diagnostic is whether your engineering quantities of interest have converged, not whether the residuals have hit an arbitrary target.