← 首页← Home

一维黏性 Burgers 方程的离散伴随:格心格式

Discrete adjoints for one-dimensional viscous Burgers: cell-centred scheme

算例是区间 [0,1][0,1] 上带源项的一维定常黏性 Burgers 方程:两端给定值,固定正黏性 ν\nu,未知量放在单元中心。本页先介绍方程、它的作用和网格,再从一个面上的通量出发,依次写出残差、前向(tangent)与伴随(adjoint),最后用它们计算振幅 aa、相位 φ\varphi 和黏性 ν\nu 的灵敏度,并与复数步长、完整重算差分、独立的 Python 大网格实测和连续伴随对照;同一问题把未知量放在节点上的格式见格点页(附录 B 说明两者的差别)。解有精确公式,所以每个导数都能和真值比较。

The test case is the steady one-dimensional viscous Burgers equation with a source on [0,1][0,1]: a prescribed value at each end, a fixed positive viscosity ν\nu, and unknowns at cell centres. After introducing the equation, what it is for and the mesh, this page starts with the flux on one face and builds the residual, the forward (tangent) and the adjoint, then uses them to compute the sensitivities to the amplitude aa, the phase φ\varphi and the viscosity ν\nu, and checks them against complex step, finite differences with full re-solves, independent large-grid Python runs and the continuous adjoint; the same problem with the unknowns at the nodes is on the node-centred page (Appendix B says where the two differ). The solution has a closed form, so every derivative can be compared with the truth.

全页路线图:从设计输入到梯度设计输入 DD = (a, φ, ν)3 个分量第 12 节求解R(U, D) = 0Newton,带状 LU第 5、6 节状态 U8 个未知量每个单元 1 个第 2 节目标 Jh线性泛函 Jhg = (∂Jh/∂U)T第 7 节梯度 dJh/dD3 个分量第 12 节前向(tangent)路线:从左往右,每个设计分量一次D˙ = ek第 k 个设计分量Av = −RD D˙​一次线性求解v = U˙​状态的切向量J˙h = gTv方向导数dJh/dDk梯度的一个分量3 个设计分量 → 3 次线性求解,每次得到梯度的一个分量(第 8、10 节)伴随(adjoint)路线:从右往左,只解一次dJh/dD = ψTRD全部 3 个分量ψ伴随变量ATψ = −g一次转置求解g = (∂Jh/∂U)T目标对状态的导数1 次转置求解,再做乘积 ψTRD(不再求解),得到全部 3 个分量(第 9、11、12 节)代价:3 个设计分量 ⇒ 前向 3 次线性求解,伴随 1 次全页路线图:从设计输入到梯度原始计算前向 ×3伴随 ×1从上往下从下往上设计输入 DD = (a, φ, ν)第 12 节求解R(U, D) = 0第 5、6 节状态 U8 个未知量第 2 节目标 Jhg = (∂Jh/∂U)T第 7 节梯度 dJh/dD3 个分量第 12 节D˙ = ek第 k 个设计分量Av = −RD D˙​一次线性求解v = U˙​状态的切向量J˙h = gTv方向导数dJh/dDk梯度的一个分量dJh/dD = ψTRD全部 3 个分量ψ伴随变量ATψ = −g一次转置求解g = (∂Jh/∂U)T目标对状态的导数3 个设计分量:前向 3 次线性求解,伴随 1 次
Page roadmap: from the design input to the gradientdesign input DD = (a, φ, ν)3 componentsSection 12solveR(U, D) = 0Newton withbanded LUSections 5–6state U8 unknownsone per cellSection 2objective Jhlinear functional Jhg = (∂Jh/∂U)TSection 7gradient dJh/dD3 componentsSection 12Tangent (forward) route: left to right, once per design componentD˙ = ekdesign component kAv = −RD D˙​one linear solvev = U˙​tangent of the stateJ˙h = gTvdirectional derivativedJh/dDkone gradient component3 design components → 3 linear solves, each giving one gradient component (Sections 8 and 10)Adjoint route: right to left, a single solvedJh/dD = ψTRDall 3 componentsψadjoint variableATψ = −gone transposed solveg = (∂Jh/∂U)Tobjective vs state1 transposed solve, then the product ψTRD (no further solve) gives all 3 components (Sections 9, 11 and 12)Cost: 3 design components ⇒ 3 tangent solves against 1 adjoint solvePage roadmap: from the design input to the gradientPrimalTangent ×3Adjoint ×1top to bottombottom to topdesign input DD = (a, φ, ν)Section 12solveR(U, D) = 0Sections 5–6state U8 unknownsSection 2objective Jhg = (∂Jh/∂U)TSection 7gradient dJh/dD3 componentsSection 12D˙ = ekcomponent kAv = −RD D˙​one linear solvev = U˙​state tangentJ˙h = gTvalong component kdJh/dDkone componentdJh/dD = ψTRDall 3 componentsψadjoint variableATψ = −gtransposed solveg = (∂Jh/∂U)Tobjective vs state3 design components:3 tangent solves, 1 adjoint solve
全页路线图 · 从设计输入到梯度。上排是原始计算:由设计输入求解离散方程,得到状态,再算出目标。前向(tangent)路线顺着计算方向,每个设计分量解一次线性方程,得到梯度的一个分量;伴随(adjoint)路线逆着计算方向,只解一次转置方程,再做一次乘积就得到全部分量。本页默认设置下有 3 个设计分量:3 次前向求解对 1 次伴随求解。方框下方的节号可以点击。Page roadmap · From the design input to the gradient. The top row is the primal computation: solve the discrete equations for the design input, obtain the state, then evaluate the objective. The tangent (forward) route follows the direction of computation and solves one linear system per design component, each giving one gradient component; the adjoint route runs against it, solves a single transposed system and obtains every component with one more product. With this page's default settings there are 3 design components: 3 tangent solves against one adjoint solve. The section numbers under the boxes are links.
本页用到的词Words used on this page
自动微分(AD)automatic differentiation (AD)
把程序逐语句用链式法则求导。前向模式(tangent)把一个输入方向推过程序;反向模式(adjoint)把一个输出权重拉回程序。differentiating a program statement by statement with the chain rule. Forward mode (tangent) pushes one input direction through the program; reverse mode (adjoint) pulls one output weight back through it.
原始(primal)primal
求导之前的原始计算。the original computation, before differentiation.
残差与 Jacobianresidual and Jacobians
R(𝐔,D)=0R(\mathbf U,D)=0 是离散方程;A=∂R/∂𝐔A=\partial R/\partial\mathbf U 与 RD=∂R/∂DR_D=\partial R/\partial D 是它对状态和对设计的 Jacobian。R(𝐔,D)=0R(\mathbf U,D)=0 are the discrete equations; A=∂R/∂𝐔A=\partial R/\partial\mathbf U and RD=∂R/∂DR_D=\partial R/\partial D are its Jacobians with respect to the state and the design.
构造解manufactured solution
先选解,再算出使它精确成立的源项,于是每个导数都有已知的真值。choose the solution first and compute the source that makes it exact, so that every derivative has a known true value.
重构与迹reconstruction and traces
重构由单元平均构造面上的值:常数(一阶)或带斜率(二阶);迹是由一侧单元重构出的面上的值(qLq_L 来自左侧,qRq_R 来自右侧)。reconstruction builds face values from cell averages: constant (first order) or with a slope (second order); a trace is the value at a face reconstructed from the cell on one side (qLq_L from the left, qRq_R from the right).
Rusanov 通量Rusanov flux
一种数值通量:取两侧物理通量的平均,再减去与跳跃成正比的耗散。a numerical flux that averages the physical fluxes of the two sides and subtracts a dissipation proportional to the jump.
网格 Péclet 数cell Péclet number
uh/νu h/\nu:一个单元尺度上对流与扩散之比。uh/νu h/\nu: the ratio of convection to diffusion over one cell.
LU、GS、GMRESLU, GS, GMRES
LU 把矩阵分解为下三角与上三角因子(这里是带状 LU);GS 是 Gauss–Seidel 迭代,逐个求解未知量,并立即使用其余未知量的最新值;GMRES 是广义最小残差法,一种只需矩阵–向量乘积的 Krylov 求解器。LU factorises a matrix into lower- and upper-triangular factors (banded LU here); GS is the Gauss–Seidel iteration, which solves for one unknown at a time with the newest values of the others; GMRES is the generalised minimal residual method, a Krylov solver that needs only matrix–vector products.
有限差分(FD)与复数步长finite differences (FD) and the complex step
有限差分由重新求解的结果的差商得到导数;复数步长取 f(x+iτ)/τf(x+\mathrm i\tau)/\tau 的虚部作导数:不做相减,没有舍入相消。finite differences take the derivative from a difference quotient of re-solved results; the complex step takes the imaginary part of f(x+iτ)/τf(x+\mathrm i\tau)/\tau: no subtraction, no cancellation.
点积检验dot test
检验伴随代码是前向代码的转置:两个内积必须在舍入误差内相等。checks that the adjoint code is the transpose of the tangent code: the two inner products must agree to rounding.
CFDCFD
计算流体力学。computational fluid dynamics.

第 1 节Section 1

方程:一维定常黏性 Burgers

The equation: steady one-dimensional viscous Burgers

本节实验:读图 1 的下图,扩散通量比对流通量小多少?再读图 2,同一个 u∗u^* 在不同 ν\nu 下需要什么样的源项?

Experiment: In the lower panel of Figure 1, how much smaller is the diffusive flux than the convective one? Then read Figure 2: what source does the same u∗u^* need at different ν\nu?

从守恒律到定常方程

From a conservation law to the steady equation

黏性 Burgers 方程在其他一维页面的 Burgers 方程上增加了分子扩散。量 u(x,t)u(x,t) 沿 xx 以自身的值为速度被输运,同时按系数 ν>0\nu>0 扩散;写成守恒形式,总通量有两部分——对流通量 u2/2u^2/2 与扩散通量 −νux-\nu u_x——区间内还有源项 s(x)s(x):

The viscous Burgers equation adds molecular diffusion to the Burgers equation of the other one-dimensional pages. A quantity u(x,t)u(x,t) is carried along xx with its own value as the speed and spreads by diffusion with the coefficient ν>0\nu>0. In conservation form the total flux has two parts, the convective flux u2/2u^2/2 and the diffusive flux −νux-\nu u_x, and a source s(x)s(x) acts inside the interval:

ut+(12u2−νux)x=s(x).u_t+\Bigl(\tfrac12u^2-\nu u_x\Bigr)_x=s(x).

本页只研究固定正黏性下的定常解。令 ut=0u_t=0,并记总通量为 q(u,ux)=12u2−νuxq(u,u_x)=\tfrac12u^2-\nu u_x,得到要离散的方程;因为含二阶导数,两端各需要一个给定值(无黏 Burgers 页面只给入口条件,不需要出口条件):

This page studies steady solutions at a fixed positive viscosity. Setting ut=0u_t=0 and writing q(u,ux)=12u2−νuxq(u,u_x)=\tfrac12u^2-\nu u_x for the total flux gives the equation to be discretised. Because it contains a second derivative it needs a prescribed value at each end (the inviscid Burgers pages, with an inlet condition only, needed none at the outlet):

qx=(12u2−νux)x=u ux−ν uxx=s(x),x∈(0,1),u(0)=uin,u(1)=uout.q_x=\Bigl(\tfrac12u^2-\nu u_x\Bigr)_x=u\,u_x-\nu\,u_{xx}=s(x),\qquad x\in(0,1),\qquad u(0)=u_{\rm in},\quad u(1)=u_{\rm out}.

ν>0\nu>0 使解光滑:陡变被扩散成薄层,层宽与 ν\nu 除以速度(或速度差)同量级。构造解本身没有层;u>0u>0 时这个问题的边界层只能出现在出口 x=1x=1(默认设计下层宽 ν/uout=0.011\nu/u_{\rm out}=0.011),入口 x=0x=0 处的层属于伴随 λ\lambda(图 4,第 11、16 节与附录 A)。在本页的格式里,网格 Péclet 数 uh/νuh/\nu 远小于 1 时离散结果才进入渐近区(第 15 节,数值观察);粗网格上的大误差主要来自两个不重构的端单元,而不是这个层(第 15、16 节)。激波属于单元中心的一维 Burgers 页的附录 B,ν→0\nu\to0 与 h→0h\to0 的极限顺序见它的附录 D(D.4);本页的 ν\nu 始终固定。

With ν>0\nu>0 the solution is smooth: a steep change is spread into a thin layer whose width is of the order of ν\nu divided by the speed (or the speed jump). The manufactured solution has no layer. With u>0u>0 a boundary layer of this problem can only sit at the outlet end x=1x=1 (width ν/uout=0.011\nu/u_{\rm out}=0.011 at the default design), while the layer at the inlet end x=0x=0 belongs to the adjoint λ\lambda (Figure 4; Sections 11 and 16 and Appendix A). In this page's scheme the discrete results reach their asymptotic range only when the cell Péclet number uh/νuh/\nu is well below 1 (Section 15, a numerical observation); the large errors on coarse meshes come mainly from the two unreconstructed end cells, not from the layer (Sections 15 and 16). Shocks belong to Appendix B of the cell-centred 1-D Burgers page and the orders of the limits ν→0\nu\to0, h→0h\to0 to its Appendix D (D.4); here ν\nu stays fixed.

一个构造解:先给解,再算源项

A manufactured solution: prescribe the solution, derive the source

要把每个导数都和精确答案比较,本页先规定解,再由解构造源项。取 u∗u^* 为在平均值 1 上叠加的正弦波,振幅为 aa,相位为 φ\varphi;u∗u^* 对每个设计都是精确解。把它代入方程,就得到源项和两端的给定值:

To compare every derivative with an exact answer, the page prescribes the solution first and builds the source from it. Take u∗u^* to be a sine wave on the mean 1, with amplitude aa and phase φ\varphi; it is the exact solution for every design. Inserting it into the equation defines the source and the two end values:

u∗(x)=1+a sin⁡z,z=2π(x−φ),q∗=12(u∗)2−νux∗,s(x)=qx∗=u∗ux∗−νuxx∗=2πa cos⁡z (1+a sin⁡z)+4π2νa sin⁡z,uin=u∗(0)=1−a sin⁡2πφ,uout=u∗(1)=uin.\begin{aligned}u^*(x)&=1+a\,\sin z,\qquad z=2\pi(x-\varphi),\qquad q^*=\tfrac12(u^*)^2-\nu u^*_x,\\ s(x)&=q^*_x=u^*u^*_x-\nu u^*_{xx}=2\pi a\,\cos z\,(1+a\,\sin z)+4\pi^2\nu a\,\sin z,\\ u_{\rm in}&=u^*(0)=1-a\,\sin 2\pi\varphi,\qquad u_{\rm out}=u^*(1)=u_{\rm in}.\end{aligned}

解不依赖 ν\nu,源项则依赖:其中 −νuxx∗=4π2νa sin⁡z-\nu u^*_{xx}=4\pi^2\nu a\,\sin z 这一项就是源项必须补上的扩散(图 2)。u∗u^* 以 1 为周期,所以两端的给定值相等;默认值下 uin=uout=0.9148u_{\rm in}=u_{\rm out}=0.9148。

The solution does not depend on ν\nu, but the source does: the term −νuxx∗=4π2νa sin⁡z-\nu u^*_{xx}=4\pi^2\nu a\,\sin z is the diffusion that the source has to supply (Figure 2). Because u∗u^* has period 1 the two end values are equal; at the defaults uin=uout=0.9148u_{\rm in}=u_{\rm out}=0.9148.

设计、目标和它们的精确导数

The design, the objective and their exact derivatives

设计输入是 D=(a,φ,ν)D=(a,\varphi,\nu),共 3 个分量。aa 与 φ\varphi 同时改变源项和两端的给定值;ν\nu 改变物理通量本身,同时也改变源项。目标是解的一个加权积分,权重 1+x1+x:

The design input is D=(a,φ,ν)D=(a,\varphi,\nu) with 3 components. Changing aa or φ\varphi changes the source and the two end values together; changing ν\nu changes the physical flux itself and, through −νuxx∗-\nu u^*_{xx}, the source. The objective is a weighted integral of the solution with the weight 1+x1+x:

J(u)=∫01(1+x) u(x) dx.J(u)=\int_0^1(1+x)\,u(x)\,\mathrm dx.

对构造解可以直接积分,目标和它的三个导数都有闭式(ν\nu 不出现,因为 u∗u^* 不依赖它):

For the manufactured solution the integral is exact, so the objective and its three derivatives have closed forms (ν\nu does not appear because u∗u^* does not depend on it):

J∗=32−a cos⁡2πφ2π,(∂J∗∂a, ∂J∗∂φ, ∂J∗∂ν)=(−cos⁡2πφ2π, a sin⁡2πφ, 0).J^*=\frac32-\frac{a\,\cos 2\pi\varphi}{2\pi},\qquad \Bigl(\frac{\partial J^*}{\partial a},\ \frac{\partial J^*}{\partial\varphi},\ \frac{\partial J^*}{\partial\nu}\Bigr)=\Bigl(-\frac{\cos 2\pi\varphi}{2\pi},\ a\,\sin 2\pi\varphi,\ 0\Bigr).

默认设计下 J∗=1.471198J^*=1.471198,梯度 (−0.144008, 0.085156, 0)(−0.144008,\ 0.085156,\ 0)。离散梯度随网格加密趋向的就是这些值(第 15 节的数据显示这一点;这是数值观察,不是证明)。有限网格上的离散目标 Jh(D)J_h(D) 是另一个函数(第 7 节),切线和伴随算出的是它的梯度,不是这个精确梯度;两者的比较见第 10 至 12 节、第 15 节和第 16 节。

At the defaults J∗=1.471198J^*=1.471198 and the gradient is (−0.144008, 0.085156, 0)(−0.144008,\ 0.085156,\ 0). These are the values that the discrete gradients approach as the mesh is refined, as the data of Section 15 show (a numerical observation, not a proof). On a finite mesh the discrete objective Jh(D)J_h(D) is a different function (Section 7), and what the tangent and the adjoint compute is its gradient, not this exact one; the two are compared in Sections 10 to 12, 15 and 16.

图 1 · 问题全貌(默认设计,N=8,无限制器线性重构)。上:构造解 u*(实线)、精确单元平均(空心圆)、本页算出的离散解 U_i(实心点);两端的方块是给定值 u_in=u_out=0.9148。下:总通量 q* 及其两部分;扩散通量 -ν u*_x 最大只有 0.0126,图中放大 20 倍。0.70.80.911.11.21.300.20.40.60.81xuuin​ = 0.9148uout​ = 0.9148精确解 u*精确单元平均离散解 Ui​(N = 8)−0.200.20.40.60.800.20.40.60.81xq总通量 q* = u*²/2 − ν u*x​对流 u*²/2扩散 −ν u*x​(×20)
图 1 · 问题全貌(默认设计,N=8N=8,无限制器线性重构)。上:构造解 u∗u^*(实线)、精确单元平均(空心圆)、本页算出的离散解 UiU_i(实心点);两端的方块是给定值 uin=uout=0.9148u_{\rm in}=u_{\rm out}=0.9148。下:总通量 q∗q^* 及其两部分;扩散通量 −νux∗-\nu u^*_x 最大只有 0.0126,图中放大 20 倍。
Figure 1 · The problem at a glance (default design, N=8, unlimited linear reconstruction). Top: the manufactured solution u* (solid), the exact cell averages (rings) and this page's discrete solution U_i (dots); the squares at the ends are the prescribed values u_in=u_out=0.9148. Bottom: the total flux q* and its two parts; the diffusive flux -ν u*_x is at most 0.0126, drawn 20 times larger.0.70.80.911.11.21.300.20.40.60.81xuuin​ = 0.9148uout​ = 0.9148exact u*exact cell averagesdiscrete Ui​ (N = 8)−0.200.20.40.60.800.20.40.60.81xqtotal flux q* = u*²/2 − ν u*x​convective u*²/2diffusive −ν u*x​ (×20)
Figure 1 · The problem at a glance (default design, N=8N=8, unlimited linear reconstruction). Top: the manufactured solution u∗u^* (solid), the exact cell averages (rings) and this page's discrete solution UiU_i (dots); the squares at the ends are the prescribed values uin=uout=0.9148u_{\rm in}=u_{\rm out}=0.9148. Bottom: the total flux q∗q^* and its two parts; the diffusive flux −νux∗-\nu u^*_x is at most 0.0126, drawn 20 times larger.

图 1 的下图回答了实验的第一问:对流通量约 0.3–0.7,扩散通量最大只有 0.0126,不超过对流通量的 4%。黏性几乎不改变解的通量,却决定了第 11、16 节里伴随场的结构;先记住这一点。

The lower panel of Figure 1 answers the first question of the experiment: the convective flux is about 0.3–0.7 and the diffusive flux is at most 0.0126, no more than 4% of it. Viscosity hardly changes the flux of the solution, yet it decides the structure of the adjoint field in Sections 11 and 16; keep that in mind.

图 2 · 同一个 u* 在不同黏性下需要的源项 s(x)。ν=0 时只有对流部分(虚线);扩散项 4π^2ν a sin z 的幅度与 ν 成正比:ν=0.01 时 0.079,ν=0.1 时 0.790。a=0.2,φ=0.07。−1.5−1−0.500.511.500.20.40.60.81xsν = 0(只有对流)ν = 0.01ν = 0.05ν = 0.1
图 2 · 同一个 u∗u^* 在不同黏性下需要的源项 s(x)s(x)。ν=0\nu=0 时只有对流部分(虚线);扩散项 4π2νa sin⁡z4\pi^2\nu a\,\sin z 的幅度与 ν\nu 成正比:ν=0.01\nu=0.01 时 0.079,ν=0.1\nu=0.1 时 0.790。a=0.2a=0.2,φ=0.07\varphi=0.07。
Figure 2 · The source s(x) that the same u* needs at different viscosities. For ν=0 only the convective part remains (dashed); the amplitude of the diffusion term 4π^2ν a sin z grows in proportion to ν: 0.079 at ν=0.01 and 0.790 at ν=0.1. a=0.2, φ=0.07.−1.5−1−0.500.511.500.20.40.60.81xsν = 0 (convective only)ν = 0.01ν = 0.05ν = 0.1
Figure 2 · The source s(x)s(x) that the same u∗u^* needs at different viscosities. For ν=0\nu=0 only the convective part remains (dashed); the amplitude of the diffusion term 4π2νa sin⁡z4\pi^2\nu a\,\sin z grows in proportion to ν\nu: 0.079 at ν=0.01\nu=0.01 and 0.790 at ν=0.1\nu=0.1. a=0.2a=0.2, φ=0.07\varphi=0.07.
图 3 · 构造解的目标与梯度随设计的变化(J* 与 ν 无关)。左:J* 随相位 φ 的变化,三条线对应三个振幅 a。右:a=0.2 时三个梯度分量随 φ 的闭式曲线;圆点是默认设计。梯度分量满足 |∂ J*/∂ a| ≤ 1/(2π) ≈ 0.16、|∂ J*/∂φ| ≤ a,比 J* ≈ 1.5 小一个量级。1.441.461.481.51.521.541.5600.20.40.60.81φJ*a = 0.1a = 0.2a = 0.4−0.4−0.200.20.400.20.40.60.81φ梯度(a = 0.2)∂J*/∂a∂J*/∂φ∂J*/∂ν
图 3 · 构造解的目标与梯度随设计的变化(J∗J^* 与 ν\nu 无关)。左:J∗J^* 随相位 φ\varphi 的变化,三条线对应三个振幅 aa。右:a=0.2a=0.2 时三个梯度分量随 φ\varphi 的闭式曲线;圆点是默认设计。梯度分量满足 ∣∂J∗/∂a∣≤1/(2π)≈0.16|\partial J^*/\partial a|\le1/(2\pi)\approx0.16、∣∂J∗/∂φ∣≤a|\partial J^*/\partial\varphi|\le a,比 J∗≈1.5J^*\approx1.5 小一个量级。
Figure 3 · The objective and gradient of the manufactured solution as functions of the design (J* does not depend on ν). Left: J* against the phase φ for three amplitudes a. Right: the closed-form curves of the three gradient components against φ at a=0.2; the dots are the default design. The gradient components satisfy |∂ J*/∂ a| ≤ 1/(2π) ≈ 0.16 and |∂ J*/∂φ| ≤ a, an order of magnitude below J* ≈ 1.5.1.441.461.481.51.521.541.5600.20.40.60.81φJ*a = 0.1a = 0.2a = 0.4−0.4−0.200.20.400.20.40.60.81φgradient (a = 0.2)∂J*/∂a∂J*/∂φ∂J*/∂ν
Figure 3 · The objective and gradient of the manufactured solution as functions of the design (J∗J^* does not depend on ν\nu). Left: J∗J^* against the phase φ\varphi for three amplitudes aa. Right: the closed-form curves of the three gradient components against φ\varphi at a=0.2a=0.2; the dots are the default design. The gradient components satisfy ∣∂J∗/∂a∣≤1/(2π)≈0.16|\partial J^*/\partial a|\le1/(2\pi)\approx0.16 and ∣∂J∗/∂φ∣≤a|\partial J^*/\partial\varphi|\le a, an order of magnitude below J∗≈1.5J^*\approx1.5.

自己动手:改变 aa、φ\varphi、ν\nu,看精确解、两部分通量和源项怎样变,并核对闭式的目标与梯度。

Try it yourself: change aa, φ\varphi and ν\nu, see how the exact solution, the two parts of the flux and the source change, and check the closed-form objective and gradient.

先看一眼后面要反复用到的结论:解几乎感觉不到黏性(图 1),但它的灵敏度感觉得到。目标的伴随场 λ\lambda(第 11、12、16 节与附录 A)在 x=0x=0 处有一个宽度约 ν/u\nu/u 的边界层,ν\nu 越小越陡;离散伴随只有在网格分辨这个层时才能重现它的形状(梯度需要的更少,见第 12 节)。

A look ahead at a result used again and again: the solution hardly feels the viscosity (Figure 1), but its sensitivity does. The adjoint field λ\lambda of the objective (Sections 11, 12, 16 and Appendix A) has a boundary layer of width about ν/u\nu/u at x=0x=0, steeper for smaller ν\nu; the discrete adjoint reproduces the shape of such a layer only if the mesh resolves it (the gradient needs less, Section 12).

图 4 · 前瞻:连续伴随 λ(-uλ_x-νλ_xx=-(1+x),λ(0)=λ(1)=0)在 ν=0.1, 0.03, 0.01 下的解(独立的谱方法求得)。x=0 处的层随 ν 减小而变陡:λ_x(0)=-13.53, -47.28, -142.7。−1.5−1−0.5000.20.40.60.81xλν = 0.1ν = 0.03ν = 0.01
图 4 · 前瞻:连续伴随 λ\lambda(−uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x),λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0)在 ν=0.1, 0.03, 0.01\nu=0.1,\,0.03,\,0.01 下的解(独立的谱方法求得)。x=0x=0 处的层随 ν\nu 减小而变陡:λx(0)=−13.53, −47.28, −142.7\lambda_x(0)=-13.53,\ -47.28,\ -142.7。
Figure 4 · A look ahead: the continuous adjoint λ (-uλ_x-νλ_xx=-(1+x), λ(0)=λ(1)=0) for ν=0.1, 0.03, 0.01 (from an independent spectral solver). The layer at x=0 steepens as ν decreases: λ_x(0)=-13.53, -47.28, -142.7.−1.5−1−0.5000.20.40.60.81xλν = 0.1ν = 0.03ν = 0.01
Figure 4 · A look ahead: the continuous adjoint λ\lambda (−uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x), λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0) for ν=0.1, 0.03, 0.01\nu=0.1,\,0.03,\,0.01 (from an independent spectral solver). The layer at x=0x=0 steepens as ν\nu decreases: λx(0)=−13.53, −47.28, −142.7\lambda_x(0)=-13.53,\ -47.28,\ -142.7.

这个方程用来做什么

What this equation is for

黏性 Burgers 方程保留了流体动量方程的非线性对流项 u uxu\,u_x,又带上分子黏性项 −νuxx-\nu u_{xx},是最简单的“对流加扩散”非线性方程。本课程把它放在无黏 Burgers 与一维 Navier–Stokes 之间,原因有五:

The viscous Burgers equation keeps the nonlinear convection term u uxu\,u_x of the momentum equation and adds the molecular viscosity term −νuxx-\nu u_{xx}: it is the simplest nonlinear convection–diffusion equation. The course puts it between the inviscid Burgers pages and the 1-D Navier–Stokes pages, for five reasons:

  • 小。默认网格只有 8 个未知量,每个数组和矩阵都能放在页面上,语句播放器也读得过来。Small. The default mesh has only 8 unknowns, so every array and matrix fits on the page and the statement players stay readable.
  • 非线性。数值通量对迹的偏导 cL=qL/2+1c_L=q_L/2+1 随状态变化,所以线性化(Jacobian)依赖于它取在哪个状态;切线与伴随都取在收敛的原始解上。Nonlinear. The derivative of the numerical flux with respect to a trace, cL=qL/2+1c_L=q_L/2+1, changes with the state, so the linearisation (the Jacobian) depends on where it is taken; the tangent and the adjoint are both evaluated at the converged primal solution.
  • 有精确答案可比。构造解给出每个设计下的精确解、精确目标和精确梯度,所以每个导数、每个收敛阶都能和真值比较。Exact answers to compare with. The manufactured solution gives the exact solution, objective and gradient for every design, so every derivative and every convergence rate can be compared with the truth.
  • 物理通量依赖导数 uxu_x。面通量要用相邻单元的差商近似 uxu_x,边界面要用半个单元的距离——这正是黏性 Navier–Stokes 页面每个面上要做的事,这里只有一个变量。The physical flux depends on the derivative uxu_x. A face flux needs a difference quotient of neighbouring cells to approximate uxu_x and a boundary face needs half a cell of distance: exactly what each face of the viscous Navier–Stokes pages does, here with one variable.
  • 设计进入物理通量和源项。a,φa,\varphi 改变源项和边界值,ν\nu 改变通量本身;第 12 节逐项分清这三条路径。The design enters the physical flux and the source. a,φa,\varphi change the source and the boundary values, ν\nu changes the flux itself; Section 12 separates the three paths one by one.

本页的数值、图和表来自本页的代码(模型在构建页面时与独立的 Python 实现逐项对照,第 15 节的大网格数据来自 Python 程序)。数值检查是验证证据,不是数学证明;本页不声称非线性方程或格式的存在性、唯一性或收敛定理(本页给出的证明列在附录 C 的 C.4)。

The numbers, figures and tables of this page come from the page's own code (the model is held to an independent Python implementation when the page is built, and the large-grid data of Section 15 come from the Python program). Numerical checks are verification evidence, not mathematical proofs; the page claims no existence, uniqueness or convergence theorem for the nonlinear equation or for the scheme (the proofs it does give are listed in C.4 of Appendix C).

第 2 节Section 2

网格:未知量与数组

The mesh: unknowns and arrays

本节实验:数一数,N=8N=8 个单元有几个面?每个内部面和每个边界面各读哪些数据?先答,再对照图 5。

Experiment: Count the faces of N=8N=8 cells: which data does each interior face and each boundary face read? Answer first, then compare with Figure 5.

第 1 节给出了方程。本节把区间 [0,1][0,1] 分成 NN 个等宽的单元,宽度 h=1/Nh=1/N,并说明页面存哪些数据。

Section 1 gave the equation. This section divides [0,1][0,1] into NN equal control volumes (cells) of width h=1/Nh=1/N and says what the page stores.

单元、面和未知量

Cells, faces and unknowns

单元 i=0,…,N−1i=0,\dots,N-1 的中心是 xi=(i+12)hx_i=(i+\tfrac12)h,它夹在面 ii 与面 i+1i+1 之间;面 f=0,…,Nf=0,\dots,N 在 xf=fhx_f=fh。未知量是每个单元上解的平均值:

Cell i=0,…,N−1i=0,\dots,N-1 has its centre at xi=(i+12)hx_i=(i+\tfrac12)h and lies between face ii and face i+1i+1; face f=0,…,Nf=0,\dots,N is at xf=fhx_f=fh. The unknown is the average of the solution over each cell:

Ui≈1h∫xi−h/2xi+h/2u(x) dx,𝐔=(U0,…,UN−1)T∈ℝN.U_i\approx\frac1h\int_{x_i-h/2}^{x_i+h/2}u(x)\,\mathrm dx,\qquad \mathbf U=(U_0,\dots,U_{N-1})^T\in\mathbb R^N.

对构造解,精确单元平均有闭式:正弦在一个单元上的平均是 sinc⁡(h)=sin⁡(πh)/(πh)\operatorname{sinc}(h)=\sin(\pi h)/(\pi h) 倍的中心值,所以

For the manufactured solution the exact cell average has a closed form: the average of the sine over a cell is sinc⁡(h)=sin⁡(πh)/(πh)\operatorname{sinc}(h)=\sin(\pi h)/(\pi h) times its value at the centre, so

⟨u∗⟩i=1+a sin⁡(πh)πh sin⁡(2π(xi−φ)).\langle u^*\rangle_i=1+a\,\frac{\sin(\pi h)}{\pi h}\,\sin\bigl(2\pi(x_i-\varphi)\bigr).

状态的误差始终拿离散解和这个精确平均比较,而不是和中心点的采样值比较(采样值只是 Newton 迭代的初值)。

The errors of the state are always measured between the discrete solution and this exact average, never against point samples at the centres (the samples are only the initial guess of the Newton iteration).

图 5 · 网格与数据(N=8)。单元 i 夹在面 i 与面 i+1 之间,存储单元平均 U_i(点);面 f 读它两侧单元的数据。两端没有单元可读,面 0 与面 N 读给定值 u_in、u_out(方块),离最近的单元中心只有 h/2(第 4 节)。f = 0f = 1f = 2f = 3f = 4f = 5f = 6f = 7f = 8U0​i = 0U1​i = 1U2​i = 2U3​i = 3U4​i = 4U5​i = 5U6​i = 6U7​i = 7uin​uout​单元中心到两侧的面都是 h/2内部面读两侧中心的值,相距 df​ = h边界面读给定值,离单元中心 d0​ = h/2单元 i 夹在面 i 与面 i+1 之间;存储的是它的单元平均 Ui​xf​ = f h,xi​ = (i + 1/2) h;两端的方块是给定的 uin​、uout​
图 5 · 网格与数据(N=8N=8)。单元 ii 夹在面 ii 与面 i+1i+1 之间,存储单元平均 UiU_i(点);面 ff 读它两侧单元的数据。两端没有单元可读,面 00 与面 NN 读给定值 uinu_{\rm in}、uoutu_{\rm out}(方块),离最近的单元中心只有 h/2h/2(第 4 节)。
Figure 5 · The mesh and its data (N=8). Cell i lies between face i and face i+1 and stores its average U_i (dots); face f reads the data of the cells on its two sides. At the ends there is no cell to read: face 0 and face N read the prescribed values u_in, u_out (squares), at a distance of only h/2 from the nearest cell centre (Section 4).f = 0f = 1f = 2f = 3f = 4f = 5f = 6f = 7f = 8U0​i = 0U1​i = 1U2​i = 2U3​i = 3U4​i = 4U5​i = 5U6​i = 6U7​i = 7uin​uout​a cell centre is h/2 from each of its facesan interior face reads two centres df​ = h aparta boundary face reads a prescribed value, d0​ = h/2 from the cell centrecell i lies between face i and face i+1; what is stored is its cell average Ui​xf​ = f h, xi​ = (i + 1/2) h; the squares at the ends are the prescribed uin​, uout​
Figure 5 · The mesh and its data (N=8N=8). Cell ii lies between face ii and face i+1i+1 and stores its average UiU_i (dots); face ff reads the data of the cells on its two sides. At the ends there is no cell to read: face 00 and face NN read the prescribed values uinu_{\rm in}, uoutu_{\rm out} (squares), at a distance of only h/2h/2 from the nearest cell centre (Section 4).

先看网格是怎样一步一步搭起来的:

First see how the mesh is built, step by step:

选一个面,看它读哪些单元;再换一种重构,数一数未知量的个数:

Select a face and see which cells it reads; then change the reconstruction and count the unknowns:

记号

Notation

默认设置:N=8N=8,无限制器线性重构,D=(a,φ,ν)=(0.2, 0.07, 0.01)D=(a,\varphi,\nu)=(0.2,\ 0.07,\ 0.01),即页首控件的初始值;图和文字没有另注时都取默认设置。

Default settings: N=8N=8, unlimited linear reconstruction and D=(a,φ,ν)=(0.2, 0.07, 0.01)D=(a,\varphi,\nu)=(0.2,\ 0.07,\ 0.01), the initial values of the controls at the top; the figures and the text use them unless another setting is stated.

按伴随优化文献的通常写法,设计变量记作 D=(a,φ,ν)D=(a,\varphi,\nu),分量 D0=aD_0=a、D1=φD_1=\varphi、D2=νD_2=\nu。残差是 R(𝐔,D)∈ℝNR(\mathbf U,D)\in\mathbb R^N,状态 Jacobian 是 A=R𝐔A=R_{\mathbf U},设计 Jacobian 是 RDR_D,离散目标是 JhJ_h,伴随变量是 ψ\psi。

As is usual in the adjoint-optimization literature, the design variables are written D=(a,φ,ν)D=(a,\varphi,\nu), with components D0=aD_0=a, D1=φD_1=\varphi, D2=νD_2=\nu. The residual is R(𝐔,D)∈ℝNR(\mathbf U,D)\in\mathbb R^N, the state Jacobian is A=R𝐔A=R_{\mathbf U}, the design Jacobian is RDR_D, the discrete objective is JhJ_h and the adjoint variable is ψ\psi.

切线(前向,tangent)与伴随(反向,adjoint)一律用自动微分的记号:程序变量 xx 的切线写 x˙\dot x,伴随写 xˉ\bar x,伴随累加写 xˉ+=…\bar x\mathrel{\text{+=}}\dots,伴随语句按逆序执行;x˙\dot x 与 xˉ\bar x 一一对应 Tapenade 等工具里的变量 x_d 与 x_b,本页的伪代码就用这些名字。变分符号 δ\delta 只出现在附录 A 的连续推导里(连续函数的变分);Newton 与 GS 的迭代增量写 Δ\Delta。

The tangent (forward) and the adjoint (reverse) always use the notation of automatic differentiation: the forward derivative of a program variable xx is x˙\dot x, its adjoint is xˉ\bar x, an adjoint accumulation is written xˉ+=…\bar x\mathrel{\text{+=}}\dots and the statements run in reverse order. They correspond one to one to the variables x_d and x_b of AD tools such as Tapenade, and the pseudocode of this page uses these names. The variation symbol δ\delta appears only in the continuous derivation of Appendix A (variations of continuous functions); the increments of the Newton and GS iterations are written Δ\Delta.

有两个与黏性有关的量,不要混淆:物理黏性 ν\nu(设计分量 D2D_2,进入物理通量 −νux-\nu u_x);Rusanov 数值通量里的耗散(第 3 节),其波速 α=2\alpha=2 是固定常数,一阶格式里它等效于随网格变化的人工黏性 hh,不是设计变量。

Two quantities that both look like a viscosity must not be confused: the physical viscosity ν\nu (the design component D2D_2, which enters the physical flux −νux-\nu u_x) and the dissipation of the Rusanov numerical flux (Section 3), whose speed α=2\alpha=2 is a fixed constant and which acts at first order as an artificial viscosity hh that changes with the mesh; it is not a design variable.

本页的主要符号

The main symbols of this page

符号Symbol含义Meaning大小Size定义处Defined in
N, h, xf, xiN,\ h,\ x_f,\ x_i单元数、宽度 h=1/Nh=1/N、面坐标、单元中心cells, width h=1/Nh=1/N, face coordinates, cell centres—第 2 节Section 2
𝐔, Ui\mathbf U,\ U_i状态:单元平均state: the cell averagesNN第 2 节Section 2
D=(a,φ,ν)D=(a,\varphi,\nu)设计:振幅、相位、黏性design: amplitude, phase, viscosity3第 1 节Section 1
R(𝐔,D), RiR(\mathbf U,D),\ R_i积分残差(不除以 hh)integrated residual (not divided by hh)NN第 5 节Section 5
Hf=Hc+HvH_f=H^c+H^v面通量:对流部分加黏性部分face flux: convective plus viscous partN+1N+1第 3 节Section 3
qL, qR, UL, UR, df, κfq_L,\ q_R,\ U_L,\ U_R,\ d_f,\ \kappa_f迹、未重构状态、距离、ν/df\nu/d_ftraces, raw states, distance, ν/df\nu/d_f—第 3 节Section 3
σi, li, ri\sigma_i,\ l_i,\ r_i斜率与两个单侧差slope and the two one-sided differencesNN第 3 节Section 3
cL, cRc_L,\ c_RHcH^c 对迹的偏导derivatives of HcH^c with respect to the tracesN+1N+1第 3 节Section 3
Qf, SiQ_f,\ S_i精确通量与积分源项 Qi+1−QiQ_{i+1}-Q_iexact flux and integrated source Qi+1−QiQ_{i+1}-Q_iN+1, NN+1,\ N第 3 节Section 3
A=R𝐔, RDA=R_{\mathbf U},\ R_D状态与设计 Jacobianstate and design JacobiansN×N, N×3N\times N,\ N\times3第 6、8 节Sections 6 and 8
Jh=wT𝐔, g=wJ_h=w^T\mathbf U,\ g=w离散目标与状态梯度discrete objective and state gradient1, N1,\ N第 7 节Section 7
v=𝐔˙, D˙=ekv=\dot{\mathbf U},\ \dot D=e_k切线与设计种子tangent and design seedN, 3N,\ 3第 8、10 节Sections 8 and 10
ψ, Dˉ\psi,\ \bar D伴随变量与设计伴随(梯度)adjoint variable and design adjoint (the gradient)N, 3N,\ 3第 9、11 节Sections 9 and 11
λ\lambda连续伴随场the continuous adjoint field—第 1、11、12、16 节、附录 ASections 1, 11, 12 and 16 and Appendix A

下标的约定:ii 总是单元,ff 总是面;数字下标写在 xx 上时指单元中心(x4=4.5 hx_4=4.5\,h 是单元 4 的中心),面坐标写 xfx_f(面 4 在 xf=4hx_f=4h)。伪代码里的数组 s[i] 存斜率 σi\sigma_i,它不是第 1 节的源项 s(x)s(x)。

Subscript convention: ii always names a cell and ff a face; a number written on xx names a cell centre (x4=4.5 hx_4=4.5\,h is the centre of cell 4), and face coordinates are written xfx_f (face 4 is at xf=4hx_f=4h). In the pseudocode the array s[i] stores the slope σi\sigma_i; it is not the source s(x)s(x) of Section 1.

默认网格上的数组(N=8N=8)

The arrays on the default mesh (N=8N=8)

单元 iiCell ii中心 xix_iCentre xix_i目标权重 wi=h(1+xi)w_i=h(1+x_i)Objective weight wi=h(1+xi)w_i=h(1+x_i)精确单元平均 ⟨u∗⟩i\langle u^*\rangle_iExact average ⟨u∗⟩i\langle u^*\rangle_i离散解 UiU_i(无限制器线性)Discrete UiU_i (unlimited linear)
00.06250.132810.990821.02465
10.18750.148441.131171.10219
20.31250.164061.194681.13883
30.43750.179691.144151.06834
40.56250.195311.009180.91706
50.68750.210940.868830.78348
60.81250.226560.805320.77176
70.93750.242190.855850.86868

权重 wiw_i 是第 7 节离散目标 Jh=∑iwiUiJ_h=\sum_iw_iU_i 的系数,也是状态梯度 g=wg=w(目标对状态的导数;伴随方程 ATψ=−gA^T\psi=-g 的右端是 −g-g)。

The weights wiw_i are the coefficients of the discrete objective Jh=∑iwiUiJ_h=\sum_iw_iU_i of Section 7 and also the state gradient g=wg=w (the right-hand side of the adjoint equation ATψ=−gA^T\psi=-g is −g-g).

后面各节要用到的所有数组和它们的形状都在图 6 里:左边是向量,右边是矩阵(颜色表示正负与大小,蓝正橙负)。它们都是本页在默认设计 DD 和 N=8N=8 下真实算出的量;AA 是 N×NN\times N 的五对角矩阵,RDR_D 只有 3 列,所以一次伴随求解(右端项 −g-g)给出梯度的全部 3 个分量,而切线求解要做 3 次。

All the arrays that the later sections use, with their shapes, are in Figure 6: vectors on the left, matrices on the right (colour shows sign and size: blue positive, orange negative). They are real quantities of this page at the default design DD and N=8N=8: AA is an N×NN\times N five-band matrix and RDR_D has only 3 columns, so one adjoint solve (right-hand side −g-g) gives all 3 design components while the tangent solves must be done 3 times.

图 6 · 页面存储的数组与形状(默认设计,N=8,无限制器线性重构):设计 D、状态 U、残差 R、面通量 H、权重 w、目标 J_h;右边是 A=R_(U)、R_D、三个切线解 v_k 和伴随 ψ 的真实数值。设计 D(3)aφν状态 U(N)残差 R(N)面通量 H(N+1)权重 w = g(N)目标 Jh​(1)状态 Jacobian A = RU​(N×N,五对角)0123456701234567设计 Jacobian RD​(N×3)01201234567伴随 ψ(N)012345670切线解 vk​(k = 0, 1, 2)01234567012
图 6 · 页面存储的数组与形状(默认设计,N=8N=8,无限制器线性重构):设计 DD、状态 𝐔\mathbf U、残差 RR、面通量 HH、权重 ww、目标 JhJ_h;右边是 A=R𝐔A=R_{\mathbf U}、RDR_D、三个切线解 vkv_k 和伴随 ψ\psi 的真实数值。
Figure 6 · The arrays the page stores and their shapes (default design, N=8, unlimited linear reconstruction): design D, state U, residual R, face fluxes H, weights w, objective J_h; on the right the real values of A=R_(U), R_D, the three tangents v_k and the adjoint ψ.design D (3)aφνstate U (N)residual R (N)face fluxes H (N+1)weights w = g (N)objective Jh​ (1)state Jacobian A = RU​ (N×N, five bands)0123456701234567design Jacobian RD​ (N×3)01201234567adjoint ψ (N)012345670tangents vk​ (k = 0, 1, 2)01234567012
Figure 6 · The arrays the page stores and their shapes (default design, N=8N=8, unlimited linear reconstruction): design DD, state 𝐔\mathbf U, residual RR, face fluxes HH, weights ww, objective JhJ_h; on the right the real values of A=R𝐔A=R_{\mathbf U}, RDR_D, the three tangents vkv_k and the adjoint ψ\psi.
第 3 节Section 3

面上的通量:对流、黏性与重构

The flux on a face: convection, viscosity and reconstruction

本节实验:选定一个面和一种重构,这个面读哪几个单元?两个迹 qL,qRq_L,q_R 哪个等于单元平均?先预测,再用本节末尾的面板验证。

Experiment: Select a face and a reconstruction: which cells does the face read, and which of the traces qL,qRq_L,q_R equals a cell average? Predict first, then check with the panel at the end of this section.

第 2 节把区间分成了单元。本节把方程写成单元上的通量差,用数值通量把面两侧的数据变成一个面通量(对流部分和黏性部分),再说明二阶格式怎样把单元平均重构成面上的状态。

Section 2 divided the interval into control volumes. This section writes the equation as a flux difference over a control volume, turns the data on the two sides of a face into one face flux (a convective part and a viscous part), and then shows how the second-order scheme reconstructs face states from the cell averages.

从方程到通量差

From the equation to a flux difference

第 1 节的方程是 qx=sq_x=s,q=12u2−νuxq=\tfrac12u^2-\nu u_x。在单元 ii(面 ii 到面 i+1i+1)上积分,由微积分基本定理,通量的导数变成两端通量之差,等于单元内的总源项:

The equation of Section 1 is qx=sq_x=s with q=12u2−νuxq=\tfrac12u^2-\nu u_x. Integrate it over cell ii (face ii to face i+1i+1): by the fundamental theorem of calculus the derivative of the flux becomes the difference of the end fluxes, which equals the total source in the cell:

q(xi+h2)−q(xi−h2)=∫xi−h/2xi+h/2s(x) dx=:Si=Qi+1−Qi,Qf=q∗(xf).q\bigl(x_i+\tfrac h2\bigr)-q\bigl(x_i-\tfrac h2\bigr)=\int_{x_i-h/2}^{x_i+h/2}s(x)\,\mathrm dx=:S_i=Q_{i+1}-Q_i,\qquad Q_f=q^*(x_f).

对构造解,源项是 s=qx∗s=q^*_x,所以一个单元的总源项就是精确通量 Qf=q∗(xf;D)Q_f=q^*(x_f;D) 在这个单元两个面上的差,不需要数值积分;第 5 节的残差用的就是这个精确的积分源项。离散化要做的只剩一件事:用两侧单元的数据近似每个面上的通量。

For the manufactured solution the source is s=qx∗s=q^*_x, so the total source of a cell is exactly the difference of the exact flux Qf=q∗(xf;D)Q_f=q^*(x_f;D) at its two faces, with no numerical quadrature; the residual of Section 5 uses this exact integrated source. What remains for the discretisation is to approximate the flux at each face from the data of the cells on its two sides.

一个面上的数值通量:对流加黏性

The numerical flux on a face: convective plus viscous

面 ff 的通量分两部分,用不同的输入:对流部分用面两侧重构出的状态 qL,qRq_L,q_R(下面叫“迹”),黏性部分用两侧的未重构状态 UL,URU_L,U_R(边界面上其中一个是给定值)和它们之间的距离 dfd_f:

The flux of face ff has two parts that use different inputs: the convective part uses the states qL,qRq_L,q_R reconstructed on its two sides (called traces below) and the viscous part uses the raw states UL,URU_L,U_R (on a boundary face one of them is the prescribed value) and the distance dfd_f between them:

Hf=14(qL2+qR2)−α2 (qR−qL)⏟Hc(qL,qR) − νdf (UR−UL)⏟Hv,α=2.H_f=\underbrace{\tfrac14\bigl(q_L^2+q_R^2\bigr)-\tfrac{\alpha}{2}\,(q_R-q_L)}_{H^c(q_L,q_R)}\ \underbrace{-\,\frac{\nu}{d_f}\,(U_R-U_L)}_{H^v},\qquad \alpha=2.

本页其他地方(包括本节开头的公式),qq 与 q∗q^* 表示总通量;面上的重构状态沿用其他一维页面的写法 qL,qRq_L,q_R。

Elsewhere on this page, including the first display of this section, qq and q∗q^* denote the total flux; for the face states the page follows the other 1-D pages and writes qL,qRq_L,q_R.

对流部分是 Rusanov 通量:两侧物理通量 F(u)=u2/2F(u)=u^2/2 的平均,减去与状态跳跃成比例的耗散。耗散项里的波速 α=2\alpha=2 取固定值,不随状态或设计变化,所以求导时没有隐藏的波速项(通常的波速 max⁡(∣qL∣,∣qR∣)\max(|q_L|,|q_R|) 在 ∣qL∣=∣qR∣|q_L|=|q_R| 处不可导,用它构成的 Rusanov 通量在 qL=−qR≠0q_L=-q_R\ne0 处不可导);控制面板允许的所有设计与网格上,收敛状态的迹都满足 ∣q∣<2|q|<2。Rusanov 通量满足相容性 Hc(u,u)=F(u)H^c(u,u)=F(u),并且同一个 HfH_f 离开左边的单元、进入右边的单元,使内部通量在全局求和中抵消。黏性部分是物理通量 −νux-\nu u_x 的中心差分近似:内部面 df=hd_f=h,边界面 df=h/2d_f=h/2(第 4 节)。

The convective part is the Rusanov flux: the average of the physical fluxes F(u)=u2/2F(u)=u^2/2 of the two sides, minus a dissipation proportional to the jump of the state. The dissipation speed α=2\alpha=2 is a fixed number that depends on neither the state nor the design, so differentiation hides no wave-speed term (the usual wave speed max⁡(∣qL∣,∣qR∣)\max(|q_L|,|q_R|) is not differentiable where ∣qL∣=∣qR∣|q_L|=|q_R|, and the Rusanov flux built with it is not differentiable where qL=−qR≠0q_L=-q_R\ne0); on all designs and meshes that the controls allow, the converged states have traces below 2 in magnitude, ∣q∣<2|q|<2. It is consistent, Hc(u,u)=F(u)H^c(u,u)=F(u), and the same HfH_f leaves the cell on the left and enters the cell on the right, so the interior fluxes cancel in a global sum. The viscous part is the central-difference approximation of the physical flux −νux-\nu u_x: df=hd_f=h on interior faces and df=h/2d_f=h/2 on boundary faces (Section 4).

耗散项 −(α/2)(qR−qL)-(\alpha/2)(q_R-q_L) 是人工黏性,它的作用可以写成精确的恒等式(下面的面板在当前状态上再验算一遍)。一阶时迹等于单元平均,内部行 jj 的通量差 Hj+1−Hj=Rj+SjH_{j+1}-H_j=R_j+S_j 是

The dissipation term −(α/2)(qR−qL)-(\alpha/2)(q_R-q_L) is artificial viscosity, and what it does can be written as exact identities (the panel below checks them again on the current state). At first order the traces equal the cell averages and the flux difference of an interior row jj, Hj+1−Hj=Rj+SjH_{j+1}-H_j=R_j+S_j, is

Rj+Sj=14(Uj+12−Uj−12)−(1+νh)(Uj+1−2Uj+Uj−1).R_j+S_j=\tfrac14\bigl(U_{j+1}^2-U_{j-1}^2\bigr)-\Bigl(1+\frac{\nu}{h}\Bigr)\bigl(U_{j+1}-2U_j+U_{j-1}\bigr).

这正是物理黏性 ν\nu 再加人工黏性 hh 的中心格式(除以 hh 后是 u ux−(ν+h) uxxu\,u_x-(\nu+h)\,u_{xx} 的中心差分):一阶格式在内部行上就是黏性 ν+h\nu+h 的中心格式。默认 N=8N=8 时 h=0.125h=0.125,是 ν=0.01\nu=0.01 的 12.5 倍;hh 要小到与 ν\nu 同量级(这里 N≈100N\approx100),人工黏性才不再主导。无限制器线性重构时,在两侧单元都做了重构的面上(2≤f≤N−22\le f\le N-2),耗散项是三阶差分:

This is exactly the central scheme for the physical viscosity ν\nu plus an artificial viscosity hh (divided by hh it is the central difference of u ux−(ν+h) uxxu\,u_x-(\nu+h)\,u_{xx}): on interior rows the first-order scheme is the central scheme for the viscosity ν+h\nu+h. At the default N=8N=8 one has h=0.125h=0.125, that is 12.5 times ν=0.01\nu=0.01; hh has to become comparable with ν\nu (about N≈100N\approx100 here) before the artificial viscosity stops dominating. With unlimited linear reconstruction, on a face whose two neighbouring cells are both reconstructed (2≤f≤N−22\le f\le N-2) the dissipation of the face is a third difference:

−(qR−qL)=14(Uf+1−3Uf+3Uf−1−Uf−2),-(q_R-q_L)=\tfrac14\bigl(U_{f+1}-3U_f+3U_{f-1}-U_{f-2}\bigr),

行 jj(2≤j≤N−32\le j\le N-3,即两个面之差)的耗散是四阶差分,对光滑数据是 O(h4)O(h^4):

and that of a row 2≤j≤N−32\le j\le N-3 (the difference of two faces) is a fourth difference, O(h4)O(h^4) for smooth data:

14(Uj+2−4Uj+1+6Uj−4Uj−1+Uj−2)=O(h4).\tfrac14\bigl(U_{j+2}-4U_{j+1}+6U_j-4U_{j-1}+U_{j-2}\bigr)=O(h^4).

所以远离端点时二阶格式没有二阶导数形式的人工黏性,只有四阶的超黏性;但在面 0,1,N−1,N0,1,N-1,N 上,有一侧的迹没有重构,耗散约为 −h2ux-\tfrac h2u_x,相当于 h/2h/2 的人工黏性(第 4 节)。一阶格式的人工黏性 hh 是两种阶数的主要差别,第 15 节(状态与梯度的误差)和第 16 节(伴随)把这个差别量出来。光滑限制器时权重随状态变化,没有这样的闭式。

So away from the ends the second-order scheme has no artificial viscosity of second-derivative form, only a fourth-order hyperviscosity; on faces 0,1,N−1,N0,1,N-1,N one trace is not reconstructed and the dissipation is about −h2ux-\tfrac h2u_x, an artificial viscosity h/2h/2 (Section 4). The artificial viscosity hh of the first-order scheme is the main difference between the two orders, and Section 15 (the errors of the state and the gradient) and Section 16 (the adjoint) put that difference in numbers. With the smooth limiter the weights change with the state and there is no such closed form.

重构:从单元平均到面上的状态

Reconstruction: from cell averages to face states

每个单元用一个斜率 σi\sigma_i 重构成一条线段,线段在单元两端的值就是相邻面的迹。斜率由两个单侧差 li=Ui−Ui−1l_i=U_i-U_{i-1}、ri=Ui+1−Uir_i=U_{i+1}-U_i 决定(σi\sigma_i 是穿过整个单元的变化量,不除以 hh);两端的单元不重构,σ0=σN−1=0\sigma_0=\sigma_{N-1}=0:

Each cell is reconstructed as a line segment with one slope σi\sigma_i, and the values of the segment at the two ends of the cell are the traces of the neighbouring faces. The slope is determined by the two one-sided differences li=Ui−Ui−1l_i=U_i-U_{i-1} and ri=Ui+1−Uir_i=U_{i+1}-U_i (σi\sigma_i is the change across the whole cell, not divided by hh); the two end cells are not reconstructed, σ0=σN−1=0\sigma_0=\sigma_{N-1}=0:

σi={0(𝚏𝚒𝚛𝚜𝚝),li+ri2(𝚗𝚘𝚗𝚎),li ri (li+ri)li2+ri2+ϵ2(𝚜𝚖𝚘𝚘𝚝𝚑), ϵ=0.01,qL=Uf−1+12σf−1,qR=Uf−12σf.\sigma_i=\begin{cases}0&(\mathtt{first}),\\[2pt] \dfrac{l_i+r_i}2&(\mathtt{none}),\\[6pt] \dfrac{l_i\,r_i\,(l_i+r_i)}{l_i^2+r_i^2+\epsilon^2}&(\mathtt{smooth}),\ \epsilon=0.01,\end{cases}\qquad q_L=U_{f-1}+\tfrac12\sigma_{f-1},\quad q_R=U_f-\tfrac12\sigma_f.

公式中的 first、none、smooth 是三种重构在代码里的名字,分别对应控制面板中的“一阶”“无限制器线性(二阶)”“光滑限制器”。“none”是无限制器的中心斜率,二阶精度,但不保证单调;“smooth”是 van Albada 型的光滑有理斜率:把它写成中心斜率乘一个因子,σi=li+ri2⋅2lirili2+ri2+ϵ2\sigma_i=\dfrac{l_i+r_i}2\cdot\dfrac{2l_ir_i}{l_i^2+r_i^2+\epsilon^2},因子严格落在 (−1,1)(-1,1) 内。li,ril_i,r_i 同号、相近且远大于 ϵ\epsilon 时因子接近 1,斜率回到中心斜率;有一个差分为零时因子为 0;在极值处(liri<0l_ir_i<0)因子为负,斜率很小并且与中心斜率反向,而不是被截成零。这个限制器没有硬开关,ϵ\epsilon 使它光滑,所以斜率处处可微;本页不声称它具有 TVD 或保正性。

In the formula, “first”, “none” and “smooth” are the code names of the three reconstructions (First order, Unlimited linear (second order) and Smooth limiter in the control panel). The slope “none” is the unlimited central slope: second-order accurate but not monotone. The slope “smooth” is the van Albada form, smooth because of ϵ\epsilon: written as the central slope times a factor, σi=li+ri2⋅2lirili2+ri2+ϵ2\sigma_i=\dfrac{l_i+r_i}2\cdot\dfrac{2l_ir_i}{l_i^2+r_i^2+\epsilon^2}, where the factor lies strictly inside (−1,1)(-1,1). It is close to 1 when li,ril_i,r_i have the same sign, are close to each other and are much larger than ϵ\epsilon, so the slope returns to the central one; it is 0 when one difference vanishes; at an extremum (liri<0l_ir_i<0) it is negative, so the slope is small and points against the central slope instead of being cut to zero. There is no hard switch, so the slope is differentiable everywhere; the page claims no TVD or positivity property for it.

无限制器线性重构时,迹是未知量的固定线性组合:内部面 qL=−14Uf−2+Uf−1+14Ufq_L=-\tfrac14U_{f-2}+U_{f-1}+\tfrac14U_f、qR=14Uf−1+Uf−14Uf+1q_R=\tfrac14U_{f-1}+U_f-\tfrac14U_{f+1},所以一个内部面依赖 4 个未知量(紧邻边界的面是 3 个,边界面是 1 个);一阶时只依赖 2 个。光滑限制器时这些权重随状态变化。

With unlimited linear reconstruction the traces are fixed linear combinations of the unknowns: on an interior face qL=−14Uf−2+Uf−1+14Ufq_L=-\tfrac14U_{f-2}+U_{f-1}+\tfrac14U_f and qR=14Uf−1+Uf−14Uf+1q_R=\tfrac14U_{f-1}+U_f-\tfrac14U_{f+1}, so an interior face depends on 4 unknowns (3 next to a boundary, 1 on a boundary face) and only on 2 at first order. With the smooth limiter these weights change with the state.

先用滑块看斜率:给定两个单侧差,三种重构在中间单元里画出什么线段。

First look at the slope with the sliders: given the two one-sided differences, what segment does each reconstruction draw in the middle cell.

图 7 · 一个内部面(面 f=4,默认设计的收敛解,无限制器线性重构)。四个单元的平均值(虚线)、各自的线性重构(实线)、面上的两个迹 q_L、q_R,以及用它们算出的对流、黏性与总通量。单元 2:U2​ = 1.1388单元 3:U3​ = 1.0683单元 4:U4​ = 0.9171单元 5:U5​ = 0.7835面 f = 4(x = 0.500)qL​ = 1.0129qR​ = 0.9883虚线:单元平均(黏性通量用)实线:线性重构,端点是迹(对流通量用)对流 Hc​ = ¼(qL​² + qR​²) − (qR​ − qL​) = 0.52529黏性 Hv​ = −κf​ (UR​ − UL​) = −0.080 × (0.91706 − 1.06834) = 0.01210Hf​ = Hc​ + Hv​ = 0.53739
图 7 · 一个内部面(面 f=4f=4,默认设计的收敛解,无限制器线性重构)。四个单元的平均值(虚线)、各自的线性重构(实线)、面上的两个迹 qLq_L、qRq_R,以及用它们算出的对流、黏性与总通量。
Figure 7 · One interior face (face f=4, converged solution of the default design, unlimited linear reconstruction). The averages of the four cells (dashed), their linear reconstructions (solid), the two traces q_L, q_R at the face, and the convective, viscous and total flux computed from them.cell 2: U2​ = 1.1388cell 3: U3​ = 1.0683cell 4: U4​ = 0.9171cell 5: U5​ = 0.7835face f = 4 (x = 0.500)qL​ = 1.0129qR​ = 0.9883dashed: cell averages (viscous flux)solid: linear reconstruction, its end points are the traces (convective flux)convective Hc​ = ¼(qL​² + qR​²) − (qR​ − qL​) = 0.52529viscous Hv​ = −κf​ (UR​ − UL​) = −0.080 × (0.91706 − 1.06834) = 0.01210Hf​ = Hc​ + Hv​ = 0.53739
Figure 7 · One interior face (face f=4f=4, converged solution of the default design, unlimited linear reconstruction). The averages of the four cells (dashed), their linear reconstructions (solid), the two traces qLq_L, qRq_R at the face, and the convective, viscous and total flux computed from them.

下面的播放器把这个面的计算拆成七步,每一步写出当时的数值;这七步就是第 5 节、第 8 节的四条语句(取值、重构、通量、分发),只是把迹和通量的两个部分分开显示。按“播放”或用步进按钮,换面、换重构再看一遍。

The player below splits the computation of this face into seven steps and writes the numbers of each step; the seven steps are the four statements gather, reconstruct, flux and scatter of Section 5 and Section 8, with the traces and the two parts of the flux shown separately. Press Play or use the step buttons, and change the face and the reconstruction to see it again.

一个面上的局部导数

Local derivatives on one face

第 8、9 节的切线与伴随,在面上只用到三类局部导数:数值通量对迹的偏导、对未重构状态的偏导,以及迹对未知量的偏导(此外还有通量对设计 ν\nu 的偏导,以及边界值和精确通量对设计的偏导)。数值通量是多项式,逐项求导:

On a face, the tangent and the adjoint of Sections 8 and 9 use only three kinds of local derivative: those of the numerical flux with respect to the traces, those with respect to the raw states, and those of the traces with respect to the unknowns (plus the derivative of the flux with respect to the design ν\nu and those of the boundary values and the exact fluxes with respect to the design). The numerical flux is a polynomial, so it is differentiated term by term:

cL=∂H∂qL=qL2+1,cR=∂H∂qR=qR2−1,∂H∂UL=+κf,∂H∂UR=−κf,κf=νdf,∂H∂ν=−UR−ULdf.c_L=\frac{\partial H}{\partial q_L}=\frac{q_L}2+1,\qquad c_R=\frac{\partial H}{\partial q_R}=\frac{q_R}2-1,\qquad \frac{\partial H}{\partial U_L}=+\kappa_f,\quad\frac{\partial H}{\partial U_R}=-\kappa_f,\quad \kappa_f=\frac{\nu}{d_f},\qquad \frac{\partial H}{\partial\nu}=-\frac{U_R-U_L}{d_f}.

有两个性质可以检验这些公式。相容性 Hc(u,u)=u2/2H^c(u,u)=u^2/2 沿 qL=qR=uq_L=q_R=u 求导,得 cL+cR=uc_L+c_R=u:两个偏导把波速分成上游和下游两份。当 ∣qL∣,∣qR∣<2|q_L|,|q_R|<2 时 cL>0>cRc_L>0>c_R:通量随左状态增加、随右状态减小。默认设计的各面上(无限制器线性)cLc_L 在 1.374 与 1.565 之间,cRc_R 在 −0.625 与 −0.426 之间。黏性偏导 ±κf\pm\kappa_f 是常数,内部面 κf=ν/h=0.080\kappa_f=\nu/h=0.080。

Two properties check these formulas. Consistency Hc(u,u)=u2/2H^c(u,u)=u^2/2 differentiated along qL=qR=uq_L=q_R=u gives cL+cR=uc_L+c_R=u: the two partial derivatives split the wave speed into an upstream and a downstream share. For ∣qL∣,∣qR∣<2|q_L|,|q_R|<2 one has cL>0>cRc_L>0>c_R: the flux increases with the left state and decreases with the right one. On the faces of the default design (unlimited linear) cLc_L lies between 1.374 and 1.565 and cRc_R between −0.625 and −0.426. The viscous partials ±κf\pm\kappa_f are constants, κf=ν/h=0.080\kappa_f=\nu/h=0.080 on interior faces.

迹对未知量的导数在无限制器线性重构下就是上面的权重,与状态无关;光滑限制器时多一项:qL=Uf−1+12σf−1q_L=U_{f-1}+\tfrac12\sigma_{f-1} 的导数含 ∂σ/∂l, ∂σ/∂r\partial\sigma/\partial l,\ \partial\sigma/\partial r,它们随状态变化(线性重构时它们是常数 12,12\tfrac12,\tfrac12)。图 8 左:cL,cRc_L,c_R 随状态变化,灰带是本页各面迹的范围;右:每个面的通量对每个未知量的导数 ∂Hf/∂Uj\partial H_f/\partial U_j,一阶时每个内部面涉及 2 个未知量,无限制器线性时涉及 4 个。

The derivative of a trace with respect to the unknowns is the weight above and does not depend on the state for unlimited linear reconstruction; with the smooth limiter there is one more term: the derivative of qL=Uf−1+12σf−1q_L=U_{f-1}+\tfrac12\sigma_{f-1} contains ∂σ/∂l, ∂σ/∂r\partial\sigma/\partial l,\ \partial\sigma/\partial r, which change with the state (for linear reconstruction they are the constants 12,12\tfrac12,\tfrac12). Figure 8 left: cL,cRc_L,c_R against the state, the grey band being the range of the traces of this page; right: the derivative of every face flux with respect to every unknown, ∂Hf/∂Uj\partial H_f/\partial U_j; an interior face touches 2 unknowns at first order and 4 with unlimited linear reconstruction.

图 8 · 一个面上的导数(默认设计)。左:q_L=q_R=u 时 c_L=u/2+1 与 c_R=u/2-1,虚线是它们的和 u,灰带是本页各面迹的范围。右:∂ H_f/∂ U_j,蓝正橙负;一阶(上)每个内部面涉及两个未知量,无限制器线性(下)涉及四个(紧邻边界的面三个,边界面一个)。−0.500.511.50.40.60.811.21.4面上的状态 u(qL​ = qR​ = u)cL​ = u/2 + 1cR​ = u/2 − 1cL​ + cR​ = u−0.641.60−0.531.63−0.541.62−0.601.56−0.671.49−0.701.46−0.691.47−0.651.5901234567012345678一阶:∂Hf​/∂Uj​列 j(未知量)−0.651.48−0.540.12−0.391.54−0.120.11−0.391.54−0.130.11−0.381.46−0.210.13−0.361.36−0.310.15−0.341.30−0.360.16−0.351.48−0.301.5901234567012345678无限制器线性:∂Hf​/∂Uj​
图 8 · 一个面上的导数(默认设计)。左:qL=qR=uq_L=q_R=u 时 cL=u/2+1c_L=u/2+1 与 cR=u/2−1c_R=u/2-1,虚线是它们的和 uu,灰带是本页各面迹的范围。右:∂Hf/∂Uj\partial H_f/\partial U_j,蓝正橙负;一阶(上)每个内部面涉及两个未知量,无限制器线性(下)涉及四个(紧邻边界的面三个,边界面一个)。
Figure 8 · Derivatives on one face (default design). Left: c_L=u/2+1 and c_R=u/2-1 for equal traces q_L=q_R=u, the dashed line is their sum u, the grey band is the range of the traces of this page. Right: ∂ H_f/∂ U_j, blue positive and orange negative; at first order (top) an interior face touches two unknowns, with unlimited linear reconstruction (bottom) four (three next to a boundary, one on a boundary face).−0.500.511.50.40.60.811.21.4state u at the face (qL​ = qR​ = u)cL​ = u/2 + 1cR​ = u/2 − 1cL​ + cR​ = u−0.641.60−0.531.63−0.541.62−0.601.56−0.671.49−0.701.46−0.691.47−0.651.5901234567012345678first order: ∂Hf​/∂Uj​column j (unknown)−0.651.48−0.540.12−0.391.54−0.120.11−0.391.54−0.130.11−0.381.46−0.210.13−0.361.36−0.310.15−0.341.30−0.360.16−0.351.48−0.301.5901234567012345678unlimited linear: ∂Hf​/∂Uj​
Figure 8 · Derivatives on one face (default design). Left: cL=u/2+1c_L=u/2+1 and cR=u/2−1c_R=u/2-1 for equal traces qL=qR=uq_L=q_R=u, the dashed line is their sum uu, the grey band is the range of the traces of this page. Right: ∂Hf/∂Uj\partial H_f/\partial U_j, blue positive and orange negative; at first order (top) an interior face touches two unknowns, with unlimited linear reconstruction (bottom) four (three next to a boundary, one on a boundary face).

一个面上的数值(面 f=4f=4,x=0.500x=0.500)

One face with the page's numbers (face f=4f=4, x=0.500x=0.500)

下表是三种重构各自的收敛解在同一个面上的量;每个重构的解不同,所以连未重构状态 UL,URU_L,U_R 也不同。验证:Hf=Hc+HvH_f=H^c+H^v,cL,cRc_L,c_R 由迹算出。

The table lists the quantities of the same face in the converged solution of each reconstruction; the solutions differ, so even the raw states UL,URU_L,U_R differ. Check: Hf=Hc+HvH_f=H^c+H^v, and cL,cRc_L,c_R follow from the traces.

量Quantity公式Formula一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
qLq_LUf−1+12σf−1U_{f-1}+\tfrac12\sigma_{f-1}0.9509581.0128990.994602
qRq_RUf−12σfU_f-\tfrac12\sigma_f0.8231700.9882740.949153
UL, URU_L,\ U_RUf−1, UfU_{f-1},\ U_f0.95096, 0.823171.06834, 0.917061.04010, 0.87288
HcH^c14(qL2+qR2)−(qR−qL)\tfrac14(q_L^2+q_R^2)-(q_R-q_L)0.5232700.5252870.517980
HvH^v−κf(UR−UL)-\kappa_f(U_R-U_L)0.0102230.0121020.013378
HfH_fHc+HvH^c+H^v0.5334930.5373890.531358
cL, cRc_L,\ c_RqL/2+1, qR/2−1q_L/2+1,\ q_R/2-11.4755, −0.58841.5064, −0.50591.4973, −0.5254

注意一阶时两个迹等于单元平均,对流部分的跳跃 qR−qL=UR−ULq_R-q_L=U_R-U_L 较大,人工黏性起作用;无限制器线性时跳跃小得多。换一个面、换一种重构试试:

Note that at first order the traces equal the cell averages, the jump qR−qL=UR−ULq_R-q_L=U_R-U_L of the convective part is larger and the artificial viscosity acts; with unlimited linear reconstruction the jump is much smaller. Try another position and another reconstruction:

第 4 节处理两个边界面:它们没有单元可读,用给定的边界值和半个单元的距离。第 5 节把面的计算(清单中的语句 5–9)写成残差代码。

Section 4 writes the two end faces: they have no cell to read and use the prescribed boundary value and half a cell of distance. Section 5 writes the face computation (statements 5–9 of its listing) as the residual code.

第 4 节Section 4

边界条件:两个边界面

Boundary conditions: the two end faces

本节实验:面 00 只有右边有单元。先预测:把精确单元平均代入残差,单元 0 的 R0R_0 和内部单元的 RiR_i 哪个更大、差几阶 hh?端点行如果更不准,整个解的误差会因此降阶吗?写下预测,再看图 12。

Experiment: Face 00 has a cell on its right only. Predict first: when the exact cell averages are put into the residual, which is larger, R0R_0 of cell 0 or the RiR_i of an interior cell, and by how many powers of hh? If the end rows are less accurate, does the error of the whole solution lose an order? Write your prediction down, then look at Figure 12.

第 3 节写的是两侧都有单元的面。区间两端的面 f=0f=0 与 f=Nf=N 只有一侧有单元;本节说明它们读什么、怎样求导、有多准,以及为什么它们不太准却不改变整个解的渐近阶。

Section 3 wrote the flux of a face with a cell on each side. The two faces at the ends of the interval, f=0f=0 and f=Nf=N, have a cell on one side only; this section says what they read, how they are differentiated, how accurate they are, and why their lower accuracy does not change the asymptotic order of the whole solution.

为什么两端各要一个值

Why each end needs a value

把定常方程 qx=sq_x=s 从 00 积到 xx:

Integrate the steady equation qx=sq_x=s from 00 to xx:

q(x)=q(0)+∫0xs dt=q(0)+q∗(x)−q∗(0),ν ux=12u2−q(x).q(x)=q(0)+\int_0^xs\,\mathrm dt=q(0)+q^*(x)-q^*(0),\qquad \nu\,u_x=\tfrac12u^2-q(x).

第一式说明通量只剩一个待定常数 q(0)q(0);第二式是 uu 的一阶常微分方程,又带来一个积分常数。两个常数要两个条件:u(0)=uinu(0)=u_{\rm in},u(1)=uoutu(1)=u_{\rm out}。没有黏性(ν=0\nu=0)时第二式变成代数关系 12u2=q(x)\tfrac12u^2=q(x),只剩常数 q(0)q(0),入口给一个值就够了——这就是无黏 Burgers 页面只给入口条件的原因。对构造解 u=u∗u=u^*,q(0)=q∗(0)q(0)=q^*(0),即 q=q∗q=q^*。第 5 节会看到,离散解满足同样形式的关系,只是多出一个不为零的常数。

The first relation says that the flux is fixed up to one constant, q(0)q(0); the second is a first-order ordinary differential equation for uu, which brings a second constant of integration. Two constants need two conditions: u(0)=uinu(0)=u_{\rm in} and u(1)=uoutu(1)=u_{\rm out}. Without viscosity (ν=0\nu=0) the second relation becomes the algebraic 12u2=q(x)\tfrac12u^2=q(x), only the constant q(0)q(0) is left, and one inlet value is enough: this is why the inviscid Burgers pages prescribe an inlet value only. For the manufactured solution u=u∗u=u^* one has q(0)=q∗(0)q(0)=q^*(0), that is q=q∗q=q^*. Section 5 shows that the discrete solution satisfies a relation of the same form, with an extra constant that is not zero.

边界面读什么

What the end faces read

注意字母 qq 的两种用法:上一小节的 qq、q∗q^* 是方程的总通量,下面的 qL,qRq_L,q_R 是第 3 节的迹(重构到面上的状态)。面 00 在 x=0x=0,右边是单元 00,左边没有单元。给定值 uinu_{\rm in} 顶替缺失的左侧,而且在通量的两部分里都顶替:对流部分的左迹 qL(0)=uinq_L(0)=u_{\rm in},黏性部分的左状态 UL(0)=uinU_L(0)=u_{\rm in};黏性差商的距离是从边界到单元 00 中心的 d0=h/2d_0=h/2。面 NN 对称地用 uoutu_{\rm out} 顶替右侧:

Note the two uses of the letter qq: the qq and q∗q^* above are total fluxes of the equation, the qL,qRq_L,q_R below are the traces of Section 3 (states reconstructed at a face). Face 00 is at x=0x=0 with cell 00 on its right and no cell on its left. The prescribed value uinu_{\rm in} takes the place of the missing left side, in both parts of the flux: the left trace of the convective part is qL(0)=uinq_L(0)=u_{\rm in} and the left state of the viscous part is UL(0)=uinU_L(0)=u_{\rm in}; the distance of the viscous difference quotient is d0=h/2d_0=h/2, from the boundary to the centre of cell 00. Face NN uses uoutu_{\rm out} in place of its missing right side, symmetrically:

qL(0)=UL(0)=uin,qR(0)=UR(0)=U0,d0=h2;qL(N)=UL(N)=UN−1,qR(N)=UR(N)=uout,dN=h2.q_L(0)=U_L(0)=u_{\rm in},\quad q_R(0)=U_R(0)=U_0,\quad d_0=\tfrac h2;\qquad q_L(N)=U_L(N)=U_{N-1},\quad q_R(N)=U_R(N)=u_{\rm out},\quad d_N=\tfrac h2.

为什么 qR(0)q_R(0) 就是 U0U_0?单元 00 的斜率 σ0\sigma_0 需要左差分 l0=U0−U−1l_0=U_0-U_{-1},而 U−1U_{-1} 在区间之外。格式不造虚拟单元,干脆不重构两端的单元:σ0=σN−1=0\sigma_0=\sigma_{N-1}=0。于是单元 00 在它两个面上的迹都等于平均值,qR(0)=U0q_R(0)=U_0,而且 qL(1)=U0q_L(1)=U_0;同理 qL(N)=qR(N−1)=UN−1q_L(N)=q_R(N-1)=U_{N-1}。后果有两个:两个边界面通量各只依赖一个未知量(三种重构都如此);面 11 与面 N−1N-1 各有一个迹没有重构,它们只有一阶精度(下面会量到)。

Why is qR(0)q_R(0) just U0U_0? The slope σ0\sigma_0 of cell 00 would need the left difference l0=U0−U−1l_0=U_0-U_{-1}, and U−1U_{-1} lies outside the interval. The scheme invents no ghost cell; it simply does not reconstruct the two end cells: σ0=σN−1=0\sigma_0=\sigma_{N-1}=0. So the traces of cell 00 on both its faces equal its average, qR(0)=U0q_R(0)=U_0 and also qL(1)=U0q_L(1)=U_0; likewise qL(N)=qR(N−1)=UN−1q_L(N)=q_R(N-1)=U_{N-1}. This has two consequences: each end-face flux depends on a single unknown (for all three reconstructions), and faces 11 and N−1N-1 each have one unreconstructed trace, which makes them only first-order accurate (measured below).

图 9 · 两个边界面读的数据(默认设计的收敛解,N=8,无限制器线性重构)。虚线框是不存在的单元,紫色方块是给定值,紫色箭头是半个单元的距离 d=h/2;端单元的线段是水平的(σ_0=σ_(N-1)=0),其余单元是线性重构。每一端旁边是那个边界面通量的分项和它的导数,数字来自本页的模型。面 0(x = 0):uin​ 顶替缺失的左侧U0​单元 0σ = 0,不重构U1​单元 1U2​单元 2无单元uin​d = h/2qL​ = UL​ = uin​ = 0.91484qR​ = UR​ = U0​ = 1.02465Hc​ = 0.36191,Hv​ = −0.01757H0​ = 0.34434∂H0​/∂U0​ = U0​/2 − 1 − 2ν/h = −0.6477∂H0​/∂uin​ = uin​/2 + 1 + 2ν/h = 1.6174∂H0​/∂ν = −(U0​ − uin​)/(h/2) = −1.7569面 N = 8(x = 1):uout​ 顶替缺失的右侧U5​单元 5U6​单元 6U7​单元 7σ = 0,不重构无单元uout​d = h/2qL​ = UL​ = UN−1​ = 0.86868qR​ = UR​ = uout​ = 0.91484Hc​ = 0.35172,Hv​ = −0.00739HN​ = 0.34434∂HN​/∂UN−1​ = UN−1​/2 + 1 + 2ν/h = 1.5943∂HN​/∂uout​ = uout​/2 − 1 − 2ν/h = −0.7026∂HN​/∂ν = −(uout​ − UN−1​)/(h/2) = −0.7386
图 9 · 两个边界面读的数据(默认设计的收敛解,N=8N=8,无限制器线性重构)。虚线框是不存在的单元,紫色方块是给定值,紫色箭头是半个单元的距离 d=h/2d=h/2;端单元的线段是水平的(σ0=σN−1=0\sigma_0=\sigma_{N-1}=0),其余单元是线性重构。每一端旁边是那个边界面通量的分项和它的导数,数字来自本页的模型。
Figure 9 · What the two end faces read (converged solution of the default design, N=8, unlimited linear reconstruction). The dashed boxes are the cells that do not exist, the violet squares are the prescribed values and the violet arrows the half-cell distance d=h/2; the segments of the end cells are flat (σ_0=σ_(N-1)=0), the other cells are reconstructed linearly. Beside each end: the parts of that end-face flux and its derivatives, numbers from the page's model.face 0 (x = 0): uin​ in place of the missing left sideU0​cell 0σ = 0, flatU1​cell 1U2​cell 2no celluin​d = h/2qL​ = UL​ = uin​ = 0.91484qR​ = UR​ = U0​ = 1.02465Hc​ = 0.36191, Hv​ = −0.01757H0​ = 0.34434∂H0​/∂U0​ = U0​/2 − 1 − 2ν/h = −0.6477∂H0​/∂uin​ = uin​/2 + 1 + 2ν/h = 1.6174∂H0​/∂ν = −(U0​ − uin​)/(h/2) = −1.7569face N = 8 (x = 1): uout​ in place of the missing right sideU5​cell 5U6​cell 6U7​cell 7σ = 0, flatno celluout​d = h/2qL​ = UL​ = UN−1​ = 0.86868qR​ = UR​ = uout​ = 0.91484Hc​ = 0.35172, Hv​ = −0.00739HN​ = 0.34434∂HN​/∂UN−1​ = UN−1​/2 + 1 + 2ν/h = 1.5943∂HN​/∂uout​ = uout​/2 − 1 − 2ν/h = −0.7026∂HN​/∂ν = −(uout​ − UN−1​)/(h/2) = −0.7386
Figure 9 · What the two end faces read (converged solution of the default design, N=8N=8, unlimited linear reconstruction). The dashed boxes are the cells that do not exist, the violet squares are the prescribed values and the violet arrows the half-cell distance d=h/2d=h/2; the segments of the end cells are flat (σ0=σN−1=0\sigma_0=\sigma_{N-1}=0), the other cells are reconstructed linearly. Beside each end: the parts of that end-face flux and its derivatives, numbers from the page's model.

两个边界面通量的完整写法

The two end-face fluxes written in full

H0=14(uin2+U02)−(U0−uin)−2νh(U0−uin),HN=14(UN−12+uout2)−(uout−UN−1)−2νh(uout−UN−1).\begin{aligned}H_0&=\tfrac14\bigl(u_{\rm in}^2+U_0^2\bigr)-\bigl(U_0-u_{\rm in}\bigr)-\frac{2\nu}h\bigl(U_0-u_{\rm in}\bigr),\\ H_N&=\tfrac14\bigl(U_{N-1}^2+u_{\rm out}^2\bigr)-\bigl(u_{\rm out}-U_{N-1}\bigr)-\frac{2\nu}h\bigl(u_{\rm out}-U_{N-1}\bigr).\end{aligned}

求导只需第 3 节的局部导数,把 κf\kappa_f 换成边界面的 κ0=κN=ν/(h/2)=2ν/h\kappa_0=\kappa_N=\nu/(h/2)=2\nu/h:

Differentiating them needs only the local derivatives of Section 3, with κf\kappa_f replaced by the end-face value κ0=κN=ν/(h/2)=2ν/h\kappa_0=\kappa_N=\nu/(h/2)=2\nu/h:

∂H0∂U0=cR−κ0=U02−1−2νh,∂H0∂uin=cL+κ0=uin2+1+2νh,∂H0∂ν=−U0−uinh/2,∂HN∂UN−1=cL+κN=UN−12+1+2νh,∂HN∂uout=cR−κN=uout2−1−2νh,∂HN∂ν=−uout−UN−1h/2.\begin{aligned}\frac{\partial H_0}{\partial U_0}&=c_R-\kappa_0=\frac{U_0}2-1-\frac{2\nu}h,&\frac{\partial H_0}{\partial u_{\rm in}}&=c_L+\kappa_0=\frac{u_{\rm in}}2+1+\frac{2\nu}h,&\frac{\partial H_0}{\partial\nu}&=-\frac{U_0-u_{\rm in}}{h/2},\\ \frac{\partial H_N}{\partial U_{N-1}}&=c_L+\kappa_N=\frac{U_{N-1}}2+1+\frac{2\nu}h,&\frac{\partial H_N}{\partial u_{\rm out}}&=c_R-\kappa_N=\frac{u_{\rm out}}2-1-\frac{2\nu}h,&\frac{\partial H_N}{\partial\nu}&=-\frac{u_{\rm out}-U_{N-1}}{h/2}.\end{aligned}

默认设计下(N=8N=8,无限制器线性):uin=0.914844u_{\rm in}=0.914844,U0=1.024651U_0=1.024651,Hc=0.361906H^c=0.361906,Hv=−0.017569H^v=-0.017569,H0=0.344337H_0=0.344337,∂H0/∂U0=−0.64767\partial H_0/\partial U_0=-0.64767,∂H0/∂uin=1.61742\partial H_0/\partial u_{\rm in}=1.61742,∂H0/∂ν=−1.75690\partial H_0/\partial\nu=-1.75690。第 8 节的前向代码取种子 𝐔˙=e0, eN−1\dot{\mathbf U}=e_0,\ e_{N-1} 和 D˙=ek\dot D=e_k 时算出的 H˙0, H˙N\dot H_0,\ \dot H_N 与这些公式一致(三种重构,最大差 2.2e−16)。

At the defaults (N=8N=8, unlimited linear): uin=0.914844u_{\rm in}=0.914844, U0=1.024651U_0=1.024651, Hc=0.361906H^c=0.361906, Hv=−0.017569H^v=-0.017569, H0=0.344337H_0=0.344337, ∂H0/∂U0=−0.64767\partial H_0/\partial U_0=-0.64767, ∂H0/∂uin=1.61742\partial H_0/\partial u_{\rm in}=1.61742, ∂H0/∂ν=−1.75690\partial H_0/\partial\nu=-1.75690. The forward code of Section 8, seeded with 𝐔˙=e0, eN−1\dot{\mathbf U}=e_0,\ e_{N-1} and D˙=ek\dot D=e_k, returns H˙0, H˙N\dot H_0,\ \dot H_N equal to these formulas (all three reconstructions; largest difference 2.2e−16).

这些导数进入哪里?R0=H1−H0−S0R_0=H_1-H_0-S_0 含 −H0-H_0,所以 ∂H0/∂U0\partial H_0/\partial U_0 以负号进入对角元 A00A_{00},贡献 1−U0/2+2ν/h>01-U_0/2+2\nu/h>0:边界面加强了对角线。uinu_{\rm in} 只出现在 H0H_0 里,所以只进入 RDR_D 的第 0 行;uoutu_{\rm out} 只进入最后一行。

Where do these derivatives go? R0=H1−H0−S0R_0=H_1-H_0-S_0 contains −H0-H_0, so ∂H0/∂U0\partial H_0/\partial U_0 enters the diagonal entry A00A_{00} with a minus sign and contributes 1−U0/2+2ν/h>01-U_0/2+2\nu/h>0: the boundary face strengthens the diagonal. uinu_{\rm in} occurs in H0H_0 only, so it enters only row 0 of RDR_D; uoutu_{\rm out} enters only the last row.

边界值与它的切向量

The boundary data and their tangent

边界值由设计决定:uin=u∗(0)=1−a sin⁡2πφu_{\rm in}=u^*(0)=1-a\,\sin 2\pi\varphi;u∗u^* 以 1 为周期,所以 uout=u∗(1)=uinu_{\rm out}=u^*(1)=u_{\rm in}。它们的切向量(第 8 节前向代码的语句 2)是

The boundary data are functions of the design: uin=u∗(0)=1−a sin⁡2πφu_{\rm in}=u^*(0)=1-a\,\sin 2\pi\varphi, and since u∗u^* has period 1, uout=u∗(1)=uinu_{\rm out}=u^*(1)=u_{\rm in}. Their tangent (statement 2 of the forward code of Section 8) is

u˙in=u˙out=−sin⁡(2πφ) a˙−2πa cos⁡(2πφ) φ˙.\dot u_{\rm in}=\dot u_{\rm out}=-\sin(2\pi\varphi)\,\dot a-2\pi a\,\cos(2\pi\varphi)\,\dot\varphi.

这里没有 ν˙\dot\nu 项:u∗u^* 不依赖 ν\nu,边界值也就不依赖 ν\nu。但 ν\nu 仍然进入边界面,途径是 κ0=2ν/h\kappa_0=2\nu/h 和 ∂H0/∂ν\partial H_0/\partial\nu。默认设计下 ∂uin/∂a=−0.425779\partial u_{\rm in}/\partial a=-0.425779,∂uin/∂φ=−1.137039\partial u_{\rm in}/\partial\varphi=-1.137039;后者恰好等于 −u∗′(0)-u^{*\prime}(0),因为相位 φ\varphi 平移整条波:∂u∗/∂φ=−∂u∗/∂x\partial u^*/\partial\varphi=-\partial u^*/\partial x。

There is no ν˙\dot\nu term: u∗u^* does not depend on ν\nu, so neither do the boundary data. But ν\nu still enters the end faces, through κ0=2ν/h\kappa_0=2\nu/h and ∂H0/∂ν\partial H_0/\partial\nu. At the defaults ∂uin/∂a=−0.425779\partial u_{\rm in}/\partial a=-0.425779 and ∂uin/∂φ=−1.137039\partial u_{\rm in}/\partial\varphi=-1.137039; the latter is exactly −u∗′(0)-u^{*\prime}(0), because the phase φ\varphi shifts the whole wave: ∂u∗/∂φ=−∂u∗/∂x\partial u^*/\partial\varphi=-\partial u^*/\partial x.

自己动手:调节 U0U_0 和 uinu_{\rm in},看边界面通量的两部分、三个偏导和半单元差商怎样变;按钮可把 U0U_0 设为精确平均或求解值。

Try it: adjust U0U_0 and uinu_{\rm in} and watch the two parts of the end-face flux, its three partial derivatives and the half-cell difference quotient; the buttons set U0U_0 to the exact average or to the solved value.

半个单元的差商有多准?

How accurate is the half-cell difference quotient?

设 uu 光滑,⟨u⟩0=1h∫0hu dx\langle u\rangle_0=\frac1h\int_0^hu\,\mathrm dx 是它在单元 0 上的平均。把 uu 在 x=0x=0 处展开后逐项积分,得到第一行;减去 u(0)u(0) 再除以 h/2h/2,得到第二行:

Let uu be smooth and ⟨u⟩0=1h∫0hu dx\langle u\rangle_0=\frac1h\int_0^hu\,\mathrm dx its average over cell 0. Expanding uu about x=0x=0 and integrating term by term gives the first line; subtracting u(0)u(0) and dividing by h/2h/2 gives the second:

⟨u⟩0=u(0)+h2u′(0)+h26u′′(0)+h324u′′′(0)+O(h4),⟨u⟩0−u(0)h/2=u′(0)+h3 u′′(0)+h212 u′′′(0)+O(h3).\begin{aligned}\langle u\rangle_0&=u(0)+\frac h2u'(0)+\frac{h^2}6u''(0)+\frac{h^3}{24}u'''(0)+O(h^4),\\ \frac{\langle u\rangle_0-u(0)}{h/2}&=u'(0)+\frac h3\,u''(0)+\frac{h^2}{12}\,u'''(0)+O(h^3).\end{aligned}

这个差商只有一阶精度,首项误差是 h3u′′(0)\tfrac h3u''(0)。内部面不同:在面 xfx_f 处展开两侧平均,偶数阶项对称抵消,得到二阶精度:

This quotient is only first-order accurate, with leading error h3u′′(0)\tfrac h3u''(0). An interior face is different: expanding the two averages about xfx_f, the even terms cancel by symmetry, and the quotient is second-order accurate:

⟨u⟩f−⟨u⟩f−1h=u′(xf)+h212 u′′′(xf)+O(h4).\frac{\langle u\rangle_f-\langle u\rangle_{f-1}}h=u'(x_f)+\frac{h^2}{12}\,u'''(x_f)+O(h^4).

常见的错误:把单元平均当成中心点的值。若 U0U_0 是点值 u(h/2)u(h/2),二次项是 h28u′′\frac{h^2}8u'',系数是 h/4h/4;单元平均的二次项是 h26u′′\frac{h^2}6u'',系数是 h/3h/3。图 10 把两者都画了出来。

A common slip: treating the cell average as the value at the centre. If U0U_0 were the point value u(h/2)u(h/2) its quadratic term would be h28u′′\frac{h^2}8u'' and the coefficient h/4h/4; the average has the quadratic term h26u′′\frac{h^2}6u'' and the coefficient h/3h/3. Figure 10 draws both.

用 u∗u^* 实测:u∗′(0)=1.137039u^{*\prime}(0)=1.137039,u∗′′(0)/3=1.120606u^{*\prime\prime}(0)/3=1.120606。N=1024N=1024 时差商误差除以 hh 得 1.11695;再减去 h3u∗′′(0)\tfrac h3u^{*\prime\prime}(0) 后除以 h2h^2 得 −3.7429,对应 u∗′′′(0)/12=−3.7407u^{*\prime\prime\prime}(0)/12=-3.7407。若用中心点值,误差除以 hh 得 0.83863,对应 u∗′′(0)/4=0.84045u^{*\prime\prime}(0)/4=0.84045。展开式的前两项都由数值证实。

Measured with u∗u^*: u∗′(0)=1.137039u^{*\prime}(0)=1.137039 and u∗′′(0)/3=1.120606u^{*\prime\prime}(0)/3=1.120606. At N=1024N=1024 the error of the quotient divided by hh is 1.11695; after subtracting h3u∗′′(0)\tfrac h3u^{*\prime\prime}(0) and dividing by h2h^2 it is −3.7429, against u∗′′′(0)/12=−3.7407u^{*\prime\prime\prime}(0)/12=-3.7407. With the centre value the error divided by hh is 0.83863, against u∗′′(0)/4=0.84045u^{*\prime\prime}(0)/4=0.84045. Both terms of the expansion are confirmed numerically.

图 10 · 边界面差商的精度(u* 的精确单元平均,默认设计)。紫:边界面的半单元差商 (⟨u*⟩_0-u_in)/(h/2) 的误差,斜率 1,贴着点线 h/3u*′′(0);灰虚线:若把 U_0 当成中心点值,误差小一些(系数 h/4),但仍是一阶;蓝:内部面 x=1/2 的差商,斜率 2。10-7​10-6​10-5​10-4​10-3​10-2​10-1​1101001000N差商的误差(h/3)u*″(0)h²边界面:(⟨u*⟩0​ − uin​)/(h/2)若用中心点值 u*(h/2)内部面 x = 1/2
图 10 · 边界面差商的精度(u∗u^* 的精确单元平均,默认设计)。紫:边界面的半单元差商 (⟨u∗⟩0−uin)/(h/2)(\langle u^*\rangle_0-u_{\rm in})/(h/2) 的误差,斜率 1,贴着点线 h3u∗′′(0)\tfrac{h}{3}u^{*\prime\prime}(0);灰虚线:若把 U0U_0 当成中心点值,误差小一些(系数 h/4h/4),但仍是一阶;蓝:内部面 x=1/2x=1/2 的差商,斜率 2。
Figure 10 · The accuracy of the end-face difference quotient (exact cell averages of u*, default design). Violet: the error of the half-cell quotient (⟨u*⟩_0-u_in)/(h/2), slope 1, on the dotted line h/3u*′′(0); grey dashed: treating U_0 as the centre value gives a smaller error (coefficient h/4), still first order; blue: the quotient of the interior face x=1/2, slope 2.10-7​10-6​10-5​10-4​10-3​10-2​10-1​1101001000Nerror of the quotient(h/3)u*″(0)h²end face: (⟨u*⟩0​ − uin​)/(h/2)with the centre value u*(h/2)interior face x = 1/2
Figure 10 · The accuracy of the end-face difference quotient (exact cell averages of u∗u^*, default design). Violet: the error of the half-cell quotient (⟨u∗⟩0−uin)/(h/2)(\langle u^*\rangle_0-u_{\rm in})/(h/2), slope 1, on the dotted line h3u∗′′(0)\tfrac{h}{3}u^{*\prime\prime}(0); grey dashed: treating U0U_0 as the centre value gives a smaller error (coefficient h/4h/4), still first order; blue: the quotient of the interior face x=1/2x=1/2, slope 2.

边界面的对流部分同样只有一阶:qR(0)=⟨u∗⟩0q_R(0)=\langle u^*\rangle_0 不是面上的值,而跳跃 qR−qL≈h2u∗′(0)q_R-q_L\approx\frac h2u^{*\prime}(0) 使 Rusanov 耗散 −(qR−qL)-(q_R-q_L) 起作用,这是一个约 −h2u∗′(0)-\frac h2u^{*\prime}(0) 的人工黏性通量。记精确平均组成的向量为 ⟨u∗⟩=(⟨u∗⟩0,…,⟨u∗⟩N−1)T\langle u^*\rangle=(\langle u^*\rangle_0,\dots,\langle u^*\rangle_{N-1})^T。把 HcH^c 在 uinu_{\rm in} 处线性化(cR=uin/2−1c_R=u_{\rm in}/2-1),加上黏性部分,边界面通量在精确平均处的误差是

The convective part of the end face is first order as well: qR(0)=⟨u∗⟩0q_R(0)=\langle u^*\rangle_0 is not the value at the face, and the jump qR−qL≈h2u∗′(0)q_R-q_L\approx\frac h2u^{*\prime}(0) brings in the Rusanov dissipation −(qR−qL)-(q_R-q_L), an artificial viscous flux of about −h2u∗′(0)-\frac h2u^{*\prime}(0). Write ⟨u∗⟩=(⟨u∗⟩0,…,⟨u∗⟩N−1)T\langle u^*\rangle=(\langle u^*\rangle_0,\dots,\langle u^*\rangle_{N-1})^T for the vector of exact averages. Linearising HcH^c about uinu_{\rm in} (cR=uin/2−1c_R=u_{\rm in}/2-1) and adding the viscous part, the error of the end-face flux at the exact averages is

ζ0=H0(⟨u∗⟩)−q∗(0)=[(uin2−1)u∗′(0)2−ν3 u∗′′(0)]h+O(h2),\zeta_0=H_0(\langle u^*\rangle)-q^*(0)=\Bigl[\Bigl(\frac{u_{\rm in}}2-1\Bigr)\frac{u^{*\prime}(0)}2-\frac\nu3\,u^{*\prime\prime}(0)\Bigr]h+O(h^2),

系数为 −0.31967;实测 N=4096N=4096 时 ζ0/h=−0.31972\zeta_0/h=-0.31972。

with the coefficient −0.31967; measured at N=4096N=4096: ζ0/h=−0.31972\zeta_0/h=-0.31972.

截断误差:端点行与内部行

The truncation error: end rows against interior rows

把精确单元平均代入残差,看它离零有多远:这就是截断误差。对每个面定义面误差 ζf=Hf(⟨u∗⟩)−Qf\zeta_f=H_f(\langle u^*\rangle)-Q_f(精确平均处的数值通量减去精确通量)。源项是精确的(第 5 节),所以残差就是相邻两个面误差之差:

Put the exact cell averages into the residual and see how far it is from zero: that is the truncation error. Define for every face the face error ζf=Hf(⟨u∗⟩)−Qf\zeta_f=H_f(\langle u^*\rangle)-Q_f (the numerical flux at the exact averages minus the exact flux). The source is exact (Section 5), so the residual is the difference of two neighbouring face errors:

Ri(⟨u∗⟩)=ζi+1−ζi,ζf=Hf(⟨u∗⟩)−Qf.R_i(\langle u^*\rangle)=\zeta_{i+1}-\zeta_i,\qquad \zeta_f=H_f(\langle u^*\rangle)-Q_f.

无限制器线性时内部面的 ζf=O(h2)\zeta_f=O(h^2),并且随 ff 光滑变化,相邻两面之差再小一个 hh:内部行 Ri=O(h3)R_i=O(h^3)。端点处 ζ0=O(h)\zeta_0=O(h)(上一小节);ζ1\zeta_1 也是 O(h)O(h),因为面 1 的左迹 qL(1)=U0q_L(1)=U_0 没有重构。无限制器线性时,ζ1\zeta_1 的首项系数为 −0.8286:

With unlimited linear reconstruction an interior face has ζf=O(h2)\zeta_f=O(h^2), varying smoothly with ff, and the difference of two neighbouring faces is one power of hh smaller: the interior rows are Ri=O(h3)R_i=O(h^3). At the ends ζ0=O(h)\zeta_0=O(h) (previous subsection), and ζ1\zeta_1 is O(h)O(h) too, because the left trace qL(1)=U0q_L(1)=U_0 of face 1 is not reconstructed. With unlimited linear reconstruction the leading coefficient of ζ1\zeta_1 is −0.8286:

ζ1≈cL(⟨u∗⟩0−u∗(h))≈−(uin2+1)u∗′(0)2 h.\zeta_1\approx c_L\bigl(\langle u^*\rangle_0-u^*(h)\bigr)\approx-\Bigl(\frac{u_{\rm in}}2+1\Bigr)\frac{u^{*\prime}(0)}2\,h.

于是 R0=ζ1−ζ0R_0=\zeta_1-\zeta_0 与 R1=ζ2−ζ1R_1=\zeta_2-\zeta_1 都是 O(h)O(h),系数 −0.5089 与 0.8286(实测 N=4096N=4096:−0.5093 与 0.8289):这两行比内部行差两阶(右端的行 N−2N-2、N−1N-1 同样如此)。一阶格式的内部面 ζf≈−h u∗′(xf)\zeta_f\approx-h\,u^{*\prime}(x_f)(人工黏性 hh),内部行是 O(h2)O(h^2)。它的行 0 也是 O(h)O(h):R0=ζ1−ζ0R_0=\zeta_1-\zeta_0,其中 ζ1≈−h u∗′(0)\zeta_1\approx-h\,u^{*\prime}(0) 是内部面的人工黏性通量,ζ0\zeta_0 是上面的边界面误差,两者之差的系数为 −0.8174(实测 N=4096N=4096:−0.8180);行 1 是 O(h2)O(h^2)。

So R0=ζ1−ζ0R_0=\zeta_1-\zeta_0 and R1=ζ2−ζ1R_1=\zeta_2-\zeta_1 are both O(h)O(h), with the coefficients −0.5089 and 0.8286 (measured at N=4096N=4096: −0.5093 and 0.8289): these two rows are two orders less accurate than the interior rows (and so are rows N−2N-2 and N−1N-1 at the right end). At first order an interior face has ζf≈−h u∗′(xf)\zeta_f\approx-h\,u^{*\prime}(x_f) (the artificial viscosity hh) and the interior rows are O(h2)O(h^2). Its row 0 is O(h)O(h) as well: R0=ζ1−ζ0R_0=\zeta_1-\zeta_0, where ζ1≈−h u∗′(0)\zeta_1\approx-h\,u^{*\prime}(0) is the artificial viscous flux of an interior face and ζ0\zeta_0 the end-face error above; their difference has the coefficient −0.8174 (measured at N=4096N=4096: −0.8180); its row 1 is O(h2)O(h^2).

图 11 · 截断误差沿单元的分布:残差密度 |R_i(⟨u*⟩)|/h(对数纵轴),N=64,默认设计。无限制器线性(蓝圈)内部最大约 1.2e−3,两端各两行在 1 的量级(左端 R_0/h=-0.532、R_1/h=0.850,右端 R_(N-2)/h=-0.303、R_(N-1)/h=-0.491)。一阶(灰)内部最大约 1.23e−1,行 0(−0.851)明显突出,行 N-1(0.264)约为内部最大值的 2.1 倍。光滑限制器(橙)在 60 个内部行中的 57 行介于两者之间,在 u* 的极值处约为一阶的 95%,在行 5、6、37(x=0.086, 0.102, 0.586,都紧挨着它自己残差的变号处)低于两者。10-6​10-5​10-4​10-3​10-2​10-1​100.20.40.60.81单元中心 xi​(N = 64)|Ri​(⟨u*⟩)|/h一阶无限制器线性光滑限制器
图 11 · 截断误差沿单元的分布:残差密度 ∣Ri(⟨u∗⟩)∣/h|R_i(\langle u^*\rangle)|/h(对数纵轴),N=64N=64,默认设计。无限制器线性(蓝圈)内部最大约 1.2e−3,两端各两行在 1 的量级(左端 R0/h=−0.532R_0/h=-0.532、R1/h=0.850R_1/h=0.850,右端 RN−2/h=−0.303R_{N-2}/h=-0.303、RN−1/h=−0.491R_{N-1}/h=-0.491)。一阶(灰)内部最大约 1.23e−1,行 0(−0.851)明显突出,行 N−1N-1(0.264)约为内部最大值的 2.1 倍。光滑限制器(橙)在 60 个内部行中的 57 行介于两者之间,在 u∗u^* 的极值处约为一阶的 95%,在行 5、6、37(x=0.086, 0.102, 0.586x=0.086,\,0.102,\,0.586,都紧挨着它自己残差的变号处)低于两者。
Figure 11 · The truncation error along the cells: the residual density |R_i(⟨u*⟩)|/h (logarithmic axis), N=64, default design. Unlimited linear (blue rings): at most about 1.2e−3 inside, while the two rows at each end are of order one (R_0/h=-0.532 and R_1/h=0.850 at the left, R_(N-2)/h=-0.303 and R_(N-1)/h=-0.491 at the right). First order (grey): at most about 1.23e−1 inside; row 0 (−0.851) stands out clearly, row N-1 (0.264) is about 2.1 times the interior maximum. The smooth limiter (orange) lies between the two in 57 of the 60 interior rows, is about 95% of first order at the extrema of u*, and lies below both in rows 5, 6, 37 (x=0.086, 0.102, 0.586, each next to a sign change of its own residual).10-6​10-5​10-4​10-3​10-2​10-1​100.20.40.60.81cell centre xi​ (N = 64)|Ri​(⟨u*⟩)|/hfirst orderunlimited linearsmooth limiter
Figure 11 · The truncation error along the cells: the residual density ∣Ri(⟨u∗⟩)∣/h|R_i(\langle u^*\rangle)|/h (logarithmic axis), N=64N=64, default design. Unlimited linear (blue rings): at most about 1.2e−3 inside, while the two rows at each end are of order one (R0/h=−0.532R_0/h=-0.532 and R1/h=0.850R_1/h=0.850 at the left, RN−2/h=−0.303R_{N-2}/h=-0.303 and RN−1/h=−0.491R_{N-1}/h=-0.491 at the right). First order (grey): at most about 1.23e−1 inside; row 0 (−0.851) stands out clearly, row N−1N-1 (0.264) is about 2.1 times the interior maximum. The smooth limiter (orange) lies between the two in 57 of the 60 interior rows, is about 95% of first order at the extrema of u∗u^*, and lies below both in rows 5, 6, 37 (x=0.086, 0.102, 0.586x=0.086,\,0.102,\,0.586, each next to a sign change of its own residual).
图 12 · 精确平均处的残差随 N 的变化(N=8 到 4096,默认设计)与解的误差。前三幅:行 0、行 1 和内部各行的最大值 max_(2 ≤ i ≤ N-3)|R_i|;虚线是斜率 h, h^2, h^3 的参考线。无限制器线性的内部行按 h^3 下降,行 0、行 1 只按 h;一阶的内部行按 h^2;光滑限制器在细网格上像一阶。第四幅:解的误差 ‖U-⟨u*⟩‖_∞——无限制器线性最后两点之间的观测阶是 1.96,一阶是 1.00,光滑限制器是 0.99。10-11​10-9​10-7​10-5​10-3​10-1​101001000N|Ri​(⟨u*⟩)|hh²h³无限制器线性行 0行 1内部行最大值10-11​10-9​10-7​10-5​10-3​10-1​101001000N|Ri​(⟨u*⟩)|hh²h³一阶行 0行 1内部行最大值10-11​10-9​10-7​10-5​10-3​10-1​101001000N|Ri​(⟨u*⟩)|hh²h³光滑限制器行 0行 1内部行最大值10-6​10-5​10-4​10-3​10-2​10-1​1101001000N‖U − ⟨u*⟩‖∞hh²解的误差一阶无限制器线性光滑限制器
图 12 · 精确平均处的残差随 NN 的变化(N=8N=8 到 4096,默认设计)与解的误差。前三幅:行 0、行 1 和内部各行的最大值 max⁡2≤i≤N−3∣Ri∣\max_{2\le i\le N-3}|R_i|;虚线是斜率 h, h2, h3h,\ h^2,\ h^3 的参考线。无限制器线性的内部行按 h3h^3 下降,行 0、行 1 只按 hh;一阶的内部行按 h2h^2;光滑限制器在细网格上像一阶。第四幅:解的误差 ∥𝐔−⟨u∗⟩∥∞\|\mathbf U-\langle u^*\rangle\|_\infty——无限制器线性最后两点之间的观测阶是 1.96,一阶是 1.00,光滑限制器是 0.99。
Figure 12 · The residual at the exact averages against N (N=8 to 4096, default design) and the error of the solution. First three panels: row 0, row 1 and the largest interior row max_(2 ≤ i ≤ N-3)|R_i|; dashed reference lines of slope h, h^2, h^3. The interior rows of the unlimited linear scheme fall like h^3, rows 0 and 1 only like h; the interior rows of first order fall like h^2; the smooth limiter behaves like first order on fine meshes. Fourth panel: the error of the solution ‖U-⟨u*⟩‖_∞; the observed order between the last two points is 1.96 for unlimited linear, 1.00 for first order and 0.99 for the smooth limiter.10-11​10-9​10-7​10-5​10-3​10-1​101001000N|Ri​(⟨u*⟩)|hh²h³unlimited linearrow 0row 1largest interior row10-11​10-9​10-7​10-5​10-3​10-1​101001000N|Ri​(⟨u*⟩)|hh²h³first orderrow 0row 1largest interior row10-11​10-9​10-7​10-5​10-3​10-1​101001000N|Ri​(⟨u*⟩)|hh²h³smooth limiterrow 0row 1largest interior row10-6​10-5​10-4​10-3​10-2​10-1​1101001000N‖U − ⟨u*⟩‖∞hh²error of the solutionfirst orderunlimited linearsmooth limiter
Figure 12 · The residual at the exact averages against NN (N=8N=8 to 4096, default design) and the error of the solution. First three panels: row 0, row 1 and the largest interior row max⁡2≤i≤N−3∣Ri∣\max_{2\le i\le N-3}|R_i|; dashed reference lines of slope h, h2, h3h,\ h^2,\ h^3. The interior rows of the unlimited linear scheme fall like h3h^3, rows 0 and 1 only like hh; the interior rows of first order fall like h2h^2; the smooth limiter behaves like first order on fine meshes. Fourth panel: the error of the solution ∥𝐔−⟨u∗⟩∥∞\|\mathbf U-\langle u^*\rangle\|_\infty; the observed order between the last two points is 1.96 for unlimited linear, 1.00 for first order and 0.99 for the smooth limiter.

实测与推导一致:无限制器线性的 ∣R0∣|R_0| 从 N=8N=8 的 8.11e−2 降到 N=4096N=4096 的 1.24e−4(每加密一次减半),内部行从 1.65e−2 降到 6.55e−11(每次约除以 8)。用残差密度 Ri/hR_i/h(通常所说的局部截断误差)来看,内部是 O(h2)O(h^2),而行 0、1、N−2N-2、N−1N-1 趋于常数,并不趋于零:按逐点的说法,端点行是不相容的。可是解的误差照样趋于二阶(图 12 第四幅:N=2048N=2048 到 4096 之间观测阶 1.96)。

The measurements agree with the derivation: for unlimited linear ∣R0∣|R_0| falls from 8.11e−2 at N=8N=8 to 1.24e−4 at N=4096N=4096 (halved at each refinement) and the interior rows from 1.65e−2 to 6.55e−11 (divided by about 8 each time). Seen through the residual density Ri/hR_i/h, the usual local truncation error, the interior is O(h2)O(h^2) while rows 0, 1, N−2N-2 and N−1N-1 tend to constants, not to zero: in the pointwise sense the end rows are inconsistent. Yet the error of the solution approaches second order all the same (fourth panel of Figure 12: observed order 1.96 between N=2048N=2048 and 4096).

光滑限制器的斜率是中心斜率乘以因子 2liri/(li2+ri2+ϵ2)2l_ir_i/(l_i^2+r_i^2+\epsilon^2),有两个效应让它在这里失去二阶。其一,在 u∗u^* 极值所在的单元(x≈φ+14x\approx\varphi+\tfrac14、φ+34\varphi+\tfrac34)两个差分异号,因子为负,斜率在任何网格上都很小(N=8N=8 到 64 时不超过较大差分的 11%)。使它变小的原因随网格而变:N=8N=8 时因子为 −0.96,∣li+ri∣|l_i+r_i| 只有较大差分的 20%;N=16N=16 与 32 时极值不在单元中心,∣li+ri∣|l_i+r_i| 并不小(较大差分的 86% 与 68%),因子为 −0.24 与 −0.16;∣li∣,∣ri∣≪ϵ|l_i|,|r_i|\ll\epsilon 之后(这里 N≳64N\gtrsim64)因子本身接近零(N=64N=64 时 −0.018)。从 N=128N=128 起,这几行与一阶格式表现相同:光滑限制器内部行的最大值就出现在 u∗u^* 的极值处,与一阶格式的最大值相对只差 0.30%(N=128N=128)和 1.2×10−61.2\times10^{-6}(N=1024N=1024)。其二,ϵ=0.01\epsilon=0.01 是固定的,而光滑解的差分 li,ri≈h uxl_i,r_i\approx h\,u_x 随网格缩小;∣li∣,∣ri∣≪ϵ|l_i|,|r_i|\ll\epsilon 时因子约为 2liri/ϵ2→02l_ir_i/\epsilon^2\to0,重构在各处都关掉。这里 ∣ux∗∣≤2πa≈1.26|u^*_x|\le2\pi a\approx1.26,所以在 N≈126N\approx126 附近开始关掉:各单元因子的最大值在 N=128, 256, 512, 1024N=128,\,256,\,512,\,1024 时为 0.66、0.33、0.11、0.03。解的误差的观测阶在 N=2048N=2048 与 4096 之间为 0.99,在 N=128N=128 到 256 之间只有 0.44。固定 ϵ\epsilon 的光滑限制器在细网格上不是二阶格式。

The smooth slope is the central slope times the factor 2liri/(li2+ri2+ϵ2)2l_ir_i/(l_i^2+r_i^2+\epsilon^2), and two effects cost it the second order here. First, at the cell of an extremum of u∗u^* (x≈φ+14x\approx\varphi+\tfrac14, φ+34\varphi+\tfrac34) the two differences have opposite signs, the factor is negative, and the slope is small on every mesh (for N=8N=8 to 64 at most 11% of the larger difference). What makes it small depends on the mesh. At N=8N=8 the factor is −0.96 and ∣li+ri∣|l_i+r_i| is only 20% of the larger difference. At N=16N=16 and 32 the extremum is not centred in a cell, ∣li+ri∣|l_i+r_i| is not small (86% and 68% of the larger difference), and the factor is −0.24 and −0.16. Once ∣li∣,∣ri∣≪ϵ|l_i|,|r_i|\ll\epsilon (here N≳64N\gtrsim64) the factor itself is near zero (−0.018 at N=64N=64). From N=128N=128 on these rows behave like first order: the largest interior row of the smooth limiter sits at an extremum of u∗u^* and differs from that of the first-order scheme by only 0.30% at N=128N=128 and by 1.2×10−61.2\times10^{-6} (relative) at N=1024N=1024. Second, ϵ=0.01\epsilon=0.01 is fixed while the differences of a smooth solution, li,ri≈h uxl_i,r_i\approx h\,u_x, shrink with the mesh; once ∣li∣,∣ri∣≪ϵ|l_i|,|r_i|\ll\epsilon the factor is about 2liri/ϵ2→02l_ir_i/\epsilon^2\to0 and the reconstruction switches itself off everywhere. Here ∣ux∗∣≤2πa≈1.26|u^*_x|\le2\pi a\approx1.26, so the switch-off begins near N≈126N\approx126: the largest factor over all cells is 0.66, 0.33, 0.11, 0.03 at N=128, 256, 512, 1024N=128,\,256,\,512,\,1024. The observed order of the error of the solution is 0.99 between N=2048N=2048 and 4096 and only 0.44 between N=128N=128 and 256. With a fixed ϵ\epsilon the smooth limiter is not a second-order scheme on fine meshes.

为什么端点行不拖累整体的阶

Why the end rows do not drag the order down

第 5 节会证明:R(𝐔,D)=0R(\mathbf U,D)=0 等价于每个面上 Hf(𝐔)−QfH_f(\mathbf U)-Q_f 都等于同一个常数 cHc_H。于是解与精确平均的面通量之差是 Hf(𝐔)−Hf(⟨u∗⟩)=cH−ζfH_f(\mathbf U)-H_f(\langle u^*\rangle)=c_H-\zeta_f。面 0 只依赖 U0U_0,而 H0H_0 是 U0U_0 的二次式,两值之差可以精确分解:

Section 5 proves that R(𝐔,D)=0R(\mathbf U,D)=0 is the same as saying that Hf(𝐔)−QfH_f(\mathbf U)-Q_f is one constant cHc_H on every face. So the face fluxes of the solution and of the exact averages differ by Hf(𝐔)−Hf(⟨u∗⟩)=cH−ζfH_f(\mathbf U)-H_f(\langle u^*\rangle)=c_H-\zeta_f. Face 0 depends on U0U_0 only and H0H_0 is quadratic in U0U_0, so the difference of its two values factorises exactly:

H0(U0)−H0(⟨u∗⟩0)=(U0−⟨u∗⟩0)[14(U0+⟨u∗⟩0)−1−2νh].H_0(U_0)-H_0(\langle u^*\rangle_0)=\bigl(U_0-\langle u^*\rangle_0\bigr)\Bigl[\tfrac14\bigl(U_0+\langle u^*\rangle_0\bigr)-1-\frac{2\nu}h\Bigr].

所以单元 0 的误差精确地等于

The error of cell 0 is therefore exactly

U0−⟨u∗⟩0=cH−ζ014(U0+⟨u∗⟩0)−1−2ν/h.U_0-\langle u^*\rangle_0=\frac{c_H-\zeta_0}{\tfrac14\bigl(U_0+\langle u^*\rangle_0\bigr)-1-2\nu/h}.

O(h)O(h) 的面误差 ζ0\zeta_0 要除以一个分母;当 h≪2νh\ll2\nu(2ν/h≫12\nu/h\gg1)时,分母随 2ν/h2\nu/h 增大,单元 0 的误差就是 O(h)⋅h/(2ν)=O(h2)O(h)\cdot h/(2\nu)=O(h^2)。2ν/h2\nu/h 小时分母约为 (U0+⟨u∗⟩0)/4−1≈−0.5(U_0+\langle u^*\rangle_0)/4-1\approx-0.5,单元 0 的误差是 O(h)O(h):N=8N=8 时分母为 −0.656(2ν/h=0.162\nu/h=0.16);N=16, 32, 64N=16,\,32,\,64 时已变为 −0.841、−1.173、−1.818(2ν/h=0.32, 0.64, 1.282\nu/h=0.32,\,0.64,\,1.28),绝对值随 2ν/h2\nu/h 增大。−(1−uin/2)≈−0.543-(1-u_{\rm in}/2)\approx-0.543 只是 h→0h\to0 与 2ν/h→02\nu/h\to0 同时成立(ν≪h≪1\nu\ll h\ll1)时的极限;固定 N=8N=8 而令 ν→0\nu\to0,分母趋于 −0.494。这个关系之所以精确成立,是因为 Hf−QfH_f-Q_f 在每个面上都相同:在各网格、三种重构的计算解上 max⁡f∣Hf−Qf−cH∣≤3×10−13\max_f|H_f-Q_f-c_H|\le3\times10^{-13}(cHc_H 取各面平均)。用这个 cHc_H,上式复现到相对偏差 2e−10;取中间面的值作 cHc_H 时,复现到 4e−10。下表是无限制器线性的实测。

The O(h)O(h) face error ζ0\zeta_0 is divided by a denominator; once h≪2νh\ll2\nu (2ν/h≫12\nu/h\gg1) the denominator grows like 2ν/h2\nu/h and the error of cell 0 is O(h)⋅h/(2ν)=O(h2)O(h)\cdot h/(2\nu)=O(h^2). Where 2ν/h2\nu/h is small the denominator is about (U0+⟨u∗⟩0)/4−1≈−0.5(U_0+\langle u^*\rangle_0)/4-1\approx-0.5, so the error of cell 0 is O(h)O(h): the denominator is −0.656 at N=8N=8 (2ν/h=0.162\nu/h=0.16). At N=16, 32, 64N=16,\,32,\,64 (2ν/h=0.32, 0.64, 1.282\nu/h=0.32,\,0.64,\,1.28) it is already −0.841, −1.173, −1.818, its magnitude growing with 2ν/h2\nu/h. The value −(1−uin/2)≈−0.543-(1-u_{\rm in}/2)\approx-0.543 is its limit only when h→0h\to0 and 2ν/h→02\nu/h\to0 together (ν≪h≪1\nu\ll h\ll1); at fixed N=8N=8 and ν→0\nu\to0 it tends to −0.494 instead. The relation is exact because Hf−QfH_f-Q_f is the same on every face: at the computed solutions (all meshes, all three reconstructions) max⁡f∣Hf−Qf−cH∣≤3×10−13\max_f|H_f-Q_f-c_H|\le3\times10^{-13} (with cHc_H the mean over the faces); with this cHc_H the relation is reproduced to a relative deviation of 2e−10, and with cHc_H taken at the middle face to 4e−10. The table lists the measurements for unlimited linear.

NN分母 14(U0+⟨u∗⟩0)−1−2ν/h\tfrac14(U_0+\langle u^*\rangle_0)-1-2\nu/hdenominator 14(U0+⟨u∗⟩0)−1−2ν/h\tfrac14(U_0+\langle u^*\rangle_0)-1-2\nu/hζ0\zeta_0cHc_HU0−⟨u∗⟩0U_0-\langle u^*\rangle_0∥𝐔−⟨u∗⟩∥∞\|\mathbf U-\langle u^*\rangle\|_\infty
8−0.6561−4.056e−2−6.276e−23.383e−29.212e−2
64−1.8179−5.036e−3−6.498e−38.043e−47.997e−3
512−10.7820−6.251e−4−2.776e−4−3.223e−53.443e−4
4096−82.4625−7.806e−5−5.306e−6−8.822e−76.589e−6

单元 0 只是一个单元;解的最大误差由 cHc_H 决定。远离两端时,面误差 ζf\zeta_f 很小,Hf(𝐔)−Hf(⟨u∗⟩)≈cHH_f(\mathbf U)-H_f(\langle u^*\rangle)\approx c_H;按首项 H≈u2/2H\approx u^2/2,得 Ui−⟨u∗⟩i≈cH/u∗(xi)U_i-\langle u^*\rangle_i\approx c_H/u^*(x_i),所以最大误差出现在 u∗u^* 最小处,约为 ∣cH∣/min⁡u∗|c_H|/\min u^*。实测 N≥32N\ge32 时最大误差位于 x≈0.80x\approx0.80 到 0.86,∥𝐔−⟨u∗⟩∥∞/∣cH∣\|\mathbf U-\langle u^*\rangle\|_\infty/|c_H| 在 1.222 与 1.242 之间,而 1/min⁡u∗=1/(1−a)=1.2501/\min u^*=1/(1-a)=1.250。cHc_H 的观测阶从粗网格的约 1(N=8→16N=8\to16:1.03)逐渐升到细网格的约 2(N=2048→4096N=2048\to4096:1.96),解的误差跟着它:N≤256N\le256 时观测阶在 1.15 与 1.52 之间,到 N≳1000N\gtrsim1000 才接近 2。

Cell 0 is only one cell; the largest error of the solution is set by cHc_H. Away from the ends the face errors ζf\zeta_f are small and Hf(𝐔)−Hf(⟨u∗⟩)≈cHH_f(\mathbf U)-H_f(\langle u^*\rangle)\approx c_H; with the leading term H≈u2/2H\approx u^2/2 this gives Ui−⟨u∗⟩i≈cH/u∗(xi)U_i-\langle u^*\rangle_i\approx c_H/u^*(x_i), so the largest error sits where u∗u^* is smallest and is about ∣cH∣/min⁡u∗|c_H|/\min u^*. Measured for N≥32N\ge32: the maximum lies at x≈0.80x\approx0.80 to 0.86 and ∥𝐔−⟨u∗⟩∥∞/∣cH∣\|\mathbf U-\langle u^*\rangle\|_\infty/|c_H| between 1.222 and 1.242, against 1/min⁡u∗=1/(1−a)=1.2501/\min u^*=1/(1-a)=1.250. The observed order of cHc_H rises from about 1 on coarse meshes (1.03 for N=8→16N=8\to16) to about 2 on fine ones (1.96 for N=2048→4096N=2048\to4096), and the error of the solution follows it: for N≤256N\le256 its observed order lies between 1.15 and 1.52, and it approaches 2 only for N≳1000N\gtrsim1000.

用下面的加密播放器一步一步看:每一步把 NN 加倍,左图是截断误差的分布,右图是解的误差 Ui−⟨u∗⟩iU_i-\langle u^*\rangle_i。

Step through it with the refinement player below: each step doubles NN; the left panel is the distribution of the truncation error, the right panel the error of the solution Ui−⟨u∗⟩iU_i-\langle u^*\rangle_i.

两个容易误读的地方。其一,端点行的残差密度 Ri/hR_i/h 不趋于零,这不是程序错误:积分残差 RiR_i 本身仍是 O(h)O(h),而且它是两个面误差之差,解的误差由面误差决定。其二,N≤256N\le256 时的观测阶还没进入渐近区,不能当作格式的阶;端点行不改变渐近阶,却决定粗网格上误差的大小,并使二阶行为来得很晚(第 15 节测量这一点)。

Two things that are easily misread. First, the residual density Ri/hR_i/h of the end rows does not tend to zero, and this is not a bug: the integrated residual RiR_i itself is still O(h)O(h), it is a difference of two face errors, and the error of the solution is governed by the face errors. Second, the orders observed for N≤256N\le256 are not yet asymptotic and must not be taken for the order of the scheme; the end rows do not change the asymptotic order, but they set the size of the error on coarse meshes and delay the second-order behaviour (Section 15 measures this).

第 5 节Section 5

残差与 Newton 求解

The residual and the Newton solve

本节实验:第 4 节说边界面通量在精确平均处有 O(h)O(h) 的误差,那么解满足 R(𝐔,D)=0R(\mathbf U,D)=0 时,各个面通量 Hf(𝐔)H_f(\mathbf U) 满足什么?先预测,再看图 13。第二问:N=8N=8 时 Newton 法要迭代几次?残差是二次收敛的吗?

Experiment: Section 4 says the end-face fluxes are off by O(h)O(h) at the exact averages. What, then, do the face fluxes Hf(𝐔)H_f(\mathbf U) satisfy when the solution satisfies R(𝐔,D)=0R(\mathbf U,D)=0? Predict, then look at Figure 13. Second question: how many Newton iterations does N=8N=8 need, and does the residual fall quadratically?

第 3、4 节给出了每个面的通量。本节把它们装配成残差(它的零点就是离散解),说明“解出来了”是什么意思,再用 Newton 法解 R=0R=0。

Sections 3 and 4 gave the flux of every face. This section assembles them into the residual, the function whose zero is the discrete solution, says what “solved” means, and solves R=0R=0 by Newton's method.

残差代码

The residual code

残差由一个面循环算出:每个面只访问一次,通量只算一次,然后分发给面两侧的两个单元(左单元加、右单元减)。下面就是本页 model.js 中 residual 的语句,编号与第 8、9 节的前向、反向代码一致:

The residual is computed by one loop over the faces: each face is visited once, its flux is computed once and scattered to the two cells on its two sides (plus to the left cell, minus to the right cell). These are the statements of residual in this page's model.js, numbered as in the forward and reverse codes of Sections 8 and 9:

residual(U, D) -> res                     U = (U[0], ..., U[N-1]),D = (a, phi, nu)
 1  res = 0
 2  uin = u*(0; D);  uout = u*(1; D)                       边界值(第 4 节)
    for i = 1 .. N-2:                                      (s[0] = s[N-1] = 0)
 3    l = U[i] - U[i-1];  r = U[i+1] - U[i]                单侧差
 4    s[i] = sigma(l, r)                                   斜率 σ_i(第 3 节;不是源项 s(x))
    for f = 0 .. N:
 5    if f == 0: qL = UL = uin                             取值 + 重构:左侧
      else:      qL = U[f-1] + s[f-1]/2;  UL = U[f-1]
 6    if f == N: qR = UR = uout                            右侧
      else:      qR = U[f] - s[f]/2;      UR = U[f]
 7    d = h/2 if f in (0, N) else h
      H = (qL^2 + qR^2)/4 - (qR - qL) - nu*(UR - UL)/d     通量
 8    if f >= 1:    res[f-1] += H                          分发:左单元加
 9    if f <= N-1:  res[f]   -= H                          右单元减
    for f = 0 .. N:
10    Q[f] = q*(xf[f]; D)                                  精确通量
    for i = 0 .. N-1:
11    res[i] -= Q[i+1] - Q[i]                              精确积分源项
    return res
residual(U, D) -> res                     U = (U[0], ..., U[N-1]),  D = (a, phi, nu)
 1  res = 0
 2  uin = u*(0; D);  uout = u*(1; D)                       boundary data (Section 4)
    for i = 1 .. N-2:                                      (s[0] = s[N-1] = 0)
 3    l = U[i] - U[i-1];  r = U[i+1] - U[i]                one-sided differences
 4    s[i] = sigma(l, r)                                   slopes σ_i (Section 3; not the source s(x))
    for f = 0 .. N:
 5    if f == 0: qL = UL = uin                             gather + reconstruct: left
      else:      qL = U[f-1] + s[f-1]/2;  UL = U[f-1]
 6    if f == N: qR = UR = uout                            right
      else:      qR = U[f] - s[f]/2;      UR = U[f]
 7    d = h/2 if f in (0, N) else h
      H = (qL^2 + qR^2)/4 - (qR - qL) - nu*(UR - UL)/d     flux
 8    if f >= 1:    res[f-1] += H                          scatter: plus to the left cell
 9    if f <= N-1:  res[f]   -= H                          minus to the right cell
    for f = 0 .. N:
10    Q[f] = q*(xf[f]; D)                                  exact flux
    for i = 0 .. N-1:
11    res[i] -= Q[i+1] - Q[i]                              exact integrated source
    return res

语句 5–9 是第 3 节的面计算(5–6 取值并重构,7 通量,8–9 分发);语句 2 提供第 4 节的边界值,语句 3–4 是斜率(两端单元不重构),语句 10–11 是精确源项。model.js 在一个单元循环里算斜率(语句 3–4),在一个面循环里算出所有面的数组(语句 5–7),再用第二个面循环按同样的顺序分发(语句 8–9),最后逐个单元减去源项(语句 10–11);浮点运算的次序完全相同,所以下面的播放器按这段伪代码重放,得到的 RR 与 model.js 逐位相同(已验证)。

Statements 5–9 are the face computation of Section 3 (5–6 gather and reconstruct, 7 the flux, 8–9 the scatter); statement 2 supplies the boundary values of Section 4, statements 3–4 the slopes (the end cells are not reconstructed), statements 10–11 the exact source. model.js computes the slopes in a cell loop (statements 3–4), the arrays of all faces in a face loop (5–7), scatters them in a second face loop in the same order (8–9) and subtracts the source cell by cell (10–11); the floating-point operations happen in the same sequence, so the player below, which replays this pseudocode, gets the same RR as model.js bit for bit (verified).

精确的积分源项

The exact integrated source

单元残差是 qx−sq_x-s 在单元上的积分。通量部分给出 Hi+1−HiH_{i+1}-H_i;源项部分,因为构造时就令 s=qx∗s=q^*_x(第 1 节),由微积分基本定理得

The cell residual is the integral of qx−sq_x-s over the cell. The flux part gives Hi+1−HiH_{i+1}-H_i; for the source part, since s=qx∗s=q^*_x by construction (Section 1), the fundamental theorem of calculus gives

Si=∫xi−h/2xi+h/2s dx=Qi+1−Qi,Ri(𝐔,D)=Hi+1−Hi−(Qi+1−Qi).S_i=\int_{x_i-h/2}^{x_i+h/2}s\,\mathrm dx=Q_{i+1}-Q_i,\qquad R_i(\mathbf U,D)=H_{i+1}-H_i-(Q_{i+1}-Q_i).

这里不需要求积公式,对任何 NN 都精确。验算:在每个单元上用 20 点 Gauss 求积积分 s=u∗ux∗−νuxx∗s=u^*u^*_x-\nu u^*_{xx},与 Qi+1−QiQ_{i+1}-Q_i 的最大差是 1.7e−16(N=8N=8)。所以残差唯一的误差来源是数值通量,第 4 节才能写出 Ri(⟨u∗⟩)=ζi+1−ζiR_i(\langle u^*\rangle)=\zeta_{i+1}-\zeta_i。

No quadrature rule is needed, and the source is exact for every NN. Check: integrating s=u∗ux∗−νuxx∗s=u^*u^*_x-\nu u^*_{xx} over every cell with 20 Gauss points gives Qi+1−QiQ_{i+1}-Q_i to 1.7e−16 (N=8N=8). The numerical flux is therefore the only source of error in the residual, which is why Section 4 could write Ri(⟨u∗⟩)=ζi+1−ζiR_i(\langle u^*\rangle)=\zeta_{i+1}-\zeta_i.

守恒:把所有行加起来,内部面的通量成对抵消,只剩两个边界面:∑iRi=(HN−QN)−(H0−Q0)\sum_iR_i=(H_N-Q_N)-(H_0-Q_0)。在 Newton 初值处(N=8N=8)等式左右两边都是 −0.048765632351。

Conservation: adding all rows, the fluxes of the interior faces cancel in pairs and only the two end faces remain: ∑iRi=(HN−QN)−(H0−Q0)\sum_iR_i=(H_N-Q_N)-(H_0-Q_0). At the Newton initial guess (N=8N=8) both sides are −0.048765632351.

“解出来了”是什么意思:R=0R=0 等价于各面通量误差相等

What “solved” means: R=0R=0 makes the flux error one constant

Ri=0R_i=0 对所有 ii 成立,就是 Hi+1−Qi+1=Hi−QiH_{i+1}-Q_{i+1}=H_i-Q_i 对所有 ii 成立:每个面上的通量误差都相同。

Ri=0R_i=0 for every ii says Hi+1−Qi+1=Hi−QiH_{i+1}-Q_{i+1}=H_i-Q_i for every ii: the flux mismatch is the same on every face.

R(𝐔,D)=0  ⟺  Hf(𝐔)=Qf+cH(f=0,…,N).R(\mathbf U,D)=0\iff H_f(\mathbf U)=Q_f+c_H\quad(f=0,\dots,N).

这里 cHc_H 是同一个常数(下标 HH 表示通量,它与第 3 节的偏导 cL,cRc_L,c_R 无关)。连续解的通量就是 q∗q^*(第 4 节开头);离散解的通量是精确通量加一个常数 cHc_H——NN 个方程定下 NN 个未知量,剩下的这个常数就是边界误差留下的痕迹。默认设计下 cH=−0.062763c_H=-0.062763(无限制器线性,N=8N=8,取各面平均),各面与它之差不超过 3×10−163\times10^{-16};一阶与光滑限制器分别是 −0.066659 与 −0.068794。加密后 cH→0c_H\to0:无限制器线性在 N=4096N=4096 时是 −5.31e−6,一阶是 −2.83e−4。

Here cHc_H is one and the same constant (the subscript HH stands for the flux; it has nothing to do with the partial derivatives cL,cRc_L,c_R of Section 3). The continuous solution has the flux q∗q^* (beginning of Section 4); the discrete solution has the exact flux plus a constant cHc_H: NN equations fix NN unknowns, and this one constant is what the boundary errors leave behind. At the defaults cH=−0.062763c_H=-0.062763 (unlimited linear, N=8N=8, the mean over the faces), every face within 3×10−163\times10^{-16} of it; first order and the smooth limiter give −0.066659 and −0.068794. Under refinement cH→0c_H\to0: −5.31e−6 at N=4096N=4096 for unlimited linear, −2.83e−4 for first order.

图 13 · 逐面装配(默认设计,N=8,无限制器线性)。上:数值通量 H_f(柱)与精确通量 Q_f(圈);中:二者之差 H_f-Q_f;下:残差 R_i=(H_(i+1)-Q_(i+1))-(H_i-Q_i),画在单元上。左:Newton 初值,面误差参差不齐,相邻两面误差之差 R_i 不为零。右:收敛解,所有面的误差都等于同一个常数 c_H(虚线),所以 R=0。00.20.40.60.800.20.40.60.81面 xf​Hf​Newton 初值(u* 的中心点值)数值通量 Hf​精确通量 Qf​−0.1−0.0500.050.100.20.40.60.81面 xf​Hf​ − Qf​−0.1−0.0500.050.100.20.40.60.81单元 xi​Ri​00.20.40.60.800.20.40.60.81面 xf​Hf​收敛解数值通量 Hf​精确通量 Qf​−0.1−0.0500.050.100.20.40.60.81面 xf​Hf​ − Qf​cH​ = −0.0628−0.1−0.0500.050.100.20.40.60.81单元 xi​Ri​
图 13 · 逐面装配(默认设计,N=8N=8,无限制器线性)。上:数值通量 HfH_f(柱)与精确通量 QfQ_f(圈);中:二者之差 Hf−QfH_f-Q_f;下:残差 Ri=(Hi+1−Qi+1)−(Hi−Qi)R_i=(H_{i+1}-Q_{i+1})-(H_i-Q_i),画在单元上。左:Newton 初值,面误差参差不齐,相邻两面误差之差 RiR_i 不为零。右:收敛解,所有面的误差都等于同一个常数 cHc_H(虚线),所以 R=0R=0。
Figure 13 · Assembly face by face (default design, N=8, unlimited linear). Top: the numerical flux H_f (bars) and the exact flux Q_f (rings); middle: their difference H_f-Q_f; bottom: the residual R_i=(H_(i+1)-Q_(i+1))-(H_i-Q_i), drawn at the cells. Left: the Newton initial guess; the face mismatches differ and R_i, the difference of two neighbouring face mismatches, is not zero. Right: the converged solution; every face has the same mismatch c_H (dashed), so R=0.00.20.40.60.800.20.40.60.81face xf​Hf​Newton initial guess (centre samples of u*)numerical flux Hf​exact flux Qf​−0.1−0.0500.050.100.20.40.60.81face xf​Hf​ − Qf​−0.1−0.0500.050.100.20.40.60.81cell xi​Ri​00.20.40.60.800.20.40.60.81face xf​Hf​converged solutionnumerical flux Hf​exact flux Qf​−0.1−0.0500.050.100.20.40.60.81face xf​Hf​ − Qf​cH​ = −0.0628−0.1−0.0500.050.100.20.40.60.81cell xi​Ri​
Figure 13 · Assembly face by face (default design, N=8N=8, unlimited linear). Top: the numerical flux HfH_f (bars) and the exact flux QfQ_f (rings); middle: their difference Hf−QfH_f-Q_f; bottom: the residual Ri=(Hi+1−Qi+1)−(Hi−Qi)R_i=(H_{i+1}-Q_{i+1})-(H_i-Q_i), drawn at the cells. Left: the Newton initial guess; the face mismatches differ and RiR_i, the difference of two neighbouring face mismatches, is not zero. Right: the converged solution; every face has the same mismatch cHc_H (dashed), so R=0R=0.

实践中“解出来了”指 Newton 修正量 ∥Δ𝐔∥∞≤10−13\|\Delta\mathbf U\|_\infty\le10^{-13}(或 ∥R∥∞<10−15\|R\|_\infty<10^{-15})。残差本身降不到舍入误差平台以下:每个 RiR_i 是两个约 0.5 的通量之差,舍入误差约 10−1610^{-16} 到 10−1510^{-15}。

In practice “solved” means a Newton correction ∥Δ𝐔∥∞≤10−13\|\Delta\mathbf U\|_\infty\le10^{-13} (or ∥R∥∞<10−15\|R\|_\infty<10^{-15}). The residual itself cannot fall below its rounding floor: each RiR_i is a difference of fluxes of about 0.5, with rounding errors of about 10−1610^{-16} to 10−1510^{-15}.

下面的播放器逐句执行这段伪代码:可以选 Newton 初值、收敛解或精确平均,看每个面的取值、通量和分发怎样把 RR 一点一点累加出来。

The player below executes the pseudocode one statement at a time: choose the Newton initial guess, the converged solution or the exact averages, and watch the gather, the flux and the scatter of each face build up RR step by step.

Newton 法:model.solve 的做法

Newton's method as model.solve does it

线性化(A=R𝐔A=R_{\mathbf U},第 6 节):

Linearise (A=R𝐔A=R_{\mathbf U}, Section 6):

R(𝐔+Δ𝐔)=R(𝐔)+A(𝐔) Δ𝐔+O(∥Δ𝐔∥2).R(\mathbf U+\Delta\mathbf U)=R(\mathbf U)+A(\mathbf U)\,\Delta\mathbf U+O(\|\Delta\mathbf U\|^2).

令线性近似 R(𝐔)+A Δ𝐔R(\mathbf U)+A\,\Delta\mathbf U 为零,得到 Newton 修正 A(𝐔k) Δ𝐔k=−R(𝐔k)A(\mathbf U^k)\,\Delta\mathbf U^k=-R(\mathbf U^k)。本页求解器 solve 的逻辑逐句如下:

Setting the linear approximation R(𝐔)+A Δ𝐔R(\mathbf U)+A\,\Delta\mathbf U to zero gives the Newton correction A(𝐔k) Δ𝐔k=−R(𝐔k)A(\mathbf U^k)\,\Delta\mathbf U^k=-R(\mathbf U^k). The page's solver solve is, statement by statement:

solve(D):
    U = (u*(x_0), ..., u*(x_{N-1}))            u* 的中心点值:只是初值
    for k = 0, 1, ..., 34:
        R = residual(U, D);  A = R_U(U, D)      (N 次前向计算,第 6 节)
        解 A ΔU = -R                            (LU)
        记录 ‖R‖∞, ‖ΔU‖∞
        if ‖ΔU‖∞ ≤ 1e-13 或 ‖R‖∞ < 1e-15:  return U        收敛(不再加 ΔU)
        t = 1
        至多 25 次:
            Ut = U + t ΔU
            if 0.1 < min Ut, max Ut < 1.9 且 ‖R(Ut, D)‖∞ < (1 - 1e-4 t) ‖R‖∞:
                U = Ut; 进入下一个 k
            t = t/2
        return U                                 线搜索失败
    return U                                     迭代次数用完
solve(D):
    U = (u*(x_0), ..., u*(x_{N-1}))            centre samples of u*: an initial guess only
    for k = 0, 1, ..., 34:
        R = residual(U, D);  A = R_U(U, D)      (N forward evaluations, Section 6)
        solve A ΔU = -R                         (LU)
        record ‖R‖∞, ‖ΔU‖∞
        if ‖ΔU‖∞ ≤ 1e-13 or ‖R‖∞ < 1e-15:  return U       converged (ΔU is not added)
        t = 1
        at most 25 times:
            Ut = U + t ΔU
            if 0.1 < min Ut, max Ut < 1.9 and ‖R(Ut, D)‖∞ < (1 - 1e-4 t) ‖R‖∞:
                U = Ut; go on with the next k
            t = t/2
        return U                                 line search failed
    return U                                     iteration limit

几个细节:初值是 u∗u^* 的中心点值——页面知道精确解,但只拿它当起点,结果是离散解而不是 u∗u^*;先试整步,回溯时步长 tt 减半(这里 tt 是步长;第 8、10、11 节的 tt 是别的参数),直到试探状态留在 0.1<U<1.90.1<U<1.9 内并且残差降到原来的 (1−10−4t)(1-10^{-4}t) 倍以下;修正量 ≤10−13\le10^{-13} 时停止,返回的是最后一个迭代值(最后的修正不再加上)。默认设计下三种重构的每一步都是整步 t=1t=1(重放线搜索可以逐位重现每个迭代值)。

Some details: the initial guess is the centre samples of u∗u^* (the page knows the exact solution but uses it only as a starting point; the result is the discrete solution, not u∗u^*); the full step is tried first and the backtracking halves the step length tt (here tt is the step length; Sections 8, 10 and 11 use tt for other parameters) until the trial state stays inside 0.1<U<1.90.1<U<1.9 and the residual falls below (1−10−4t)(1-10^{-4}t) times its old value; the iteration stops when the correction is ≤10−13\le10^{-13} and returns the last iterate (the last correction is not added). At the defaults every step of all three reconstructions is a full step t=1t=1 (replaying the line search reproduces every iterate bit for bit).

二次收敛,可以精确写出来

Quadratic convergence, written out exactly

一阶与无限制器线性的残差是 𝐔\mathbf U 的二次多项式:HH 是迹的二次式,而迹是 𝐔\mathbf U 的线性函数。所以 Taylor 展开到二次项就结束了,整步之后残差恰好是二次余项:

For first order and unlimited linear reconstruction the residual is a quadratic polynomial in 𝐔\mathbf U: HH is quadratic in the traces and the traces are linear in 𝐔\mathbf U. The Taylor expansion therefore stops at the quadratic term, and after a full step the residual is exactly the quadratic remainder:

Ri(𝐔k+Δ𝐔k)=χi+1−χi,χf=14[(ΔqL)f2+(ΔqR)f2]≥0,R_i(\mathbf U^k+\Delta\mathbf U^k)=\chi_{i+1}-\chi_i,\qquad\chi_f=\tfrac14\bigl[(\Delta q_L)_f^2+(\Delta q_R)_f^2\bigr]\ge0,

其中 ΔqL,ΔqR\Delta q_L,\Delta q_R 是 Δ𝐔k\Delta\mathbf U^k 引起的迹增量。由此 ∥R(𝐔k+1)∥∞≤C ∥Δ𝐔k∥∞2\|R(\mathbf U^{k+1})\|_\infty\le C\,\|\Delta\mathbf U^k\|_\infty^2。无限制器线性时由 ∣Ri∣≤max⁡(χi+1,χi)≤max⁡fχf|R_i|\le\max(\chi_{i+1},\chi_i)\le\max_f\chi_f 与 ∣Δq∣≤32∥Δ𝐔∥∞|\Delta q|\le\tfrac32\|\Delta\mathbf U\|_\infty 得简单的上界 C=98C=\tfrac98;一阶时迹就是单元值,χi+1\chi_{i+1} 与 χi\chi_i 共有的一项 14ΔUi2\tfrac14\Delta U_i^2 在差中消去,于是内部行 Ri(𝐔k+1)=14(ΔUi+12−ΔUi−12)R_i(\mathbf U^{k+1})=\tfrac14(\Delta U_{i+1}^2-\Delta U_{i-1}^2),行 0 是 14ΔU12\tfrac14\Delta U_1^2,行 N−1N-1 是 −14ΔUN−22-\tfrac14\Delta U_{N-2}^2,所以 C=14C=\tfrac14,而且不能再小。单用 max⁡fχf\max_f\chi_f 得不到这个常数,因为 max⁡fχf\max_f\chi_f 可达 12∥Δ𝐔∥∞2\tfrac12\|\Delta\mathbf U\|_\infty^2(N=128N=128 的一阶 Newton 步上 max⁡fχf/∥Δ𝐔k∥∞2\max_f\chi_f/\|\Delta\mathbf U^k\|_\infty^2 实测为 0.500)。这就是二次收敛。实测:二次余项恒等式的偏差为 4.3e−16;比值 ∥Rk+1∥∞/∥Δ𝐔k∥∞2\|R^{k+1}\|_\infty/\|\Delta\mathbf U^k\|_\infty^2 在一阶时为 0.245、0.250、0.250,无限制器线性时为 0.321、0.341、0.453,都在上界之内。光滑限制器的斜率是有理函数,残差不是多项式,没有这个恒等式;光滑限制器时 Newton 法在 N=8N=8 用了 7 次迭代,前两步残差只降到上一步的 0.70 倍和 0.36 倍,之后才二次下降。

where ΔqL,ΔqR\Delta q_L,\Delta q_R are the trace increments of Δ𝐔k\Delta\mathbf U^k. Hence ∥R(𝐔k+1)∥∞≤C ∥Δ𝐔k∥∞2\|R(\mathbf U^{k+1})\|_\infty\le C\,\|\Delta\mathbf U^k\|_\infty^2. For unlimited linear, ∣Ri∣≤max⁡(χi+1,χi)≤max⁡fχf|R_i|\le\max(\chi_{i+1},\chi_i)\le\max_f\chi_f and ∣Δq∣≤32∥Δ𝐔∥∞|\Delta q|\le\tfrac32\|\Delta\mathbf U\|_\infty give the simple bound C=98C=\tfrac98. At first order the traces are the cell values and the term 14ΔUi2\tfrac14\Delta U_i^2 shared by χi+1\chi_{i+1} and χi\chi_i cancels in their difference, so an interior row is Ri(𝐔k+1)=14(ΔUi+12−ΔUi−12)R_i(\mathbf U^{k+1})=\tfrac14(\Delta U_{i+1}^2-\Delta U_{i-1}^2), row 0 is 14ΔU12\tfrac14\Delta U_1^2 and row N−1N-1 is −14ΔUN−22-\tfrac14\Delta U_{N-2}^2: C=14C=\tfrac14, and no smaller constant works. max⁡fχf\max_f\chi_f alone would not give this constant, since it can reach 12∥Δ𝐔∥∞2\tfrac12\|\Delta\mathbf U\|_\infty^2 (along the first-order Newton steps at N=128N=128 the ratio max⁡fχf/∥Δ𝐔k∥∞2\max_f\chi_f/\|\Delta\mathbf U^k\|_\infty^2 is 0.500). This is quadratic convergence. Measured: the remainder identity holds to 4.3e−16; the ratio ∥Rk+1∥∞/∥Δ𝐔k∥∞2\|R^{k+1}\|_\infty/\|\Delta\mathbf U^k\|_\infty^2 is 0.245, 0.250, 0.250 at first order and 0.321, 0.341, 0.453 for unlimited linear, all within the bounds. The smooth slope is a rational function, the residual is no polynomial and there is no such identity; with the smooth limiter Newton's method needed 7 iterations at N=8N=8, its residual fell only to 0.70 and 0.36 times the previous value in the first two steps, and quadratically after that.

图 14 · 二次收敛的直观检验:每个 Newton 步的修正量 ‖ΔU^k‖_∞(横轴)与下一个残差 ‖R(U^(k+1))‖_∞(纵轴),N=8 到 128、三种重构的所有步(舍入误差平台以下的点略去)。虚线是上面证明的上界 1/4‖ΔU‖^2(一阶,不能再小)与 9/8‖ΔU‖^2(无限制器线性):这两种重构的点都落在各自的线上或线下(比值最大 0.250 与 0.453;双对数图上两条线的斜率都是 2)。光滑限制器的残差不是多项式。Taylor 定理仍给出这样的上界,但常数取决于斜率函数 σ 的二阶导数,其中纯二阶导数 σ_ll,σ_rr 在所有 (l,r) 上的最大值约为 118(约 1.18/ε),缺的是精确的恒等式和一个小的通用常数。光滑限制器的比值最大为 20.14。10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-7​10-6​10-5​10-4​10-3​10-2​10-1​1Newton 修正 ‖ΔUk​‖∞下一个残差 ‖R(Uk+1​)‖∞一阶无限制器线性光滑限制器¼‖ΔU‖²(9/8)‖ΔU‖²
图 14 · 二次收敛的直观检验:每个 Newton 步的修正量 ∥Δ𝐔k∥∞\|\Delta\mathbf U^k\|_\infty(横轴)与下一个残差 ∥R(𝐔k+1)∥∞\|R(\mathbf U^{k+1})\|_\infty(纵轴),N=8N=8 到 128、三种重构的所有步(舍入误差平台以下的点略去)。虚线是上面证明的上界 14∥Δ𝐔∥2\tfrac14\|\Delta\mathbf U\|^2(一阶,不能再小)与 98∥Δ𝐔∥2\tfrac98\|\Delta\mathbf U\|^2(无限制器线性):这两种重构的点都落在各自的线上或线下(比值最大 0.250 与 0.453;双对数图上两条线的斜率都是 2)。光滑限制器的残差不是多项式。Taylor 定理仍给出这样的上界,但常数取决于斜率函数 σ\sigma 的二阶导数,其中纯二阶导数 σll,σrr\sigma_{ll},\sigma_{rr} 在所有 (l,r)(l,r) 上的最大值约为 118(约 1.18/ϵ1.18/\epsilon),缺的是精确的恒等式和一个小的通用常数。光滑限制器的比值最大为 20.14。
Figure 14 · Quadratic convergence at a glance: the correction ‖ΔU^k‖_∞ of every Newton step (horizontal) against the next residual ‖R(U^(k+1))‖_∞ (vertical), all steps for N=8 to 128 and the three reconstructions (points below the rounding floor left out). The dashed lines are the bounds proved above, 1/4‖ΔU‖^2 (first order, sharp) and 9/8‖ΔU‖^2 (unlimited linear): the points of these two reconstructions lie on or below their lines (largest ratios 0.250 and 0.453; on the log-log axes both lines have slope 2). The residual of the smooth limiter is no polynomial. Taylor's theorem still gives such a bound, but its constant depends on the second derivatives of the slope function σ, whose pure parts σ_ll,σ_rr reach about 118 over all (l,r) (about 1.18/ε); what is missing is an exact identity and a small universal constant. Its largest ratio is 20.14.10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-7​10-6​10-5​10-4​10-3​10-2​10-1​1Newton correction ‖ΔUk​‖∞next residual ‖R(Uk+1​)‖∞first orderunlimited linearsmooth limiter¼‖ΔU‖²(9/8)‖ΔU‖²
Figure 14 · Quadratic convergence at a glance: the correction ∥Δ𝐔k∥∞\|\Delta\mathbf U^k\|_\infty of every Newton step (horizontal) against the next residual ∥R(𝐔k+1)∥∞\|R(\mathbf U^{k+1})\|_\infty (vertical), all steps for N=8N=8 to 128 and the three reconstructions (points below the rounding floor left out). The dashed lines are the bounds proved above, 14∥Δ𝐔∥2\tfrac14\|\Delta\mathbf U\|^2 (first order, sharp) and 98∥Δ𝐔∥2\tfrac98\|\Delta\mathbf U\|^2 (unlimited linear): the points of these two reconstructions lie on or below their lines (largest ratios 0.250 and 0.453; on the log-log axes both lines have slope 2). The residual of the smooth limiter is no polynomial. Taylor's theorem still gives such a bound, but its constant depends on the second derivatives of the slope function σ\sigma, whose pure parts σll,σrr\sigma_{ll},\sigma_{rr} reach about 118 over all (l,r)(l,r) (about 1.18/ϵ1.18/\epsilon); what is missing is an exact identity and a small universal constant. Its largest ratio is 20.14.
图 15 · Newton 迭代的残差 ‖R(U^k)‖_∞(实线)与修正量 ‖ΔU^k‖_∞(虚线),默认设计,N=8。一阶 5 次、无限制器线性 5 次、光滑限制器 7 次(含最后一次只检查不更新的迭代)。一阶与无限制器线性的指数每一步大约翻倍(二次收敛),直到舍入误差平台;光滑限制器的前两步慢得多。10-15​10-12​10-9​10-6​10-3​10123456Newton 迭代 k无穷范数停止:‖ΔU‖∞ ≤ 1e−13一阶无限制器线性光滑限制器实线 ‖R‖∞,虚线 ‖ΔU‖∞
图 15 · Newton 迭代的残差 ∥R(𝐔k)∥∞\|R(\mathbf U^k)\|_\infty(实线)与修正量 ∥Δ𝐔k∥∞\|\Delta\mathbf U^k\|_\infty(虚线),默认设计,N=8N=8。一阶 5 次、无限制器线性 5 次、光滑限制器 7 次(含最后一次只检查不更新的迭代)。一阶与无限制器线性的指数每一步大约翻倍(二次收敛),直到舍入误差平台;光滑限制器的前两步慢得多。
Figure 15 · The residual ‖R(U^k)‖_∞ (solid) and the correction ‖ΔU^k‖_∞ (dashed) of the Newton iterations, default design, N=8: 5 iterations at first order, 5 for unlimited linear and 7 for the smooth limiter (counting the last one, which only checks and does not update). For first order and unlimited linear the exponent roughly doubles at each step (quadratic convergence) down to the rounding floor; the first two steps of the smooth limiter are much slower.10-15​10-12​10-9​10-6​10-3​10123456Newton iteration kmax normstop: ‖ΔU‖∞ ≤ 1e−13first orderunlimited linearsmooth limitersolid ‖R‖∞, dashed ‖ΔU‖∞
Figure 15 · The residual ∥R(𝐔k)∥∞\|R(\mathbf U^k)\|_\infty (solid) and the correction ∥Δ𝐔k∥∞\|\Delta\mathbf U^k\|_\infty (dashed) of the Newton iterations, default design, N=8N=8: 5 iterations at first order, 5 for unlimited linear and 7 for the smooth limiter (counting the last one, which only checks and does not update). For first order and unlimited linear the exponent roughly doubles at each step (quadratic convergence) down to the rounding floor; the first two steps of the smooth limiter are much slower.

下面的播放器每步执行一次 Newton 迭代,显示迭代值(与精确平均对比)、修正量、步长、残差,以及这一步用的 Newton 矩阵 A(𝐔k)A(\mathbf U^k)(第 6 节的主角)。

The player below takes one Newton iteration per step: the iterate against the exact averages, the correction, the step, the residual, and the Newton matrix A(𝐔k)A(\mathbf U^k) of this step (the subject of Section 6).

停止准则要考虑舍入误差平台。∥Δ𝐔∥∞≤10−13\|\Delta\mathbf U\|_\infty\le10^{-13} 在细网格上不一定达得到:光滑限制器 N=2048N=2048 时(带状求解器),迭代值 𝐔2\mathbf U^{2} 的残差已是 9.2e−15,修正量却是 3.4e−13,大于 10−1310^{-13}。在舍入误差平台上,试探步能否通过下降判据只取决于舍入:本次运行中 25 次试探都没有通过,线搜索报告失败(同一算法的另一个实现碰巧接受了整步,再迭代一次就停止)。这时的状态其实已经收敛到舍入精度。全局控件的 N≤128N\le128,不会遇到这种情况。

A stopping rule must allow for the rounding floor. ∥Δ𝐔∥∞≤10−13\|\Delta\mathbf U\|_\infty\le10^{-13} cannot always be reached on fine meshes: for the smooth limiter at N=2048N=2048 (band solver) the residual of the iterate 𝐔2\mathbf U^{2} is already 9.2e−15 while the correction is 3.4e−13, above 10−1310^{-13}. At the rounding floor, whether a trial step still passes the decrease test is a matter of rounding: in this run none of the 25 trials passes and the line search reports a failure (another implementation of the same algorithm happened to accept the full step and stopped one iteration later). The state has in fact converged to rounding accuracy. The global controls stop at N=128N=128, where this does not happen.

格式的相容性

Consistency of the scheme

所谓相容性,是指精确解代入离散方程后,误差随网格加密而消失。下表把第 4 节的测量写成残差密度(无限制器线性):内部 O(h2)O(h^2);两端各两行(第 0,1,N−2,N−10,1,N-2,N-1 行)趋于常数;同时 cHc_H 趋于零。积分残差 RiR_i 本身在每一行都趋于零(端点行是 O(h)O(h)),解也照样收敛。所以“少数几个端点行的局部截断误差是 O(1)O(1)”并不意味着格式不相容;起作用的是通量差的形式。

Consistency asks whether the exact solution satisfies the discrete equations up to an error that vanishes under refinement. The table writes the measurements of Section 4 as residual densities (unlimited linear): O(h2)O(h^2) inside, constants in the two rows at each end (rows 0,1,N−2,N−10,1,N-2,N-1), and cHc_H tends to zero. The integrated residual RiR_i itself tends to zero in every row (O(h)O(h) in the end rows), and the solution converges all the same. So “a local truncation error of O(1)O(1) in a few boundary rows” does not mean an inconsistent scheme; what matters is the flux-difference form.

NNmax⁡2≤i≤N−3∣Ri∣/h\max_{2\le i\le N-3}|R_i|/hR0/hR_0/hR1/hR_1/hRN−2/hR_{N-2}/hRN−1/hR_{N-1}/hcHc_H
81.32e−1−0.64900.9565−0.3475−0.3523−6.28e−2
325.16e−3−0.55470.8673−0.2965−0.4694−1.45e−2
1282.77e−4−0.52060.8396−0.3063−0.5008−2.61e−3
5121.70e−5−0.51180.8314−0.3080−0.5070−2.78e−4
20481.07e−6−0.50960.8293−0.3084−0.5084−2.06e−5
40962.68e−7−0.50930.8289−0.3084−0.5087−5.31e−6
第 6 节Section 6

Jacobian 与 Gauss–Seidel

The Jacobian and Gauss–Seidel

本节实验:先数一数,一阶与无限制器线性重构时 AA 的第 3 行各有几个非零元?再预测,Gauss–Seidel 解 Newton 修正方程收敛吗?N=8N=8 与 N=128N=128 各要扫多少遍——几遍还是几百遍?图 17、图 18 和下面的面板给出答案。

Experiment: Count first: how many nonzero entries does row 3 of AA have at first order and with unlimited linear reconstruction? Then predict: does Gauss–Seidel converge on the Newton correction system, and how many sweeps does it need for N=8N=8 and for N=128N=128: a few, or hundreds? Figure 17, Figure 18 and the panels below answer.

第 5 节把 A=R𝐔A=R_{\mathbf U} 当作黑盒用在 Newton 法里。本节构造它,看它的结构和可以证明的性质,再用一阶矩阵上的 Gauss–Seidel(GS)近似地解 Newton 修正方程,并实测 GS 收敛有多快。

Section 5 used A=R𝐔A=R_{\mathbf U} as a black box inside Newton's method. This section builds it, looks at its structure and at the properties that can be proved, then solves the Newton correction system approximately with Gauss–Seidel (GS) on the first-order matrix and measures how fast GS converges.

用前向代码按列得到 A=R𝐔A=R_{\mathbf U}

A=R𝐔A=R_{\mathbf U} by columns of the forward code

AA 的第 jj 列是残差对 UjU_j 的单位变化的响应,也就是第 8 节前向代码在种子 𝐔˙=ej\dot{\mathbf U}=e_j、D˙=0\dot D=0 下的输出:NN 次前向计算得到整个矩阵(model.js 的 jacState)。如果只需要乘积,就不必组装矩阵:一次前向计算就给出 AvAv(这里 vv 是任意向量,不是后面几节的切线解 vkv_k)。

Column jj of AA is the response of the residual to a unit change of UjU_j, that is, the output of the forward code of Section 8 with the seed 𝐔˙=ej\dot{\mathbf U}=e_j, D˙=0\dot D=0: NN forward evaluations give the whole matrix (jacState in model.js). A product needs no matrix at all: one forward evaluation gives AvAv (here vv is any vector, not the tangent solutions vkv_k of the later sections).

A ej=R˙∣𝐔˙=ej, D˙=0,A v=R˙∣𝐔˙=v, D˙=0.A\,e_j=\dot R\Big|_{\dot{\mathbf U}=e_j,\ \dot D=0},\qquad A\,v=\dot R\Big|_{\dot{\mathbf U}=v,\ \dot D=0}.

验算:用组装好的矩阵算出的 AvAv 与一次前向计算之差为 4.4e−16(三种重构,N=8N=8)。还可以更省:第 ii 行只涉及 Ui−2,…,Ui+2U_{i-2},\dots,U_{i+2},所以相距 5 的两列不会出现在同一行;把 jj 除以 5 余数相同的列分为一组(同一“颜色”),每组一起作种子,5 次前向计算就得到整条带,与 NN 无关(与逐列组装之差 0)。本页细网格上的计算(NN 到 4096)就是这样组装带状矩阵、用带状 LU 求解的。

Check: AvAv from the assembled matrix and one forward evaluation differ by 4.4e−16 (all three reconstructions, N=8N=8). One can do even better: row ii involves only Ui−2,…,Ui+2U_{i-2},\dots,U_{i+2}, so two columns five apart never share a row; grouping the columns by jj mod 5 (one “colour” per group) and seeding each group at once, 5 forward evaluations give the whole band, whatever NN is (difference from the column-by-column assembly 0). The fine-mesh computations of this page (NN up to 4096) assemble the band this way and solve with a band LU.

结构:五对角或三对角

The structure: five diagonals or three

第 ii 行是 Ri=Hi+1−Hi−SiR_i=H_{i+1}-H_i-S_i。面 ff 涉及 Uf−2,…,Uf+1U_{f-2},\dots,U_{f+1}(无限制器线性、光滑限制器)或 Uf−1,UfU_{f-1},U_f(一阶,第 3 节),所以第 ii 行涉及 Ui−2,…,Ui+2U_{i-2},\dots,U_{i+2}(五对角)或 Ui−1,Ui,Ui+1U_{i-1},U_i,U_{i+1}(三对角)。一阶时第 3 节已经写出内部行:它是黏性为 ν+h\nu+h 的中心格式。逐项求导就得到它的 Jacobian 行:

Row ii is Ri=Hi+1−Hi−SiR_i=H_{i+1}-H_i-S_i. Face ff involves Uf−2,…,Uf+1U_{f-2},\dots,U_{f+1} (unlimited linear, smooth limiter) or Uf−1,UfU_{f-1},U_f (first order, Section 3), so row ii involves Ui−2,…,Ui+2U_{i-2},\dots,U_{i+2} (five diagonals) or Ui−1,Ui,Ui+1U_{i-1},U_i,U_{i+1} (three diagonals). At first order Section 3 wrote out the interior row: it is the central scheme for the viscosity ν+h\nu+h. Differentiating it term by term gives its Jacobian row:

Aj,j−1=−(Uj−12+1+νh),Ajj=2(1+νh),Aj,j+1=Uj+12−1−νh.A_{j,j-1}=-\Bigl(\frac{U_{j-1}}2+1+\frac\nu h\Bigr),\qquad A_{jj}=2\Bigl(1+\frac\nu h\Bigr),\qquad A_{j,j+1}=\frac{U_{j+1}}2-1-\frac\nu h.

一阶时,首末两行由第 4 节的边界面导数得到:

At first order the first and the last row follow from the end-face derivatives of Section 4:

A00=∂H1∂U0−∂H0∂U0=(U02+1+νh)−(U02−1−2νh)=2+3νh,AN−1,N−1=2+3νh.A_{00}=\frac{\partial H_1}{\partial U_0}-\frac{\partial H_0}{\partial U_0}=\Bigl(\frac{U_0}2+1+\frac\nu h\Bigr)-\Bigl(\frac{U_0}2-1-\frac{2\nu}h\Bigr)=2+\frac{3\nu}h,\qquad A_{N-1,N-1}=2+\frac{3\nu}h.

这些公式与前向代码组装的 AA 一致(默认设计的收敛解和 Newton 初值两个状态,最大差 4.4e−16)。

These formulas agree with the AA assembled by the forward code (at the converged solution of the default design and at the Newton initial guess; largest difference 4.4e−16).

图 16 · 三种重构的 A=R_(U)(默认设计的收敛解,N=8),蓝正橙负,格子里是数值。一阶是三对角,无限制器线性和光滑限制器是五对角。无限制器线性最外两条对角线全为正(c_L/4 与 -c_R/4);光滑限制器的外对角线带有斜率导数 σ_l,σ_r 作为因子,可正可负(这里外对角线上有 3 个负元素,紧邻主对角线的两条对角线上有 1 个正元素)。一阶2.24−0.53−1.602.16−0.54−1.632.16−0.60−1.622.16−0.67−1.562.16−0.70−1.492.16−0.69−1.462.16−0.65−1.472.240123456701234567无限制器线性2.12−0.540.12−1.872.08−0.230.110.39−1.931.65−0.230.110.39−1.911.59−0.320.130.38−1.821.56−0.440.150.36−1.701.61−0.510.160.34−1.651.84−0.450.35−1.481.890123456701234567光滑限制器2.24−0.730.21−1.601.400.246e−5−4e−4−1.451.71−0.274e−30.79−3.032.62−0.680.170.88−2.591.96−0.580.120.24−1.231.15−0.18−3e−3−0.06−1.612.39−0.650.86−2.342.250123456701234567
图 16 · 三种重构的 A=R𝐔A=R_{\mathbf U}(默认设计的收敛解,N=8N=8),蓝正橙负,格子里是数值。一阶是三对角,无限制器线性和光滑限制器是五对角。无限制器线性最外两条对角线全为正(cL/4c_L/4 与 −cR/4-c_R/4);光滑限制器的外对角线带有斜率导数 σl,σr\sigma_l,\sigma_r 作为因子,可正可负(这里外对角线上有 3 个负元素,紧邻主对角线的两条对角线上有 1 个正元素)。
Figure 16 · The matrix A=R_(U) of the three reconstructions (converged solution of the default design, N=8), blue positive and orange negative, values in the cells. First order is tridiagonal, unlimited linear and the smooth limiter have five diagonals. The two outer diagonals of unlimited linear are all positive (c_L/4 and -c_R/4); those of the smooth limiter carry the slope derivatives σ_l,σ_r and have either sign (here 3 negative entries on the outer diagonals and 1 positive entry on the two diagonals next to the main one).first order2.24−0.53−1.602.16−0.54−1.632.16−0.60−1.622.16−0.67−1.562.16−0.70−1.492.16−0.69−1.462.16−0.65−1.472.240123456701234567unlimited linear2.12−0.540.12−1.872.08−0.230.110.39−1.931.65−0.230.110.39−1.911.59−0.320.130.38−1.821.56−0.440.150.36−1.701.61−0.510.160.34−1.651.84−0.450.35−1.481.890123456701234567smooth limiter2.24−0.730.21−1.601.400.246e−5−4e−4−1.451.71−0.274e−30.79−3.032.62−0.680.170.88−2.591.96−0.580.120.24−1.231.15−0.18−3e−3−0.06−1.612.39−0.650.86−2.342.250123456701234567
Figure 16 · The matrix A=R𝐔A=R_{\mathbf U} of the three reconstructions (converged solution of the default design, N=8N=8), blue positive and orange negative, values in the cells. First order is tridiagonal, unlimited linear and the smooth limiter have five diagonals. The two outer diagonals of unlimited linear are all positive (cL/4c_L/4 and −cR/4-c_R/4); those of the smooth limiter carry the slope derivatives σl,σr\sigma_l,\sigma_r and have either sign (here 3 negative entries on the outer diagonals and 1 positive entry on the two diagonals next to the main one).

在下面的面板里换重构(NN 由全局控件决定),看 AA、一阶矩阵 PP、它们的差和 A−1A^{-1} 的符号:

In the panel below change the reconstruction (NN is set by the global controls) and look at AA, the first-order matrix PP, their difference and the signs of A−1A^{-1}:

关于 AA 能说什么

What can be said about AA

符号。一阶时,只要 ∣U∣<2|U|<2(Newton 法的范围 0.1<U<1.90.1<U<1.9 保证这一点),Aj,j±1<0<AjjA_{j,j\pm1}<0<A_{jj}:AA 是 Z 矩阵(非对角元都不正)。重构后最外两条对角线上出现了重构权重:无限制器线性时 Aj,j−2=cL(j)/4>0A_{j,j-2}=c_L(j)/4>0,Aj,j+2=−cR(j+1)/4>0A_{j,j+2}=-c_R(j+1)/4>0,出现正的非对角元(N=8N=8 时有 12 个),AA 不再是 Z 矩阵;光滑限制器时外对角线带有因子 σl,σr\sigma_l,\sigma_r,可正可负。

Signs. At first order, as long as ∣U∣<2|U|<2 (Newton's range 0.1<U<1.90.1<U<1.9 guarantees it), Aj,j±1<0<AjjA_{j,j\pm1}<0<A_{jj}: AA is a Z-matrix (no positive off-diagonal entry). With reconstruction the reconstruction weights appear on the two outer diagonals: for unlimited linear Aj,j−2=cL(j)/4>0A_{j,j-2}=c_L(j)/4>0 and Aj,j+2=−cR(j+1)/4>0A_{j,j+2}=-c_R(j+1)/4>0, so positive off-diagonal entries appear (12 of them at N=8N=8) and AA is no longer a Z-matrix; for the smooth limiter the outer diagonals carry σl,σr\sigma_l,\sigma_r and have either sign.

行和。一阶内部行的行和是 (Uj+1−Uj−1)/2(U_{j+1}-U_{j-1})/2,解下降的地方为负:AA 不是按行对角占优的(N=8N=8 一阶时行和从 −0.124 到 1.712)。

Row sums. The row sum of a first-order interior row is (Uj+1−Uj−1)/2(U_{j+1}-U_{j-1})/2, negative where the solution decreases: AA is not diagonally dominant by rows (at first order, N=8N=8, the row sums range from −0.124 to 1.712).

列和。守恒律体现在列和上:∑iAij=∂(∑iRi)/∂Uj=∂(HN−H0)/∂Uj\sum_iA_{ij}=\partial(\sum_iR_i)/\partial U_j=\partial(H_N-H_0)/\partial U_j(第 5 节的守恒)。边界面只依赖端单元,所以三种重构都有

Column sums. Conservation shows in the column sums: ∑iAij=∂(∑iRi)/∂Uj=∂(HN−H0)/∂Uj\sum_iA_{ij}=\partial(\sum_iR_i)/\partial U_j=\partial(H_N-H_0)/\partial U_j (the conservation of Section 5). The end faces depend on the end cells only, so for all three reconstructions

∑iAij=0(0<j<N−1),∑iAi0=1−U02+2νh>0,∑iAi,N−1=UN−12+1+2νh>0.\sum_iA_{ij}=0\quad(0<j<N-1),\qquad\sum_iA_{i0}=1-\frac{U_0}2+\frac{2\nu}h>0,\qquad\sum_iA_{i,N-1}=\frac{U_{N-1}}2+1+\frac{2\nu}h>0.

实测(N=8N=8,无限制器线性):内部列和 ≤3×10−16\le3\times10^{-16},第 0 列和为 0.6477,第 N−1N-1 列和为 1.5943,与上式一致。

Measured (N=8N=8, unlimited linear): interior column sums ≤3×10−16\le3\times10^{-16}, column 0 sums to 0.6477, column N−1N-1 to 1.5943, as the formulas above say.

一阶的 AA 是 M 矩阵。定理(Varga) 设 AA 是对角元为正的 Z 矩阵。若 AA 不可约、按行弱对角占优,且至少有一行严格对角占优,则 AA 非奇异,且 A−1A^{-1} 的元素全为正。

At first order A is an M-matrix. Theorem (Varga). Let AA be a Z-matrix with positive diagonal. If AA is irreducible, weakly diagonally dominant by rows and strictly diagonally dominant in at least one row, then AA is nonsingular and every entry of A−1A^{-1} is positive.

一阶 AA 是 M 矩阵的证明:ATA^T 也是对角元为正的 Z 矩阵,它的行和就是 AA 的列和:内部各列的列和为 0,第 0 列与第 N−1N-1 列的列和为正。对这样的矩阵,“行和非负”恰好就是“按行弱对角占优”,所以 ATA^T 按行弱对角占优,且有两行严格占优。AA 三对角,上、下次对角元都不为零,所以 ATA^T 不可约。由定理,(AT)−1>0(A^T)^{-1}>0,即 A−1>0A^{-1}>0。这对 0.1<U<1.90.1<U<1.9 内的任何状态都成立。实测:N=8N=8 时 min⁡ij(A−1)ij=6.68×10−4>0\min_{ij}(A^{-1})_{ij}=6.68\times10^{-4}>0。二阶时 AA 不是 Z 矩阵,定理不适用;N=8N=8 时无限制器线性的 A−1A^{-1} 有 14 个负元素,最小 −0.0774,但 N=128N=128 时它没有超出舍入误差的负元素。

Proof that the first-order AA is an M-matrix: ATA^T is also a Z-matrix with positive diagonal, and its row sums are the column sums of AA: 0 for the interior columns, positive for columns 0 and N−1N-1. For such a matrix a nonnegative row sum is exactly weak diagonal dominance, so ATA^T is weakly diagonally dominant by rows, strictly in two rows. AA is tridiagonal with nonzero sub- and superdiagonal entries, so ATA^T is irreducible. By the theorem (AT)−1>0(A^T)^{-1}>0, that is A−1>0A^{-1}>0. This holds for every state with 0.1<U<1.90.1<U<1.9. Measured: min⁡ij(A−1)ij=6.68×10−4>0\min_{ij}(A^{-1})_{ij}=6.68\times10^{-4}>0 at N=8N=8. At second order AA is not a Z-matrix and the theorem does not apply; at N=8N=8 the inverse of the unlimited linear AA has 14 negative entries, the smallest −0.0774, but at N=128N=128 it has none above the rounding level.

条件数。cond⁡1(A)=∥A∥1∥A−1∥1\operatorname{cond}_1(A)=\|A\|_1\|A^{-1}\|_1(用带状 LU 逐列精确算出,不是估计)随 NN 增长:无限制器线性从 N=8N=8 的 31.06 到 N=1024N=1024 的 4.458e4;最后一次加倍时变为原来的 3.64 倍,趋近于扩散算子的 N2N^2(每加倍一次变为 4 倍);粗网格上对流占优,增长较慢。LU 求解不受影响(误差约 cond⁡1(A)⋅10−16\operatorname{cond}_1(A)\cdot10^{-16}),但迭代法会变慢,下面会看到。

Condition number. cond⁡1(A)=∥A∥1∥A−1∥1\operatorname{cond}_1(A)=\|A\|_1\|A^{-1}\|_1 (computed exactly column by column with the band LU, not estimated) grows with NN: for unlimited linear from 31.06 at N=8N=8 to 4.458e4 at N=1024N=1024; the last doubling multiplies it by 3.64, approaching the N2N^2 of a diffusion operator (a factor of 4 per doubling); on coarse meshes convection dominates and the growth is slower. LU solves do not care (their error is about cond⁡1(A)⋅10−16\operatorname{cond}_1(A)\cdot10^{-16}), but iterative methods slow down, as we see next.

用一阶矩阵做 Gauss–Seidel

Gauss–Seidel with the first-order matrix

LU 精确地解 A Δ𝐔=−RA\,\Delta\mathbf U=-R(稠密 O(N3)O(N^3),带状 O(N)O(N))。经典的替代办法是迭代:每一步只需要一个便宜的近似解。为了与第 17 节一致,本节把要解的线性方程组写成 Ax=bAx=b:xmx^m 是第 mm 次迭代值,x∗x^* 是精确解,r=b−Axr=b-Ax 叫缺陷(线性方程组的残差);它们与坐标 xx、第 7 节的矩 mim_i、第 3 节的单侧差 rir_i 无关。取同一状态下的一阶 Jacobian PP(三对角),把它拆成对角、严格下三角和严格上三角三部分:P=diag⁡(P)+P−+P+P=\operatorname{diag}(P)+P_-+P_+(用 P±P_\pm 是为了不和状态 𝐔\mathbf U 混淆)。从零出发在 PP 上做一次前向 GS 扫描,就是逐行解下三角方程组 (diag⁡(P)+P−) Δx=r(\operatorname{diag}(P)+P_-)\,\Delta x=r;记这个映射为 Δx=Br\Delta x=Br(这里的 BB 是 GS 映射,与第 8 节的关联矩阵 ℬ\mathcal B 无关)。缺陷校正是

LU solves A Δ𝐔=−RA\,\Delta\mathbf U=-R exactly (dense O(N3)O(N^3), banded O(N)O(N)). The classical alternative is an iteration that needs only a cheap approximate solve at each step. To match Section 17, this section writes the linear system as Ax=bAx=b, with the iterates xmx^m (iteration counter mm), the exact solution x∗x^* and the defect r=b−Axr=b-Ax (the residual of the linear system); they have nothing to do with the coordinate xx, the moments mim_i of Section 7 or the one-sided differences rir_i of Section 3. Take the first-order Jacobian PP at the same state (tridiagonal) and split it into its diagonal, strictly lower and strictly upper parts, P=diag⁡(P)+P−+P+P=\operatorname{diag}(P)+P_-+P_+ (written P±P_\pm so as not to clash with the state 𝐔\mathbf U). One forward GS sweep on PP from zero solves the lower-triangular system (diag⁡(P)+P−) Δx=r(\operatorname{diag}(P)+P_-)\,\Delta x=r row by row; call this map Δx=Br\Delta x=Br (here BB is the GS map; it has nothing to do with the incidence matrix ℬ\mathcal B of Section 8). Defect correction is

xm+1=xm+ω B(b−Axm),B=(diag⁡(P)+P−)−1,xm+1−x∗=E (xm−x∗),E=I−ωBA.x^{m+1}=x^m+\omega\,B\bigl(b-Ax^m\bigr),\qquad B=\bigl(\operatorname{diag}(P)+P_-\bigr)^{-1},\qquad x^{m+1}-x^*=E\,(x^m-x^*),\quad E=I-\omega BA.
缺陷校正:解 A x = b,用 P(一阶 Jacobian)和松弛因子 ω
    x = 0
    for m = 0, 1, 2, ...:
        r = b - A x                         缺陷(只需要乘积 A x)
        if ‖r‖∞ ≤ tol: 停止
        for i = 0 .. N-1:                   P 上的一次前向 GS 扫描,从 Δx = 0 开始
            Δx_i = (r_i - Σ_{j<i} P_ij Δx_j) / P_ii     (P 是三对角:只有 j = i-1)
        x = x + ω Δx
defect correction: solve A x = b with P (the first-order Jacobian) and the relaxation ω
    x = 0
    for m = 0, 1, 2, ...:
        r = b - A x                         defect (needs the product A x only)
        if ‖r‖∞ ≤ tol: stop
        for i = 0 .. N-1:                   one forward GS sweep on P, from Δx = 0
            Δx_i = (r_i - Σ_{j<i} P_ij Δx_j) / P_ii     (P is tridiagonal: only j = i-1)
        x = x + ω Δx

一阶(A=PA=P)且 ω=1\omega=1 时,它就是 AA 上的 Gauss–Seidel:(diag⁡(P)+P−) xm+1=b−P+xm(\operatorname{diag}(P)+P_-)\,x^{m+1}=b-P_+x^m,误差传播矩阵 E=−(diag⁡(P)+P−)−1P+E=-(\operatorname{diag}(P)+P_-)^{-1}P_+。因为 PP 是 M 矩阵,所以 diag⁡(P)+P−\operatorname{diag}(P)+P_- 也是 M 矩阵,逆矩阵非负;又 −P+≥0-P_+\ge0,故 E≥0E\ge0。由 Perron–Frobenius 定理,谱半径 ρ(E)\rho(E)(本节的 ρ\rho 都指谱半径)本身就是 EE 的特征值,有非负特征向量(最慢的误差模态);在这些网格上它是唯一模为 ρ\rho 的特征值(实测,N≤128N\le128),所以误差方向趋于这个特征向量。这个分裂是 M 矩阵的正则分裂,由 Varga 定理得 ρ(E)<1\rho(E)<1:一阶系统上 GS 对任何 NN、0.1<U<1.90.1<U<1.9 内的任何状态都收敛。EE 的最小元素为 0(第 0 列恒为零)。

At first order (A=PA=P) with ω=1\omega=1 this is Gauss–Seidel on AA: (diag⁡(P)+P−) xm+1=b−P+xm(\operatorname{diag}(P)+P_-)\,x^{m+1}=b-P_+x^m, with the error propagator E=−(diag⁡(P)+P−)−1P+E=-(\operatorname{diag}(P)+P_-)^{-1}P_+. Since PP is an M-matrix, diag⁡(P)+P−\operatorname{diag}(P)+P_- is an M-matrix too, with a nonnegative inverse; and −P+≥0-P_+\ge0, so E≥0E\ge0. By Perron–Frobenius, the spectral radius ρ(E)\rho(E) (in this section ρ\rho always denotes a spectral radius) is itself an eigenvalue of EE, with a nonnegative eigenvector (the slowest error mode); on these meshes it is the only eigenvalue of modulus ρ\rho (measured, N≤128N\le128), so the direction of the error tends to this eigenvector. The splitting is a regular splitting of an M-matrix, so ρ(E)<1\rho(E)<1 by Varga's theorem: on the first-order system GS converges for every NN and every state with 0.1<U<1.90.1<U<1.9. The smallest entry of EE is 0 (its column 0 is zero).

有多快?实测 ρ(E)\rho(E)(一阶,收敛解):0.7487(N=8N=8)、0.8290(N=16N=16)、0.8840(N=32N=32)、0.9305(N=64N=64)、0.9655(N=128N=128),随 NN 趋于 1。把误差缩小到原来的 10−1010^{-10},一阶时要 ln⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rho 次扫描:N=8N=8 时 80 次,N=128N=128 时 656 次。GS 在细网格上很慢。

How fast? Measured ρ(E)\rho(E) (first order, converged solution): 0.7487 at N=8N=8, 0.8290 at N=16N=16, 0.8840 at N=32N=32, 0.9305 at N=64N=64, 0.9655 at N=128N=128, tending to 1 with NN. Reducing the error to 10−1010^{-10} of its initial size takes ln⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rho sweeps at first order: 80 at N=8N=8 and 656 at N=128N=128. GS is slow on fine meshes.

二阶(A≠PA\ne P)时 E=I−BAE=I-BA 不再非负(无限制器线性 N=8N=8 时最小元素 −0.0723),也没有定理保证收敛。默认设计下实测 ρ(E)\rho(E) 都小于 1(无限制器线性:0.5748、0.6786、0.7618、0.8757、0.9481,N=8N=8 到 128),而且在每个 NN 上都比一阶的小:迭代收敛,比一阶更快;N≤32N\le32 时模最大的特征值是一对复数。这些是一个设计下的测量,不是保证。

At second order (A≠PA\ne P) E=I−BAE=I-BA is no longer nonnegative (smallest entry −0.0723 for unlimited linear at N=8N=8) and no theorem guarantees convergence. At the default design the measured ρ(E)\rho(E) is below 1 throughout (unlimited linear: 0.5748, 0.6786, 0.7618, 0.8757, 0.9481 for N=8N=8 to 128), and below the first-order value at every NN: the iteration converges, faster than at first order; for N≤32N\le32 the eigenvalues of largest modulus are a complex pair. These are measurements at one design, not a guarantee.

松弛。Eω=I−ωBA=(1−ω)I+ωE1E_\omega=I-\omega BA=(1-\omega)I+\omega E_1。一阶时 E1E_1 的特征值都是实数,落在区间 [0,ρ(E1)][0,\rho(E_1)] 内(是 Jacobi 特征值的平方 μk2\mu_k^2 和 0),所以 ρ(Eω)=max⁡(∣1−ω∣, 1−ω(1−ρ(E1)))\rho(E_\omega)=\max\bigl(|1-\omega|,\,1-\omega(1-\rho(E_1))\bigr),在 ω∗=2/(2−ρ(E1))\omega^*=2/(2-\rho(E_1)) 处最小(在第一个 Newton 修正方程上,N=8N=8 时为 1.55,N=128N=128 时为 1.93):精确算术下超松弛有好处。在这个方程上,ω=1.3\omega=1.3 所需的扫描次数是一阶 53、141、559,无限制器线性 36、84、500(N=8,32,128N=8,32,128),都少于 ω=1\omega=1 时的次数。但不能只看 ρ\rho 一路加大 ω\omega:E1E_1 的零特征值是亏损的(代数重数 N/2N/2,只有一个特征向量),ω>1\omega>1 时它移到 1−ω<01-\omega<0,迭代可能先放大很多个数量级再衰减——N=128N=128、ω=1.8\omega=1.8 时 ρ(Eω)=0.937\rho(E_\omega)=0.937,缺陷却在 119 次扫描内涨到 10810^{8} 以上(计算在那里停止)。双精度下 ω∗\omega^* 本身在 N=64, 128N=64,\,128 时不收敛;在 ω=1.00,1.05,…,1.90\omega=1.00,1.05,\dots,1.90 中收敛最快的是 ω=1.45, 1.55, 1.60, 1.60\omega=1.45,\,1.55,\,1.60,\,1.60(N=8,32,64,128N=8,32,64,128,分别 46、116、209、452 次扫描)。光滑限制器下 ω\omega 稍大也会停滞:N=8N=8、ω=1.3\omega=1.3 要 15138 次扫描。

Relaxation. Eω=I−ωBA=(1−ω)I+ωE1E_\omega=I-\omega BA=(1-\omega)I+\omega E_1. At first order the eigenvalues of E1E_1 are real and lie in [0,ρ(E1)][0,\rho(E_1)] (they are the squares μk2\mu_k^2 of the Jacobi eigenvalues, and 0), so ρ(Eω)=max⁡(∣1−ω∣, 1−ω(1−ρ(E1)))\rho(E_\omega)=\max\bigl(|1-\omega|,\,1-\omega(1-\rho(E_1))\bigr), smallest at ω∗=2/(2−ρ(E1))\omega^*=2/(2-\rho(E_1)) (on the first Newton correction system 1.55 at N=8N=8, 1.93 at N=128N=128): in exact arithmetic over-relaxation helps. On this system ω=1.3\omega=1.3 needs 53, 141, 559 sweeps at first order and 36, 84, 500 for unlimited linear (N=8,32,128N=8,32,128), fewer than ω=1\omega=1 in every case. But ω\omega cannot be raised by looking at ρ\rho alone: the zero eigenvalue of E1E_1 is defective (algebraic multiplicity N/2N/2, a single eigenvector), for ω>1\omega>1 it moves to 1−ω<01-\omega<0, and the iteration can grow by many orders of magnitude before it decays: at N=128N=128 and ω=1.8\omega=1.8 one has ρ(Eω)=0.937\rho(E_\omega)=0.937, yet the defect exceeds 10810^{8} within 119 sweeps (where the computation stops). In double precision ω∗\omega^* itself does not converge at N=64, 128N=64,\,128; on the grid ω=1.00,1.05,…,1.90\omega=1.00,1.05,\dots,1.90 the fastest convergent ω\omega is 1.45, 1.55, 1.60, 1.60 for N=8, 32, 64, 128N=8,\,32,\,64,\,128 (46, 116, 209, 452 sweeps). With the smooth limiter a moderately large ω\omega can stall: N=8N=8 and ω=1.3\omega=1.3 need 15138 sweeps.

图 17 · 左:GS 缺陷校正的误差传播矩阵 E=I-BA 的谱半径(ω=1,默认设计的收敛解;一阶由 Jacobi 特征值 μ_k^2 精确算出,其余由 QR 算法算出)。三种重构的 ρ 都随 N 趋于 1。右:cond_1(A),虚线是 ∝ N、∝ N^2 的参考线。0.50.60.70.80.9110100Nρ(E)GS 缺陷校正的谱半径(ω = 1)一阶无限制器线性光滑限制器10102​103​104​105​101001000Ncond1​(A)NN²条件数 ‖A‖1​ ‖A−1​‖1​一阶无限制器线性光滑限制器
图 17 · 左:GS 缺陷校正的误差传播矩阵 E=I−BAE=I-BA 的谱半径(ω=1\omega=1,默认设计的收敛解;一阶由 Jacobi 特征值 μk2\mu_k^2 精确算出,其余由 QR 算法算出)。三种重构的 ρ\rho 都随 NN 趋于 1。右:cond⁡1(A)\operatorname{cond}_1(A),虚线是 ∝N\propto N、∝N2\propto N^2 的参考线。
Figure 17 · Left: the spectral radius of the error propagator E=I-BA of GS defect correction (ω=1, converged solution of the default design; exact from the Jacobi eigenvalues μ_k^2 at first order, by the QR algorithm otherwise). For all three reconstructions ρ tends to 1 with N. Right: cond_1(A); the dashed lines are reference lines ∝ N and ∝ N^2.0.50.60.70.80.9110100Nρ(E)spectral radius of GS defect correction (ω = 1)first orderunlimited linearsmooth limiter10102​103​104​105​101001000Ncond1​(A)NN²condition number ‖A‖1​ ‖A−1​‖1​first orderunlimited linearsmooth limiter
Figure 17 · Left: the spectral radius of the error propagator E=I−BAE=I-BA of GS defect correction (ω=1\omega=1, converged solution of the default design; exact from the Jacobi eigenvalues μk2\mu_k^2 at first order, by the QR algorithm otherwise). For all three reconstructions ρ\rho tends to 1 with NN. Right: cond⁡1(A)\operatorname{cond}_1(A); the dashed lines are reference lines ∝N\propto N and ∝N2\propto N^2.

播放器在一个真实的线性系统上逐行执行 GS:第一个 Newton 修正方程 A(𝐔0) Δ𝐔=−R(𝐔0)A(\mathbf U^0)\,\Delta\mathbf U=-R(\mathbf U^0)(𝐔0\mathbf U^0 是 Newton 初值),每一步更新一个单元,显示用到的数值、新值、缺陷,以及与 LU 精确解的误差。

The player executes GS row by row on a real linear system, the first Newton correction system A(𝐔0) Δ𝐔=−R(𝐔0)A(\mathbf U^0)\,\Delta\mathbf U=-R(\mathbf U^0) (𝐔0\mathbf U^0 the Newton initial guess): each step updates one cell and shows the numbers used, the new value, the defect and the error against the exact LU solution.

图 18 · 第一个 Newton 修正方程上的 GS 缺陷校正(ω=1,初值 x=0):缺陷 ‖b-Ax^m‖_∞ 随外迭代的变化,三幅分别是 N=8, 32, 128(灰:一阶,蓝:无限制器线性;注意横轴的范围不同)。到 10^(-12) 所需的扫描次数:一阶 73、187、730,无限制器线性 44、116、656。直线部分的斜率是 log_10ρ(E);N=128 时缺陷先迅速下降,然后几乎停滞(一阶约 153 次、无限制器线性约 196 次扫描里每 50 次下降不到一半),之后才以这个速率下降(暂态)。10-12​10-9​10-6​10-3​10204060m‖b − A xm​‖∞N = 8一阶无限制器线性10-12​10-9​10-6​10-3​1050100150mN = 3210-12​10-9​10-6​10-3​10200400600mN = 128
图 18 · 第一个 Newton 修正方程上的 GS 缺陷校正(ω=1\omega=1,初值 x=0x=0):缺陷 ∥b−Axm∥∞\|b-Ax^m\|_\infty 随外迭代的变化,三幅分别是 N=8, 32, 128N=8,\,32,\,128(灰:一阶,蓝:无限制器线性;注意横轴的范围不同)。到 10−1210^{-12} 所需的扫描次数:一阶 73、187、730,无限制器线性 44、116、656。直线部分的斜率是 log⁡10ρ(E)\log_{10}\rho(E);N=128N=128 时缺陷先迅速下降,然后几乎停滞(一阶约 153 次、无限制器线性约 196 次扫描里每 50 次下降不到一半),之后才以这个速率下降(暂态)。
Figure 18 · GS defect correction on the first Newton correction system (ω=1, initial guess x=0): the defect ‖b-Ax^m‖_∞ against the outer iteration, one panel each for N=8, 32, 128 (grey first order, blue unlimited linear; note the different horizontal ranges). Sweeps needed to reach 10^(-12): 73, 187, 730 at first order and 44, 116, 656 for unlimited linear. The slope of the straight part is log_10ρ(E); at N=128 the defect first falls quickly, then nearly stalls (for about 153 sweeps at first order and 196 for unlimited linear it falls by less than a factor 2 per 50 sweeps) before it falls at that rate (a transient).10-12​10-9​10-6​10-3​10204060m‖b − A xm​‖∞N = 8first orderunlimited linear10-12​10-9​10-6​10-3​1050100150mN = 3210-12​10-9​10-6​10-3​10200400600mN = 128
Figure 18 · GS defect correction on the first Newton correction system (ω=1\omega=1, initial guess x=0x=0): the defect ∥b−Axm∥∞\|b-Ax^m\|_\infty against the outer iteration, one panel each for N=8, 32, 128N=8,\,32,\,128 (grey first order, blue unlimited linear; note the different horizontal ranges). Sweeps needed to reach 10−1210^{-12}: 73, 187, 730 at first order and 44, 116, 656 for unlimited linear. The slope of the straight part is log⁡10ρ(E)\log_{10}\rho(E); at N=128N=128 the defect first falls quickly, then nearly stalls (for about 153 sweeps at first order and 196 for unlimited linear it falls by less than a factor 2 per 50 sweeps) before it falls at that rate (a transient).

最后一个面板把迭代跑到底:选 ω\omega、看缺陷的历史、量出渐近收敛因子,并与 EE 的全部特征值(复平面上的点)比较;它还画出最慢的误差模态。一阶时这个模态集中在出口 x=1x=1 前的最后几个单元(N=32N=32 时最大值在单元 28,单元编号从 0 到 31)。这个位置由 PP 决定,与扫描方向无关:PP 以对流为主(∣Aj,j−1∣>∣Aj,j+1∣|A_{j,j-1}|>|A_{j,j+1}|;N=32N=32 时 ∣Aj,j−1/Aj,j+1∣\sqrt{|A_{j,j-1}/A_{j,j+1}|} 在 1.36 与 1.61 之间),所以慢模态向下游增长。反向 GS 扫描(从 x=1x=1 扫到 x=0x=0)的谱半径与前向 GS 扫描相同(二者的特征值都是 μk2\mu_k^2 与 0;N=8,32,128N=8,32,128 时算得的谱半径最多相差 5e−11,是舍入误差),最慢模态也在出口(N=32N=32 时在单元 29);顺流扫描只缩短暂态(N=128N=128 时 730 对 898 次扫描)。第 17 节再把 GS、GMRES(以 BB 为预处理)和 LU 用在切线与伴随方程上比较。

The last panel runs the iteration to the end: choose ω\omega, watch the history of the defect, measure the asymptotic convergence factor and compare it with all eigenvalues of EE (points in the complex plane); it also draws the slowest error mode. At first order this mode sits in the last cells before the outlet end x=1x=1 (at N=32N=32 its largest entry is in cell 28 of 0,…,310,\dots,31). The location belongs to PP, not to the sweep: PP is convection-dominated (∣Aj,j−1∣>∣Aj,j+1∣|A_{j,j-1}|>|A_{j,j+1}|; at N=32N=32, ∣Aj,j−1/Aj,j+1∣\sqrt{|A_{j,j-1}/A_{j,j+1}|} lies between 1.36 and 1.61), so its slow modes grow downstream. A backward GS sweep (from x=1x=1 to x=0x=0) has the same spectral radius (both spectra consist of the squares μk2\mu_k^2 and zeros; the computed spectral radii differ by at most 5e−11 at N=8,32,128N=8,32,128, which is rounding) and its slowest mode also sits at the outlet (cell 29 at N=32N=32); sweeping with the flow only shortens the transient (730 against 898 sweeps at N=128N=128). Section 17 compares GS, GMRES (with BB as the preconditioner) and LU on the tangent and adjoint systems.

第 7 节Section 7

目标函数:一个线性泛函

The objective: a linear functional

本节实验:Jh(⟨u∗⟩)J_h(\langle u^*\rangle) 用的是精确单元平均和权重 h(1+xi)h(1+x_i)。它等于 J∗J^* 吗?如果不等,N=8N=8 时差多少?先预测,再看图 19。

Experiment: Jh(⟨u∗⟩)J_h(\langle u^*\rangle) uses the exact cell averages and the weights h(1+xi)h(1+x_i). Is it equal to J∗J^*? If not, how large is the difference at N=8N=8? Predict, then look at Figure 19.

连续问题的目标是 J(u)=∫01(1+x) u dxJ(u)=\int_0^1(1+x)\,u\,\mathrm dx(第 1 节)。本节把它变成单元平均的函数,写出状态梯度 gg(伴随方程的右端项是 −g-g),并查清离散目标的误差从哪里来。

The objective of the continuous problem is J(u)=∫01(1+x) u dxJ(u)=\int_0^1(1+x)\,u\,\mathrm dx (Section 1). This section turns it into a function of the cell averages, writes the state gradient gg (the right-hand side of the adjoint equation is −g-g), and finds out where the error of the discrete objective comes from.

从积分到权重

From the integral to the weights

把积分拆到各个单元,并把权重在单元中心展开:1+x=(1+xi)+(x−xi)1+x=(1+x_i)+(x-x_i)。

Split the integral into the cells and expand the weight about the cell centre: 1+x=(1+xi)+(x−xi)1+x=(1+x_i)+(x-x_i).

J(u)=∑i∫xi−h/2xi+h/2(1+x) u dx=∑ih(1+xi)⏟wi ⟨u⟩i+∑imi,mi=∫xi−h/2xi+h/2(x−xi) u dx.J(u)=\sum_i\int_{x_i-h/2}^{x_i+h/2}(1+x)\,u\,\mathrm dx=\sum_i\underbrace{h(1+x_i)}_{w_i}\,\langle u\rangle_i+\sum_im_i,\qquad m_i=\int_{x_i-h/2}^{x_i+h/2}(x-x_i)\,u\,\mathrm dx.

离散目标保留第一个和,并用未知量代替精确平均:

The discrete objective keeps the first sum, with the unknowns in place of the exact averages:

Jh(𝐔)=∑i=0N−1wiUi=wT𝐔,wi=h (1+xi).J_h(\mathbf U)=\sum_{i=0}^{N-1}w_iU_i=w^T\mathbf U,\qquad w_i=h\,(1+x_i).

它是线性的。状态梯度就是权重向量本身,与状态无关;它不显式依赖设计;二阶导数为零:

It is linear. Its state gradient is the weight vector itself, independent of the state; it does not depend on the design explicitly; its second derivative is zero:

g=(∂Jh/∂𝐔)T=w,∂Jh∂D=0,∂2Jh∂𝐔2=0.g=(\partial J_h/\partial\mathbf U)^T=w,\qquad\frac{\partial J_h}{\partial D}=0,\qquad\frac{\partial^2J_h}{\partial\mathbf U^2}=0.

所以伴随方程 ATψ=−gA^T\psi=-g 的右端项 −g=−w-g=-w 在每个状态、每个设计下都相同,变的只有 ATA^T;而且 JhJ_h 对设计的导数只经过状态:dJh/dD=wT d𝐔/dD\mathrm dJ_h/\mathrm dD=w^T\,\mathrm d\mathbf U/\mathrm dD。N=8N=8 时 ww 从 w0=0.132813w_0=0.132813 线性增到 wN−1=0.242188w_{N-1}=0.242188。

So the right-hand side −g=−w-g=-w of the adjoint equation ATψ=−gA^T\psi=-g is the same at every state and every design; only ATA^T changes. And the derivative of JhJ_h with respect to the design goes through the state only: dJh/dD=wT d𝐔/dD\mathrm dJ_h/\mathrm dD=w^T\,\mathrm d\mathbf U/\mathrm dD. At N=8N=8 the weights grow linearly from w0=0.132813w_0=0.132813 to wN−1=0.242188w_{N-1}=0.242188.

权重规则是精确的吗?

Is the weight rule exact?

丢掉的只有 ∑imi\sum_im_i,即 uu 关于各单元中心的一阶矩之和。对光滑的 uu,Taylor 展开给出 mi=u′(xi) h3/12+O(h5)m_i=u'(x_i)\,h^3/12+O(h^5),求和后一般是二阶误差:

The only thing dropped is ∑imi\sum_im_i, the sum of the first moments of uu about the cell centres. For a smooth uu a Taylor expansion gives mi=u′(xi) h3/12+O(h5)m_i=u'(x_i)\,h^3/12+O(h^5), and the sum is in general a second-order error:

∑imi≈h212∑ih u′(xi)≈h212[u(1)−u(0)].\sum_im_i\approx\frac{h^2}{12}\sum_ih\,u'(x_i)\approx\frac{h^2}{12}\bigl[u(1)-u(0)\bigr].

对本页的 u∗u^*,u∗(1)=u∗(0)u^*(1)=u^*(0)(周期函数),首项消失。实际上整个和都为零:对正弦函数可以精确积分(下式的 θi\theta_i 是单元 ii 中心的相位),

For this page's u∗u^*, u∗(1)=u∗(0)u^*(1)=u^*(0) (it is periodic) and the leading term vanishes. In fact the whole sum vanishes: for the sine the moment integrates exactly (below, θi\theta_i is the phase of the centre of cell ii),

mi=a cos⁡θi[sin⁡πh2π2−h cos⁡πh2π],θi=2π(xi−φ),∑i=0N−1cos⁡θi=Re⁡(ei(πh−2πφ)∑i=0N−1e2πi i/N)=0(N≥2),m_i=a\,\cos\theta_i\Bigl[\frac{\sin\pi h}{2\pi^2}-\frac{h\,\cos\pi h}{2\pi}\Bigr],\quad\theta_i=2\pi(x_i-\varphi),\qquad\sum_{i=0}^{N-1}\cos\theta_i=\operatorname{Re}\Bigl(e^{\mathrm i(\pi h-2\pi\varphi)}\sum_{i=0}^{N-1}e^{2\pi\mathrm i\,i/N}\Bigr)=0\quad(N\ge2),

因为 NN 个 NN 次单位根之和为零。所以对每个 N≥2N\ge2,Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^* 严格成立。实测:N=8N=8 到 4096 时 ∣Jh(⟨u∗⟩)−J∗∣≤3.2×10−15|J_h(\langle u^*\rangle)-J^*|\le3.2\times10^{-15}(舍入);N=8N=8 时方括号的值是 1.007e−3,矩之和 −1.9e−19。对这个构造解,离散目标没有求积误差。把恒等式 Jh(⟨u∗⟩(D))=J∗(D)J_h(\langle u^*\rangle(D))=J^*(D) 对 DD 求导,得 wT∂⟨u∗⟩/∂D=∂J∗/∂Dw^T\partial\langle u^*\rangle/\partial D=\partial J^*/\partial D:梯度也没有求积误差。

because the NN NN-th roots of unity add up to zero. So Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^* holds exactly for every N≥2N\ge2. Measured: ∣Jh(⟨u∗⟩)−J∗∣≤3.2×10−15|J_h(\langle u^*\rangle)-J^*|\le3.2\times10^{-15} for N=8N=8 to 4096 (rounding); at N=8N=8 the bracket is 1.007e−3 and the sum of the moments −1.9e−19. For this manufactured solution the discrete objective has no quadrature error. Differentiating the identity Jh(⟨u∗⟩(D))=J∗(D)J_h(\langle u^*\rangle(D))=J^*(D) with respect to DD gives wT∂⟨u∗⟩/∂D=∂J∗/∂Dw^T\partial\langle u^*\rangle/\partial D=\partial J^*/\partial D: the gradient has no quadrature error either.

图 19 · 被丢掉的一阶矩 m_i=∫(x-x_i) u dx,N=8。左:u*(周期),正负相消,和为 −1.9e−19(舍入)。右:非周期的检验函数 u=e^x,矩全为正,和为 2.237e−3;它与首项 (h^2)/12(e-1)=2.237 × 10^(-3) 之差 −5.82e−7 正是下一项 -(h^4)/720(u''(1)-u''(0))=-5.83 × 10^(-7)。−4e−4−2e−402e−44e−400.20.40.60.81xi​mi​u*(周期):Σ mi​ = −1.9e−19−4e−4−2e−402e−44e−400.20.40.60.81xi​mi​u = ex​(非周期):Σ mi​ = 2.237e−3
图 19 · 被丢掉的一阶矩 mi=∫(x−xi) u dxm_i=\int(x-x_i)\,u\,\mathrm dx,N=8N=8。左:u∗u^*(周期),正负相消,和为 −1.9e−19(舍入)。右:非周期的检验函数 u=exu=e^x,矩全为正,和为 2.237e−3;它与首项 h212(e−1)=2.237×10−3\tfrac{h^2}{12}(e-1)=2.237\times10^{-3} 之差 −5.82e−7 正是下一项 −h4720(u′′(1)−u′′(0))=−5.83×10−7-\tfrac{h^4}{720}\bigl(u''(1)-u''(0)\bigr)=-5.83\times10^{-7}。
Figure 19 · The dropped first moments m_i=∫(x-x_i) u dx, N=8. Left: u* (periodic); positive and negative moments cancel and the sum is −1.9e−19 (rounding). Right: the non-periodic test function u=e^x; all moments are positive and the sum is 2.237e−3; its difference from the leading term (h^2)/12(e-1)=2.237 × 10^(-3), −5.82e−7, is the next term -(h^4)/720(u''(1)-u''(0))=-5.83 × 10^(-7).−4e−4−2e−402e−44e−400.20.40.60.81xi​mi​u* (periodic): Σ mi​ = −1.9e−19−4e−4−2e−402e−44e−400.20.40.60.81xi​mi​u = ex​ (not periodic): Σ mi​ = 2.237e−3
Figure 19 · The dropped first moments mi=∫(x−xi) u dxm_i=\int(x-x_i)\,u\,\mathrm dx, N=8N=8. Left: u∗u^* (periodic); positive and negative moments cancel and the sum is −1.9e−19 (rounding). Right: the non-periodic test function u=exu=e^x; all moments are positive and the sum is 2.237e−3; its difference from the leading term h212(e−1)=2.237×10−3\tfrac{h^2}{12}(e-1)=2.237\times10^{-3}, −5.82e−7, is the next term −h4720(u′′(1)−u′′(0))=−5.83×10−7-\tfrac{h^4}{720}\bigl(u''(1)-u''(0)\bigr)=-5.83\times10^{-7}.

Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^* 是这个构造解(周期)的性质,不是格式的性质。对非周期的解,权重规则丢掉 h212(u(1)−u(0))\tfrac{h^2}{12}\bigl(u(1)-u(0)\bigr):Jh(⟨u⟩)=J(u)−h212(u(1)−u(0))+O(h4)J_h(\langle u\rangle)=J(u)-\tfrac{h^2}{12}\bigl(u(1)-u(0)\bigr)+O(h^4),仍是二阶,不会拖累二阶格式。

Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^* is a property of this (periodic) manufactured solution, not of the scheme. For a non-periodic solution the weight rule drops h212(u(1)−u(0))\tfrac{h^2}{12}\bigl(u(1)-u(0)\bigr): Jh(⟨u⟩)=J(u)−h212(u(1)−u(0))+O(h4)J_h(\langle u\rangle)=J(u)-\tfrac{h^2}{12}\bigl(u(1)-u(0)\bigr)+O(h^4), still second order, so it would not spoil a second-order scheme either.

JhJ_h 的误差全是状态误差

The error of JhJ_h is all state error

既然 Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^*,离散目标的误差就只来自解的误差:

Since Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^*, the error of the discrete objective comes from the error of the solution alone:

Jh(𝐔)−J∗=wT(𝐔−⟨u∗⟩)=∑iwi (Ui−⟨u∗⟩i).J_h(\mathbf U)-J^*=w^T\bigl(\mathbf U-\langle u^*\rangle\bigr)=\sum_iw_i\,\bigl(U_i-\langle u^*\rangle_i\bigr).

默认设计下(N=8N=8):J∗=1.471198J^*=1.471198,JhJ_h 在一阶、无限制器线性、光滑限制器下分别是 1.357470、1.408114、1.380649;无限制器线性的 Jh−J∗=−0.063084J_h-J^*=-0.063084,与加权误差 wT(𝐔−⟨u∗⟩)=−0.063084w^T(\mathbf U-\langle u^*\rangle)=-0.063084 相同。权重都为正,所以 Jh−J∗J_h-J^* 是解的带符号误差的正权加权和。

At the defaults (N=8N=8): J∗=1.471198J^*=1.471198, and JhJ_h is 1.357470, 1.408114 and 1.380649 for first order, unlimited linear and the smooth limiter; for unlimited linear Jh−J∗=−0.063084J_h-J^*=-0.063084, the same as the weighted error wT(𝐔−⟨u∗⟩)=−0.063084w^T(\mathbf U-\langle u^*\rangle)=-0.063084. The weights are all positive, so Jh−J∗J_h-J^* is a positively weighted sum of the signed error of the solution.

图 20 · 目标的组成(默认设计,N=8,无限制器线性)。左:权重 w_i=h(1+x_i)(紫)与每个单元的贡献 w_iU_i(蓝)。右:贡献的部分和,最后一点就是 J_h=1.408114,虚线是 J*=1.471198。00.050.10.150.20.2500.20.40.60.81xi​权重与贡献gi​ = wi​ = h(1 + xi​)wi​ Ui​00.20.40.60.811.21.41.600.20.40.60.81xi​J* = 1.471198Jh​ = 1.408114部分和 Σj≤i​ wj​ Uj​
图 20 · 目标的组成(默认设计,N=8N=8,无限制器线性)。左:权重 wi=h(1+xi)w_i=h(1+x_i)(紫)与每个单元的贡献 wiUiw_iU_i(蓝)。右:贡献的部分和,最后一点就是 Jh=1.408114J_h=1.408114,虚线是 J∗=1.471198J^*=1.471198。
Figure 20 · What the objective is made of (default design, N=8, unlimited linear). Left: the weights w_i=h(1+x_i) (violet) and the contribution w_iU_i of every cell (blue). Right: the partial sums of the contributions; the last point is J_h=1.408114, the dashed line J*=1.471198.00.050.10.150.20.2500.20.40.60.81xi​weights and contributionsgi​ = wi​ = h(1 + xi​)wi​ Ui​00.20.40.60.811.21.41.600.20.40.60.81xi​J* = 1.471198Jh​ = 1.408114partial sums Σj≤i​ wj​ Uj​
Figure 20 · What the objective is made of (default design, N=8N=8, unlimited linear). Left: the weights wi=h(1+xi)w_i=h(1+x_i) (violet) and the contribution wiUiw_iU_i of every cell (blue). Right: the partial sums of the contributions; the last point is Jh=1.408114J_h=1.408114, the dashed line J∗=1.471198J^*=1.471198.

加密下 Jh−J∗J_h-J^* 的收敛于是就是状态误差的收敛:Jh−J∗J_h-J^* 在最后一次加倍时的观测阶,无限制器线性是 1.96,一阶是 0.99,光滑限制器是 0.98(第 4 节说明了为什么光滑限制器在细网格上是一阶)。独立的 Python 程序(solve.py)存储的目标值与本页 JhJ_h 之差,在一阶与无限制器线性、N=32N=32 到 4096 上不超过 3.1e−12。

Under refinement the convergence of Jh−J∗J_h-J^* is therefore the convergence of the state error: the observed order of Jh−J∗J_h-J^* over the last doubling is 1.96 for unlimited linear, 0.99 for first order and 0.98 for the smooth limiter (Section 4 explains why the smooth limiter is first order on fine meshes). The objectives stored by the independent Python program (solve.py) differ from this page's JhJ_h by at most 3.1e−12 for first order and unlimited linear, N=32N=32 to 4096.

图 21 · |J_h(U)-J*| 随 N 的变化(默认设计,N=8 到 4096)。三种重构的误差都是状态误差;方块是精确平均处的 |J_h(⟨u*⟩)-J*|,停在舍入误差平台上。虚线是 ∝ h、∝ h^2 的参考线。10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​1101001000N|Jh​ − J*|hh²Jh​(U) − J*,一阶Jh​(U) − J*,无限制器线性Jh​(U) − J*,光滑限制器Jh​(⟨u*⟩) − J*(舍入)
图 21 · ∣Jh(𝐔)−J∗∣|J_h(\mathbf U)-J^*| 随 NN 的变化(默认设计,N=8N=8 到 4096)。三种重构的误差都是状态误差;方块是精确平均处的 ∣Jh(⟨u∗⟩)−J∗∣|J_h(\langle u^*\rangle)-J^*|,停在舍入误差平台上。虚线是 ∝h\propto h、∝h2\propto h^2 的参考线。
Figure 21 · |J_h(U)-J*| against N (default design, N=8 to 4096). For all three reconstructions the error is state error; the squares are |J_h(⟨u*⟩)-J*| at the exact averages, which stays on the rounding floor. The dashed lines are reference lines ∝ h and ∝ h^2.10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​1101001000N|Jh​ − J*|hh²Jh​(U) − J*, first orderJh​(U) − J*, unlimited linearJh​(U) − J*, smooth limiterJh​(⟨u*⟩) − J* (rounding)
Figure 21 · ∣Jh(𝐔)−J∗∣|J_h(\mathbf U)-J^*| against NN (default design, N=8N=8 to 4096). For all three reconstructions the error is state error; the squares are ∣Jh(⟨u∗⟩)−J∗∣|J_h(\langle u^*\rangle)-J^*| at the exact averages, which stays on the rounding floor. The dashed lines are reference lines ∝h\propto h and ∝h2\propto h^2.

在当前设计下自己量一遍(N=8N=8 到 256,在浏览器里求解):

Measure it yourself at the current design (N=8N=8 to 256, solved in the browser):

伴随方程的右端项就是 −g=−w-g=-w:分量全为负,绝对值随 xx 线性增大(从 w0w_0 到 wN−1w_{N-1}),与状态无关。第 9、11 节用它求伴随 ψ\psi。

The right-hand side of the adjoint equation is −g=−w-g=-w: a negative vector whose magnitude grows linearly with xx, from w0w_0 to wN−1w_{N-1}, and does not depend on the state. Sections 9 and 11 use it to compute the adjoint ψ\psi.

第 8 节Section 8

前向:沿着面循环传播切向量

Forward: the tangent through the face loop

本节实验:只给一个未知量一个单位的扰动 𝐔˙=e3\dot{\mathbf U}=e_3,设计不动:残差的哪几行会变、各变多少?先用第 3 节的模板预测,再在本节的逐列播放器里验证。

Experiment: Seed one unknown, 𝐔˙=e3\dot{\mathbf U}=e_3, and hold the design fixed: which rows of the residual change, and by how much? Predict from the stencil of Section 3, then check with the column player of this section.

第 5–7 节写出了残差代码 R(𝐔,D)R(\mathbf U,D),解出了 R=0R=0,定义了目标 JhJ_h。本节用前向模式对残差代码求导:输入是未知量与设计的一个联合方向 (𝐔˙,D˙)(\dot{\mathbf U},\dot D),输出是每个残差沿这个方向的导数,全程不形成矩阵。第 9 节把同一段代码倒过来运行。

Sections 5–7 built the residual code R(𝐔,D)R(\mathbf U,D), solved R=0R=0 and defined the objective JhJ_h. This section differentiates the residual code in forward mode: a joint direction (𝐔˙,D˙)(\dot{\mathbf U},\dot D) of the unknowns and the design goes in, the derivative of every residual along that direction comes out, and no matrix is formed. Section 9 runs the same code backwards.

矩阵乘积可以写成方向导数

A matrix product as a directional derivative

先固定设计(D˙=0\dot D=0),让所有未知量沿方向 vv 一起变化:𝐔(t)=𝐔+tv\mathbf U(t)=\mathbf U+t v。向量 vv 就是状态切向量 𝐔˙\dot{\mathbf U},它规定每个未知量随 tt 变化的快慢。对每个残差在 t=0t=0 处关于 tt 求导,得到残差切向量 R˙=Av\dot R=Av:一次矩阵向量乘积,却不需要矩阵本身。

First hold the design fixed (D˙=0\dot D=0) and move all unknowns together along a direction vv: 𝐔(t)=𝐔+tv\mathbf U(t)=\mathbf U+t v. The vector vv is the state tangent 𝐔˙\dot{\mathbf U}; it says how fast each unknown changes with tt. Differentiating each residual with respect to tt at t=0t=0 gives the residual tangent R˙=Av\dot R=Av: a matrix–vector product, computed without the matrix.

R˙i=(Av)i=ddtRi(𝐔+tv,D)∣t=0=∑j∂Ri∂Uj vj.\dot R_i=(Av)_i=\frac{\mathrm d}{\mathrm dt}R_i(\mathbf U+t v,D)\Big|_{t=0}=\sum_j\frac{\partial R_i}{\partial U_j}\,v_j.

再让设计也动起来,D(t)=D+tD˙D(t)=D+t\dot D,链式法则多出设计 Jacobian 一项。自动微分的前向(切线)模式就是这样计算的:残差代码里的每个中间量 xx 都配一个切向量 x˙\dot x,按 xx 本身的计算顺序算出。

Let the design move as well, D(t)=D+tD˙D(t)=D+t\dot D, and the chain rule adds the design Jacobian. The forward (tangent) mode of automatic differentiation computes exactly this: every intermediate xx of the residual code gets a tangent x˙\dot x, computed in the same order as xx itself.

R˙=ddtR(𝐔+t𝐔˙, D+tD˙)∣t=0=A 𝐔˙+RD D˙.\dot R=\frac{\mathrm d}{\mathrm dt}R\big(\mathbf U+t\dot{\mathbf U},\,D+t\dot D\big)\Big|_{t=0}=A\,\dot{\mathbf U}+R_D\,\dot D.

记号:上点 x˙\dot x 与上横线 xˉ\bar x 是离散程序的前向导数与反向(伴随)导数。代码沿用 Tapenade 等自动微分工具的命名:前向子程序 residual_d 读入种子 u_d ≡𝐔˙\equiv\dot{\mathbf U}、D_d ≡D˙\equiv\dot D,返回 res_d ≡R˙\equiv\dot R;第 9 节的 residual_b 读入 res_b ≡Rˉ\equiv\bar R,返回 u_b ≡𝐔ˉ\equiv\bar{\mathbf U} 与 D_b ≡Dˉ\equiv\bar D。

Notation: the dot x˙\dot x and the bar xˉ\bar x are the forward and the reverse (adjoint) derivatives of the discrete program. The code uses the names of AD tools such as Tapenade: the forward routine residual_d takes the seeds u_d ≡𝐔˙\equiv\dot{\mathbf U} and D_d ≡D˙\equiv\dot D and returns res_d ≡R˙\equiv\dot R; the residual_b of Section 9 takes res_b ≡Rˉ\equiv\bar R and returns u_b ≡𝐔ˉ\equiv\bar{\mathbf U} and D_b ≡Dˉ\equiv\bar D.

图 22 · 一个面的前向数据流(面 f=4,默认设计,无限制器线性重构;种子 U=v_0、D-dot=e_0,即第 10 节振幅 a 方向的切线解)。从左到右是程序顺序:(1)面读入 4 个未知量;(2)斜率、迹 q_L,q_R、未重构状态 U_L,U_R 和黏性 ν 组成面输入 z_f(面的输入向量,不是第 1 节正弦的自变量 z=2π(x-φ));(3)通量 H_f;(4)分发到 R_3、R_4。每个方框给出原始值和(绿色的)切向量,每条箭头上是它所乘的局部导数。在面 0 和面 N 上,边界值 u_in,u_out(a,φ) 代替缺失的单元(紫色)。(1)取值(2)重构:斜率、迹、未重构状态、ν(3)通量(4)分发1111½−½cL​κf​−κf​cR​−(UR​ − UL​)/df​+1−1U2​ = 1.1388U̇2​ = 0.7301U3​ = 1.0683U̇3​ = 0.3555U4​ = 0.9171U̇4​ = −0.4787U5​ = 0.7835U̇5​ = −1.1686σ3​ = −0.1109σ̇3​ = −0.6044σ4​ = −0.1424σ̇4​ = −0.7620σi​ 读 Ui−1​, Ui​, Ui+1​权重 −σl​, σl​ − σr​, σr​qL​ = 1.0129q̇L​ = 0.0533UL​ = 1.0683U̇L​ = 0.3555UR​ = 0.9171U̇R​ = −0.4787qR​ = 0.9883q̇R​ = −0.0977ν = 0.010ν̇ = 0.0000H4​ = 0.5374Ḣ4​ = 0.1964R3​ += H4​Ṙ3​ += 0.1964R4​ −= H4​Ṙ4​ −= 0.1964Ḣ4​ = cL​ q̇L​ + cR​ q̇R​ + κf​(U̇L​ − U̇R​) − ν̇(UR​ − UL​)/df​ = 0.1964种子:U̇ = v0​(a 方向的切线解),Ḋ = e0​;ν 不变,所以 ν̇ = 0
图 22 · 一个面的前向数据流(面 f=4f=4,默认设计,无限制器线性重构;种子 𝐔˙=v0\dot{\mathbf U}=v_0、D˙=e0\dot D=e_0,即第 10 节振幅 aa 方向的切线解)。从左到右是程序顺序:(1)面读入 4 个未知量;(2)斜率、迹 qL,qRq_L,q_R、未重构状态 UL,URU_L,U_R 和黏性 ν\nu 组成面输入 zfz_f(面的输入向量,不是第 1 节正弦的自变量 z=2π(x−φ)z=2\pi(x-\varphi));(3)通量 HfH_f;(4)分发到 R3R_3、R4R_4。每个方框给出原始值和(绿色的)切向量,每条箭头上是它所乘的局部导数。在面 00 和面 NN 上,边界值 uin,uout(a,φ)u_{\rm in},u_{\rm out}(a,\varphi) 代替缺失的单元(紫色)。
Figure 22 · The forward data flow of one face (face f=4, default design, unlimited linear reconstruction; seed U=v_0, D-dot=e_0, the tangent solution of Section 10 for the amplitude a). Left to right in program order: (1) the face gathers four unknowns, (2) the slopes, the traces q_L,q_R, the raw states U_L,U_R and the viscosity ν form the face inputs z_f (the input vector of the face, not the argument z=2π(x-φ) of the sine in Section 1), (3) the flux H_f, (4) the scatter into R_3 and R_4. Each box carries its primal value and, in green, its tangent; each arrow carries the local derivative it multiplies. On face 0 and face N the boundary data u_in,u_out(a,φ) take the place of the missing cell (violet).(1) gather(2) reconstruct: slopes, traces, raw states, ν(3) flux(4) scatter1111½−½cL​κf​−κf​cR​−(UR​ − UL​)/df​+1−1U2​ = 1.1388U̇2​ = 0.7301U3​ = 1.0683U̇3​ = 0.3555U4​ = 0.9171U̇4​ = −0.4787U5​ = 0.7835U̇5​ = −1.1686σ3​ = −0.1109σ̇3​ = −0.6044σ4​ = −0.1424σ̇4​ = −0.7620σi​ reads Ui−1​, Ui​, Ui+1​with −σl​, σl​ − σr​, σr​qL​ = 1.0129q̇L​ = 0.0533UL​ = 1.0683U̇L​ = 0.3555UR​ = 0.9171U̇R​ = −0.4787qR​ = 0.9883q̇R​ = −0.0977ν = 0.010ν̇ = 0.0000H4​ = 0.5374Ḣ4​ = 0.1964R3​ += H4​Ṙ3​ += 0.1964R4​ −= H4​Ṙ4​ −= 0.1964Ḣ4​ = cL​ q̇L​ + cR​ q̇R​ + κf​(U̇L​ − U̇R​) − ν̇(UR​ − UL​)/df​ = 0.1964seed: U̇ = v0​ (the tangent solution of a), Ḋ = e0​; ν does not move, so ν̇ = 0
Figure 22 · The forward data flow of one face (face f=4f=4, default design, unlimited linear reconstruction; seed 𝐔˙=v0\dot{\mathbf U}=v_0, D˙=e0\dot D=e_0, the tangent solution of Section 10 for the amplitude aa). Left to right in program order: (1) the face gathers four unknowns, (2) the slopes, the traces qL,qRq_L,q_R, the raw states UL,URU_L,U_R and the viscosity ν\nu form the face inputs zfz_f (the input vector of the face, not the argument z=2π(x−φ)z=2\pi(x-\varphi) of the sine in Section 1), (3) the flux HfH_f, (4) the scatter into R3R_3 and R4R_4. Each box carries its primal value and, in green, its tangent; each arrow carries the local derivative it multiplies. On face 00 and face NN the boundary data uin,uout(a,φ)u_{\rm in},u_{\rm out}(a,\varphi) take the place of the missing cell (violet).

先看最小的一步:一个面的通量

The smallest step first: one face flux

第 3 节的通量有五个输入:两个迹、两个未重构状态和黏性,H=H(qL,qR,UL,UR,ν)H=H(q_L,q_R,U_L,U_R,\nu)(dfd_f 由网格决定,是常数)。对每个输入求偏导,乘以该输入的切向量,再相加:

The flux of Section 3 has five inputs: the two traces, the two raw states and the viscosity, H=H(qL,qR,UL,UR,ν)H=H(q_L,q_R,U_L,U_R,\nu) (dfd_f is fixed by the mesh). Differentiate it with respect to each input, multiply by that input's tangent and add:

H˙f=cL q˙L+cR q˙R⏟H˙c+κf (U˙L−U˙R)−ν˙ UR−ULdf⏟H˙v,cL=qL2+1,cR=qR2−1,κf=νdf.\dot H_f=\underbrace{c_L\,\dot q_L+c_R\,\dot q_R}_{\dot H^c}+\underbrace{\kappa_f\,(\dot U_L-\dot U_R)-\dot\nu\,\frac{U_R-U_L}{d_f}}_{\dot H^v},\qquad c_L=\frac{q_L}2+1,\quad c_R=\frac{q_R}2-1,\quad \kappa_f=\frac{\nu}{d_f}.

对流部分 H˙c\dot H^c 与黏性部分 H˙v\dot H^v 分别是第 3 节 HcH^c、HvH^v 的切向量。五个偏导数在第 3 节都已写出;最后一项值得单独说:黏性是设计变量,在通量中乘以差商 (UR−UL)/df(U_R-U_L)/d_f,所以设计种子 ν˙\dot\nu 直接作用在每一个面上,系数是 −(UR−UL)/df-(U_R-U_L)/d_f;aa 和 φ\varphi 没有这样的项,它们只通过两个边界面上的 uin,uoutu_{\rm in},u_{\rm out} 进入通量。

The convective part H˙c\dot H^c and the viscous part H˙v\dot H^v are the tangents of the HcH^c and HvH^v of Section 3, where all five partial derivatives were written out. The last term deserves a word of its own: the viscosity is a design variable that multiplies the difference quotient (UR−UL)/df(U_R-U_L)/d_f in the flux, so a design seed ν˙\dot\nu acts directly on every face, with the factor −(UR−UL)/df-(U_R-U_L)/d_f; aa and φ\varphi have no such term and reach the fluxes only through uin,uoutu_{\rm in},u_{\rm out} on the two boundary faces.

手算一个面:取默认收敛解(无限制器线性)的面 f=4f=4,这里 cL=1.5064c_L=1.5064,cR=−0.5059c_R=-0.5059,κf=ν/h=0.08\kappa_f=\nu/h=0.08,UR−UL=−0.1513U_R-U_L=-0.1513。(i)只扰动未知量 U3U_3:它在 qLq_L 里的权重是 1,在 qRq_R 里是 14\tfrac14(斜率 σ4=(U5−U3)/2\sigma_4=(U_5-U_3)/2 含有它),在 ULU_L 里是 1、在 URU_R 里是 0,所以 q˙L=1\dot q_L=1,q˙R=14\dot q_R=\tfrac14,U˙L=1\dot U_L=1,U˙R=0\dot U_R=0,ν˙=0\dot\nu=0,H˙4=cL+cR/4+κf=1.4600\dot H_4=c_L+c_R/4+\kappa_f=1.4600,这正是第 3 节图 8 里的元素 ∂H4/∂U3\partial H_4/\partial U_3。(ii)只扰动黏性,ν˙=1\dot\nu=1:所有状态切向量为零,H˙4=−(UR−UL)/df=1.2102\dot H_4=-(U_R-U_L)/d_f=1.2102,这是这个面上 ν\nu 的显式路径。然后像 HfH_f 加到 Rf−1R_{f-1}、从 RfR_f 减去一样,把 H˙f\dot H_f 加到 R˙f−1\dot R_{f-1}、从 R˙f\dot R_f 减去。

Work one face by hand: face f=4f=4 of the converged default solution (unlimited linear), where cL=1.5064c_L=1.5064, cR=−0.5059c_R=-0.5059, κf=ν/h=0.08\kappa_f=\nu/h=0.08 and UR−UL=−0.1513U_R-U_L=-0.1513. (i) Seed only the unknown U3U_3: its weight is 1 in qLq_L, 14\tfrac14 in qRq_R (the slope σ4=(U5−U3)/2\sigma_4=(U_5-U_3)/2 contains it), 1 in ULU_L and 0 in URU_R, so q˙L=1\dot q_L=1, q˙R=14\dot q_R=\tfrac14, U˙L=1\dot U_L=1, U˙R=0\dot U_R=0, ν˙=0\dot\nu=0 and H˙4=cL+cR/4+κf=1.4600\dot H_4=c_L+c_R/4+\kappa_f=1.4600: the entry ∂H4/∂U3\partial H_4/\partial U_3 of Figure 8 in Section 3. (ii) Seed only the viscosity, ν˙=1\dot\nu=1: every state tangent vanishes and H˙4=−(UR−UL)/df=1.2102\dot H_4=-(U_R-U_L)/d_f=1.2102, the explicit ν\nu-path of this face. Then H˙f\dot H_f is added to R˙f−1\dot R_{f-1} and subtracted from R˙f\dot R_f, exactly as HfH_f is added to Rf−1R_{f-1} and subtracted from RfR_f.

从状态切向量到通量切向量:一个面读哪些未知量

From state tangents to flux tangents: which unknowns a face reads

无限制器线性重构时,迹是未知量的固定线性组合(第 3 节),所以迹的切向量是状态切向量的同一组合。对两侧单元都被重构的内部面(2≤f≤N−22\le f\le N-2):

With the unlimited linear reconstruction the traces are fixed linear combinations of the unknowns (Section 3), so their tangents are the same combinations of the state tangents. For an interior face whose two cells are both reconstructed (2≤f≤N−22\le f\le N-2):

q˙L=−14U˙f−2+U˙f−1+14U˙f,q˙R=14U˙f−1+U˙f−14U˙f+1,U˙L=U˙f−1,U˙R=U˙f,\dot q_L=-\tfrac14\dot U_{f-2}+\dot U_{f-1}+\tfrac14\dot U_f,\qquad \dot q_R=\tfrac14\dot U_{f-1}+\dot U_f-\tfrac14\dot U_{f+1},\qquad \dot U_L=\dot U_{f-1},\quad \dot U_R=\dot U_f,
H˙f=−cL4U˙f−2+(cL+cR4+κf)U˙f−1+(cL4+cR−κf)U˙f−cR4U˙f+1−ν˙ Uf−Uf−1h.\dot H_f=-\frac{c_L}4\dot U_{f-2}+\Big(c_L+\frac{c_R}4+\kappa_f\Big)\dot U_{f-1}+\Big(\frac{c_L}4+c_R-\kappa_f\Big)\dot U_f-\frac{c_R}4\dot U_{f+1}-\dot\nu\,\frac{U_f-U_{f-1}}h.

四个系数就是第 3 节图 8 中矩阵 ∂Hf/∂Uj\partial H_f/\partial U_j 的第 ff 行:面 4 上是 −0.3766-0.3766、1.46001.4600、−0.2093-0.2093、0.12650.1265。黏性部分给中间两个系数中左边的加 +κf+\kappa_f、右边的加 −κf-\kappa_f,不扩大模板。在默认状态下,每个面 2≤f≤N−22\le f\le N-2 上都有 cL+cR/4>0c_L+c_R/4>0 和 cL/4+cR<0c_L/4+c_R<0,所以这两项都被加强;但这不是对每个状态都成立:cL/4+cRc_L/4+c_R 可以变正,这时 −κf-\kappa_f 把它拉向零。只要 κf<2(cL/4+cR)\kappa_f<2(c_L/4+c_R),它的绝对值就变小(κf\kappa_f 超过 cL/4+cRc_L/4+c_R 时已经变号;D=(0.45,0.61,0.01)D=(0.45,0.61,0.01)、N=8N=8 时面 6 上 0.168→0.0880.168\to0.088);否则它变号且绝对值变大(同一状态的面 5 上 0.0003→−0.0800.0003\to-0.080)。靠近边界时端单元不重构(σ0=σN−1=0\sigma_0=\sigma_{N-1}=0),所以面 1 读 3 个未知量,面 0 只读 U0U_0 和边界值 uinu_{\rm in}(q˙L=U˙L=u˙in\dot q_L=\dot U_L=\dot u_{\rm in}),右端对称。一阶时 σ≡0\sigma\equiv0,一个面只读 Uf−1,UfU_{f-1},U_f。光滑限制器时 qLq_L 中的权重不再是 −14,1,14-\tfrac14,1,\tfrac14,而是 −σl/2, 1+(σl−σr)/2, σr/2-\sigma_l/2,\ 1+(\sigma_l-\sigma_r)/2,\ \sigma_r/2,其中 σl,σr\sigma_l,\sigma_r 随状态变化(下表第 4 条语句;qRq_R 同理);图 23 显示,在默认解的面 4 上,这些权重与 −14,1,14-\tfrac14,1,\tfrac14 相差很远。

The four coefficients are row ff of the matrix ∂Hf/∂Uj\partial H_f/\partial U_j of Figure 8 in Section 3: at face 4 they are −0.3766-0.3766, 1.46001.4600, −0.2093-0.2093 and 0.12650.1265. The viscous part adds +κf+\kappa_f to the left and −κf-\kappa_f to the right central coefficient and widens nothing. At the default state cL+cR/4>0c_L+c_R/4>0 and cL/4+cR<0c_L/4+c_R<0 on every face 2≤f≤N−22\le f\le N-2, so both entries are strengthened; this does not hold for every state: cL/4+cRc_L/4+c_R can turn positive, and −κf-\kappa_f then pulls it towards zero. Its magnitude shrinks while κf<2(cL/4+cR)\kappa_f<2(c_L/4+c_R) (the sign already flips once κf\kappa_f exceeds cL/4+cRc_L/4+c_R; face 6 for D=(0.45,0.61,0.01)D=(0.45,0.61,0.01), N=8N=8: 0.168→0.0880.168\to0.088); beyond that it changes sign and grows in magnitude (face 5 of the same state: 0.0003→−0.0800.0003\to-0.080). Next to a boundary the end cells are not reconstructed (σ0=σN−1=0\sigma_0=\sigma_{N-1}=0), so face 1 reads 3 unknowns, face 0 only U0U_0 and the boundary value uinu_{\rm in} (q˙L=U˙L=u˙in\dot q_L=\dot U_L=\dot u_{\rm in}), and symmetrically at the right end. At first order σ≡0\sigma\equiv0 and a face reads only Uf−1,UfU_{f-1},U_f. With the smooth limiter the weights in qLq_L are no longer −14,1,14-\tfrac14,1,\tfrac14 but −σl/2, 1+(σl−σr)/2, σr/2-\sigma_l/2,\ 1+(\sigma_l-\sigma_r)/2,\ \sigma_r/2 with the state-dependent σl,σr\sigma_l,\sigma_r of statement 4 in the table below (qRq_R alike); Figure 23 shows that at face 4 of the default solution these weights are far from −14,1,14-\tfrac14,1,\tfrac14.

图 23 · 一个面的切向量读哪些未知量(面 f=4,默认设计,各重构自己的收敛解)。每行是面两侧的四个单元;格子上方是该单元在 q-dot_L、q-dot_R 中的权重(未重构状态 U-dot_L=U-dot_3、U-dot_R=U-dot_4 的权重总是 1),格子里是前向计算中与 U-dot_j 相乘的导数 ∂ H_4/∂ U_j(蓝正橙负,白色为零)。一阶:2 个未知量;无限制器线性:4 个,权重固定为 ± 1/4;光滑限制器:同样 4 个,权重随状态变化(这里 q_L 中是 -0.58 与 1.58,而不是 -1/4 与 1)。面 f = 4 的切向量读哪些未知量:∂H4​/∂Uj​(格子里)与迹的权重(格子上方)一阶读 2 个未知量q̇L​: 0.000 q̇R​: 0.000U2​0q̇L​: 1.000 q̇R​: 0.000U3​∂H4​/∂U3​ = 1.5555q̇L​: 0.000 q̇R​: 1.000U4​∂H4​/∂U4​ = −0.6684q̇L​: 0.000 q̇R​: 0.000U5​0f = 4无限制器线性读 4 个未知量q̇L​: −0.250 q̇R​: 0.000U2​∂H4​/∂U2​ = −0.3766q̇L​: 1.000 q̇R​: 0.250U3​∂H4​/∂U3​ = 1.4600q̇L​: 0.250 q̇R​: 1.000U4​∂H4​/∂U4​ = −0.2093q̇L​: 0.000 q̇R​: −0.250U5​∂H4​/∂U5​ = 0.1265f = 4光滑限制器读 4 个未知量q̇L​: −0.584 q̇R​: 0.000U2​∂H4​/∂U2​ = −0.8751q̇L​: 1.575 q̇R​: 0.175U3​∂H4​/∂U3​ = 2.3469q̇L​: 0.009 q̇R​: 1.157U4​∂H4​/∂U4​ = −0.6745q̇L​: 0.000 q̇R​: −0.332U5​∂H4​/∂U5​ = 0.1746f = 4未重构状态 UL​ = U3​、UR​ = U4​ 的权重总是 1(黏性通量 ±κf​);一阶 σ ≡ 0;光滑限制器的权重随状态变化。
图 23 · 一个面的切向量读哪些未知量(面 f=4f=4,默认设计,各重构自己的收敛解)。每行是面两侧的四个单元;格子上方是该单元在 q˙L\dot q_L、q˙R\dot q_R 中的权重(未重构状态 U˙L=U˙3\dot U_L=\dot U_3、U˙R=U˙4\dot U_R=\dot U_4 的权重总是 1),格子里是前向计算中与 U˙j\dot U_j 相乘的导数 ∂H4/∂Uj\partial H_4/\partial U_j(蓝正橙负,白色为零)。一阶:2 个未知量;无限制器线性:4 个,权重固定为 ±14\pm\tfrac14;光滑限制器:同样 4 个,权重随状态变化(这里 qLq_L 中是 −0.58-0.58 与 1.581.58,而不是 −14-\tfrac14 与 1)。
Figure 23 · Which unknowns the tangent of one face reads (face f=4, default design, each reconstruction's own converged solution). Each row shows the four cells around the face; above a cell its weights in q-dot_L and q-dot_R (the raw states U-dot_L=U-dot_3, U-dot_R=U-dot_4 always have weight 1), inside it the derivative ∂ H_4/∂ U_j that the forward computation multiplies by U-dot_j (blue positive, orange negative, white zero). First order: two unknowns; unlimited linear: four, with the fixed weights ± 1/4; smooth limiter: the same four with weights that depend on the state (here -0.58 and 1.58 in q_L instead of -1/4 and 1).What the tangent of face f = 4 reads: ∂H4​/∂Uj​ (inside) and the weights of the traces (above)first orderreads 2 unknownsq̇L​: 0.000 q̇R​: 0.000U2​0q̇L​: 1.000 q̇R​: 0.000U3​∂H4​/∂U3​ = 1.5555q̇L​: 0.000 q̇R​: 1.000U4​∂H4​/∂U4​ = −0.6684q̇L​: 0.000 q̇R​: 0.000U5​0f = 4unlimited linearreads 4 unknownsq̇L​: −0.250 q̇R​: 0.000U2​∂H4​/∂U2​ = −0.3766q̇L​: 1.000 q̇R​: 0.250U3​∂H4​/∂U3​ = 1.4600q̇L​: 0.250 q̇R​: 1.000U4​∂H4​/∂U4​ = −0.2093q̇L​: 0.000 q̇R​: −0.250U5​∂H4​/∂U5​ = 0.1265f = 4smooth limiterreads 4 unknownsq̇L​: −0.584 q̇R​: 0.000U2​∂H4​/∂U2​ = −0.8751q̇L​: 1.575 q̇R​: 0.175U3​∂H4​/∂U3​ = 2.3469q̇L​: 0.009 q̇R​: 1.157U4​∂H4​/∂U4​ = −0.6745q̇L​: 0.000 q̇R​: −0.332U5​∂H4​/∂U5​ = 0.1746f = 4The raw states UL​ = U3​, UR​ = U4​ always have weight 1 (viscous flux ±κf​); first order σ ≡ 0; the smooth-limiter weights change with the state.
Figure 23 · Which unknowns the tangent of one face reads (face f=4f=4, default design, each reconstruction's own converged solution). Each row shows the four cells around the face; above a cell its weights in q˙L\dot q_L and q˙R\dot q_R (the raw states U˙L=U˙3\dot U_L=\dot U_3, U˙R=U˙4\dot U_R=\dot U_4 always have weight 1), inside it the derivative ∂H4/∂Uj\partial H_4/\partial U_j that the forward computation multiplies by U˙j\dot U_j (blue positive, orange negative, white zero). First order: two unknowns; unlimited linear: four, with the fixed weights ±14\pm\tfrac14; smooth limiter: the same four with weights that depend on the state (here −0.58-0.58 and 1.581.58 in qLq_L instead of −14-\tfrac14 and 1).

逐句求导:残差代码的前向语句

The residual code differentiated statement by statement

前向模式对第 5 节残差代码的每条赋值语句 y=ϕ(x1,…,xm)y=\phi(x_1,\dots,x_m)(这里 ϕ\phi 是任意初等函数,不是设计的相位 φ\varphi)应用一次链式法则,y˙=∑k(∂ϕ/∂xk) x˙k\dot y=\sum_k(\partial\phi/\partial x_k)\,\dot x_k,紧跟在原语句之后,按同样的顺序执行。下表对本页代码的每条语句都这样做,同时允许状态种子 𝐔˙\dot{\mathbf U} 与设计种子 D˙\dot D(语句 5–9 在面循环 f=0,…,Nf=0,\dots,N 里):

Forward mode applies the chain rule once to every assignment y=ϕ(x1,…,xm)y=\phi(x_1,\dots,x_m) of the residual code of Section 5 (here ϕ\phi is any elementary function, not the phase φ\varphi of the design), y˙=∑k(∂ϕ/∂xk) x˙k\dot y=\sum_k(\partial\phi/\partial x_k)\,\dot x_k, placed after it and executed in the same order. The table does it for every statement of this page's code, with a state seed 𝐔˙\dot{\mathbf U} and a design seed D˙\dot D both allowed (statements 5–9 run inside the face loop f=0,…,Nf=0,\dots,N):

#原始语句Primal statement前向语句(同一顺序)Tangent statement (same order)所用局部导数Local derivative used
1R←0R\leftarrow0R˙←0\dot R\leftarrow0—
2uin=u∗(0;D),  uout=u∗(1;D)u_{\rm in}=u^*(0;D),\ \ u_{\rm out}=u^*(1;D)u˙in=∂uin∂aa˙+∂uin∂φφ˙\dot u_{\rm in}=\frac{\partial u_{\rm in}}{\partial a}\dot a+\frac{\partial u_{\rm in}}{\partial\varphi}\dot\varphi,u˙out\dot u_{\rm out} 同理u˙in=∂uin∂aa˙+∂uin∂φφ˙\dot u_{\rm in}=\frac{\partial u_{\rm in}}{\partial a}\dot a+\frac{\partial u_{\rm in}}{\partial\varphi}\dot\varphi, u˙out\dot u_{\rm out} alike∂uin∂a=−sin⁡2πφ\frac{\partial u_{\rm in}}{\partial a}=-\sin2\pi\varphi,∂uin∂φ=−2πacos⁡2πφ\frac{\partial u_{\rm in}}{\partial\varphi}=-2\pi a\cos2\pi\varphi(uoutu_{\rm out} 相同)∂uin∂a=−sin⁡2πφ\frac{\partial u_{\rm in}}{\partial a}=-\sin2\pi\varphi, ∂uin∂φ=−2πacos⁡2πφ\frac{\partial u_{\rm in}}{\partial\varphi}=-2\pi a\cos2\pi\varphi (the same for uoutu_{\rm out})
3li=Ui−Ui−1,  ri=Ui+1−Ui  (1≤i≤N−2)l_i=U_i-U_{i-1},\ \ r_i=U_{i+1}-U_i\ \ (1\le i\le N-2)l˙i=U˙i−U˙i−1,  r˙i=U˙i+1−U˙i\dot l_i=\dot U_i-\dot U_{i-1},\ \ \dot r_i=\dot U_{i+1}-\dot U_i±1\pm1
4σi=σ(li,ri);  σ0=σN−1=0\sigma_i=\sigma(l_i,r_i);\ \ \sigma_0=\sigma_{N-1}=0σ˙i=σl l˙i+σr r˙i\dot\sigma_i=\sigma_l\,\dot l_i+\sigma_r\,\dot r_i(σl,σr)(\sigma_l,\sigma_r):一阶 (0,0)(0,0),无限制器 (12,12)(\tfrac12,\tfrac12),光滑限制器随状态变化(第 3 节)(σl,σr)(\sigma_l,\sigma_r): (0,0)(0,0) first order, (12,12)(\tfrac12,\tfrac12) unlimited, state-dependent for the smooth limiter (Section 3)
5qL=Uf−1+12σf−1q_L=U_{f-1}+\tfrac12\sigma_{f-1},UL=Uf−1U_L=U_{f-1};面 0:qL=UL=uinq_L=U_L=u_{\rm in}qL=Uf−1+12σf−1q_L=U_{f-1}+\tfrac12\sigma_{f-1}, UL=Uf−1U_L=U_{f-1}; face 0: qL=UL=uinq_L=U_L=u_{\rm in}q˙L=U˙f−1+12σ˙f−1\dot q_L=\dot U_{f-1}+\tfrac12\dot\sigma_{f-1},U˙L=U˙f−1\dot U_L=\dot U_{f-1};面 0:q˙L=U˙L=u˙in\dot q_L=\dot U_L=\dot u_{\rm in}q˙L=U˙f−1+12σ˙f−1\dot q_L=\dot U_{f-1}+\tfrac12\dot\sigma_{f-1}, U˙L=U˙f−1\dot U_L=\dot U_{f-1}; face 0: q˙L=U˙L=u˙in\dot q_L=\dot U_L=\dot u_{\rm in}1, 121,\ \tfrac12
6qR=Uf−12σfq_R=U_f-\tfrac12\sigma_f,UR=UfU_R=U_f;面 NN:qR=UR=uoutq_R=U_R=u_{\rm out}qR=Uf−12σfq_R=U_f-\tfrac12\sigma_f, UR=UfU_R=U_f; face NN: qR=UR=uoutq_R=U_R=u_{\rm out}q˙R=U˙f−12σ˙f\dot q_R=\dot U_f-\tfrac12\dot\sigma_f,U˙R=U˙f\dot U_R=\dot U_f;面 NN:q˙R=U˙R=u˙out\dot q_R=\dot U_R=\dot u_{\rm out}q˙R=U˙f−12σ˙f\dot q_R=\dot U_f-\tfrac12\dot\sigma_f, U˙R=U˙f\dot U_R=\dot U_f; face NN: q˙R=U˙R=u˙out\dot q_R=\dot U_R=\dot u_{\rm out}1, −121,\ -\tfrac12
7Hf=14(qL2+qR2)−(qR−qL)−ν UR−ULdfH_f=\tfrac14(q_L^2+q_R^2)-(q_R-q_L)-\nu\,\frac{U_R-U_L}{d_f}H˙f=cLq˙L+cRq˙R+κf(U˙L−U˙R)−ν˙ UR−ULdf\dot H_f=c_L\dot q_L+c_R\dot q_R+\kappa_f(\dot U_L-\dot U_R)-\dot\nu\,\frac{U_R-U_L}{d_f}cL, cR, ±κf, −UR−ULdfc_L,\ c_R,\ \pm\kappa_f,\ -\frac{U_R-U_L}{d_f}
8Rf−1+=Hf  (f≥1)R_{f-1}\mathrel{\text{+=}}H_f\ \ (f\ge1)R˙f−1+=H˙f\dot R_{f-1}\mathrel{\text{+=}}\dot H_f1
9Rf-=Hf  (f≤N−1)R_f\mathrel{\text{-=}}H_f\ \ (f\le N-1)R˙f-=H˙f\dot R_f\mathrel{\text{-=}}\dot H_f−1
10Qf=q∗(xf;D),  f=0,…,NQ_f=q^*(x_f;D),\ \ f=0,\dots,NQ˙f=∂Q∂aa˙+∂Q∂φφ˙+∂Q∂νν˙\dot Q_f=\frac{\partial Q}{\partial a}\dot a+\frac{\partial Q}{\partial\varphi}\dot\varphi+\frac{\partial Q}{\partial\nu}\dot\nu∂Q/∂D\partial Q/\partial D(见下式)∂Q/∂D\partial Q/\partial D (below)
11Ri-=Qi+1−QiR_i\mathrel{\text{-=}}Q_{i+1}-Q_iR˙i-=Q˙i+1−Q˙i\dot R_i\mathrel{\text{-=}}\dot Q_{i+1}-\dot Q_i∓1\mp1

语句 10 的精确通量偏导数来自 Qf=q∗(xf;D)=12(u∗)2−νux∗Q_f=q^*(x_f;D)=\tfrac12(u^*)^2-\nu u^*_x,其中 u∗=1+asin⁡zu^*=1+a\sin z,ux∗=2πacos⁡zu^*_x=2\pi a\cos z,z=2π(xf−φ)z=2\pi(x_f-\varphi):

The exact-flux partial derivatives of statement 10 come from Qf=q∗(xf;D)=12(u∗)2−νux∗Q_f=q^*(x_f;D)=\tfrac12(u^*)^2-\nu u^*_x, with u∗=1+asin⁡zu^*=1+a\sin z, ux∗=2πacos⁡zu^*_x=2\pi a\cos z and z=2π(xf−φ)z=2\pi(x_f-\varphi):

∂Q∂a=u∗sin⁡z−2πνcos⁡z,∂Q∂φ=−2πa u∗cos⁡z−4π2νasin⁡z,∂Q∂ν=−2πacos⁡z.\frac{\partial Q}{\partial a}=u^*\sin z-2\pi\nu\cos z,\qquad \frac{\partial Q}{\partial\varphi}=-2\pi a\,u^*\cos z-4\pi^2\nu a\sin z,\qquad \frac{\partial Q}{\partial\nu}=-2\pi a\cos z.

设计进入代码的地方恰好有三处,每处是表中的一行:(i)边界值 uin,uoutu_{\rm in},u_{\rm out}(语句 2)依赖 aa 和 φ\varphi,作为面 0 的 qL,ULq_L,U_L 和面 NN 的 qR,URq_R,U_R 进入两个边界面;(ii)黏性通过 κf=ν/df\kappa_f=\nu/d_f 和显式项 −ν˙(UR−UL)/df-\dot\nu(U_R-U_L)/d_f 进入每个面的通量(语句 7);(iii)精确通量 QfQ_f(语句 10)依赖全部三个分量,通过源项(语句 11)进入每一行。取 𝐔˙=v\dot{\mathbf U}=v、D˙=0\dot D=0,代码返回 AvAv;取 𝐔˙=0\dot{\mathbf U}=0、D˙=ek\dot D=e_k,返回 RDR_D 的第 kk 列 RDekR_De_k。除了原始代码本来就有的数组,前向代码还多存斜率的切向量 σ˙i\dot\sigma_i(s_d)、精确通量的切向量 Q˙f\dot Q_f(Q_d)和输出 R˙\dot R(以及两个数 u˙in\dot u_{\rm in}、u˙out\dot u_{\rm out});局部导数(cL,cR,κf,(UR−UL)/df,σl,σrc_L,c_R,\kappa_f,(U_R-U_L)/d_f,\sigma_l,\sigma_r)算出后立即使用,不必存下(存下 σl,σr\sigma_l,\sigma_r 的是第 9 节的 residual_b)。

The design enters the code in exactly three places, each a row of the table: (i) the boundary data uin,uoutu_{\rm in},u_{\rm out} (statement 2) depend on aa and φ\varphi and enter the two boundary faces as qL,ULq_L,U_L of face 0 and qR,URq_R,U_R of face NN; (ii) the viscosity enters the flux of every face (statement 7), through κf=ν/df\kappa_f=\nu/d_f and the explicit term −ν˙(UR−UL)/df-\dot\nu(U_R-U_L)/d_f; (iii) the exact fluxes QfQ_f (statement 10) depend on all three components and enter every row through the source (statement 11). With 𝐔˙=v\dot{\mathbf U}=v and D˙=0\dot D=0 the code returns AvAv; with 𝐔˙=0\dot{\mathbf U}=0 and D˙=ek\dot D=e_k it returns the column RDekR_De_k. Besides the arrays the primal code already has, the tangent code keeps the slope tangents σ˙i\dot\sigma_i (s_d), the exact-flux tangents Q˙f\dot Q_f (Q_d) and the output R˙\dot R (and the two numbers u˙in\dot u_{\rm in}, u˙out\dot u_{\rm out}); the local derivatives (cL,cR,κf,(UR−UL)/df,σl,σrc_L,c_R,\kappa_f,(U_R-U_L)/d_f,\sigma_l,\sigma_r) are used as soon as they are computed and need not be stored (it is the residual_b of Section 9 that keeps σl,σr\sigma_l,\sigma_r).

为什么是同一顺序:一条前向语句需要它的输入的切向量,而这些切向量由前面原始语句的前向语句算出。所以前向代码可以和原始代码逐句交替、按原始顺序运行;必须倒着运行的是第 9 节的反向模式。

Why the same order: a tangent statement needs the tangents of its inputs, and those are computed by the tangent statements of the earlier primal statements. The tangent code can therefore run interleaved with the primal, statement by statement, in the primal's order; it is the reverse mode of Section 9 that must run backwards.

写成自动微分工具的代码(原始语句同时执行;a_d, phi_d, nu_d 是 D˙\dot D 的三个分量,xf[f] 是面的位置 xfx_f):

As code, in the names of an AD tool (the primal statements run alongside; a_d, phi_d, nu_d are the three components of D˙\dot D, xf[f] is the face position xfx_f):

residual_d(U, u_d, D, D_d) -> res, res_d
 1  res = 0;  res_d = 0;  s = 0;  s_d = 0               (s[0] = s[N-1] = 0 stay)
 2  uin = u*(0; D);  uout = u*(1; D)
    uin_d = -sin(2 pi phi)*a_d - 2 pi a cos(2 pi phi)*phi_d;  uout_d = uin_d
    for i = 1 .. N-2:
 3    l = U[i] - U[i-1];        l_d = u_d[i] - u_d[i-1]
      r = U[i+1] - U[i];        r_d = u_d[i+1] - u_d[i]
 4    s[i] = sigma(l, r);       s_d[i] = sl(l, r)*l_d + sr(l, r)*r_d
    for f = 0 .. N:
 5    if f == 0: qL = UL = uin;     qL_d = UL_d = uin_d
      else:      qL = U[f-1] + s[f-1]/2;  UL = U[f-1];  qL_d = u_d[f-1] + s_d[f-1]/2;  UL_d = u_d[f-1]
 6    if f == N: qR = UR = uout;    qR_d = UR_d = uout_d
      else:      qR = U[f] - s[f]/2;      UR = U[f];    qR_d = u_d[f] - s_d[f]/2;      UR_d = u_d[f]
 7    d = h/2 if f in (0, N) else h;  cL = qL/2 + 1;  cR = qR/2 - 1
      H   = (qL^2 + qR^2)/4 - (qR - qL) - nu*(UR - UL)/d
      H_d = cL*qL_d + cR*qR_d + nu/d*(UL_d - UR_d) - nu_d*(UR - UL)/d
 8    if f >= 1:    res[f-1] += H;   res_d[f-1] += H_d
 9    if f <= N-1:  res[f]   -= H;   res_d[f]   -= H_d
    for f = 0 .. N:
10    Q[f] = q*(xf[f]; D);  Q_d[f] = dQda(xf[f])*a_d + dQdphi(xf[f])*phi_d + dQdnu(xf[f])*nu_d
    for i = 0 .. N-1:
11    res[i] -= Q[i+1] - Q[i];  res_d[i] -= Q_d[i+1] - Q_d[i]

播放器在当前网格上逐面运行这段代码。选一个种子:单位状态种子 eje_j、光滑的测试种子 U˙j=sin⁡(j+0.3)\dot U_j=\sin(j+0.3),或设计种子 D˙=ek\dot D=e_k;逐条语句前进,看 R˙\dot R 一点点填满(虚线框是最终值 A𝐔˙+RDD˙A\dot{\mathbf U}+R_D\dot D)。

The player runs this code on the current mesh, face by face. Choose a seed: a unit state seed eje_j, the smooth test seed U˙j=sin⁡(j+0.3)\dot U_j=\sin(j+0.3), or a design seed D˙=ek\dot D=e_k; step through the statements and watch R˙\dot R fill up (dashed frames: the final values A𝐔˙+RDD˙A\dot{\mathbf U}+R_D\dot D).

A 的每一列是一次前向扫描

Every column of A is one tangent sweep

取种子 𝐔˙=ej\dot{\mathbf U}=e_j,代码返回 R˙=Aej\dot R=Ae_j,即 Jacobian 的第 jj 列:所有残差对一个未知量的导数。这次扫描碰到的面是模板含 jj 的那些面(一阶 2 个;二阶时内部 4 个,靠近边界 3 个),每个面写两行,所以这一列至多有 3 个(一阶)或 5 个(二阶)非零元:AA 的带宽来自一个面的模板。用 e0,…,eN−1e_0,\dots,e_{N-1} 做 NN 次扫描得到整个 AA,再用 D˙=e0,e1,e2\dot D=e_0,e_1,e_2 做三次得到 RDR_D。播放器在当前网格上逐列演示。

With the seed 𝐔˙=ej\dot{\mathbf U}=e_j the code returns R˙=Aej\dot R=Ae_j, column jj of the Jacobian: the derivatives of all residuals with respect to one unknown. The faces it touches are those whose stencil contains jj (two at first order; four at second order, three next to a boundary), and each touched face writes two rows, so the column has at most 3 (first order) or 5 (second order) nonzero entries: the bandwidth of AA comes from the stencil of one face. NN sweeps with the seeds e0,…,eN−1e_0,\dots,e_{N-1} build all of AA; three more with D˙=e0,e1,e2\dot D=e_0,e_1,e_2 build RDR_D. The player steps through these sweeps on the current mesh.

用本页的数字看一个面

One face with the page's own numbers

取默认网格(N=8N=8)、设计种子 D˙=e0\dot D=e_0(振幅 aa),𝐔˙=v0\dot{\mathbf U}=v_0 取第 10 节这个方向的切线解(Av0=−RDe0Av_0=-R_De_0),看内部面 f=4f=4(x=0.5x=0.5,单元 3 与 4 之间)和边界面 f=0f=0(x=0x=0)。每种重构有自己的收敛解和自己的 v0v_0,所以连原始值也不同:

Take the default mesh (N=8N=8), the design seed D˙=e0\dot D=e_0 (the amplitude aa) and for 𝐔˙=v0\dot{\mathbf U}=v_0 the solution of the tangent solve of Section 10 for that direction (Av0=−RDe0Av_0=-R_De_0), and look at the interior face f=4f=4 (x=0.5x=0.5, between cells 3 and 4) and the boundary face f=0f=0 (x=0x=0). Each reconstruction has its own converged solution and its own v0v_0, so even the primal values differ:

内部面 f=4f=4,种子 (𝐔˙,D˙)=(v0,e0)(\dot{\mathbf U},\dot D)=(v_0,e_0)Interior face f=4f=4, seed (𝐔˙,D˙)=(v0,e0)(\dot{\mathbf U},\dot D)=(v_0,e_0)
量Quantity公式Formula一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
qLq_LUf−1+12σf−1U_{f-1}+\tfrac12\sigma_{f-1}0.9509581.0128990.994602
qRq_RUf−12σfU_f-\tfrac12\sigma_f0.8231700.9882740.949153
UL, URU_L,\ U_RUf−1, UfU_{f-1},\ U_f0.95096, 0.823171.06834, 0.917061.04010, 0.87288
cL, cRc_L,\ c_RqL/2+1, qR/2−1q_L/2+1,\ q_R/2-11.4755, −0.58841.5064, −0.50591.4973, −0.5254
HfH_fHc+HvH^c+H^v0.5334930.5373890.531358
q˙L\dot q_LU˙f−1+12σ˙f−1\dot U_{f-1}+\tfrac12\dot\sigma_{f-1}−0.3067620.053283−0.077448
q˙R\dot q_RU˙f−12σ˙f\dot U_f-\tfrac12\dot\sigma_f−0.975747−0.097658−0.389863
U˙L, U˙R\dot U_L,\ \dot U_Rv0,f−1, v0,fv_{0,f-1},\ v_{0,f}−0.30676, −0.975750.35548, −0.478680.18370, −0.78519
H˙f\dot H_fcLq˙L+cRq˙R+κf(U˙L−U˙R)c_L\dot q_L+c_R\dot q_R+\kappa_f(\dot U_L-\dot U_R)0.1750420.1964010.166392
Q˙f\dot Q_f∂Q/∂a\partial Q/\partial a0.5188890.5188890.518889
H˙f−Q˙f\dot H_f-\dot Q_f−0.343846−0.322488−0.352497
边界面 f=0f=0,同一个种子Boundary face f=0f=0, the same seed
量Quantity公式Formula一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
qL=ULq_L=U_Luinu_{\rm in}0.9148440.9148440.914844
qR=URq_R=U_RU0  (σ0=0)U_0\ \ (\sigma_0=0)1.0306801.0246511.033996
κ0\kappa_0ν/(h/2)\nu/(h/2)0.16000.16000.1600
cL, cRc_L,\ c_RqL/2+1, qR/2−1q_L/2+1,\ q_R/2-11.4574, −0.48471.4574, −0.48771.4574, −0.4830
H0H_0Hc+HvH^c+H^v0.3404410.3443370.338305
q˙L=U˙L\dot q_L=\dot U_Lu˙in=∂uin/∂a\dot u_{\rm in}=\partial u_{\rm in}/\partial a−0.425779−0.425779−0.425779
q˙R=U˙R\dot q_R=\dot U_Rv0,0v_{0,0}0.1575330.1238220.171393
H˙0\dot H_0(cL+κ0)u˙in+(cR−κ0)U˙0(c_L+\kappa_0)\dot u_{\rm in}+(c_R-\kappa_0)\dot U_0−0.790220−0.768861−0.798871
Q˙0\dot Q_0∂Q/∂a\partial Q/\partial a−0.446374−0.446374−0.446374
H˙0−Q˙0\dot H_0-\dot Q_0−0.343846−0.322488−0.352497

在面 0 上,左侧输入是边界值:对每种重构都有 q˙L=U˙L=u˙in=−sin⁡2πφ=−0.4258\dot q_L=\dot U_L=\dot u_{\rm in}=-\sin2\pi\varphi=-0.4258(uinu_{\rm in} 与格式无关),而 κ0=ν/(h/2)=0.16\kappa_0=\nu/(h/2)=0.16 是内部值的两倍。

On face 0 the left inputs are the boundary data: q˙L=U˙L=u˙in=−sin⁡2πφ=−0.4258\dot q_L=\dot U_L=\dot u_{\rm in}=-\sin2\pi\varphi=-0.4258 for every reconstruction (uinu_{\rm in} does not depend on the scheme), and κ0=ν/(h/2)=0.16\kappa_0=\nu/(h/2)=0.16 is twice the interior value.

所有面的 H˙f\dot H_f 还给出一个检验。第 5 节的残差是面值之差,Ri=(Hi+1−Qi+1)−(Hi−Qi)R_i=(H_{i+1}-Q_{i+1})-(H_i-Q_i),它的切向量也是。当 vkv_k 解出切线方程时,每个单元都有 R˙=Avk+RDek=0\dot R=Av_k+R_De_k=0,所以 H˙f−Q˙f\dot H_f-\dot Q_f 在每个面上是同一个数:通量切向量跨过单元 ii 的跳跃恰好等于源项切向量 S˙i=Q˙i+1−Q˙i\dot S_i=\dot Q_{i+1}-\dot Q_i,即设计注入这个单元的量的切向量。这里源项在每个单元都依赖 aa、φ\varphi、ν\nu,所以 H˙f\dot H_f 每跨过一个单元都会变,但它与 Q˙f\dot Q_f 之差不变(图 24):无限制器线性重构时,在全部 9 个面上 H˙f−Q˙f=−0.3225\dot H_f-\dot Q_f=-0.3225(aa)、−0.0430-0.0430(φ\varphi)、−0.1964-0.1964(ν\nu),三种重构、三个方向的最大偏差是 1.4×10−151.4\times10^{-15}。原始解有同样的结构(第 5 节):收敛时每个面上的 Hf−QfH_f-Q_f 是同一个常数,无限制器线性重构时为 −0.0628-0.0628(一阶 −0.0667-0.0667,光滑限制器 −0.0688-0.0688),离散通量与精确通量只差这一个常数。

The H˙f\dot H_f of all faces make one more check. The residual of Section 5 is a difference of face values, Ri=(Hi+1−Qi+1)−(Hi−Qi)R_i=(H_{i+1}-Q_{i+1})-(H_i-Q_i), and so is its tangent. When vkv_k solves the tangent equation, R˙=Avk+RDek=0\dot R=Av_k+R_De_k=0 in every cell, so H˙f−Q˙f\dot H_f-\dot Q_f is the same number on every face: the flux tangent jumps across cell ii by exactly the source tangent S˙i=Q˙i+1−Q˙i\dot S_i=\dot Q_{i+1}-\dot Q_i, the tangent of what the design injects into that cell. Here the source depends on aa, φ\varphi and ν\nu in every cell, so H˙f\dot H_f changes across every cell, but its difference from Q˙f\dot Q_f does not (Figure 24): for the unlimited linear reconstruction H˙f−Q˙f=−0.3225\dot H_f-\dot Q_f=-0.3225 (aa), −0.0430-0.0430 (φ\varphi) and −0.1964-0.1964 (ν\nu) on all 9 faces, and the largest spread over the three reconstructions and the three directions is 1.4×10−151.4\times10^{-15}. The primal has the same structure (Section 5): at the converged state Hf−QfH_f-Q_f is one constant on every face, −0.0628-0.0628 for the unlimited linear reconstruction (−0.0667-0.0667 first order, −0.0688-0.0688 smooth limiter), the one constant by which the discrete flux misses the exact flux.

图 24 · 切线方程的解使每个单元的 R-dot_i=0:面通量切向量 H-dot_f(实心点)与精确通量切向量 Q-dot_f(空心圈)逐面变化,它们的差(方块)在全部 9 个面上是同一个常数(默认设计,无限制器线性,种子 (v_k,e_k),k=0,1,2)。三种重构的常数:一阶 (-0.3438, -0.1664, -0.2212),无限制器线性 (-0.3225, -0.0430, -0.1964),光滑限制器 (-0.3525, -0.0136, -0.2603)。−1.5−1−0.500.511.500.20.40.60.81xf​−0.3225a 方向:Ḋ = e0​−1.5−1−0.500.511.500.20.40.60.81xf​−0.0430φ 方向:Ḋ = e1​−1.5−1−0.500.511.500.20.40.60.81xf​−0.1964ν 方向:Ḋ = e2​Ḣf​Q̇f​Ḣf​ − Q̇f​
图 24 · 切线方程的解使每个单元的 R˙i=0\dot R_i=0:面通量切向量 H˙f\dot H_f(实心点)与精确通量切向量 Q˙f\dot Q_f(空心圈)逐面变化,它们的差(方块)在全部 9 个面上是同一个常数(默认设计,无限制器线性,种子 (vk,ek)(v_k,e_k),k=0,1,2k=0,1,2)。三种重构的常数:一阶 (−0.3438, −0.1664, −0.2212)(-0.3438,\ -0.1664,\ -0.2212),无限制器线性 (−0.3225, −0.0430, −0.1964)(-0.3225,\ -0.0430,\ -0.1964),光滑限制器 (−0.3525, −0.0136, −0.2603)(-0.3525,\ -0.0136,\ -0.2603)。
Figure 24 · The tangent solution makes R-dot_i=0 in every cell: the face-flux tangent H-dot_f (dots) and the exact-flux tangent Q-dot_f (rings) change from face to face, and their difference (squares) is one constant on all 9 faces (default design, unlimited linear, seeds (v_k,e_k), k=0,1,2). The constants of the three reconstructions: first order (-0.3438, -0.1664, -0.2212), unlimited linear (-0.3225, -0.0430, -0.1964), smooth limiter (-0.3525, -0.0136, -0.2603).−1.5−1−0.500.511.500.20.40.60.81xf​−0.3225a: Ḋ = e0​−1.5−1−0.500.511.500.20.40.60.81xf​−0.0430φ: Ḋ = e1​−1.5−1−0.500.511.500.20.40.60.81xf​−0.1964ν: Ḋ = e2​Ḣf​Q̇f​Ḣf​ − Q̇f​
Figure 24 · The tangent solution makes R˙i=0\dot R_i=0 in every cell: the face-flux tangent H˙f\dot H_f (dots) and the exact-flux tangent Q˙f\dot Q_f (rings) change from face to face, and their difference (squares) is one constant on all 9 faces (default design, unlimited linear, seeds (vk,ek)(v_k,e_k), k=0,1,2k=0,1,2). The constants of the three reconstructions: first order (−0.3438, −0.1664, −0.2212)(-0.3438,\ -0.1664,\ -0.2212), unlimited linear (−0.3225, −0.0430, −0.1964)(-0.3225,\ -0.0430,\ -0.1964), smooth limiter (−0.3525, −0.0136, −0.2603)(-0.3525,\ -0.0136,\ -0.2603).

前向导数与有限差分

The tangent against finite differences

前向导数精确到舍入误差;残差的差商则不然。步长为 τ\tau 时的单侧差商与中心差商是

The tangent is exact up to rounding; a finite-difference quotient of the residual is not. The forward and the central quotient with a step τ\tau are

FDτ+=R(𝐔+τ𝐔˙,D+τD˙)−R(𝐔,D)τ,FDτc=R(𝐔+τ𝐔˙,D+τD˙)−R(𝐔−τ𝐔˙,D−τD˙)2τ.\mathrm{FD}_\tau^+=\frac{R(\mathbf U+\tau\dot{\mathbf U},D+\tau\dot D)-R(\mathbf U,D)}{\tau},\qquad \mathrm{FD}_\tau^{\rm c}=\frac{R(\mathbf U+\tau\dot{\mathbf U},D+\tau\dot D)-R(\mathbf U-\tau\dot{\mathbf U},D-\tau\dot D)}{2\tau}.

FDτ+\mathrm{FD}_\tau^+ 的截断误差是 O(τ)O(\tau),FDτc\mathrm{FD}_\tau^{\rm c} 的是 O(τ2)O(\tau^2);两者都还有约 εmachM/τ\varepsilon_{\rm mach}M/\tau 的舍入误差(εmach\varepsilon_{\rm mach} 是机器精度,不是第 3 节限制器的常数 ϵ\epsilon),其中 M≈max⁡f(∣Hf∣,∣Qf∣)M\approx\max_f(|H_f|,|Q_f|)(这里约 0.710.71;这个 MM 是量级,不是附录 A 的配点数)是残差中相加各项的大小;即使 RR 本身为零(收敛状态正是如此),它也不会变小。所以误差随 τ\tau 的双对数图一般呈 V 形:右支是截断,左支是舍入,没有一个 τ\tau 能达到前向导数的精度。

FDτ+\mathrm{FD}_\tau^+ has a truncation error O(τ)O(\tau), FDτc\mathrm{FD}_\tau^{\rm c} one of O(τ2)O(\tau^2), and both carry a rounding error of about εmachM/τ\varepsilon_{\rm mach}M/\tau (εmach\varepsilon_{\rm mach} is the machine epsilon, not the limiter constant ϵ\epsilon of Section 3), where M≈max⁡f(∣Hf∣,∣Qf∣)M\approx\max_f(|H_f|,|Q_f|) (about 0.710.71 here; this MM is a size, not the number of collocation points of Appendix A) is the size of the terms summed into a residual; it does not shrink when RR itself is zero, as at the converged state. So the error against τ\tau is in general a V in a log-log plot: truncation on the right, rounding on the left, and no τ\tau reaches the tangent's accuracy.

本页的残差有一个特殊结构,实验会显示出来。一阶或无限制器线性重构时,通量是迹的二次式,迹是 𝐔\mathbf U 的线性式,uinu_{\rm in} 是 aa 的线性式、QfQ_f 是 aa 的二次式,ν\nu 只以 ν (UR−UL)\nu\,(U_R-U_L) 和 −νux∗-\nu u^*_x 的形式出现:沿 𝐔\mathbf U、aa、ν\nu 中的任何方向,残差都是 τ\tau 的二次多项式。于是 FDτc\mathrm{FD}_\tau^{\rm c} 根本没有截断误差(误差全是舍入,随 τ\tau 增大而减小);只动 ν\nu 时残差甚至是线性的,两种差商都没有截断误差。只有含 φ\varphi 的方向(正弦、余弦),或者光滑限制器时改变斜率的状态方向(任何非常数的 𝐔˙\dot{\mathbf U};限制器是 li,ril_i,r_i 的有理函数),才让两种差商都出现完整的 V 形;只动 aa 或 ν\nu 时,光滑限制器的残差仍是二次或线性的,因为斜率不依赖设计。实验在当前状态上对 τ=10−1\tau=10^{-1} 到 10−1310^{-13} 计算两种差商,并说明看到的是哪种形状。第 13 节在整个求解上使用这类差商,第 14 节用复数步长去掉舍入那一支。

The residual of this page has a special structure, which the lab shows. With the first-order or the unlimited linear reconstruction the flux is quadratic in the traces, the traces are linear in 𝐔\mathbf U, uinu_{\rm in} is linear and QfQ_f quadratic in aa, and ν\nu enters only as ν (UR−UL)\nu\,(U_R-U_L) and −νux∗-\nu u^*_x: along any direction in 𝐔\mathbf U, aa and ν\nu the residual is a polynomial of degree 2 in τ\tau. The central quotient then has no truncation error at all (its error is pure rounding, falling as τ\tau grows), and along ν\nu alone the residual is even linear, so neither quotient has one. Only a direction containing φ\varphi (sines and cosines), or, with the smooth limiter, a state direction that changes the slopes (any non-constant 𝐔˙\dot{\mathbf U}: the limiter is a rational function of li,ril_i,r_i), gives both quotients the full V; along aa or ν\nu alone even the smooth-limiter residual stays quadratic or linear, because the slopes do not see the design. The lab evaluates both quotients for τ\tau from 10−110^{-1} to 10−1310^{-13} on the current state and says which shape it sees. Section 13 uses such quotients on the whole solve, and Section 14 removes the rounding branch with the complex step.

局部导数怎样组成全局 Jacobian

How local derivatives form the global Jacobian

网格固定时,令 zf=(qL,qR,UL,UR,ν)Tz_f=(q_L,q_R,U_L,U_R,\nu)^T 收集面 ff 的通量的五个输入。它们来自这个面读的未知量(集合 𝒮f\mathcal S_f:二阶时内部面 2≤f≤N−22\le f\le N-2 读单元 f−2,…,f+1f-2,\dots,f+1,面 1 与面 N−1N-1 读 3 个单元,面 0 与面 NN 只读 1 个;一阶时读 f−1,ff-1,f 中存在的单元)和设计。记 ZfZ_f、KfK_f 为 zfz_f 对这些未知量和对 DD 的导数,Hz,fH_{z,f} 为五个通量导数组成的行,ℬ\mathcal B 为面与单元的有向关联矩阵(ℬf−1,f=+1\mathcal B_{f-1,f}=+1,ℬf,f=−1\mathcal B_{f,f}=-1:面把通量加给左边的单元、从右边的单元减去)。源项行 Si=Qi+1−QiS_i=Q_{i+1}-Q_i 用的是同一个关联矩阵,S=ℬQS=\mathcal BQ,所以 R=ℬ(H−Q)R=\mathcal B(H-Q)。

At a fixed mesh, let zf=(qL,qR,UL,UR,ν)Tz_f=(q_L,q_R,U_L,U_R,\nu)^T collect the five inputs of the flux of face ff. They come from the unknowns the face reads (the set 𝒮f\mathcal S_f: at second order the cells f−2,…,f+1f-2,\dots,f+1 for 2≤f≤N−22\le f\le N-2, three cells for f=1f=1 and f=N−1f=N-1, one cell for f=0f=0 and f=Nf=N; at first order the cells f−1,ff-1,f that exist) and from the design. Let ZfZ_f and KfK_f be the derivatives of zfz_f with respect to those unknowns and to DD, Hz,fH_{z,f} the row of the five flux derivatives, and ℬ\mathcal B the oriented incidence of faces and cells (ℬf−1,f=+1\mathcal B_{f-1,f}=+1, ℬf,f=−1\mathcal B_{f,f}=-1: a face adds its flux to the cell on its left and subtracts it from the cell on its right). The source rows Si=Qi+1−QiS_i=Q_{i+1}-Q_i use the same incidence, S=ℬQS=\mathcal BQ, so R=ℬ(H−Q)R=\mathcal B(H-Q).

Hz,f=∂H∂zf=(cL, cR, κf, −κf, −UR−ULdf),z˙f=Zf 𝒢f𝐔˙+Kf D˙,H˙f=Hz,f z˙f,R˙=∑fℬ:,f H˙f−∂S∂DD˙,H_{z,f}=\frac{\partial H}{\partial z_f}=\Big(c_L,\ c_R,\ \kappa_f,\ -\kappa_f,\ -\frac{U_R-U_L}{d_f}\Big),\qquad \dot z_f=Z_f\,\mathcal G_f\dot{\mathbf U}+K_f\,\dot D,\qquad \dot H_f=H_{z,f}\,\dot z_f,\qquad \dot R=\sum_f\mathcal B_{:,f}\,\dot H_f-\frac{\partial S}{\partial D}\dot D,
A=∑fℬ:,f Hz,f Zf 𝒢f,RD=∑fℬ:,f Hz,f Kf−∂S∂D.A=\sum_f\mathcal B_{:,f}\,H_{z,f}\,Z_f\,\mathcal G_f,\qquad R_D=\sum_f\mathcal B_{:,f}\,H_{z,f}\,K_f-\frac{\partial S}{\partial D}.

AA 里没有 −∂S/∂𝐔-\partial S/\partial\mathbf U 一项:本页的源项只依赖设计。KfK_f 在内部面上只有一行非零,即 ν\nu 那一行 (0,0,1)(0,0,1);面 0 上 qLq_L 与 ULU_L 两行是 ∂uin/∂D=(−sin⁡2πφ, −2πacos⁡2πφ, 0)\partial u_{\rm in}/\partial D=(-\sin2\pi\varphi,\,-2\pi a\cos2\pi\varphi,\,0),面 NN 上 qRq_R 与 URU_R 两行是 ∂uout/∂D\partial u_{\rm out}/\partial D。所以内部面上 Hz,fKf=(0,0,−(UR−UL)/df)H_{z,f}K_f=(0,0,-(U_R-U_L)/d_f)。设计的三条路径就是三项:面 0 上的 (cL+κ0) ∂uin/∂D(c_L+\kappa_0)\,\partial u_{\rm in}/\partial D(面 NN 上的 (cR−κN) ∂uout/∂D(c_R-\kappa_N)\,\partial u_{\rm out}/\partial D),每个面上的 −(UR−UL)/df-(U_R-U_L)/d_f 乘 ν˙\dot\nu,以及每一行的 −∂S/∂D-\partial S/\partial D。图 25 画出 AA 的和式中的一项。

There is no −∂S/∂𝐔-\partial S/\partial\mathbf U term in AA: the source of this page depends on the design only. KfK_f has one nonzero row on an interior face, the ν\nu-row (0,0,1)(0,0,1); on face 0 the rows of qLq_L and ULU_L hold ∂uin/∂D=(−sin⁡2πφ, −2πacos⁡2πφ, 0)\partial u_{\rm in}/\partial D=(-\sin2\pi\varphi,\,-2\pi a\cos2\pi\varphi,\,0), on face NN those of qRq_R and URU_R hold ∂uout/∂D\partial u_{\rm out}/\partial D. So Hz,fKf=(0,0,−(UR−UL)/df)H_{z,f}K_f=(0,0,-(U_R-U_L)/d_f) on an interior face. The three paths of the design are three terms: (cL+κ0) ∂uin/∂D(c_L+\kappa_0)\,\partial u_{\rm in}/\partial D on face 0 (and (cR−κN) ∂uout/∂D(c_R-\kappa_N)\,\partial u_{\rm out}/\partial D on face NN), −(UR−UL)/df-(U_R-U_L)/d_f times ν˙\dot\nu on every face, and −∂S/∂D-\partial S/\partial D in every row. Figure 25 draws one term of the sum for AA.

图 25 · 面 f=4 对 A 的贡献 A_4= B_(:,4)H_(z,4)Z_4 G_4(默认设计,无限制器线性)。上:四个初等 Jacobian 及其形状。G_4 从 8 个未知量中取出 U_2,…,U_5;Z_4 是迹和未重构状态对它们的导数(ν 那一行为零);H_(z,4) 是五个通量导数;B_(:,4) 把结果以 +1、-1 写入第 3、4 行。下:乘积是一个只有 2 × 4 块非零的 8 × 8 矩阵(左);右边 9 个面之和 A 中框出的块,等于 A_4 的块加上相邻面写入同两行的贡献。面 f = 4 对 A 的贡献:A4​ = B:,4​ Hz,4​ Z4​ G4​(默认设计,无限制器线性)1−1B:,4​8×11.506−0.5060.080−0.0801.210Hz,4​1×5cL​cR​κf​−κf​−(UR​−UL​)/df​−0.2510.25000.251−0.25010000100000Z4​5×4qL​qR​UL​UR​νU2​U3​U4​U5​G4​4×81111= A4​(8×8,只有 2×4 块非零)−0.381.46−0.210.130.38−1.460.21−0.130123456701234567A = Σf​ Af​(9 个面的和;框出的是面 4 的块)2.12−0.540.12−1.872.08−0.230.110.39−1.931.65−0.230.110.39−1.911.59−0.320.130.38−1.821.56−0.440.150.36−1.701.61−0.510.160.34−1.651.84−0.450.35−1.481.890123456701234567+ …
图 25 · 面 f=4f=4 对 AA 的贡献 A4=ℬ:,4Hz,4Z4𝒢4A_4=\mathcal B_{:,4}H_{z,4}Z_4\mathcal G_4(默认设计,无限制器线性)。上:四个初等 Jacobian 及其形状。𝒢4\mathcal G_4 从 8 个未知量中取出 U2,…,U5U_2,\dots,U_5;Z4Z_4 是迹和未重构状态对它们的导数(ν\nu 那一行为零);Hz,4H_{z,4} 是五个通量导数;ℬ:,4\mathcal B_{:,4} 把结果以 +1+1、−1-1 写入第 3、4 行。下:乘积是一个只有 2×42\times4 块非零的 8×88\times8 矩阵(左);右边 9 个面之和 AA 中框出的块,等于 A4A_4 的块加上相邻面写入同两行的贡献。
Figure 25 · The contribution of face f=4 to A, A_4= B_(:,4)H_(z,4)Z_4 G_4 (default design, unlimited linear). Top: the four elementary Jacobians and their shapes. G_4 picks U_2,…,U_5 out of the 8 unknowns; Z_4 holds the derivatives of the traces and the raw states with respect to them (the ν-row is zero); H_(z,4) the five flux derivatives; B_(:,4) writes the result into rows 3 and 4 with +1 and -1. Bottom: the product is an 8 × 8 matrix with one nonzero 2 × 4 block (left); the sum A over the 9 faces (right) contains it in the framed block, together with the contributions of the neighbouring faces to the same rows.The contribution of face f = 4 to A: A4​ = B:,4​ Hz,4​ Z4​ G4​ (default design, unlimited linear)1−1B:,4​8×11.506−0.5060.080−0.0801.210Hz,4​1×5cL​cR​κf​−κf​−(UR​−UL​)/df​−0.2510.25000.251−0.25010000100000Z4​5×4qL​qR​UL​UR​νU2​U3​U4​U5​G4​4×81111= A4​ (8×8, a 2×4 nonzero block)−0.381.46−0.210.130.38−1.460.21−0.130123456701234567A = Σf​ Af​ (the sum over the 9 faces; framed: the block of face 4)2.12−0.540.12−1.872.08−0.230.110.39−1.931.65−0.230.110.39−1.911.59−0.320.130.38−1.821.56−0.440.150.36−1.701.61−0.510.160.34−1.651.84−0.450.35−1.481.890123456701234567+ …
Figure 25 · The contribution of face f=4f=4 to AA, A4=ℬ:,4Hz,4Z4𝒢4A_4=\mathcal B_{:,4}H_{z,4}Z_4\mathcal G_4 (default design, unlimited linear). Top: the four elementary Jacobians and their shapes. 𝒢4\mathcal G_4 picks U2,…,U5U_2,\dots,U_5 out of the 8 unknowns; Z4Z_4 holds the derivatives of the traces and the raw states with respect to them (the ν\nu-row is zero); Hz,4H_{z,4} the five flux derivatives; ℬ:,4\mathcal B_{:,4} writes the result into rows 3 and 4 with +1+1 and −1-1. Bottom: the product is an 8×88\times8 matrix with one nonzero 2×42\times4 block (left); the sum AA over the 9 faces (right) contains it in the framed block, together with the contributions of the neighbouring faces to the same rows.

从程序到前向导数:逐条线性化面循环的四条语句

From program to tangent: linearise the four statements of the face loop

上面的 z˙f\dot z_f、H˙f\dot H_f、R˙\dot R 来自一段短程序:残差代码在每个面上执行四条语句。把这个面读的未知量排成 𝐮f\mathbf u_f:

The z˙f\dot z_f, H˙f\dot H_f and R˙\dot R above come from one short program: the residual code runs four statements on every face. Stack the unknowns the face reads as 𝐮f\mathbf u_f:

(1) 𝐮f=𝒢f𝐔,(2) zf=zf(𝐮f,D),(3) Hf=H(zf),(4) R+=ℬ:,fHf.(1)\ \mathbf u_f=\mathcal G_f\mathbf U,\qquad (2)\ z_f=z_f(\mathbf u_f,D),\qquad (3)\ H_f=H(z_f),\qquad (4)\ R\mathrel{\text{+=}}\mathcal B_{:,f}H_f.

(1)取值:𝒢f\mathcal G_f 的每一行只有一个 1,从全局数组中取出 𝒮f\mathcal S_f 的一个未知量。(2)重构:斜率、迹 qL,qRq_L,q_R、未重构状态 UL,URU_L,U_R 和黏性,即通量的全部五个输入(边界面上用 uinu_{\rm in} 或 uoutu_{\rm out})。(3)通量。(4)分发:ℬ\mathcal B 的第 ff 列,第 f−1f-1 行为 +1+1,第 ff 行为 −1-1。前向模式对每条语句用一次链式法则,每个中间变量都有自己的切向量:

(1) Gather: each row of 𝒢f\mathcal G_f holds a single 1 and picks one unknown of 𝒮f\mathcal S_f out of the global array. (2) Reconstruct: the slopes, the traces qL,qRq_L,q_R, the raw states UL,URU_L,U_R and the viscosity, all five inputs of the flux (with uinu_{\rm in} or uoutu_{\rm out} on the boundary faces). (3) Flux. (4) Scatter: column ff of ℬ\mathcal B, +1+1 in row f−1f-1 and −1-1 in row ff. Forward mode applies the chain rule once per statement, and every intermediate variable gets a tangent of its own:

(1) 𝐮˙f=𝒢f𝐔˙,(2) z˙f=Zf𝐮˙f+KfD˙,(3) H˙f=Hz,fz˙f,(4) R˙+=ℬ:,fH˙f.(1)\ \dot{\mathbf u}_f=\mathcal G_f\dot{\mathbf U},\qquad (2)\ \dot z_f=Z_f\dot{\mathbf u}_f+K_f\dot D,\qquad (3)\ \dot H_f=H_{z,f}\dot z_f,\qquad (4)\ \dot R\mathrel{\text{+=}}\mathcal B_{:,f}\dot H_f.

取值和分发是线性的:它们的切向量就是把同样的取值和分发作用在切向量上。只有重构和通量带来依赖当前状态的局部导数(Hz,fH_{z,f} 总是如此,ZfZ_f 只在光滑限制器时如此)。把(1)代入(2)、(2)代入(3)、(3)代入(4),一个面对 AA 的贡献就是四个初等 Jacobian 的乘积,按程序运行的顺序从右向左作用:

Gather and scatter are linear: their tangents are the same gather and scatter applied to the tangents. Only reconstruct and flux bring local derivatives that depend on the current state (ZfZ_f with the smooth limiter, Hz,fH_{z,f} always). Substituting (1) into (2), (2) into (3) and (3) into (4) gives one face's contribution to AA as a product of four elementary Jacobians, applied right to left in the order the program runs:

Af=ℬ:,f Hz,f Zf 𝒢f,Af𝐔˙=ℬ:,f(Hz,f(Zf(𝒢f𝐔˙))).A_f=\mathcal B_{:,f}\,H_{z,f}\,Z_f\,\mathcal G_f,\qquad A_f\dot{\mathbf U}=\mathcal B_{:,f}\Big(H_{z,f}\Big(Z_f\big(\mathcal G_f\dot{\mathbf U}\big)\Big)\Big).

算例:面 4 的前向扫描。设计种子取 D˙=e1\dot D=e_1(相位 φ\varphi),未知量取同一方向的切线解 𝐔˙=v1\dot{\mathbf U}=v_1。φ\varphi 不直接进入内部面(K4e1=0K_4e_1=0),所以 H˙4\dot H_4 完全来自状态切向量。数字(默认设计,无限制器线性):

A worked example: the forward sweep of face 4. Seed the design with D˙=e1\dot D=e_1 (the phase φ\varphi) and the unknowns with the tangent solution of the same direction, 𝐔˙=v1\dot{\mathbf U}=v_1. The phase does not enter an interior face directly (K4e1=0K_4e_1=0), so H˙4\dot H_4 comes entirely from the state tangents. The numbers (default design, unlimited linear):

语句Statement量Quantity原始值Primal value切向量Tangent
(1)取值(1) gatherU2U_{2}1.138830.02123
U3U_{3}1.068340.91116
U4U_{4}0.917061.24442
U5U_{5}0.783480.75421
设计种子design seedφ\varphi0.071
(2)重构(2) reconstructqL, qRq_L,\ q_R1.01290, 0.988271.21696, 1.28366
UL, URU_L,\ U_R1.06834, 0.917060.91116, 1.24442
ν\nu0.010
(3)通量(3) fluxH4H_40.537391.15727
(4)分发(4) scatterR3+=H4R_3\mathrel{\text{+=}}H_40.537391.15727
R4-=H4R_4\mathrel{\text{-=}}H_4−0.53739−1.15727

对所有面和源项行求和,这些贡献给出 Av1+RDe1=0Av_1+R_De_1=0,这就是切线方程。若取 D˙=e2\dot D=e_2(ν\nu),这个面还会多出 K4e2=(0,0,0,0,1)TK_4e_2=(0,0,0,0,1)^T 带来的 −(UR−UL)/df-(U_R-U_L)/d_f 一项。下面的播放器对任意面、任意方向重放这四步。

Summed over all faces and the source rows, these contributions give Av1+RDe1=0Av_1+R_De_1=0: the tangent equation. With D˙=e2\dot D=e_2 (ν\nu) this face would get the extra term −(UR−UL)/df-(U_R-U_L)/d_f from K4e2=(0,0,0,0,1)TK_4e_2=(0,0,0,0,1)^T. The player below replays the four steps for any face and any direction.

前向求解用它做什么

What the tangent solve does with it

一次 residual_d 扫描是乘积,不是求解。第 10 节用它解切线方程,求出使 R=0R=0 沿设计方向保持成立的状态切向量 v=𝐔˙v=\dot{\mathbf U}:取种子 D˙=ek\dot D=e_k,解 Av=−RD D˙Av=-R_D\,\dot D,每个设计分量解一次;目标沿这个方向的导数是 J˙h=gTv\dot J_h=g^Tv。上面面表里的 v0v_0 就是这样的解,所以每个 R˙i\dot R_i 都为零(上面检验的九个种子中最大的 ∣R˙i∣|\dot R_i| 是 1×10−151\times10^{-15})。

A sweep of residual_d is a product, not a solve. Section 10 uses it to solve the tangent equation for the state tangent v=𝐔˙v=\dot{\mathbf U} that keeps R=0R=0 along a design direction: with the seed D˙=ek\dot D=e_k it solves Av=−RD D˙Av=-R_D\,\dot D, one solve per design component; the derivative of the objective along that direction is J˙h=gTv\dot J_h=g^Tv. The v0v_0 of the face tables above was such a solution: that is why every R˙i\dot R_i vanished (the largest ∣R˙i∣|\dot R_i| over the nine seeds of the check above is 1×10−151\times10^{-15}).

第 9 节Section 9

伴随:把同一个面循环倒过来

Reverse: the adjoint of the same face loop

本节实验:给一个残差一个单位权重 Rˉ=e4\bar R=e_4,运行反向代码后,哪些未知量会收到贡献?三个设计分量里哪些会?先从前向模板预测,再用反向播放器(或后面的“列与行”实验)检查。

Experiment: Put a unit weight on one residual, Rˉ=e4\bar R=e_4, and run the reverse code: which unknowns receive a contribution, and which of the three design components? Predict from the forward stencil, then check with the reverse player (or the row-and-column lab further down).

第 8 节把一个方向 (𝐔˙,D˙)(\dot{\mathbf U},\dot D) 沿残差代码向前推,得到 R˙=A𝐔˙+RDD˙\dot R=A\dot{\mathbf U}+R_D\dot D。本节把一个权重向量 Rˉ\bar R 沿同一段代码向后拉,得到 𝐔ˉ=ATRˉ\bar{\mathbf U}=A^T\bar R 和 Dˉ=RDTRˉ\bar D=R_D^T\bar R:这是反向(伴随)模式。取 Rˉ=ψ\bar R=\psi(第 11 节伴随方程的解)时,一次扫描得到的 Dˉ\bar D 就是整个梯度 dJh/dD\mathrm dJ_h/\mathrm dD。

Section 8 pushed a direction (𝐔˙,D˙)(\dot{\mathbf U},\dot D) forward through the residual code and obtained R˙=A𝐔˙+RDD˙\dot R=A\dot{\mathbf U}+R_D\dot D. This section pulls a weight vector Rˉ\bar R backwards through the same code and obtains 𝐔ˉ=ATRˉ\bar{\mathbf U}=A^T\bar R and Dˉ=RDTRˉ\bar D=R_D^T\bar R: the reverse (adjoint) mode. With Rˉ=ψ\bar R=\psi, the solution of the adjoint equation of Section 11, one sweep gives the whole gradient dJh/dD\mathrm dJ_h/\mathrm dD as Dˉ\bar D.

伴随为什么存在:转置由内积定义

Why the adjoint exists: the transpose is defined by a dot product

线性映射 ℰ\mathcal E 的转置 ℰT\mathcal E^T 就是把它从内积的一边移到另一边的那个映射:对所有 x˙\dot x 和 yˉ\bar y,

A linear map ℰ\mathcal E has a transpose ℰT\mathcal E^T, the map that moves it from one side of a dot product to the other: for all x˙\dot x and yˉ\bar y,

⟨yˉ,ℰx˙⟩=⟨ℰTyˉ,x˙⟩.\langle\bar y,\mathcal E\dot x\rangle=\langle\mathcal E^T\bar y,\dot x\rangle.

把这个定义用到第 8 节的线性映射 (𝐔˙,D˙)↦R˙=A𝐔˙+RDD˙(\dot{\mathbf U},\dot D)\mapsto\dot R=A\dot{\mathbf U}+R_D\dot D 上。这个映射的转置把残差上的权重 Rˉ\bar R 映成输入上的权重 𝐔ˉ=ATRˉ\bar{\mathbf U}=A^T\bar R、Dˉ=RDTRˉ\bar D=R_D^T\bar R,定义式就成了自动微分的对偶恒等式:

Apply this to the linear map of Section 8, (𝐔˙,D˙)↦R˙=A𝐔˙+RDD˙(\dot{\mathbf U},\dot D)\mapsto\dot R=A\dot{\mathbf U}+R_D\dot D. Its transpose maps a weight Rˉ\bar R on the residuals to weights on the inputs, 𝐔ˉ=ATRˉ\bar{\mathbf U}=A^T\bar R and Dˉ=RDTRˉ\bar D=R_D^T\bar R, and the definition becomes the duality identity of AD:

RˉTR˙=RˉT(A𝐔˙+RDD˙)=(ATRˉ)T𝐔˙+(RDTRˉ)TD˙=𝐔ˉT𝐔˙+DˉTD˙.\bar R^T\dot R=\bar R^T\big(A\dot{\mathbf U}+R_D\dot D\big)=\big(A^T\bar R\big)^T\dot{\mathbf U}+\big(R_D^T\bar R\big)^T\dot D=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D.

xˉ\bar x 是加权输出 RˉTR\bar R^TR 对 xx 的灵敏度。反向代码逐句转置程序来计算 𝐔ˉ\bar{\mathbf U} 和 Dˉ\bar D,不形成 AA 或 RDR_D;它的代价是一次残差计算的一个不大的常数倍,与输入的个数无关(在本页的实现中实测约为 1 倍;后面“解出来的伴随,以及它省下的代价”一段末尾的计时实验会在你的浏览器里测量)。这个恒等式就是它的检验(后面的点积检验)。

xˉ\bar x is the sensitivity of the weighted output RˉTR\bar R^TR to xx. The reverse code computes 𝐔ˉ\bar{\mathbf U} and Dˉ\bar D by transposing the program statement by statement, without forming AA or RDR_D; its cost is a small constant multiple of one residual evaluation, independent of the number of inputs (about one for this page's implementation, as measured; the cost lab at the end of “The solved adjoint, and what it saves” measures it in your browser). The identity is its test (the dot test further down).

先转置一个面的局部矩阵

First transpose the local matrix of one face

先不管重构。一个内部面有五个输入、两个输出:它对残差切向量的贡献 ℬ:,fH˙f\mathcal B_{:,f}\dot H_f 只落在第 f−1f-1、ff 两行,第二行是第一行的相反数(右边单元收到 −Hf-H_f)。这个贡献不是完整的 R˙f−1,R˙f\dot R_{f-1},\dot R_f:相邻的面也往这两行写。把这个 2×52\times5 局部矩阵的转置作用在两行的权重上,直接得到反向语句:先把两个种子相减,再乘以五个通量导数:

Leave the reconstruction aside for a moment. One interior face has five inputs and two outputs: its contribution ℬ:,fH˙f\mathcal B_{:,f}\dot H_f to the residual tangent falls on the rows f−1f-1 and ff only, the second the negative of the first (the right cell receives −Hf-H_f). It is not the whole of R˙f−1,R˙f\dot R_{f-1},\dot R_f: the neighbouring faces write into the same rows. The transpose of this 2×52\times5 local matrix, applied to the weights of the two rows, gives the reverse statements directly: subtract the two seeds, then multiply by the five flux derivatives:

(ℬ:,fH˙f)f−1, f=[1−1]Hz,f z˙f,zˉf=[qˉLqˉRUˉLUˉRνˉ]=Hz,fT[1−1][Rˉf−1Rˉf]=[cLcRκf−κf−(UR−UL)/df]Hˉf,Hˉf=Rˉf−1−Rˉf.\big(\mathcal B_{:,f}\dot H_f\big)_{f-1,\,f}=\begin{bmatrix}1\\ -1\end{bmatrix}H_{z,f}\,\dot z_f,\qquad \bar z_f=\begin{bmatrix}\bar q_L\\ \bar q_R\\ \bar U_L\\ \bar U_R\\ \bar\nu\end{bmatrix}=H_{z,f}^T\begin{bmatrix}1&-1\end{bmatrix}\begin{bmatrix}\bar R_{f-1}\\ \bar R_f\end{bmatrix}=\begin{bmatrix}c_L\\ c_R\\ \kappa_f\\ -\kappa_f\\ -(U_R-U_L)/d_f\end{bmatrix}\bar H_f,\qquad \bar H_f=\bar R_{f-1}-\bar R_f.

取默认解的面 4,两行的权重用第 11 节伴随解的值 Rˉ3=ψ3=−1.0178\bar R_3=\psi_3=-1.0178、Rˉ4=ψ4=−0.8275\bar R_4=\psi_4=-0.8275,于是 Hˉ4=−0.1903\bar H_4=-0.1903,qˉL=cLHˉ4=−0.2867\bar q_L=c_L\bar H_4=-0.2867,qˉR=0.0963\bar q_R=0.0963,UˉL=−0.0152\bar U_L=-0.0152,UˉR=0.0152\bar U_R=0.0152,νˉ=−0.2303\bar\nu=-0.2303。配上第 8 节手算的切向量(种子 e3e_3:q˙L=1\dot q_L=1,q˙R=14\dot q_R=\tfrac14,U˙L=1\dot U_L=1,U˙R=0\dot U_R=0,ν˙=0\dot\nu=0),恒等式两边在这个面上相等(左边只是面 4 对第 3、4 行的贡献;完整的 R˙3,R˙4\dot R_3,\dot R_4 还含面 3、面 5 的贡献):

Take face 4 of the default solution and, as the weights of its two rows, the values of the adjoint solution of Section 11, Rˉ3=ψ3=−1.0178\bar R_3=\psi_3=-1.0178 and Rˉ4=ψ4=−0.8275\bar R_4=\psi_4=-0.8275: then Hˉ4=−0.1903\bar H_4=-0.1903, qˉL=cLHˉ4=−0.2867\bar q_L=c_L\bar H_4=-0.2867, qˉR=0.0963\bar q_R=0.0963, UˉL=−0.0152\bar U_L=-0.0152, UˉR=0.0152\bar U_R=0.0152 and νˉ=−0.2303\bar\nu=-0.2303. With the hand-worked tangents of Section 8 (seed e3e_3: q˙L=1\dot q_L=1, q˙R=14\dot q_R=\tfrac14, U˙L=1\dot U_L=1, U˙R=0\dot U_R=0, ν˙=0\dot\nu=0) both sides of the identity agree on this face (the left side is face 4's share of rows 3 and 4 only; the full R˙3,R˙4\dot R_3,\dot R_4 also contain the contributions of faces 3 and 5):

RˉT(ℬ:,4H˙4)=Rˉ3H˙4−Rˉ4H˙4=Hˉ4H˙4=−0.277863,qˉLq˙L+qˉRq˙R+UˉLU˙L+UˉRU˙R+νˉν˙=−0.277863.\bar R^T\big(\mathcal B_{:,4}\dot H_4\big)=\bar R_3\dot H_4-\bar R_4\dot H_4=\bar H_4\dot H_4=-0.277863,\qquad \bar q_L\dot q_L+\bar q_R\dot q_R+\bar U_L\dot U_L+\bar U_R\dot U_R+\bar\nu\dot\nu=-0.277863.
图 26 · 同一个面的反向数据流(面 4,种子 R-bar=ψ)。从右到左,把 倒过来:(4′)两个残差权重汇集成 H-bar_4=R-bar_3-R-bar_4;(3′)通量的转置给出五个输入伴随;(2′)重构的转置累加到斜率伴随 σ 和设计伴随 ν;(1′)取值的转置把这个面的份额累加进 U(每个未知量一个数:直接的与经过斜率的之和)。每条箭头都反向,带着与前向图相同的局部导数;横线量是伴随(橙色)。(1′)加回 Ū(2′)重构的转置(3′)通量的转置(4′)取值1111½−½cL​κf​−κf​cR​−(UR​ − UL​)/df​+1−1U2​ = 1.1388Ū2​ += 0.0717U3​ = 1.0683Ū3​ += −0.2779U4​ = 0.9171Ū4​ += 0.0398U5​ = 0.7835Ū5​ += −0.0241σ3​ = −0.1109σ̄3​ += −0.1434σ4​ = −0.1424σ̄4​ += −0.0481σi​ 读 Ui−1​, Ui​, Ui+1​权重 −σl​, σl​ − σr​, σr​qL​ = 1.0129q̄L​ = −0.2867UL​ = 1.0683ŪL​ = −0.0152UR​ = 0.9171ŪR​ = 0.0152qR​ = 0.9883q̄R​ = 0.0963ν = 0.010ν̄ += −0.2303H4​ = 0.5374H̄4​ = −0.1903R̄3​ = −1.0178读入,×(+1)R̄4​ = −0.8275读入,×(−1)H̄4​ = R̄3​ − R̄4​ = −0.1903; q̄L​ = cL​ H̄4​, q̄R​ = cR​ H̄4​, ŪL​ = −ŪR​ = κf​ H̄4​, ν̄ += −(UR​ − UL​)/df​ · H̄4​种子:R̄ = ψ(第 11 节的伴随解);方框里的 Ūj​ 是这一个面的份额(直接的与经过斜率的)
图 26 · 同一个面的反向数据流(面 4,种子 Rˉ=ψ\bar R=\psi)。从右到左,把图 22 倒过来:(4′)两个残差权重汇集成 Hˉ4=Rˉ3−Rˉ4\bar H_4=\bar R_3-\bar R_4;(3′)通量的转置给出五个输入伴随;(2′)重构的转置累加到斜率伴随 σˉ\bar\sigma 和设计伴随 νˉ\bar\nu;(1′)取值的转置把这个面的份额累加进 𝐔ˉ\bar{\mathbf U}(每个未知量一个数:直接的与经过斜率的之和)。每条箭头都反向,带着与前向图相同的局部导数;横线量是伴随(橙色)。
Figure 26 · The reverse data flow of the same face (face 4, seed R-bar=ψ). Right to left, the reverse of : (4′) the two residual weights are gathered into H-bar_4=R-bar_3-R-bar_4, (3′) the transposed flux gives the five input adjoints, (2′) the transposed reconstruction adds into the slope adjoints σ and the design adjoint ν, (1′) the transposed gather adds this face's share into U (one number per unknown: the direct part plus the part through the slopes). Every arrow is reversed and carries the same local derivative as in the forward graph; the barred quantities are adjoints (orange).(1′) add into Ū(2′) reconstruction, transposed(3′) flux, transposed(4′) gather1111½−½cL​κf​−κf​cR​−(UR​ − UL​)/df​+1−1U2​ = 1.1388Ū2​ += 0.0717U3​ = 1.0683Ū3​ += −0.2779U4​ = 0.9171Ū4​ += 0.0398U5​ = 0.7835Ū5​ += −0.0241σ3​ = −0.1109σ̄3​ += −0.1434σ4​ = −0.1424σ̄4​ += −0.0481σi​ reads Ui−1​, Ui​, Ui+1​with −σl​, σl​ − σr​, σr​qL​ = 1.0129q̄L​ = −0.2867UL​ = 1.0683ŪL​ = −0.0152UR​ = 0.9171ŪR​ = 0.0152qR​ = 0.9883q̄R​ = 0.0963ν = 0.010ν̄ += −0.2303H4​ = 0.5374H̄4​ = −0.1903R̄3​ = −1.0178read, ×(+1)R̄4​ = −0.8275read, ×(−1)H̄4​ = R̄3​ − R̄4​ = −0.1903; q̄L​ = cL​ H̄4​, q̄R​ = cR​ H̄4​, ŪL​ = −ŪR​ = κf​ H̄4​, ν̄ += −(UR​ − UL​)/df​ · H̄4​seed: R̄ = ψ (the adjoint solution of Section 11); the Ūj​ in the boxes are this face's share (direct and through the slopes)
Figure 26 · The reverse data flow of the same face (face 4, seed Rˉ=ψ\bar R=\psi). Right to left, the reverse of Figure 22: (4′) the two residual weights are gathered into Hˉ4=Rˉ3−Rˉ4\bar H_4=\bar R_3-\bar R_4, (3′) the transposed flux gives the five input adjoints, (2′) the transposed reconstruction adds into the slope adjoints σˉ\bar\sigma and the design adjoint νˉ\bar\nu, (1′) the transposed gather adds this face's share into 𝐔ˉ\bar{\mathbf U} (one number per unknown: the direct part plus the part through the slopes). Every arrow is reversed and carries the same local derivative as in the forward graph; the barred quantities are adjoints (orange).

逐句倒推:残差代码的反向语句

The residual code reversed statement by statement

下表对第 8 节表中的每条语句写出它的伴随语句 xˉk+=(∂ϕ/∂xk) yˉ\bar x_k\mathrel{\text{+=}}(\partial\phi/\partial x_k)\,\bar y,从最后一条原始语句倒回第一条;在面循环里,面按 f=N,…,0f=N,\dots,0 倒序处理,每个面里的语句也倒着执行。种子是 Rˉ\bar R,其余伴随量(包括每个面、每个单元上的局部伴随 qˉL,lˉi,…\bar q_L,\bar l_i,\dots)都从零开始:

The table lists, for every statement of the table of Section 8, its adjoint statements xˉk+=(∂ϕ/∂xk) yˉ\bar x_k\mathrel{\text{+=}}(\partial\phi/\partial x_k)\,\bar y, from the last primal statement back to the first; inside the face loop the faces run from f=Nf=N down to 0 and the statements of each face also run backwards. The seed is Rˉ\bar R; every other adjoint (the local ones of each face and cell, qˉL,lˉi,…\bar q_L,\bar l_i,\dots, included) starts at zero:

#原始语句Primal statement伴随语句(倒序执行)Adjoint statements (run in reverse order)写入的伴随量Adjoints written
11Ri-=Qi+1−QiR_i\mathrel{\text{-=}}Q_{i+1}-Q_iQˉi+1+=−Rˉi\bar Q_{i+1}\mathrel{\text{+=}}-\bar R_i,Qˉi+=Rˉi\bar Q_i\mathrel{\text{+=}}\bar R_i(i=N−1,…,0i=N-1,\dots,0)Qˉi+1+=−Rˉi\bar Q_{i+1}\mathrel{\text{+=}}-\bar R_i, Qˉi+=Rˉi\bar Q_i\mathrel{\text{+=}}\bar R_i (i=N−1,…,0i=N-1,\dots,0)Qˉf\bar Q_f
10Qf=q∗(xf;D)Q_f=q^*(x_f;D)Dˉ+=(∂Qf∂D)TQˉf\bar D\mathrel{\text{+=}}\big(\frac{\partial Q_f}{\partial D}\big)^T\bar Q_f(f=N,…,0f=N,\dots,0)Dˉ+=(∂Qf∂D)TQˉf\bar D\mathrel{\text{+=}}\big(\frac{\partial Q_f}{\partial D}\big)^T\bar Q_f (f=N,…,0f=N,\dots,0)aˉ, φˉ, νˉ\bar a,\ \bar\varphi,\ \bar\nu
9Rf-=HfR_f\mathrel{\text{-=}}H_fHˉf←0\bar H_f\leftarrow0;Hˉf-=Rˉf\bar H_f\mathrel{\text{-=}}\bar R_f(面循环 f=N,…,0f=N,\dots,0)Hˉf←0\bar H_f\leftarrow0; Hˉf-=Rˉf\bar H_f\mathrel{\text{-=}}\bar R_f (face loop f=N,…,0f=N,\dots,0)Hˉf\bar H_f
8Rf−1+=HfR_{f-1}\mathrel{\text{+=}}H_fHˉf+=Rˉf−1\bar H_f\mathrel{\text{+=}}\bar R_{f-1}Hˉf\bar H_f
7Hf=H(qL,qR,UL,UR,ν)H_f=H(q_L,q_R,U_L,U_R,\nu)qˉL+=cLHˉf\bar q_L\mathrel{\text{+=}}c_L\bar H_f,qˉR+=cRHˉf\bar q_R\mathrel{\text{+=}}c_R\bar H_f,UˉL+=κfHˉf\bar U_L\mathrel{\text{+=}}\kappa_f\bar H_f,UˉR+=−κfHˉf\bar U_R\mathrel{\text{+=}}-\kappa_f\bar H_f,νˉ+=−UR−ULdfHˉf\bar\nu\mathrel{\text{+=}}-\frac{U_R-U_L}{d_f}\bar H_fqˉL+=cLHˉf\bar q_L\mathrel{\text{+=}}c_L\bar H_f, qˉR+=cRHˉf\bar q_R\mathrel{\text{+=}}c_R\bar H_f, UˉL+=κfHˉf\bar U_L\mathrel{\text{+=}}\kappa_f\bar H_f, UˉR+=−κfHˉf\bar U_R\mathrel{\text{+=}}-\kappa_f\bar H_f, νˉ+=−UR−ULdfHˉf\bar\nu\mathrel{\text{+=}}-\frac{U_R-U_L}{d_f}\bar H_fqˉL,qˉR,UˉL,UˉR,νˉ\bar q_L,\bar q_R,\bar U_L,\bar U_R,\bar\nu
6qR=Uf−12σf,  UR=Ufq_R=U_f-\tfrac12\sigma_f,\ \ U_R=U_fUˉf+=qˉR+UˉR\bar U_f\mathrel{\text{+=}}\bar q_R+\bar U_R,σˉf+=−12qˉR\bar\sigma_f\mathrel{\text{+=}}-\tfrac12\bar q_R;面 NN:uˉout+=qˉR+UˉR\bar u_{\rm out}\mathrel{\text{+=}}\bar q_R+\bar U_RUˉf+=qˉR+UˉR\bar U_f\mathrel{\text{+=}}\bar q_R+\bar U_R, σˉf+=−12qˉR\bar\sigma_f\mathrel{\text{+=}}-\tfrac12\bar q_R; face NN: uˉout+=qˉR+UˉR\bar u_{\rm out}\mathrel{\text{+=}}\bar q_R+\bar U_RUˉf, σˉf, uˉout\bar U_f,\ \bar\sigma_f,\ \bar u_{\rm out}
5qL=Uf−1+12σf−1,  UL=Uf−1q_L=U_{f-1}+\tfrac12\sigma_{f-1},\ \ U_L=U_{f-1}Uˉf−1+=qˉL+UˉL\bar U_{f-1}\mathrel{\text{+=}}\bar q_L+\bar U_L,σˉf−1+=12qˉL\bar\sigma_{f-1}\mathrel{\text{+=}}\tfrac12\bar q_L;面 0:uˉin+=qˉL+UˉL\bar u_{\rm in}\mathrel{\text{+=}}\bar q_L+\bar U_LUˉf−1+=qˉL+UˉL\bar U_{f-1}\mathrel{\text{+=}}\bar q_L+\bar U_L, σˉf−1+=12qˉL\bar\sigma_{f-1}\mathrel{\text{+=}}\tfrac12\bar q_L; face 0: uˉin+=qˉL+UˉL\bar u_{\rm in}\mathrel{\text{+=}}\bar q_L+\bar U_LUˉf−1, σˉf−1, uˉin\bar U_{f-1},\ \bar\sigma_{f-1},\ \bar u_{\rm in}
4σi=σ(li,ri)\sigma_i=\sigma(l_i,r_i)lˉi+=σlσˉi\bar l_i\mathrel{\text{+=}}\sigma_l\bar\sigma_i,rˉi+=σrσˉi\bar r_i\mathrel{\text{+=}}\sigma_r\bar\sigma_i(i=N−2,…,1i=N-2,\dots,1,在面循环之后)lˉi+=σlσˉi\bar l_i\mathrel{\text{+=}}\sigma_l\bar\sigma_i, rˉi+=σrσˉi\bar r_i\mathrel{\text{+=}}\sigma_r\bar\sigma_i (i=N−2,…,1i=N-2,\dots,1, after the face loop)lˉi, rˉi\bar l_i,\ \bar r_i
3li=Ui−Ui−1,  ri=Ui+1−Uil_i=U_i-U_{i-1},\ \ r_i=U_{i+1}-U_iUˉi+=lˉi−rˉi\bar U_i\mathrel{\text{+=}}\bar l_i-\bar r_i,Uˉi−1+=−lˉi\bar U_{i-1}\mathrel{\text{+=}}-\bar l_i,Uˉi+1+=rˉi\bar U_{i+1}\mathrel{\text{+=}}\bar r_iUˉi+=lˉi−rˉi\bar U_i\mathrel{\text{+=}}\bar l_i-\bar r_i, Uˉi−1+=−lˉi\bar U_{i-1}\mathrel{\text{+=}}-\bar l_i, Uˉi+1+=rˉi\bar U_{i+1}\mathrel{\text{+=}}\bar r_i𝐔ˉ\bar{\mathbf U}
2uin=u∗(0;D),  uout=u∗(1;D)u_{\rm in}=u^*(0;D),\ \ u_{\rm out}=u^*(1;D)aˉ+=∂uin∂a(uˉin+uˉout)\bar a\mathrel{\text{+=}}\frac{\partial u_{\rm in}}{\partial a}(\bar u_{\rm in}+\bar u_{\rm out}),φˉ+=∂uin∂φ(uˉin+uˉout)\bar\varphi\mathrel{\text{+=}}\frac{\partial u_{\rm in}}{\partial\varphi}(\bar u_{\rm in}+\bar u_{\rm out})aˉ+=∂uin∂a(uˉin+uˉout)\bar a\mathrel{\text{+=}}\frac{\partial u_{\rm in}}{\partial a}(\bar u_{\rm in}+\bar u_{\rm out}), φˉ+=∂uin∂φ(uˉin+uˉout)\bar\varphi\mathrel{\text{+=}}\frac{\partial u_{\rm in}}{\partial\varphi}(\bar u_{\rm in}+\bar u_{\rm out})aˉ, φˉ\bar a,\ \bar\varphi
1R←0R\leftarrow0无:Rˉ\bar R 是种子(扫描前 𝐔ˉ←0\bar{\mathbf U}\leftarrow0,Dˉ←0\bar D\leftarrow0)nothing: Rˉ\bar R is the seed (𝐔ˉ←0\bar{\mathbf U}\leftarrow0, Dˉ←0\bar D\leftarrow0 before the sweep)—

有三点值得注意。(i)分发的伴随是取值:语句 8、9 把一个数写进两行,它们的伴随 Hˉf=Rˉf−1−Rˉf\bar H_f=\bar R_{f-1}-\bar R_f 把两行读回一个数。(ii)每个输入的伴随都用 += 累加:UjU_j 被几个面读(还经过斜率),σi\sigma_i 被两个面读,设计被每个面和每一行读;链式法则对每次使用给出一项(见下图)。(iii)源项行也由同一个取值倒转:Qˉf=Rˉf−Rˉf−1=−Hˉf\bar Q_f=\bar R_f-\bar R_{f-1}=-\bar H_f(边界面上取 Rˉ−1=RˉN=0\bar R_{-1}=\bar R_N=0),所以源项给设计伴随的贡献是 −∑fHˉf (∂Qf/∂D)T-\sum_f\bar H_f\,(\partial Q_f/\partial D)^T。语句 2 用了 ∂uout/∂D=∂uin/∂D\partial u_{\rm out}/\partial D=\partial u_{\rm in}/\partial D(u∗u^* 以 1 为周期)。反向语句要读的原始值(cL,cR,κf,UR−UL,σl,σrc_L,c_R,\kappa_f,U_R-U_L,\sigma_l,\sigma_r)由收敛解 𝐔\mathbf U 重算(或在一次前向扫描中存下)。

Three things to notice. (i) The adjoint of a scatter is a gather: statements 8 and 9 wrote one number into two rows, and their adjoints Hˉf=Rˉf−1−Rˉf\bar H_f=\bar R_{f-1}-\bar R_f read two rows back into one number. (ii) Every input adjoint accumulates with +=: UjU_j is read by several faces (and through the slopes), σi\sigma_i by two faces, the design by every face and every row; the chain rule gives one term per use (the figure below). (iii) The source rows are reversed by the same gather: Qˉf=Rˉf−Rˉf−1=−Hˉf\bar Q_f=\bar R_f-\bar R_{f-1}=-\bar H_f (with Rˉ−1=RˉN=0\bar R_{-1}=\bar R_N=0 on the boundary faces), so the source contributes −∑fHˉf (∂Qf/∂D)T-\sum_f\bar H_f\,(\partial Q_f/\partial D)^T to the design adjoint. Statement 2 uses ∂uout/∂D=∂uin/∂D\partial u_{\rm out}/\partial D=\partial u_{\rm in}/\partial D (u∗u^* has period 1). The primal values the reverse statements read (cL,cR,κf,UR−UL,σl,σrc_L,c_R,\kappa_f,U_R-U_L,\sigma_l,\sigma_r) are recomputed from the converged solution 𝐔\mathbf U (or stored by a forward sweep).

写成自动微分工具生成的 residual_b:

As the residual_b an AD tool would generate:

residual_b(U, D, res_b) -> u_b, D_b          # D_b = (a_b, phi_b, nu_b)
    (the primal statements 2-4 run first: uin, uout, s[i] and the slope partials sl[i], sr[i])
 0  u_b = 0;  D_b = 0;  s_b = 0;  Q_b = 0;  uin_b = 0;  uout_b = 0
    for i = N-1 .. 0:
11'   Q_b[i+1] += -res_b[i];  Q_b[i] += res_b[i]
    for f = N .. 0:
10'   a_b += dQda(xf[f])*Q_b[f];  phi_b += dQdphi(xf[f])*Q_b[f];  nu_b += dQdnu(xf[f])*Q_b[f]
    for f = N .. 0:
      (recompute qL, qR, UL, UR, d, cL, cR of face f: statements 5-7 of the primal)
      H_b = 0
 9'   if f <= N-1:  H_b -= res_b[f]
 8'   if f >= 1:    H_b += res_b[f-1]
 7'   qL_b = cL*H_b;  qR_b = cR*H_b;  UL_b = nu/d*H_b;  UR_b = -nu/d*H_b
      nu_b += -(UR - UL)/d*H_b
 6'   if f == N:  uout_b += qR_b + UR_b
      else:       u_b[f] += qR_b + UR_b;    s_b[f] += -qR_b/2
 5'   if f == 0:  uin_b += qL_b + UL_b
      else:       u_b[f-1] += qL_b + UL_b;  s_b[f-1] += qL_b/2
    for i = N-2 .. 1:
 4'   l_b = sl[i]*s_b[i];  r_b = sr[i]*s_b[i]
 3'   u_b[i] += l_b - r_b;  u_b[i-1] += -l_b;  u_b[i+1] += r_b
 2' a_b   += -sin(2 pi phi)*(uin_b + uout_b)
    phi_b += -2 pi a cos(2 pi phi)*(uin_b + uout_b)

为什么用 +=:程序的扇出就是反向代码的扇入

Why +=: a fan-out of the program is a fan-in of the reverse code

二阶时,内部的未知量 UjU_j(2≤j≤N−32\le j\le N-3)被四个面读:作为面 jj 的右状态和面 j+1j+1 的左状态,此外还通过斜率 σj−1,σj+1\sigma_{j-1},\sigma_{j+1} 被面 j−1j-1 和 j+2j+2 读(共 6 个迹、2 个未重构状态);靠近边界的 U0,U1,UN−2,UN−1U_0,U_1,U_{N-2},U_{N-1} 被三个面读(端单元不重构);一阶时每个 UjU_j 被两个面读。链式法则对每次使用给出一项,所以 Uˉj\bar U_j 是一个和;每条反向语句必须把自己的项加上去(+=),而不是覆盖前面的项:

At second order an interior unknown UjU_j (2≤j≤N−32\le j\le N-3) is read by four faces: as the right state of face jj and the left state of face j+1j+1, and through the slopes σj−1,σj+1\sigma_{j-1},\sigma_{j+1} by the faces j−1j-1 and j+2j+2 as well (six traces and two raw states in all); next to a boundary U0,U1,UN−2,UN−1U_0,U_1,U_{N-2},U_{N-1} are read by three faces (the end cells are not reconstructed); at first order every UjU_j is read by two faces. The chain rule gives one term per use, so Uˉj\bar U_j is a sum, and every reverse statement must add its term (+=) instead of overwriting the earlier ones:

Uˉj=∑f: j∈𝒮f∂Hf∂Uj Hˉf.\bar U_j=\sum_{f:\ j\in\mathcal S_f}\frac{\partial H_f}{\partial U_j}\,\bar H_f.

取种子 Rˉ=ψ\bar R=\psi 时这个和是 Uˉj=(ATψ)j=−wj\bar U_j=(A^T\psi)_j=-w_j(第 11 节),所以扇入有已知的总和:在默认解的单元 4 上,四个面加上 −0.0196-0.0196、0.03980.0398、−0.3012-0.3012、0.08570.0857,和为 −0.1953125=−w4-0.1953125=-w_4(图 27)。如果用覆盖代替累加,只会留下最后一个面的项。下面的点积检验实验可以植入这个错误。

With the seed Rˉ=ψ\bar R=\psi the sum is Uˉj=(ATψ)j=−wj\bar U_j=(A^T\psi)_j=-w_j (Section 11), so the fan-in has a known total: at cell 4 of the default solution the four faces add −0.0196-0.0196, 0.03980.0398, −0.3012-0.3012, 0.08570.0857, which sum to −0.1953125=−w4-0.1953125=-w_4 (Figure 27). Overwriting instead of adding keeps only the last face's term: the dot-test lab below lets you plant this bug.

图 27 · 单元 4 的扇入(默认设计,种子 R-bar=ψ)。每个读 U_4 的面贡献 (∂ H_f/∂ U_4) H-bar_f,方框里写出它经过的输入(q_L,q_R 是迹,“经 σ”表示通过斜率)。上:一阶,面 4、5;下:无限制器线性,面 3–6。两种情况的和都是 U-bar_4=(A^Tψ)_4=-w_4=-0.1953125。一阶:2 个面读 U4​f = 4: H̄4​ = −0.1546∂H4​/∂U4​ = −0.6684qR​, UR​+= 0.1033f = 5: H̄5​ = −0.2002∂H5​/∂U4​ = 1.4916qL​, UL​+= −0.2986Ū4​ = Σ = −0.1953125= −w4​ = −0.1953125(因为 AT​ ψ = −w)无限制器线性:4 个面读 U4​f = 3: H̄3​ = −0.1792∂H3​/∂U4​ = 0.1095qR​(经 σ3​)+= −0.0196f = 4: H̄4​ = −0.1903∂H4​/∂U4​ = −0.2093qR​, UR​, qL​(经 σ3​)+= 0.0398f = 5: H̄5​ = −0.2223∂H5​/∂U4​ = 1.3554qL​, UL​, qR​(经 σ5​)+= −0.3012f = 6: H̄6​ = −0.2496∂H6​/∂U4​ = −0.3434qL​(经 σ5​)+= 0.0857Ū4​ = Σ = −0.1953125= −w4​ = −0.1953125(因为 AT​ ψ = −w)
图 27 · 单元 4 的扇入(默认设计,种子 Rˉ=ψ\bar R=\psi)。每个读 U4U_4 的面贡献 (∂Hf/∂U4) Hˉf(\partial H_f/\partial U_4)\,\bar H_f,方框里写出它经过的输入(qL,qRq_L,q_R 是迹,“经 σ\sigma”表示通过斜率)。上:一阶,面 4、5;下:无限制器线性,面 3–6。两种情况的和都是 Uˉ4=(ATψ)4=−w4=−0.1953125\bar U_4=(A^T\psi)_4=-w_4=-0.1953125。
Figure 27 · The fan-in at cell 4 (default design, seed R-bar=ψ). Every face that reads U_4 contributes (∂ H_f/∂ U_4) H-bar_f; its box lists the inputs it goes through (q_L,q_R are traces, "via σ" means through a slope). Top: first order, faces 4 and 5; bottom: unlimited linear, faces 3–6. In both cases the sum is U-bar_4=(A^Tψ)_4=-w_4=-0.1953125.first order: 2 faces read U4​f = 4: H̄4​ = −0.1546∂H4​/∂U4​ = −0.6684qR​, UR​+= 0.1033f = 5: H̄5​ = −0.2002∂H5​/∂U4​ = 1.4916qL​, UL​+= −0.2986Ū4​ = Σ = −0.1953125= −w4​ = −0.1953125 (because AT​ ψ = −w)unlimited linear: 4 faces read U4​f = 3: H̄3​ = −0.1792∂H3​/∂U4​ = 0.1095qR​ (via σ3​)+= −0.0196f = 4: H̄4​ = −0.1903∂H4​/∂U4​ = −0.2093qR​, UR​, qL​ (via σ3​)+= 0.0398f = 5: H̄5​ = −0.2223∂H5​/∂U4​ = 1.3554qL​, UL​, qR​ (via σ5​)+= −0.3012f = 6: H̄6​ = −0.2496∂H6​/∂U4​ = −0.3434qL​ (via σ5​)+= 0.0857Ū4​ = Σ = −0.1953125= −w4​ = −0.1953125 (because AT​ ψ = −w)
Figure 27 · The fan-in at cell 4 (default design, seed Rˉ=ψ\bar R=\psi). Every face that reads U4U_4 contributes (∂Hf/∂U4) Hˉf(\partial H_f/\partial U_4)\,\bar H_f; its box lists the inputs it goes through (qL,qRq_L,q_R are traces, "via σ\sigma" means through a slope). Top: first order, faces 4 and 5; bottom: unlimited linear, faces 3–6. In both cases the sum is Uˉ4=(ATψ)4=−w4=−0.1953125\bar U_4=(A^T\psi)_4=-w_4=-0.1953125.

分发的伴随是取值,取值的伴随是分发

The adjoint of a scatter is a gather (and of a gather, a scatter)

这是最该记住的一幅图。前向面循环读入这个面的未知量(取值),把通量写进两行残差(分发)。反向面循环读入两个残差权重(取值,即分发的转置),把这个面的伴随写回它读过的未知量的位置(带 += 的分发,即取值的转置)。循环还是同一个循环,只是两端交换了角色:

This is the picture to remember. The forward face loop reads the unknowns of the face (gather) and writes its flux into two residual rows (scatter). The reverse face loop reads two residual weights (a gather: the transposed scatter) and writes the face's adjoints back into the places of the unknowns it read (a scatter with +=: the transposed gather). It is the same loop; its two ends exchange their roles:

R+=ℬ:,fHf ⟷ Hˉf=ℬ:,fTRˉ,𝐮f=𝒢f𝐔 ⟷ 𝐔ˉ+=𝒢fT𝐮ˉf.R\mathrel{\text{+=}}\mathcal B_{:,f}H_f\ \longleftrightarrow\ \bar H_f=\mathcal B_{:,f}^T\bar R,\qquad \mathbf u_f=\mathcal G_f\mathbf U\ \longleftrightarrow\ \bar{\mathbf U}\mathrel{\text{+=}}\mathcal G_f^T\bar{\mathbf u}_f.
图 28 · 分发与取值互为转置(面 4,默认设计,无限制器线性)。上:前向面循环从 U_2,…,U_5 取值,算出 H_4,以 +1、-1 分发到 R_3、R_4。下:反向面循环从 R-bar_3=ψ_3、R-bar_4=ψ_4 取值(H-bar_4=R-bar_3-R-bar_4),把这个面的份额用 += 分发回 U-bar_2,…,U-bar_5。箭头的方向全部反过来,两端互换了角色。前向面循环:取值 → 通量 → 分发UU0​1.0247U1​1.1022U2​1.1388U3​1.0683U4​0.9171U5​0.7835U6​0.7718U7​0.8687H4​ = H(z4​)= 0.5374取值 G4​:读 4 个未知量RR0​R1​R2​R3​R4​R5​R6​R7​+= 0.5374−= 0.5374分发 B:,4​:写 2 行(+1,−1)反向面循环:分发的转置是取值,取值的转置是带 += 的分发R̄R̄0​ = ψ0​−0.9243R̄1​ = ψ1​−1.2308R̄2​ = ψ2​−1.1969R̄3​ = ψ3​−1.0178R̄4​ = ψ4​−0.8275R̄5​ = ψ5​−0.6052R̄6​ = ψ6​−0.3556R̄7​ = ψ7​−0.1632H̄4​ = R̄3​ − R̄4​= −0.1903取值 B:,4​T​:读 2 行(+1,−1)ŪŪ0​Ū1​Ū2​Ū3​Ū4​Ū5​Ū6​Ū7​+= 0.0717+= −0.2779+= 0.0398+= −0.0241分发 G4​T​:+= 到 4 个位置
图 28 · 分发与取值互为转置(面 4,默认设计,无限制器线性)。上:前向面循环从 U2,…,U5U_2,\dots,U_5 取值,算出 H4H_4,以 +1+1、−1-1 分发到 R3R_3、R4R_4。下:反向面循环从 Rˉ3=ψ3\bar R_3=\psi_3、Rˉ4=ψ4\bar R_4=\psi_4 取值(Hˉ4=Rˉ3−Rˉ4\bar H_4=\bar R_3-\bar R_4),把这个面的份额用 += 分发回 Uˉ2,…,Uˉ5\bar U_2,\dots,\bar U_5。箭头的方向全部反过来,两端互换了角色。
Figure 28 · Scatter and gather are transposes of each other (face 4, default design, unlimited linear). Top: the forward face loop gathers U_2,…,U_5, computes H_4 and scatters it into R_3 and R_4 with +1 and -1. Bottom: the reverse face loop gathers R-bar_3=ψ_3 and R-bar_4=ψ_4 (H-bar_4=R-bar_3-R-bar_4) and scatters this face's share back into U-bar_2,…,U-bar_5 with +=. Every arrow is reversed; the two ends have exchanged their roles.Forward face loop: gather → flux → scatterUU0​1.0247U1​1.1022U2​1.1388U3​1.0683U4​0.9171U5​0.7835U6​0.7718U7​0.8687H4​ = H(z4​)= 0.5374gather G4​: reads 4 unknownsRR0​R1​R2​R3​R4​R5​R6​R7​+= 0.5374−= 0.5374scatter B:,4​: writes 2 rows (+1, −1)Reverse face loop: the transpose of the scatter is a gather, the transpose of the gather a scatter with +=R̄R̄0​ = ψ0​−0.9243R̄1​ = ψ1​−1.2308R̄2​ = ψ2​−1.1969R̄3​ = ψ3​−1.0178R̄4​ = ψ4​−0.8275R̄5​ = ψ5​−0.6052R̄6​ = ψ6​−0.3556R̄7​ = ψ7​−0.1632H̄4​ = R̄3​ − R̄4​= −0.1903gather B:,4​T​: reads 2 rows (+1, −1)ŪŪ0​Ū1​Ū2​Ū3​Ū4​Ū5​Ū6​Ū7​+= 0.0717+= −0.2779+= 0.0398+= −0.0241scatter G4​T​: += into 4 places
Figure 28 · Scatter and gather are transposes of each other (face 4, default design, unlimited linear). Top: the forward face loop gathers U2,…,U5U_2,\dots,U_5, computes H4H_4 and scatters it into R3R_3 and R4R_4 with +1+1 and −1-1. Bottom: the reverse face loop gathers Rˉ3=ψ3\bar R_3=\psi_3 and Rˉ4=ψ4\bar R_4=\psi_4 (Hˉ4=Rˉ3−Rˉ4\bar H_4=\bar R_3-\bar R_4) and scatters this face's share back into Uˉ2,…,Uˉ5\bar U_2,\dots,\bar U_5 with +=. Every arrow is reversed; the two ends have exchanged their roles.

面与面之间互不依赖:每个面读固定的状态和种子,加到一个单独的输出数组里。所以反向循环中各个面的先后顺序可以任意(点积实验提供正序 f=0,…,Nf=0,\dots,N 这一选项,检验照样通过)。必须倒过来的是相互依赖的语句的顺序:分发在通量之前,通量在重构之前;斜率语句在原始代码中位于面循环之前,在反向代码中必须位于面循环之后,等读 σi\sigma_i 的两个面都把贡献加进 σˉi\bar\sigma_i 之后再倒转。

The faces do not depend on each other: each face reads the fixed state and the seed and adds into a separate output array. The face order of the reverse loop is therefore free (the dot-test lab offers the forward order f=0,…,Nf=0,\dots,N, and the test still passes); what must be reversed is the order of the statements that depend on each other: the scatter before the flux, the flux before the reconstruction; and the slope statements, which run before the face loop in the primal, run after it in reverse, once both faces that read σi\sigma_i have added their parts to σˉi\bar\sigma_i.

反向播放器在当前网格上运行 residual_b。选种子(单位行 eie_i、目标的权重 ww、伴随解 ψ\psi 或随机向量),从源项行开始,经过面 f=N,…,0f=N,\dots,0,到斜率和边界值;柱条显示 𝐔ˉ\bar{\mathbf U} 和 Dˉ\bar D 的累加,刚更新的分量加框,虚线框是最终值 ATRˉA^T\bar R、RDTRˉR_D^T\bar R。

The reverse player runs residual_b on the current mesh. Choose the seed (a unit row eie_i, the weights ww of the objective, the adjoint solution ψ\psi, or a random vector) and step from the source rows through the faces f=N,…,0f=N,\dots,0 to the slopes and the boundary data; the bars show 𝐔ˉ\bar{\mathbf U} and Dˉ\bar D accumulating, the entries just updated framed, the final values ATRˉA^T\bar R and RDTRˉR_D^T\bar R dashed.

用本页的数字反向走同样的面

The same faces in reverse, with the page's numbers

继续看第 8 节的面 4 和面 0,现在以第 11 节伴随方程的解为种子,Rˉ=ψ\bar R=\psi。反向语句先把两个种子汇集成 Hˉf\bar H_f,再乘以同样的五个偏导数;最后两行把它们与第 8 节面表的切向量(种子 (v0,e0)(v_0,e_0))配对:

Continue with the faces 4 and 0 of Section 8, now seeded with the solution of the adjoint equation of Section 11, Rˉ=ψ\bar R=\psi. The reverse statements first gather the two seeds into Hˉf\bar H_f, then multiply by the same five partial derivatives; the last two rows pair them with the tangents of the face table of Section 8 (seed (v0,e0)(v_0,e_0)):

内部面 f=4f=4,种子 Rˉ=ψ\bar R=\psiInterior face f=4f=4, seed Rˉ=ψ\bar R=\psi
量Quantity公式Formula一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
Hˉf\bar H_fψf−1−ψf\psi_{f-1}-\psi_f−0.154553−0.190320−0.112775
qˉL\bar q_LcLHˉfc_L\bar H_f−0.228040−0.286707−0.168858
qˉR\bar q_RcRHˉfc_R\bar H_f0.0909420.0962760.059255
UˉL=−UˉR\bar U_L=-\bar U_RκfHˉf\kappa_f\bar H_f−0.012364−0.015226−0.009022
νˉ\bar\nu−UR−ULdfHˉf-\frac{U_R-U_L}{d_f}\bar H_f−0.158000−0.230334−0.150869
HˉfH˙f\bar H_f\dot H_f输出端output side−0.027053385−0.037378968−0.018764767
zˉfTz˙f\bar z_f^T\dot z_f输入端input side−0.027053385−0.037378968−0.018764767
边界面 f=0f=0,种子 Rˉ=ψ\bar R=\psiBoundary face f=0f=0, seed Rˉ=ψ\bar R=\psi
量Quantity公式Formula一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
Hˉ0\bar H_0−ψ0-\psi_00.9260600.9242540.959257
qˉL+UˉL\bar q_L+\bar U_L(cL+κ0)Hˉ0→uˉin(c_L+\kappa_0)\bar H_0\to\bar u_{\rm in}1.4978301.4949091.551524
qˉR+UˉR\bar q_R+\bar U_R(cR−κ0)Hˉ0→Uˉ0(c_R-\kappa_0)\bar H_0\to\bar U_0−0.596994−0.598616−0.616804
νˉ\bar\nu−UR−ULd0Hˉ0-\frac{U_R-U_L}{d_0}\bar H_0−1.716338−1.623825−1.828763
Hˉ0H˙0\bar H_0\dot H_0输出端output side−0.731791340−0.710623290−0.766322900
zˉ0Tz˙0\bar z_0^T\dot z_0输入端input side−0.731791340−0.710623290−0.766322900

面 0 的左边没有单元:Hˉ0=−Rˉ0=−ψ0\bar H_0=-\bar R_0=-\psi_0,左侧输入的伴随归入边界值,uˉin+=qˉL+UˉL\bar u_{\rm in}\mathrel{\text{+=}}\bar q_L+\bar U_L。每个面上输出端与输入端在舍入误差内相等,这就是局部对偶。对整个代码求和时它有了意义:v0v_0 解出切线方程,所以 R˙=0\dot R=0;ψ\psi 解出伴随方程,所以 𝐔ˉ=ATψ=−g\bar{\mathbf U}=A^T\psi=-g。恒等式变成 0=RˉTR˙=−gTv0+Dˉ00=\bar R^T\dot R=-g^Tv_0+\bar D_0,即 Dˉ0=gTv0\bar D_0=g^Tv_0,也就是说,伴随给出的梯度分量等于前向给出的方向导数。无限制器线性时两者都是 −0.486650-0.486650(一阶 −0.745986-0.745986,光滑限制器 −0.656527-0.656527);三种重构、三个分量上 Dˉk\bar D_k 与 gTvkg^Tv_k 相差不超过 7.3×10−167.3\times10^{-16}。

Face 0 has no cell on its left: Hˉ0=−Rˉ0=−ψ0\bar H_0=-\bar R_0=-\psi_0, and the adjoints of the left inputs go to the boundary value, uˉin+=qˉL+UˉL\bar u_{\rm in}\mathrel{\text{+=}}\bar q_L+\bar U_L. On each face the output and the input side agree to rounding: the local duality. Summed over the whole code it carries meaning: v0v_0 solves the tangent equation, so R˙=0\dot R=0; ψ\psi solves the adjoint equation, so 𝐔ˉ=ATψ=−g\bar{\mathbf U}=A^T\psi=-g. The identity then reads 0=RˉTR˙=−gTv0+Dˉ00=\bar R^T\dot R=-g^Tv_0+\bar D_0, that is Dˉ0=gTv0\bar D_0=g^Tv_0: the gradient component from the adjoint equals the directional derivative from the tangent. For the unlimited linear reconstruction both are −0.486650-0.486650 (first order −0.745986-0.745986, smooth limiter −0.656527-0.656527); over the three reconstructions and the three components Dˉk\bar D_k and gTvkg^Tv_k differ by at most 7.3×10−167.3\times10^{-16}.

点积检验

The dot test

对偶恒等式也是检验反向代码的标准方法:取随机种子 (𝐔˙,D˙)(\dot{\mathbf U},\dot D) 和 Rˉ\bar R,用前向代码算 R˙\dot R,用反向代码算 (𝐔ˉ,Dˉ)(\bar{\mathbf U},\bar D);两边必须在舍入误差内相等,而反向语句中一处错误的转置会让两边相差远大于舍入误差。种子要随机:例如取 D˙=0\dot D=0 时,Dˉ\bar D 里的错误根本看不见。图 29 用一组固定的(非随机)种子把它拆成三个层次:残差层 ∑iRˉiR˙i\sum_i\bar R_i\dot R_i;面层 ∑fHˉfH˙f+∑fQˉfQ˙f\sum_f\bar H_f\dot H_f+\sum_f\bar Q_f\dot Q_f(因为 R=ℬ(H−Q)R=\mathcal B(H-Q));输入层 ∑jUˉjU˙j+∑kDˉkD˙k\sum_j\bar U_j\dot U_j+\sum_k\bar D_k\dot D_k。逐项不同,总和在舍入误差内相同。

The duality identity is also the standard test of a reverse code: take random seeds (𝐔˙,D˙)(\dot{\mathbf U},\dot D) and Rˉ\bar R, run the forward code for R˙\dot R and the reverse code for (𝐔ˉ,Dˉ)(\bar{\mathbf U},\bar D); the two sides must agree to rounding, and one wrong transpose in the reverse statements makes them differ far beyond rounding. The seeds must be random: with D˙=0\dot D=0, for instance, an error in Dˉ\bar D would be invisible. Figure 29 splits it into three levels with deterministic seeds: the residual level ∑iRˉiR˙i\sum_i\bar R_i\dot R_i; the face level ∑fHˉfH˙f+∑fQˉfQ˙f\sum_f\bar H_f\dot H_f+\sum_f\bar Q_f\dot Q_f (because R=ℬ(H−Q)R=\mathcal B(H-Q)); and the input level ∑jUˉjU˙j+∑kDˉkD˙k\sum_j\bar U_j\dot U_j+\sum_k\bar D_k\dot D_k. Term by term the levels differ; the totals agree to rounding.

图 29 · 点积检验的三个层次(默认设计,无限制器线性;种子 U-dot_j=sin(j+0.3),D-dot=(1,1,1),R-bar_i=cos(i+0.4))。上:残差层各项 R-bar_iR-dot_i;中:面层各项 H-bar_fH-dot_f 与 Q-bar_fQ-dot_f;下:输入层各项 U-bar_jU-dot_j 与 D-bar_kD-dot_k。三层的项各不相同,三个总和都是 9.579980571112。同一个内积,三个层次:逐项不同,总和相同残差层R̄i​ Ṙi​01234567Σ =9.579980571112面层H̄f​ Ḣf​, Q̄f​ Q̇f​012345678012345678H̄f​ Ḣf​Q̄f​ Q̇f​Σ =9.579980571112输入层Ūj​ U̇j​, D̄k​ Ḋk​01234567aφνŪj​ U̇j​D̄k​ Ḋk​Σ =9.579980571112
图 29 · 点积检验的三个层次(默认设计,无限制器线性;种子 U˙j=sin⁡(j+0.3)\dot U_j=\sin(j+0.3),D˙=(1,1,1)\dot D=(1,1,1),Rˉi=cos⁡(i+0.4)\bar R_i=\cos(i+0.4))。上:残差层各项 RˉiR˙i\bar R_i\dot R_i;中:面层各项 HˉfH˙f\bar H_f\dot H_f 与 QˉfQ˙f\bar Q_f\dot Q_f;下:输入层各项 UˉjU˙j\bar U_j\dot U_j 与 DˉkD˙k\bar D_k\dot D_k。三层的项各不相同,三个总和都是 9.5799805711129.579980571112。
Figure 29 · The dot test at three levels (default design, unlimited linear; seeds U-dot_j=sin(j+0.3), D-dot=(1,1,1), R-bar_i=cos(i+0.4)). Top: the residual-level terms R-bar_iR-dot_i; middle: the face-level terms H-bar_fH-dot_f and Q-bar_fQ-dot_f; bottom: the input-level terms U-bar_jU-dot_j and D-bar_kD-dot_k. The terms of the three levels differ; the three totals are all 9.579980571112.One inner product at three levels: different terms, the same totalresidualR̄i​ Ṙi​01234567Σ =9.579980571112faceH̄f​ Ḣf​, Q̄f​ Q̇f​012345678012345678H̄f​ Ḣf​Q̄f​ Q̇f​Σ =9.579980571112inputŪj​ U̇j​, D̄k​ Ḋk​01234567aφνŪj​ U̇j​D̄k​ Ḋk​Σ =9.579980571112
Figure 29 · The dot test at three levels (default design, unlimited linear; seeds U˙j=sin⁡(j+0.3)\dot U_j=\sin(j+0.3), D˙=(1,1,1)\dot D=(1,1,1), Rˉi=cos⁡(i+0.4)\bar R_i=\cos(i+0.4)). Top: the residual-level terms RˉiR˙i\bar R_i\dot R_i; middle: the face-level terms HˉfH˙f\bar H_f\dot H_f and QˉfQ˙f\bar Q_f\dot Q_f; bottom: the input-level terms UˉjU˙j\bar U_j\dot U_j and DˉkD˙k\bar D_k\dot D_k. The terms of the three levels differ; the three totals are all 9.5799805711129.579980571112.

实验在当前网格、重构和设计上用随机种子重复它,还可以植入手写伴随代码里常见的错误。在默认设计下,对实验的全部网格与种子(N=8N=8 到 128128、三种重构、每种 20 组种子),正确代码两边的相对差至多为 5×10−145\times10^{-14};植入错误后,两边的相对差在 3×10−53\times10^{-5} 到 2.02.0 之间(最小的是漏掉 νˉ\bar\nu:它只影响一个设计分量)。实验也说明为什么正序运行面循环不是错误,以及一阶时漏掉斜率的倒转为什么不会被发现(σ≡0\sigma\equiv0)。

The lab repeats it with random seeds on the current mesh, reconstruction and design. It also lets you plant one of the bugs a hand-written adjoint typically has. At the default design, over the lab's meshes and seeds (N=8N=8 to 128128, the three reconstructions, 20 seed sets each) the two sides of the correct code differ by at most 5×10−145\times10^{-14} (relative), those of the planted bugs by between 3×10−53\times10^{-5} and 2.02.0 (the smallest is the forgotten νˉ\bar\nu, which affects one design component only). The lab also shows why running the faces in forward order is not a bug, and why forgetting the slope reversal goes unnoticed at first order (σ≡0\sigma\equiv0).

点积检验只能说明反向代码是前向代码的转置,不能说明二者都是残差的导数:如果两者漏掉同一项(比如斜率),检验照样通过。第 8 节中前向导数与差商的对比,以及第 14 节的复数步长,都把前向代码与残差本身对照。

The dot test checks that the reverse code is the transpose of the forward code, not that either is the derivative of the residual: if both forget the same term (say, the slopes) the test still passes. The comparison with finite differences in Section 8 and the complex step of Section 14 check the forward code against the residual itself.

一列与一行:同一个矩阵的两种读法

A column and a row: one matrix read two ways

取种子 𝐔˙=ej\dot{\mathbf U}=e_j,一次前向扫描返回 AA 的第 jj 列(第 8 节);取种子 Rˉ=ei\bar R=e_i,一次反向扫描返回 𝐔ˉ=ATei\bar{\mathbf U}=A^Te_i,即 AA 的第 ii 行,以及 Dˉ=RDTei\bar D=R_D^Te_i,即 RDR_D 的第 ii 行。NN 次前向扫描或 NN 次反向扫描得到同一个矩阵,一个按列读,一个按行读。实验逐步做两种扫描并逐元素比较。前向模式适合输入少、输出多的情形,反向模式适合输入多、输出少的情形:一个目标、许多设计变量。

With the seed 𝐔˙=ej\dot{\mathbf U}=e_j one forward sweep returns column jj of AA (Section 8); with the seed Rˉ=ei\bar R=e_i one reverse sweep returns 𝐔ˉ=ATei\bar{\mathbf U}=A^Te_i, row ii of AA, and Dˉ=RDTei\bar D=R_D^Te_i, row ii of RDR_D. NN forward sweeps or NN reverse sweeps build the same matrix, read by columns or by rows. The lab steps through both and compares them entry by entry. Forward mode suits few inputs and many outputs, reverse mode many inputs and few outputs: one objective and many design variables.

解出来的伴随,以及它省下的代价

The solved adjoint, and what it saves

目标沿设计方向的导数是 J˙h=gTv\dot J_h=g^Tv,其中 Av=−RDD˙Av=-R_D\dot D(第 8 节)。写成 v=−A−1RDD˙v=-A^{-1}R_D\dot D,再把逆矩阵移到内积的另一边:J˙h=−gTA−1RDD˙=ψTRDD˙\dot J_h=-g^TA^{-1}R_D\dot D=\psi^TR_D\dot D,其中 ψ=−A−Tg\psi=-A^{-T}g,也就是

The derivative of the objective along a design direction is J˙h=gTv\dot J_h=g^Tv with Av=−RDD˙Av=-R_D\dot D (Section 8). Write v=−A−1RDD˙v=-A^{-1}R_D\dot D and move the inverse to the other side of the dot product: J˙h=−gTA−1RDD˙=ψTRDD˙\dot J_h=-g^TA^{-1}R_D\dot D=\psi^TR_D\dot D with ψ=−A−Tg\psi=-A^{-T}g, that is

ATψ=−g,g=(∂Jh∂𝐔)T=w,dJh/dD=ψTRD.A^T\psi=-g,\qquad g=\Big(\frac{\partial J_h}{\partial\mathbf U}\Big)^T=w,\qquad \mathrm dJ_h/\mathrm dD=\psi^TR_D.

(JhJ_h 不直接依赖设计,所以梯度里没有 ∂Jh/∂D\partial J_h/\partial D 一项。)反向代码提供这个乘积:以 Rˉ=ψ\bar R=\psi 为种子,它返回 𝐔ˉ=ATψ\bar{\mathbf U}=A^T\psi(在解处等于 −g-g,可作检验:三种重构的最大偏差是 7.8×10−167.8\times10^{-16})和 Dˉ=RDTψ\bar D=R_D^T\psi,即梯度行的转置:一次扫描得到全部三个分量。前向代码每个设计分量需要一次扫描(以及一次求解 Avk=−RDekAv_k=-R_De_k,第 10 节);反向代码不论有多少设计变量,只需一次伴随求解和一次扫描。这里有 3 个分量,所以是 3 比 1;对于有几百个设计变量的外形设计,就是几百比 1。第 11 节解伴随方程,第 12 节按设计进入残差的位置拆分梯度。下面的实验在你的浏览器里测量一次扫描相当于几次残差计算。

(JhJ_h has no direct design dependence, so the gradient has no ∂Jh/∂D\partial J_h/\partial D term.) The reverse code supplies the product: seeded with Rˉ=ψ\bar R=\psi it returns 𝐔ˉ=ATψ\bar{\mathbf U}=A^T\psi (equal to −g-g at the solution, a check: the largest deviation over the three reconstructions is 7.8×10−167.8\times10^{-16}) and Dˉ=RDTψ\bar D=R_D^T\psi, the transpose of the gradient row: all three components from one sweep. The forward code needs one sweep per design component (and one solve Avk=−RDekAv_k=-R_De_k each, Section 10); the reverse code needs one adjoint solve and one sweep, whatever the number of design variables. Here there are 3 components, so the saving is 3 to 1; for a shape with hundreds of design variables it is hundreds to one. Section 11 solves the adjoint equation, and Section 12 splits the gradient by the places where the design enters the residual. The lab below measures, in your browser, how many residual evaluations one sweep costs.

从前向到伴随:转置让语句倒着执行

From tangent to adjoint: the transpose runs the statements backwards

先说明反向累加为什么给出矩阵的转置:展平之后,下面只是交换两个有限和(Dˉ\bar D 同理):

First, why reverse accumulation gives the matrix transpose: after flattening, the following merely exchanges two finite sums (Dˉ\bar D alike):

RˉTR˙=∑i∑jRˉi ∂Ri∂Uj U˙j=∑jU˙j(∑i∂Ri∂UjRˉi)=𝐔˙T(ATRˉ).\bar R^T\dot R=\sum_i\sum_j\bar R_i\,\frac{\partial R_i}{\partial U_j}\,\dot U_j=\sum_j\dot U_j\Big(\sum_i\frac{\partial R_i}{\partial U_j}\bar R_i\Big)=\dot{\mathbf U}^T\big(A^T\bar R\big).

一个面的前向导数是四个初等 Jacobian 的乘积(第 8 节)。乘积的转置是各转置按相反顺序相乘:

The tangent of one face is the product of four elementary Jacobians (Section 8). The transpose of a product is the product of the transposes in the reverse order:

AfT=(ℬ:,fHz,fZf𝒢f)T=𝒢fTZfTHz,fTℬ:,fT,(ℬ:,fHz,fKf)T=KfTHz,fTℬ:,fT.A_f^T=\big(\mathcal B_{:,f}H_{z,f}Z_f\mathcal G_f\big)^T=\mathcal G_f^TZ_f^TH_{z,f}^T\mathcal B_{:,f}^T,\qquad \big(\mathcal B_{:,f}H_{z,f}K_f\big)^T=K_f^TH_{z,f}^T\mathcal B_{:,f}^T.

从右往左读,就是反向扫描的顺序:程序最后执行的分发最先倒转,最先执行的取值最后倒转。把所有伴随置零,以 Rˉ\bar R 为种子,对每个面执行:

Read from right to left, this is the order of the reverse sweep: the scatter, which the program ran last, comes first, and the gather, which it ran first, comes last. Zero every adjoint, seed with Rˉ\bar R, and run for every face:

(0) 𝐔ˉ←0, Dˉ←0;(4′) Hˉf=ℬ:,fTRˉ=Rˉf−1−Rˉf;(3′) zˉf=Hz,fTHˉf;(2′) 𝐮ˉf=ZfTzˉf,  Dˉ+=KfTzˉf;(1′) 𝐔ˉ+=𝒢fT𝐮ˉf,(0)\ \bar{\mathbf U}\leftarrow0,\ \bar D\leftarrow0;\qquad (4')\ \bar H_f=\mathcal B_{:,f}^T\bar R=\bar R_{f-1}-\bar R_f;\qquad (3')\ \bar z_f=H_{z,f}^T\bar H_f;\qquad (2')\ \bar{\mathbf u}_f=Z_f^T\bar z_f,\ \ \bar D\mathrel{\text{+=}}K_f^T\bar z_f;\qquad (1')\ \bar{\mathbf U}\mathrel{\text{+=}}\mathcal G_f^T\bar{\mathbf u}_f,

源项行 R-=SR\mathrel{\text{-=}}S 也按同样的规则倒转:Sˉ=−Rˉ\bar S=-\bar R,Dˉ+=(∂S/∂D)TSˉ\bar D\mathrel{\text{+=}}(\partial S/\partial D)^T\bar S(没有状态项:∂S/∂𝐔=0\partial S/\partial\mathbf U=0)。对偶恒等式逐级成立:每一步用一次转置的定义,把一个初等 Jacobian 移到内积的另一边,所以每一级的内积都相同:

The source rows R-=SR\mathrel{\text{-=}}S are reversed by the same rule: Sˉ=−Rˉ\bar S=-\bar R, Dˉ+=(∂S/∂D)TSˉ\bar D\mathrel{\text{+=}}(\partial S/\partial D)^T\bar S (no state term: ∂S/∂𝐔=0\partial S/\partial\mathbf U=0). The duality identity holds stage by stage: each step uses the definition of the transpose once to move one elementary Jacobian across the dot product, so the inner product is the same at every stage:

RˉT(ℬ:,fH˙f)=HˉfH˙f=HˉfHz,fz˙f=zˉfTz˙f=𝐮ˉfT𝐮˙f+(KfTzˉf)TD˙=(𝒢fT𝐮ˉf)T𝐔˙+(KfTzˉf)TD˙.\bar R^T\big(\mathcal B_{:,f}\dot H_f\big)=\bar H_f\dot H_f=\bar H_fH_{z,f}\dot z_f=\bar z_f^T\dot z_f=\bar{\mathbf u}_f^T\dot{\mathbf u}_f+\big(K_f^T\bar z_f\big)^T\dot D=\big(\mathcal G_f^T\bar{\mathbf u}_f\big)^T\dot{\mathbf U}+\big(K_f^T\bar z_f\big)^T\dot D.

对所有面求和,再加上源项一对 SˉTS˙\bar S^T\dot S,右边正好累加成反向扫描的输出:RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D。

Summed over the faces, with the source pair SˉTS˙\bar S^T\dot S added, the right side accumulates exactly into the outputs of the reverse sweep: RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D.

算例:面 4 的反向扫描,种子 Rˉ=ψ\bar R=\psi,与第 8 节末尾的前向算例(种子 (v1,e1)(v_1,e_1),相位)配对。最后一列是每一级的内积;第一级 RˉT(ℬ:,4H˙4)\bar R^T(\mathcal B_{:,4}\dot H_4) 只用面 4 对第 3、4 行的贡献 ±H˙4\pm\dot H_4,而不是完整的 R˙3,R˙4\dot R_3,\dot R_4(后者在这个种子下为零):

A worked example: the reverse sweep of face 4 with the seed Rˉ=ψ\bar R=\psi, paired with the forward example at the end of Section 8 (seed (v1,e1)(v_1,e_1), the phase). The last column is the inner product at each stage; the first stage, RˉT(ℬ:,4H˙4)\bar R^T(\mathcal B_{:,4}\dot H_4), uses face 4's contributions ±H˙4\pm\dot H_4 to rows 3 and 4 only, not the full R˙3,R˙4\dot R_3,\dot R_4 (which vanish for this seed):

语句Statement量Quantity伴随值Adjoint内积Inner product
(0)置零(0) zero𝐔ˉ←0, Dˉ←0\bar{\mathbf U}\leftarrow0,\ \bar D\leftarrow00
(4′)种子(4′) seedRˉ3=ψ3, Rˉ4=ψ4\bar R_3=\psi_3,\ \bar R_4=\psi_4−1.01778, −0.82746RˉT(ℬ:,4H˙4)=\bar R^T(\mathcal B_{:,4}\dot H_4)= −0.2202519868
(4′)取值(4′) gatherHˉ4=Rˉ3−Rˉ4\bar H_4=\bar R_3-\bar R_4−0.190320Hˉ4H˙4=\bar H_4\dot H_4= −0.2202519868
(3′)通量的转置(3′) flux, transposedqˉL, qˉR\bar q_L,\ \bar q_R−0.286707, 0.096276zˉ4Tz˙4=\bar z_4^T\dot z_4= −0.2202519868
UˉL, UˉR, νˉ\bar U_L,\ \bar U_R,\ \bar\nu−0.015226, 0.015226, −0.230334
(2′)(1′)加回(2′)(1′) add backUˉ2, Uˉ3+=\bar U_2,\ \bar U_3\mathrel{\text{+=}}0.071677, −0.277863𝐮ˉ4T𝐮˙4+DˉTD˙=\bar{\mathbf u}_4^T\dot{\mathbf u}_4+\bar D^T\dot D= −0.2202519868
Uˉ4, Uˉ5+=\bar U_4,\ \bar U_5\mathrel{\text{+=}}0.039824, −0.024069
φˉ+=\bar\varphi\mathrel{\text{+=}}0

四个内积在舍入误差内相等(最大相对差 7.6×10−167.6\times10^{-16}),对偶在这个面上逐级成立。面 4 不直接依赖 φ\varphi,所以它对 Dˉ1\bar D_1 的贡献是 0;φ\varphi 只经过边界面和源项行进入 Dˉ\bar D。这个面的 νˉ\bar\nu 虽然不为零,但种子 D˙=e1\dot D=e_1 的 ν˙=0\dot\nu=0,所以 νˉ\bar\nu 不进入这里的内积。下面的播放器对任意面重放这四步,并在每一步显示内积。

The four inner products agree to rounding (largest relative difference 7.6×10−167.6\times10^{-16}): the duality holds stage by stage on this face. Face 4 does not depend on φ\varphi directly, so its contribution to Dˉ1\bar D_1 is 0; the phase reaches Dˉ\bar D only through the boundary faces and the source rows. The νˉ\bar\nu of this face is not zero, but the seed D˙=e1\dot D=e_1 has ν˙=0\dot\nu=0, so it does not enter these inner products. The player below replays the four steps for any face and shows the inner product at each.

第 10 节Section 10

前向求解:解随设计怎样变化

The tangent solve: how the solution moves with the design

本节实验:振幅 aa 增加 0.010.01 时,N=8N=8 网格上的每个 UiU_i 变化多少?JhJ_h 又变化多少?先猜哪几个单元变化最大,再读图 30,并用本节的前向求解面板核对。

Experiment: If the amplitude aa grows by 0.010.01, how much does each UiU_i of the N=8N=8 mesh move, and how much does JhJ_h move? Guess which cells move most, then read Figure 30 and check the guess in this section's tangent-solve panel.

第 8 节逐条语句地对残差代码求导:给定种子 𝐔˙\dot{\mathbf U} 与 D˙\dot D,前向代码返回 R˙=A𝐔˙+RDD˙\dot R=A\dot{\mathbf U}+R_D\dot D。它算的是一个乘积,还没有回答“设计变了,解怎样变”。本节用同一段代码来回答这个问题:设计沿 D˙\dot D 移动时,什么样的 𝐔˙\dot{\mathbf U} 能让残差一直保持为零?

Section 8 differentiated the residual code statement by statement: for seeds 𝐔˙\dot{\mathbf U} and D˙\dot D the tangent code returns R˙=A𝐔˙+RDD˙\dot R=A\dot{\mathbf U}+R_D\dot D. That is a product; it does not yet say how the solution moves when the design moves. This section puts that question to the same code: when the design moves along D˙\dot D, which 𝐔˙\dot{\mathbf U} keeps the residual at zero?

从前向代码到一个线性方程组

From the tangent code to one linear system

收敛解随设计变化:在默认设计附近,每个设计 DD 都有自己的离散解 𝐔(D)\mathbf U(D),满足 R(𝐔(D),D)=0R(\mathbf U(D),D)=0(Newton 迭代求出它,第 5 节)。让设计沿直线 D+t ekD+t\,e_k 移动,eke_k 是第 kk 个分量的单位向量(k=0,1,2k=0,1,2 依次对应 a,φ,νa,\varphi,\nu),tt 是实数。残差对每个 tt 都是零,所以它对 tt 的导数也是零。在 t=0t=0 用链式法则求导——这正是对整个求解过程使用前向模式——得到两项:

The converged state depends on the design: near the default, every design DD has its own discrete solution 𝐔(D)\mathbf U(D) with R(𝐔(D),D)=0R(\mathbf U(D),D)=0 (Newton's method finds it, Section 5). Move the design along the straight line D+t ekD+t\,e_k, where eke_k is the unit vector of component kk (k=0,1,2k=0,1,2 for a,φ,νa,\varphi,\nu) and tt is a real number. The residual is zero for every tt, so its derivative with respect to tt is zero as well. The chain rule at t=0t=0, which is the forward mode applied to the whole solve, gives two terms:

0=ddtR(𝐔(D+t ek), D+t ek)∣t=0=A vk+RD ek,vk=∂𝐔∂Dk.0=\frac{\mathrm d}{\mathrm dt}R\bigl(\mathbf U(D+t\,e_k),\,D+t\,e_k\bigr)\Big|_{t=0}=A\,v_k+R_D\,e_k,\qquad v_k=\frac{\partial\mathbf U}{\partial D_k}.

第一项是设计经由状态产生的间接影响,第二项是设计直接改变残差的部分。于是状态切向量 vkv_k 是一个线性方程组的解:矩阵是收敛状态处的状态 Jacobian A=R𝐔A=R_{\mathbf U},右端是残差自身对设计的导数:

The first term is the indirect effect of the design through the state, the second is the direct change of the residual. So the state tangent vkv_k solves a linear system whose matrix is the state Jacobian A=R𝐔A=R_{\mathbf U} at the converged state and whose right-hand side is the residual's own design derivative:

A vk=−RD ek,k=0,1,2.A\,v_k=-R_D\,e_k,\qquad k=0,1,2.

用第 8 节的话说:vk≡𝐔˙v_k\equiv\dot{\mathbf U},种子是 D˙=ek\dot D=e_k;把 (𝐔˙,D˙)=(vk,ek)(\dot{\mathbf U},\dot D)=(v_k,e_k) 送进前向代码,返回的 R˙\dot R 是零。前向代码对给定的 𝐔˙\dot{\mathbf U} 计算 R˙\dot R,前向求解则是找出使 R˙=0\dot R=0 的那个 𝐔˙\dot{\mathbf U}。本页对 AA 做 LU 分解来解这个方程组(第 17 节改用 GS 与 GMRES)。这要求 AA 在收敛状态处非奇异:本页每个状态上分解都成功——这是数值检查,不是定理。默认设计下三次求解的线性残差 max⁡k∥Avk+RDek∥∞\max_k\|Av_k+R_De_k\|_\infty 低于 10−1510^{-15}(舍入误差)。

In the words of Section 8: vk≡𝐔˙v_k\equiv\dot{\mathbf U} for the seed D˙=ek\dot D=e_k; fed with the seeds (𝐔˙,D˙)=(vk,ek)(\dot{\mathbf U},\dot D)=(v_k,e_k), the tangent code returns R˙=0\dot R=0. The tangent code evaluates R˙\dot R for a given 𝐔˙\dot{\mathbf U}; the tangent solve finds the 𝐔˙\dot{\mathbf U} that makes R˙\dot R vanish. The page solves the system with an LU factorisation of AA (Section 17 uses GS and GMRES instead). This needs AA to be nonsingular at the converged state: the factorisation succeeds at every state of this page, a numerical check rather than a theorem. At the default design the linear residual of the three solves, max⁡k∥Avk+RDek∥∞\max_k\|Av_k+R_De_k\|_\infty, is below 10−1510^{-15} (round-off).

vkv_k 是什么

What vkv_k is

vkv_k 有 NN 个分量:它是每个单元平均对设计分量 DkD_k 的响应,是整个离散解的灵敏度,不只是一个数。目标的导数由它得到一个数:第 7 节的 Jh=wT𝐔J_h=w^T\mathbf U 不显含设计(权重 wi=h(1+xi)w_i=h(1+x_i) 只依赖网格),所以 JD=0J_D=0,导数就是加权和

vkv_k has NN entries: it is the response of every cell average to the design component DkD_k, the sensitivity of the whole discrete solution and not of one number. One number follows from it. The objective Jh=wT𝐔J_h=w^T\mathbf U of Section 7 does not contain the design explicitly (the weights wi=h(1+xi)w_i=h(1+x_i) depend on the mesh only), so JD=0J_D=0 and its derivative is the weighted sum

J˙k=gTvk=wTvk=dJhdDk.\dot J_k=g^Tv_k=w^Tv_k=\frac{\mathrm dJ_h}{\mathrm dD_k}.

默认设计(N=8N=8,无限制器线性重构)下三次求解给出 J˙0=−0.486650\dot J_0=−0.486650、J˙1=−0.061039\dot J_1=−0.061039、J˙2=−0.309871\dot J_2=−0.309871。它们是这个网格上离散目标 Jh(D)J_h(D) 的精确导数,与第 1 节的连续梯度 (−0.144008, 0.085156, 0.000000)(−0.144008,\ 0.085156,\ 0.000000) 相差很大(dJh/da\mathrm dJ_h/\mathrm da 相差 238%)。对 aa 来说,主要原因是两个端单元不做重构:按第 16 节的端单元实验(那里列的是这个梯度的误差,这里是它的值)重构端单元后,同一网格给出 dJh/da=−0.174\mathrm dJ_h/\mathrm da=−0.174,而不是 −0.487−0.487(精确值 −0.144−0.144)。此外,一个正弦周期只有 8 个单元,而精确梯度只是两个 O(1)O(1) 项之间很小的差(第 12 节):N=8N=8 时 dJh/da\mathrm dJ_h/\mathrm da 的源项部分与连续值相差 58%,边界部分相差 11%;N=8N=8 时黏性尺度也没被分辨,但第 16 节说明这不是主要原因(第 15 节测量梯度怎样收敛)。实验的答案在图 30 左图:aa 增加 0.010.01 时,变化最大的是 U5U_{5} 与 U6U_{6},约 −0.0117−0.0117 与 −0.0116−0.0116;JhJ_h 变化约 0.01 J˙0=−0.004870.01\,\dot J_0=−0.00487。

At the default design (N=8N=8, unlimited linear reconstruction) the three solves give J˙0=−0.486650\dot J_0=−0.486650, J˙1=−0.061039\dot J_1=−0.061039 and J˙2=−0.309871\dot J_2=−0.309871. These are the exact derivatives of the discrete objective Jh(D)J_h(D) on this mesh, and they are far from the continuous gradient (−0.144008, 0.085156, 0.000000)(−0.144008,\ 0.085156,\ 0.000000) of Section 1 (dJh/da\mathrm dJ_h/\mathrm da is 238% off). For aa the main reason is that the two end cells are not reconstructed: with them reconstructed (the experiment of Section 16, which tabulates the error of this gradient, here its value) the same mesh gives dJh/da=−0.174\mathrm dJ_h/\mathrm da=−0.174 instead of −0.487−0.487 (exact: −0.144−0.144). In addition, 8 cells per period of the sine are few, and the exact gradient is a small difference of two terms of order one (Section 12): at N=8N=8 the source part of dJh/da\mathrm dJ_h/\mathrm da is 58% off, its boundary part 11%. The viscous scale is not resolved at N=8N=8 either, but Section 16 shows that this is not the main cause (Section 15 measures how the gradients converge). The left panel of Figure 30 answers the experiment: when aa grows by 0.010.01, the cells that move most are U5U_{5} and U6U_{6}, by about −0.0117−0.0117 and −0.0116−0.0116, and JhJ_h moves by about 0.01 J˙0=−0.004870.01\,\dot J_0=−0.00487.

图 30 · 默认设计下的三个切线解(N=8):三种重构的 v_k=∂U/∂ D_k(点、圈、方块)与连续切线 ∂ u*/∂ D_k(曲线,本节末尾推导)。振幅与相位的切向量只粗略地跟随连续切线;黏性切向量 v_2 明显不为零,尽管 u* 与 ν 无关。每幅图左上角是无限制器线性重构的 J-dot_k=w^Tv_k。连续切线 ∂u*/∂Dk​无限制器线性一阶光滑限制器−1.5−1−0.500.5100.51xvk​k = 0:振幅 aJ̇0​ = −0.4866−1−0.500.5100.51xk = 1:相位 φJ̇1​ = −0.0610−0.500.500.51xk = 2:黏性 νJ̇2​ = −0.3099
图 30 · 默认设计下的三个切线解(N=8N=8):三种重构的 vk=∂𝐔/∂Dkv_k=\partial\mathbf U/\partial D_k(点、圈、方块)与连续切线 ∂u∗/∂Dk\partial u^*/\partial D_k(曲线,本节末尾推导)。振幅与相位的切向量只粗略地跟随连续切线;黏性切向量 v2v_2 明显不为零,尽管 u∗u^* 与 ν\nu 无关。每幅图左上角是无限制器线性重构的 J˙k=wTvk\dot J_k=w^Tv_k。
Figure 30 · The three tangent solutions at the default design (N=8): v_k=∂U/∂ D_k of the three reconstructions (dots, rings, squares) and the continuous tangent ∂ u*/∂ D_k (curve, derived at the end of this section). The amplitude and phase tangents follow the continuous ones only roughly; the viscosity tangent v_2 is clearly not zero although u* does not depend on ν. Each panel shows J-dot_k=w^Tv_k of the unlimited linear reconstruction at its top left.continuous tangent ∂u*/∂Dk​unlimited linearfirst ordersmooth limiter−1.5−1−0.500.5100.51xvk​k = 0: amplitude aJ̇0​ = −0.4866−1−0.500.5100.51xk = 1: phase φJ̇1​ = −0.0610−0.500.500.51xk = 2: viscosity νJ̇2​ = −0.3099
Figure 30 · The three tangent solutions at the default design (N=8N=8): vk=∂𝐔/∂Dkv_k=\partial\mathbf U/\partial D_k of the three reconstructions (dots, rings, squares) and the continuous tangent ∂u∗/∂Dk\partial u^*/\partial D_k (curve, derived at the end of this section). The amplitude and phase tangents follow the continuous ones only roughly; the viscosity tangent v2v_2 is clearly not zero although u∗u^* does not depend on ν\nu. Each panel shows J˙k=wTvk\dot J_k=w^Tv_k of the unlimited linear reconstruction at its top left.

为什么 v2≠0v_2\neq0?精确解 u∗u^* 与 ν\nu 无关,离散解却有关:格式的误差依赖 ν\nu(默认网格上 uinh/ν≈11.4u_{\rm in}h/\nu\approx11.4,即网格 Péclet 数,见第 3 节的分辨率面板),ν\nu 一变,误差就变,𝐔\mathbf U 也跟着变。所以 J˙2=dJh/dν\dot J_2=\mathrm dJ_h/\mathrm d\nu 在粗网格上不为零,而连续的 dJ/dν=0\mathrm dJ/\mathrm d\nu=0;第 12 节把这个差别拆开来看。

Why is v2≠0v_2\neq0? The exact solution u∗u^* does not depend on ν\nu, but the discrete solution does: the error of the scheme depends on ν\nu (the cell Péclet number of the default mesh is uinh/ν≈11.4u_{\rm in}h/\nu\approx11.4; see the resolution panel of Section 3), so when ν\nu changes the error changes and 𝐔\mathbf U with it. That is why J˙2=dJh/dν\dot J_2=\mathrm dJ_h/\mathrm d\nu is not zero on a coarse mesh while the continuous dJ/dν=0\mathrm dJ/\mathrm d\nu=0; Section 12 takes this difference apart.

三个右端项

The three right-hand sides

右端 −RD ek-R_D\,e_k 同样由前向代码算出:取 𝐔˙=0\dot{\mathbf U}=0、D˙=ek\dot D=e_k,返回的 R˙\dot R 就是 RDekR_De_k。代码里只有三处读取设计,所以右端只有三条路径:

The right-hand side −RD ek-R_D\,e_k comes from the tangent code as well: with 𝐔˙=0\dot{\mathbf U}=0 and D˙=ek\dot D=e_k the returned R˙\dot R is RDekR_De_k. Only three places of the code read the design, so the right-hand side has three paths:

  • 源项行(a,φ,νa,\varphi,\nu):每一行都有 −(Q˙i+1−Q˙i)-(\dot Q_{i+1}-\dot Q_i),即精确通量 Qf=q∗(xf;D)Q_f=q^*(x_f;D) 的变化。它是源项导数在一个单元上的积分,大小约与 hh 成正比。Source rows (a,φ,νa,\varphi,\nu): every row has −(Q˙i+1−Q˙i)-(\dot Q_{i+1}-\dot Q_i), the change of the exact flux Qf=q∗(xf;D)Q_f=q^*(x_f;D). It is the integral of a derivative of the source over one cell, of a size proportional to hh.
  • 边界值(a,φa,\varphi):uin=uout=1−a sin⁡ 2πφu_{\rm in}=u_{\rm out}=1-a\,\sin\,2\pi\varphi 在面 00 上充当 qLq_L 和 ULU_L,在面 NN 上充当 qRq_R 和 URU_R,所以只出现在第一行和最后一行。这一项不随 hh 变小,其中的黏性部分 2ν/h2\nu/h 还随网格加密而变大。Boundary values (a,φa,\varphi): uin=uout=1−a sin⁡ 2πφu_{\rm in}=u_{\rm out}=1-a\,\sin\,2\pi\varphi serve as qLq_L and ULU_L on face 00 and as qRq_R and URU_R on face NN, so they appear in the first and the last row only. They do not shrink with hh, and their viscous part 2ν/h2\nu/h even grows as the mesh is refined.
  • 通量本身(只有 ν\nu):每个面的黏性通量 −ν(UR−UL)/df-\nu(U_R-U_L)/d_f 显含 ν\nu,偏导 −(UR−UL)/df-(U_R-U_L)/d_f 分发到面两侧的两行。The flux itself (ν\nu only): the viscous flux −ν(UR−UL)/df-\nu(U_R-U_L)/d_f of every face contains ν\nu explicitly; its partial derivative −(UR−UL)/df-(U_R-U_L)/d_f is scattered to the two rows beside the face.
图 31 · 三个右端项 -R_De_k(默认设计,无限制器线性)。上排 N=8,下排 N=64,每列共用纵轴。a 与 φ 两列的内部行(绿)是源项导数在单元上的积分,网格加密 8 倍后最大值分别缩小为原来的 1/7.3 与 1/7.7;首末两行(紫)承载边界值,并不缩小:a 列第一行从 0.060 变为 −1.091(N=8 时源项与边界值在这一行几乎抵消,黏性部分 2ν/h 随加密增大)。ν 列里通量部分与源项部分只在一些行里几乎抵消(逐行的情形见)。−1−0.500.500.51x−RD​ ek​k = 0:振幅 a,N = 8−3−2−10100.51xk = 1:相位 φ,N = 8−1−0.5000.51xk = 2:黏性 ν,N = 8−1−0.500.500.51x−RD​ ek​N = 64−3−2−10100.51xN = 64−1−0.5000.51xN = 64
图 31 · 三个右端项 −RDek-R_De_k(默认设计,无限制器线性)。上排 N=8N=8,下排 N=64N=64,每列共用纵轴。aa 与 φ\varphi 两列的内部行(绿)是源项导数在单元上的积分,网格加密 8 倍后最大值分别缩小为原来的 1/7.3 与 1/7.7;首末两行(紫)承载边界值,并不缩小:aa 列第一行从 0.0600.060 变为 −1.091−1.091(N=8N=8 时源项与边界值在这一行几乎抵消,黏性部分 2ν/h2\nu/h 随加密增大)。ν\nu 列里通量部分与源项部分只在一些行里几乎抵消(逐行的情形见第 12 节)。
Figure 31 · The three right-hand sides -R_De_k (default design, unlimited linear). Top row N=8, bottom row N=64; each column shares its vertical axis. The interior rows of the a and φ columns (green) are integrals of a source derivative over a cell; under eightfold refinement their largest entry shrinks by a factor of 7.3 and 7.7. The first and the last row (violet) carry the boundary values and do not shrink: the first entry of the a column goes from 0.060 to −1.091 (at N=8 the source and the boundary value nearly cancel in this row, and the viscous part 2ν/h grows under refinement). In the ν column the flux part and the source part nearly cancel only in some of the rows ( goes row by row).−1−0.500.500.51x−RD​ ek​k = 0: amplitude a, N = 8−3−2−10100.51xk = 1: phase φ, N = 8−1−0.5000.51xk = 2: viscosity ν, N = 8−1−0.500.500.51x−RD​ ek​N = 64−3−2−10100.51xN = 64−1−0.5000.51xN = 64
Figure 31 · The three right-hand sides −RDek-R_De_k (default design, unlimited linear). Top row N=8N=8, bottom row N=64N=64; each column shares its vertical axis. The interior rows of the aa and φ\varphi columns (green) are integrals of a source derivative over a cell; under eightfold refinement their largest entry shrinks by a factor of 7.3 and 7.7. The first and the last row (violet) carry the boundary values and do not shrink: the first entry of the aa column goes from 0.0600.060 to −1.091−1.091 (at N=8N=8 the source and the boundary value nearly cancel in this row, and the viscous part 2ν/h2\nu/h grows under refinement). In the ν\nu column the flux part and the source part nearly cancel only in some of the rows (Section 12 goes row by row).

为什么首末两行较大的右端项会影响整个解?vk=A−1(−RDek)v_k=A^{-1}(-R_De_k) 是一个叠加:右端项的第 jj 个分量就像加在单元 jj 上的一份源项,A−1A^{-1} 的第 jj 列是状态对单元 jj 上单位源项的响应(Av=ejAv=e_j)。图 32 画出 N=16N=16 时的 A−1A^{-1}:源项几乎只向下游(矩阵对角线以下、剖面的右侧)改变状态——单元 5 的源项使下游各单元变化 0.57–1.33,上游各单元最多变化 0.043(单元 5 自身变化的 6.6%);靠近出口时响应回落,因为 uoutu_{\rm out} 是给定的。所以第一行的右端项(入口处的边界值)影响整个区间,最后一行的右端项只影响出口附近。

Why do the large first and last right-hand-side entries affect the whole solution? vk=A−1(−RDek)v_k=A^{-1}(-R_De_k) is a superposition: the jj-th entry of the right-hand side acts like a portion of source added in cell jj, and column jj of A−1A^{-1} is the response of the state to one unit of source in cell jj (Av=ejAv=e_j). Figure 32 draws A−1A^{-1} for N=16N=16: a source changes the state mainly downstream (below the diagonal of the matrix, to the right in the profiles): a source in cell 5 moves the downstream cells by 0.57–1.33 and the upstream cells by at most 0.043 (6.6% of the cell's own response); near the outlet the response falls back because uoutu_{\rm out} is prescribed. So the first right-hand-side entry (the inlet value) acts on the whole interval, the last one only near the outlet.

图 32 · 影响矩阵 A^(-1)(N=16,无限制器线性,默认设计;蓝正橙负)。左:(A^(-1))_ij 是单元 j 加一份单位源项时 U_i 的变化;右:第 0、5、10 列的剖面。u>0,信息向下游传播,上游各单元变化小得多:源项在单元 2–9 时,上游的最大变化是该单元自身变化的 6–8%;源项越靠近两端,这个比例越大(最多 22%)。用同一个矩阵解释伴随:-ψ_j=w^TA^(-1)e_j 就是第 j 列按目标权重的和(数值上相差不到 10^(-14))。051015051015A−1​第 j 列:单元 j 加单位源项时的响应列 j(加源项的单元)行 i(响应的单元)00.20.40.60.811.21.400.250.50.751x三列的剖面:源项向下游传播j = 0j = 5j = 10
图 32 · 影响矩阵 A−1A^{-1}(N=16N=16,无限制器线性,默认设计;蓝正橙负)。左:(A−1)ij(A^{-1})_{ij} 是单元 jj 加一份单位源项时 UiU_i 的变化;右:第 0、5、10 列的剖面。u>0u>0,信息向下游传播,上游各单元变化小得多:源项在单元 2–9 时,上游的最大变化是该单元自身变化的 6–8%;源项越靠近两端,这个比例越大(最多 22%)。第 11 节用同一个矩阵解释伴随:−ψj=wTA−1ej-\psi_j=w^TA^{-1}e_j 就是第 jj 列按目标权重的和(数值上相差不到 10−1410^{-14})。
Figure 32 · The influence matrix A^(-1) (N=16, unlimited linear, default design; blue positive, orange negative). Left: (A^(-1))_ij is the change of U_i when cell j receives one unit of extra source; right: columns 0, 5 and 10 as profiles. Information travels downstream with u>0; the upstream cells change much less: by 6–8% of the cell's own response for a source in cells 2–9, more towards both ends (up to 22%). uses the same matrix to explain the adjoint: -ψ_j=w^TA^(-1)e_j is the objective-weighted sum of column j (numerically within 10^(-14)).051015051015A−1​column j: response to a unit source in cell jcolumn j (cell with the source)row i (responding cell)00.20.40.60.811.21.400.250.50.751xthree columns as profiles: a source acts downstreamj = 0j = 5j = 10
Figure 32 · The influence matrix A−1A^{-1} (N=16N=16, unlimited linear, default design; blue positive, orange negative). Left: (A−1)ij(A^{-1})_{ij} is the change of UiU_i when cell jj receives one unit of extra source; right: columns 0, 5 and 10 as profiles. Information travels downstream with u>0u>0; the upstream cells change much less: by 6–8% of the cell's own response for a source in cells 2–9, more towards both ends (up to 22%). Section 11 uses the same matrix to explain the adjoint: −ψj=wTA−1ej-\psi_j=w^TA^{-1}e_j is the objective-weighted sum of column jj (numerically within 10−1410^{-14}).

第 12 节把每一列拆成这些路径,并跟踪每条路径对梯度的贡献。下面的面板对当前设计做完整的前向求解,并用两次完整的非线性重解检查 vkv_k:中心差商 (𝐔(D+τek)−𝐔(D−τek))/(2τ)(\mathbf U(D+\tau e_k)-\mathbf U(D-\tau e_k))/(2\tau),步长取 τ=1×10−6\tau=1\times10^{-6},这个值本身并无特别之处。默认设计下三种重构、三个分量的最大差低于 10−910^{-9}(第 13 节研究步长的选择)。

Section 12 splits every column into these paths and follows each into the gradient. The panel below performs the whole tangent solve for the current design and checks vkv_k against two full nonlinear re-solves: the central difference (𝐔(D+τek)−𝐔(D−τek))/(2τ)(\mathbf U(D+\tau e_k)-\mathbf U(D-\tau e_k))/(2\tau), where the step τ=1×10−6\tau=1\times10^{-6} is just a number. At the default design the largest difference over the three reconstructions and the three components is below 10−910^{-9} (Section 13 studies the choice of the step).

“切线”的含义:扰动后重新求解

What “tangent” means: perturb and re-solve

切线解是一个预测:对很小的 tt,𝐔(D+t ek)≈𝐔+t vk\mathbf U(D+t\,e_k)\approx\mathbf U+t\,v_k。验证它只需要非线性求解器本身:在 D+t ekD+t\,e_k 上重新完整求解,再与预测比较。残差是 𝐔\mathbf U 与 DD 的光滑函数,AA 非奇异,所以 𝐔(D)\mathbf U(D) 光滑(隐函数定理),余项是二阶的:

The tangent solution is a prediction: for small tt, 𝐔(D+t ek)≈𝐔+t vk\mathbf U(D+t\,e_k)\approx\mathbf U+t\,v_k. Checking it needs nothing but the nonlinear solver: solve the full equations again at D+t ekD+t\,e_k and compare with the prediction. The residual is a smooth function of 𝐔\mathbf U and DD and AA is nonsingular, so 𝐔(D)\mathbf U(D) is smooth (implicit function theorem) and the remainder is of second order:

𝐔(D+t ek)=𝐔(D)+t vk+O(t2).\mathbf U(D+t\,e_k)=\mathbf U(D)+t\,v_k+O(t^2).

tt 很小时,把 tt 减半,误差约变为原来的四分之一(在本页测试的范围内,相邻两个步长的误差之比在 3.65–4.37 之间)。默认设计(N=8N=8,无限制器线性)下,在 ∣t∣≤0.15|t|\le0.15(aa)、∣t∣≤0.25|t|\le0.25(φ\varphi)、∣t∣≤0.008|t|\le0.008(ν\nu)范围内,比值 ∥𝐔(D+t ek)−𝐔−t vk∥∞/t2\|\mathbf U(D+t\,e_k)-\mathbf U-t\,v_k\|_\infty/t^2 分别停留在 0.45–0.60、4.13–4.85、8.7–10.3:在双对数图里误差曲线的斜率接近 2,这就是“切线”的标志。在面板里选一个单元、一个步长;其后的播放器把整条剖面做成动画。

For small tt, halving tt divides the error by about four (by 3.65–4.37 in the range tested here). At the default design (N=8N=8, unlimited linear), for ∣t∣≤0.15|t|\le0.15 (aa), ∣t∣≤0.25|t|\le0.25 (φ\varphi) and ∣t∣≤0.008|t|\le0.008 (ν\nu), the ratio ∥𝐔(D+t ek)−𝐔−t vk∥∞/t2\|\mathbf U(D+t\,e_k)-\mathbf U-t\,v_k\|_\infty/t^2 stays within 0.45–0.60, 4.13–4.85 and 8.7–10.3 respectively: on log–log axes the error curve has a slope close to 2, the signature of a tangent. Pick a cell and a step in the panel; the player after it animates the whole profile.

切线只在 tt 很小时才可靠:沿 φ\varphi 走 t=0.25t=0.25(四分之一个周期)时,预测与重解相差 0.2580.258。导数描述无穷小变化的响应;大步长的优化器必须重新求解。另一个常见错误是在未收敛的状态上求导:只有在 R(𝐔,D)=0R(\mathbf U,D)=0 处,Avk=−RDekAv_k=-R_De_k 才是解的导数;Newton 迭代中途的 AA 给出的是另一个函数的切线。

The tangent line is reliable only for small tt: a step t=0.25t=0.25 in φ\varphi (a quarter of the period) misses the re-solved state by 0.2580.258. A derivative describes the response to an infinitesimal change; an optimiser that takes large steps must re-solve. Another common slip is to differentiate at a state that has not converged: only where R(𝐔,D)=0R(\mathbf U,D)=0 is Avk=−RDekAv_k=-R_De_k the derivative of the solution; the AA of an intermediate Newton iterate gives the tangent of a different function.

连续切线问题

The continuous tangent

对第 1 节的连续问题用同样的方法求导,得到连续切线方程。记 uDk=∂u/∂Dku_{D_k}=\partial u/\partial D_k。对 Dk=a,φD_k=a,\varphi,只有源项与两端的给定值依赖 DkD_k;对 ν\nu,通量 q=u2/2−νuxq=u^2/2-\nu u_x 本身含 ν\nu,于是右端多出 uxxu_{xx}:

Differentiating the continuous problem of Section 1 in the same way gives the continuous tangent equations. Write uDk=∂u/∂Dku_{D_k}=\partial u/\partial D_k. For Dk=a,φD_k=a,\varphi only the source and the two end values depend on DkD_k; for ν\nu the flux q=u2/2−νuxq=u^2/2-\nu u_x contains ν\nu itself, which adds uxxu_{xx} to the right-hand side:

(u uDk−ν (uDk)x)x=sDk,uDk(0)=∂uin∂Dk,uDk(1)=∂uout∂Dk(Dk=a,φ),(u uν−ν (uν)x)x=sν+uxx,uν(0)=uν(1)=0.\begin{aligned}&\bigl(u\,u_{D_k}-\nu\,(u_{D_k})_x\bigr)_x=s_{D_k},\qquad u_{D_k}(0)=\frac{\partial u_{\rm in}}{\partial D_k},\quad u_{D_k}(1)=\frac{\partial u_{\rm out}}{\partial D_k}\qquad(D_k=a,\varphi),\\&\bigl(u\,u_\nu-\nu\,(u_\nu)_x\bigr)_x=s_\nu+u_{xx},\qquad u_\nu(0)=u_\nu(1)=0.\end{aligned}

对构造解不需要求解:u∗u^* 对每个设计都是解,所以它对设计的导数就是切线问题的解:ua∗=sin⁡ zu^*_a=\sin\,z,uφ∗=−2πa cos⁡ zu^*_\varphi=-2\pi a\,\cos\,z,uν∗=0u^*_\nu=0(解与 ν\nu 无关;事实上 sν=4π2a sin⁡ z=−uxx∗s_\nu=4\pi^2a\,\sin\,z=-u^*_{xx},右端为零)。本页用一个独立的 Chebyshev 配点求解器(M=64M=64;附录 A 用 M=160M=160)解前两个边值问题,与 ua∗u^*_a、uφ∗u^*_\varphi 的闭式相差不到 10−1310^{-13};ν\nu 的问题右端与边界值都恒为零,解自然是零,这一项检验是平凡的。离散的 vkv_k 逼近这些函数的单元平均 ⟨ua∗⟩i\langle u^*_a\rangle_i、⟨uφ∗⟩i\langle u^*_\varphi\rangle_i、⟨uν∗⟩i=0\langle u^*_\nu\rangle_i=0;图 33 与下表给出收敛情况。

For the manufactured solution no solve is needed: u∗u^* solves the problem for every design, so its derivative with respect to the design solves the tangent problem: ua∗=sin⁡ zu^*_a=\sin\,z, uφ∗=−2πa cos⁡ zu^*_\varphi=-2\pi a\,\cos\,z, uν∗=0u^*_\nu=0 (the solution does not depend on ν\nu; indeed sν=4π2a sin⁡ z=−uxx∗s_\nu=4\pi^2a\,\sin\,z=-u^*_{xx}, so the right-hand side vanishes). An independent Chebyshev collocation solver (M=64M=64; Appendix A uses M=160M=160) of the first two boundary-value problems reproduces the closed forms of ua∗u^*_a and uφ∗u^*_\varphi to within 10−1310^{-13}; for ν\nu the right-hand side and the boundary data vanish identically, so its zero solution is a trivial check. The discrete vkv_k approximate the cell averages ⟨ua∗⟩i\langle u^*_a\rangle_i, ⟨uφ∗⟩i\langle u^*_\varphi\rangle_i and ⟨uν∗⟩i=0\langle u^*_\nu\rangle_i=0 of these functions; Figure 33 and the table below show the convergence.

图 33 · 离散切线解向连续切线收敛(默认设计,无限制器线性)。N=8(圈)、32(点)、128(细线)的 v_k 与 ∂ u*/∂ D_k(粗线)。N=128 时 v_0,v_1 已与连续曲线重合;v_2 趋于零,但收敛最慢。连续:∂u*/∂Dk​N = 8N = 32N = 128−1−0.500.5100.51xvk​k = 0:振幅 a−1−0.500.511.500.51xk = 1:相位 φ−0.6−0.4−0.200.20.400.51xk = 2:黏性 ν
图 33 · 离散切线解向连续切线收敛(默认设计,无限制器线性)。N=8N=8(圈)、3232(点)、128128(细线)的 vkv_k 与 ∂u∗/∂Dk\partial u^*/\partial D_k(粗线)。N=128N=128 时 v0,v1v_0,v_1 已与连续曲线重合;v2v_2 趋于零,但收敛最慢。
Figure 33 · The discrete tangents converge to the continuous ones (default design, unlimited linear): v_k for N=8 (rings), 32 (dots) and 128 (thin line) against ∂ u*/∂ D_k (thick line). At N=128, v_0 and v_1 lie on the continuous curves; v_2 goes to zero, but most slowly.continuous: ∂u*/∂Dk​N = 8N = 32N = 128−1−0.500.5100.51xvk​k = 0: amplitude a−1−0.500.511.500.51xk = 1: phase φ−0.6−0.4−0.200.20.400.51xk = 2: viscosity ν
Figure 33 · The discrete tangents converge to the continuous ones (default design, unlimited linear): vkv_k for N=8N=8 (rings), 3232 (dots) and 128128 (thin line) against ∂u∗/∂Dk\partial u^*/\partial D_k (thick line). At N=128N=128, v0v_0 and v1v_1 lie on the continuous curves; v2v_2 goes to zero, but most slowly.
离散切线解与连续切线的单元平均之间的最大差(无限制器线性)Largest difference between the discrete tangents and the cell averages of the continuous tangents (unlimited linear)
Nmax⁡i∣v0,i−⟨ua∗⟩i∣\max_i|v_{0,i}-\langle u^*_a\rangle_i|max⁡i∣v1,i−⟨uφ∗⟩i∣\max_i|v_{1,i}-\langle u^*_\varphi\rangle_i|max⁡i∣v2,i∣\max_i|v_{2,i}|
85.25e−13.35e−16.54e−1
321.14e−15.05e−23.83e−1
1281.96e−21.32e−22.08e−1
5122.02e−31.61e−33.22e−2
20481.49e−41.24e−42.67e−3
40963.83e−53.22e−57.03e−4

无限制器线性重构时切线解的观测阶趋近 2(N=2048N=2048 到 40964096 之间为 1.96、1.95、1.93),一阶重构时趋近 1(1.00、0.99、1.11)——与状态本身的阶相同(第 15 节)。N=4096N=4096 时 v2v_2 仍有 7×10−47\times10^{-4},是 v0v_0 误差的 18 倍:J˙2\dot J_2 是最后收敛的梯度分量(第 12 节)。

With unlimited linear reconstruction the observed orders of the tangents approach 2 (1.96, 1.95 and 1.93 between N=2048N=2048 and 40964096), with first-order reconstruction they approach 1 (1.00, 0.99, 1.11): the orders of the state itself (Section 15). At N=4096N=4096, v2v_2 is still 7×10−47\times10^{-4}, 18 times the error of v0v_0: J˙2\dot J_2 is the last gradient component to converge (Section 12).

代价:每个设计分量解一次

The cost: one solve per design component

每次前向求解回答一个问题:对一个设计方向的响应。设计有 nDn_D 个分量,就要用同一个矩阵 AA、nDn_D 个右端项解 nDn_D 次;这里 nD=3n_D=3。好处是,每次求解给出整个向量 vkv_k,于是状态的任何其他目标,导数只需再做一次内积。当目标少而设计分量多时,第 11 节把计算倒过来:用 ATA^T 解一次,就得到 dJh/dD\mathrm dJ_h/\mathrm dD 的全部分量(图 34)。

Each tangent solve answers one question: the response to one design direction. A design with nDn_D components needs nDn_D solves with the same matrix AA and nDn_D right-hand sides; here nD=3n_D=3. In return each solve gives the whole vector vkv_k, so the derivative of any other objective of the state is one more dot product. When the objectives are few and the design components many, Section 11 turns the computation around: one solve with ATA^T gives every component of dJh/dD\mathrm dJ_h/\mathrm dD at once (Figure 34).

图 34 · 两条路线(默认设计,N=8,无限制器线性)。上:前向路线,每个种子 D-dot=e_k 解一次 Av_k=-R_De_k,得到整个 v_k 和一个数 J-dot_k。下:伴随路线(),取 g=w,解一次 A^Tψ=-g,再做三个内积 ψ^TR_De_k。两条路线给出同样的三个数,相差不到 10^(-15)。前向路线(本节):每个设计分量解一次,共 nD​ = 3 次Ḋ = e0​A v0​ = −RD​ e0​v0​J̇0​ = wT​ v0​ = −0.486650Ḋ = e1​A v1​ = −RD​ e1​v1​J̇1​ = wT​ v1​ = −0.061039Ḋ = e2​A v2​ = −RD​ e2​v2​J̇2​ = wT​ v2​ = −0.309871伴随路线(第 11 节):一次转置求解,再做三个内积g = wAT​ ψ = −gψψT​ RD​ e0​ = −0.486650ψT​ RD​ e1​ = −0.061039ψT​ RD​ e2​ = −0.309871同样的三个数:两条路线相差不到 10-15​(N = 8,无限制器线性,默认设计)
图 34 · 两条路线(默认设计,N=8N=8,无限制器线性)。上:前向路线,每个种子 D˙=ek\dot D=e_k 解一次 Avk=−RDekAv_k=-R_De_k,得到整个 vkv_k 和一个数 J˙k\dot J_k。下:伴随路线(第 11 节),取 g=wg=w,解一次 ATψ=−gA^T\psi=-g,再做三个内积 ψTRDek\psi^TR_De_k。两条路线给出同样的三个数,相差不到 10−1510^{-15}。
Figure 34 · The two routes (default design, N=8, unlimited linear). Top: the tangent route solves Av_k=-R_De_k once per seed D-dot=e_k and obtains the whole v_k and one number J-dot_k. Bottom: the adjoint route () solves A^Tψ=-g once with g=w and then takes three dot products ψ^TR_De_k. Both give the same three numbers, less than 10^(-15) apart.tangent route (this section): one solve per design component, nD​ = 3 solvesḊ = e0​A v0​ = −RD​ e0​v0​J̇0​ = wT​ v0​ = −0.486650Ḋ = e1​A v1​ = −RD​ e1​v1​J̇1​ = wT​ v1​ = −0.061039Ḋ = e2​A v2​ = −RD​ e2​v2​J̇2​ = wT​ v2​ = −0.309871adjoint route (Section 11): one transposed solve, then three dot productsg = wAT​ ψ = −gψψT​ RD​ e0​ = −0.486650ψT​ RD​ e1​ = −0.061039ψT​ RD​ e2​ = −0.309871the same three numbers: the two routes differ by less than 10-15​ (N = 8, unlimited linear, default design)
Figure 34 · The two routes (default design, N=8N=8, unlimited linear). Top: the tangent route solves Avk=−RDekAv_k=-R_De_k once per seed D˙=ek\dot D=e_k and obtains the whole vkv_k and one number J˙k\dot J_k. Bottom: the adjoint route (Section 11) solves ATψ=−gA^T\psi=-g once with g=wg=w and then takes three dot products ψTRDek\psi^TR_De_k. Both give the same three numbers, less than 10−1510^{-15} apart.
第 11 节Section 11

伴随求解:一次转置求解得到全部梯度

The adjoint solve: one transposed solve for the whole gradient

本节实验:先预测 ψi\psi_i 是正还是负、∣ψi∣|\psi_i| 在哪里最大,在图 36 里核对;再看图 38:粗网格上 ψ0\psi_0 为什么离连续伴随 λ(x0)\lambda(x_0) 那么远?

Experiment: Predict first: is ψi\psi_i positive or negative, and where is ∣ψi∣|\psi_i| largest? Check it in Figure 36. Then look at Figure 38: why is ψ0\psi_0 so far from the continuous adjoint λ(x0)\lambda(x_0) on the coarse mesh?

第 10 节每个设计分量要解一次线性方程组。只有一个目标而设计分量很多时,这样做很浪费:我们要的只是 nDn_D 个数 J˙k\dot J_k,而不是 nDn_D 个向量 vkv_k。本节把求解移到内积的另一侧。

Section 10 needed one linear solve per design component. With one objective and many design components that is wasteful: what we want are nDn_D numbers J˙k\dot J_k, not nDn_D vectors vkv_k. This section moves the solve to the other side of the dot product.

从 nDn_D 次前向求解到一次转置求解

From nDn_D tangent solves to one transposed solve

对任意种子 D˙\dot D,前向求解给出 v=−A−1RDD˙v=-A^{-1}R_D\dot D,目标的方向导数是 J˙=wTv\dot J=w^Tv。把前者代入后者,从左边把因子合并:

For any seed D˙\dot D the tangent solve gives v=−A−1RDD˙v=-A^{-1}R_D\dot D, and the directional derivative of the objective is J˙=wTv\dot J=w^Tv. Insert the first into the second and group the factors from the left:

J˙=wTv=−wTA−1RD D˙=(−A−Tw)TRD D˙=ψTRD D˙,ATψ=−g,g=w.\dot J=w^Tv=-w^TA^{-1}R_D\,\dot D=\bigl(-A^{-T}w\bigr)^TR_D\,\dot D=\psi^TR_D\,\dot D,\qquad A^T\psi=-g,\quad g=w.

向量 ψ\psi(伴随)与 D˙\dot D 无关:用转置矩阵解一次,就对所有设计方向都适用。梯度就是反向模式的设计伴随:

The vector ψ\psi, the adjoint, does not depend on D˙\dot D: one solve with the transposed matrix serves every design direction. The gradient is the design adjoint of reverse mode:

Dˉ=RDTψ,dJhdDk=Dˉk=ψTRD ek=∑i=0N−1ψi (RD)ik.\bar D=R_D^T\psi,\qquad \frac{\mathrm dJ_h}{\mathrm dD_k}=\bar D_k=\psi^TR_D\,e_k=\sum_{i=0}^{N-1}\psi_i\,(R_D)_{ik}.

用第 9 节的话说:以 Rˉ=ψ\bar R=\psi 为种子运行反向代码,它返回 𝐔ˉ=ATψ\bar{\mathbf U}=A^T\psi(ψ\psi 满足伴随方程时正好等于 −g-g)和 Dˉ=RDTψ\bar D=R_D^T\psi,即梯度。第 9 节的对偶恒等式 RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D 取 Rˉ=ψ\bar R=\psi、𝐔˙=vk\dot{\mathbf U}=v_k、D˙=ek\dot D=e_k(于是 R˙=0\dot R=0),就是 0=−gTvk+Dˉk0=-g^Tv_k+\bar D_k:前向与伴随给出同一个数。默认设计下,三种重构的反向代码返回的 𝐔ˉ\bar{\mathbf U} 都满足 ∥𝐔ˉ+w∥∞<10−15\|\bar{\mathbf U}+w\|_\infty<10^{-15};下表比较两条路线:

In the words of Section 9: run the reverse code with the seed Rˉ=ψ\bar R=\psi; it returns 𝐔ˉ=ATψ\bar{\mathbf U}=A^T\psi, which equals −g-g exactly when ψ\psi solves the adjoint equation, and Dˉ=RDTψ\bar D=R_D^T\psi, the gradient. The duality identity RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D of Section 9 with Rˉ=ψ\bar R=\psi, 𝐔˙=vk\dot{\mathbf U}=v_k and D˙=ek\dot D=e_k (so that R˙=0\dot R=0) reads 0=−gTvk+Dˉk0=-g^Tv_k+\bar D_k: the tangent and the adjoint give the same number. At the default design the reverse code returns 𝐔ˉ\bar{\mathbf U} with ∥𝐔ˉ+w∥∞<10−15\|\bar{\mathbf U}+w\|_\infty<10^{-15} for each of the three reconstructions, and the table compares the two routes:

前向与伴随(N=8N=8,默认设计):最大差低于 10−1510^{-15},舍入误差的量级Tangent against adjoint (N=8N=8, default design): largest difference below 10−1510^{-15}, the size of round-off
重构Reconstructionkk前向 wTvkw^Tv_kTangent wTvkw^Tv_k伴随 ψTRDek\psi^TR_De_kAdjoint ψTRDek\psi^TR_De_k差Difference
一阶first order00−0.745986130503−0.7459861305033.3e−16
一阶first order11−0.357341645754−0.3573416457542.2e−16
一阶first order22−0.245483618467−0.2454836184671.4e−16
无限制器线性unlimited linear00−0.486649677166−0.486649677166−2.8e−16
无限制器线性unlimited linear11−0.061038915769−0.061038915769−7.2e−16
无限制器线性unlimited linear22−0.309871355162−0.3098713551622.8e−16
光滑限制器smooth limiter00−0.656527469353−0.6565274693531.1e−16
光滑限制器smooth limiter11−0.168097300931−0.168097300931−2.5e−16
光滑限制器smooth limiter22−0.290780443262−0.2907804432626.1e−16

右端的负号是一种约定:若写 ATψ=+gA^T\psi=+g,梯度就是 −ψTRD-\psi^TR_D。本页取 ATψ=−gA^T\psi=-g,使 Jh+ψTRJ_h+\psi^TR 与附录 A 的连续形式 J+∫λ (qx−s) dxJ+\int\lambda\,(q_x-s)\,\mathrm dx 符号一致:ψi\psi_i 与 λ(xi)\lambda(x_i) 同号,也不差一个因子 hh(RiR_i 是单元上的积分残差)。

The minus sign on the right-hand side is a convention: with ATψ=+gA^T\psi=+g the gradient would be −ψTRD-\psi^TR_D. This page keeps ATψ=−gA^T\psi=-g so that Jh+ψTRJ_h+\psi^TR and its continuous counterpart J+∫λ (qx−s) dxJ+\int\lambda\,(q_x-s)\,\mathrm dx of Appendix A carry the same sign: ψi\psi_i and λ(xi)\lambda(x_i) have the same sign, and there is no factor hh between them (RiR_i is a residual integrated over a cell).

转置矩阵:倒着走的面循环

The transposed matrix: the face loop run backwards

ATA^T 是 AA 关于对角线的镜像:ATA^T 的第 jj 行是 AA 的第 jj 列,即未知量 UjU_j 进入的那些残差行。图 35 画出 N=8N=8 时的两者。反向代码从不形成转置矩阵(本页的直接求解为了方便确实形成并分解了 ATA^T;只有用 residual_b 的无矩阵路线从不形成它):第 9 节的反向面循环从最后一个面走到第一个面,给每个面种子 Hˉf=ψf−1−ψf\bar H_f=\psi_{f-1}-\psi_f(它两侧单元伴随之差),再把 cLHˉfc_L\bar H_f、cRHˉfc_R\bar H_f 和 ±κfHˉf\pm\kappa_f\bar H_f 送回这个面读过的单元。每个面送回的正是它在 AA 中各列的那几项,所以这个循环不形成矩阵就完成了与 ATA^T 的乘法。

ATA^T is AA mirrored about its diagonal: row jj of ATA^T is column jj of AA, the residual rows that the unknown UjU_j enters. Figure 35 shows both for N=8N=8. The reverse code never forms a transposed matrix (the page's direct solves do form and factor ATA^T, for convenience; only the matrix-free route through residual_b never forms it): the reverse face loop of Section 9 visits the faces from the last to the first, gives each face the seed Hˉf=ψf−1−ψf\bar H_f=\psi_{f-1}-\psi_f (the difference of the adjoints of the two cells it separates) and sends cLHˉfc_L\bar H_f, cRHˉfc_R\bar H_f and ±κfHˉf\pm\kappa_f\bar H_f back to the cells the face read. Each face sends back exactly its own entries of the columns of AA, so the loop applies ATA^T without forming it.

图 35 · 状态 Jacobian 与它的转置(N=8,无限制器线性,默认设计;蓝正橙负)。A 的第 i 行是残差 R_i 对至多 5 个未知量的导数(第一行与最后一行 3 个,第二行与倒数第二行 4 个);A^T 的第 j 行是伴随方程 (A^Tψ)_j=-w_j 的系数,即 A 的第 j 列。01234567012345672.12−0.540.12−1.872.08−0.230.110.39−1.931.65−0.230.110.39−1.911.59−0.320.130.38−1.821.56−0.440.150.36−1.701.61−0.510.160.34−1.651.84−0.450.35−1.481.8901234567012345672.12−1.870.39−0.542.08−1.930.390.12−0.231.65−1.910.380.11−0.231.59−1.820.360.11−0.321.56−1.700.340.13−0.441.61−1.650.350.15−0.511.84−1.480.16−0.451.89A = RU​(行 i:残差 Ri​;列 j:未知量 Uj​)AT​(行 j 收集 ψ:伴随方程的第 j 行)紫框:A 的第 3 列 = AT​ 的第 3 行,即 U3​ 进入的残差行
图 35 · 状态 Jacobian 与它的转置(N=8N=8,无限制器线性,默认设计;蓝正橙负)。AA 的第 ii 行是残差 RiR_i 对至多 5 个未知量的导数(第一行与最后一行 3 个,第二行与倒数第二行 4 个);ATA^T 的第 jj 行是伴随方程 (ATψ)j=−wj(A^T\psi)_j=-w_j 的系数,即 AA 的第 jj 列。
Figure 35 · The state Jacobian and its transpose (N=8, unlimited linear, default design; blue positive, orange negative). Row i of A holds the derivatives of the residual R_i with respect to at most 5 unknowns (3 in the first and the last row, 4 in the second and the second-to-last); row j of A^T holds the coefficients of the adjoint equation (A^Tψ)_j=-w_j, which are column j of A.01234567012345672.12−0.540.12−1.872.08−0.230.110.39−1.931.65−0.230.110.39−1.911.59−0.320.130.38−1.821.56−0.440.150.36−1.701.61−0.510.160.34−1.651.84−0.450.35−1.481.8901234567012345672.12−1.870.39−0.542.08−1.930.390.12−0.231.65−1.910.380.11−0.231.59−1.820.360.11−0.321.56−1.700.340.13−0.441.61−1.650.350.15−0.511.84−1.480.16−0.451.89A = RU​ (row i: residual Ri​; column j: unknown Uj​)AT​ (row j collects ψ: row j of the adjoint equation)violet frame: column 3 of A = row 3 of AT​, the residual rows that U3​ enters
Figure 35 · The state Jacobian and its transpose (N=8N=8, unlimited linear, default design; blue positive, orange negative). Row ii of AA holds the derivatives of the residual RiR_i with respect to at most 5 unknowns (3 in the first and the last row, 4 in the second and the second-to-last); row jj of ATA^T holds the coefficients of the adjoint equation (ATψ)j=−wj(A^T\psi)_j=-w_j, which are column jj of AA.

转置也颠倒了信息传播的方向。看一阶格式(N=8N=8)的第 3 行:AA 的第 3 行是 (−1.616, 2.160, −0.668)(−1.616,\ 2.160,\ −0.668)(依次乘 U2,U3,U4U_2,U_3,U_4),上游的系数 −(cL+κ)-(c_L+\kappa) 的绝对值比下游的 cR−κc_R-\kappa 大:残差 R3R_3 主要取决于上游单元——u>0u>0 时原始问题的信息从左向右传。ATA^T 的第 3 行是 AA 的第 3 列 (−0.605, 2.160, −1.555)(−0.605,\ 2.160,\ −1.555)(依次乘 ψ2,ψ3,ψ4\psi_2,\psi_3,\psi_4),大系数换到了下游一侧:伴随从右向左传,从 x=1x=1 传向 x=0x=0。连续伴随方程 −uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x)(附录 A)也是这样:它沿反方向输运,它的入口边界层(下文简称层)在 x=0x=0。

The transposition also reverses the direction in which information travels. Take row 3 of the first-order scheme (N=8N=8): row 3 of AA is (−1.616, 2.160, −0.668)(−1.616,\ 2.160,\ −0.668) (multiplying U2,U3,U4U_2,U_3,U_4); the upstream coefficient −(cL+κ)-(c_L+\kappa) is larger in magnitude than the downstream cR−κc_R-\kappa: the residual R3R_3 leans on the upstream cell, and with u>0u>0 the information of the primal problem travels from left to right. Row 3 of ATA^T is column 3 of AA, (−0.605, 2.160, −1.555)(−0.605,\ 2.160,\ −1.555) (multiplying ψ2,ψ3,ψ4\psi_2,\psi_3,\psi_4): the large coefficient has moved to the downstream side, and the adjoint travels from right to left, from x=1x=1 towards x=0x=0. The continuous adjoint equation −uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x) of Appendix A does the same: it transports in the reverse direction, and its inlet boundary layer (from here on: the layer) sits at x=0x=0.

伴随场 ψ\psi

The adjoint field ψ\psi

图 36 是默认设计下的 ψ\psi。三种重构的 ψi\psi_i 在每个单元都为负;无限制器线性时 ∣ψi∣|\psi_i| 在单元 1 最大(ψ1=−1.2308\psi_{1}=−1.2308),在单元 7 最小(−0.1632−0.1632)。实线是连续伴随 λ(x)\lambda(x)(附录 A,由独立的 Chebyshev 求解器算出),ψi≈λ(xi)\psi_i\approx\lambda(x_i),同号、无因子 hh。

Figure 36 shows ψ\psi at the default design. In all three reconstructions ψi\psi_i is negative in every cell; with unlimited linear reconstruction ∣ψi∣|\psi_i| is largest in cell 1 (ψ1=−1.2308\psi_{1}=−1.2308) and smallest in cell 7 (−0.1632−0.1632). The solid line is the continuous adjoint λ(x)\lambda(x) of Appendix A (computed by an independent Chebyshev solver): ψi≈λ(xi)\psi_i\approx\lambda(x_i), with the same sign and no factor hh.

图 36 · 默认设计的伴随场(N=8):三种重构的 ψ_i 与连续伴随 λ(x)(实线;小圈是 λ(x_i))。λ 在 x=0 有一个宽约 ν/u_in ≈ 0.011 的层,λ_x(0)=−142.66;单元 0 的中心 x_0=0.0625 已在层外,ψ_0 与 λ(x_0) 相差最大。连续伴随 λ(x)ψi​ 无限制器线性一阶光滑限制器−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xψi​, λ(x)λx​(0) = −142.66:宽约 ν/uin​ 的层
图 36 · 默认设计的伴随场(N=8N=8):三种重构的 ψi\psi_i 与连续伴随 λ(x)\lambda(x)(实线;小圈是 λ(xi)\lambda(x_i))。λ\lambda 在 x=0x=0 有一个宽约 ν/uin≈0.011\nu/u_{\rm in}\approx0.011 的层,λx(0)=−142.66\lambda_x(0)=−142.66;单元 0 的中心 x0=0.0625x_0=0.0625 已在层外,ψ0\psi_0 与 λ(x0)\lambda(x_0) 相差最大。
Figure 36 · The adjoint field at the default design (N=8): ψ_i of the three reconstructions and the continuous adjoint λ(x) (solid; the small rings are λ(x_i)). λ has a layer of width about ν/u_in ≈ 0.011 at x=0 with λ_x(0)=−142.66; the centre of cell 0, x_0=0.0625, is already outside it, and there ψ_0 and λ(x_0) differ most.continuous adjoint λ(x)ψi​ unlimited linearfirst ordersmooth limiter−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xψi​, λ(x)λx​(0) = −142.66: a layer of width ν/uin​
Figure 36 · The adjoint field at the default design (N=8N=8): ψi\psi_i of the three reconstructions and the continuous adjoint λ(x)\lambda(x) (solid; the small rings are λ(xi)\lambda(x_i)). λ\lambda has a layer of width about ν/uin≈0.011\nu/u_{\rm in}\approx0.011 at x=0x=0 with λx(0)=−142.66\lambda_x(0)=−142.66; the centre of cell 0, x0=0.0625x_0=0.0625, is already outside it, and there ψ0\psi_0 and λ(x0)\lambda(x_0) differ most.

ψi\psi_i 的含义:在一个单元加一点源项

What ψi\psi_i means: add a little source to one cell

给单元 ii 的积分源项加上一个数 tt:第 ii 行变成 Ri−tR_i-t,其余行不变。前向种子 t˙=1\dot t=1 给出 R˙=Av−ei=0\dot R=Av-e_i=0,即 Av=eiAv=e_i;用伴随方程 ψT=−wTA−1\psi^T=-w^TA^{-1}:

Add a number tt to the integrated source of cell ii: row ii becomes Ri−tR_i-t and the other rows do not change. The forward seed t˙=1\dot t=1 gives R˙=Av−ei=0\dot R=Av-e_i=0, that is Av=eiAv=e_i, and with the adjoint equation, ψT=−wTA−1\psi^T=-w^TA^{-1}:

dJhdt=wTv=wTA−1ei=−ψTei=−ψi.\frac{\mathrm dJ_h}{\mathrm dt}=w^Tv=w^TA^{-1}e_i=-\psi^Te_i=-\psi_i.

所以 −ψi-\psi_i 是“单元 ii 多一个单位源项时 JhJ_h 增加多少”。ψi<0\psi_i<0:任何单元加源项都使 JhJ_h 增大。图 37 不用伴随直接测量这个关系:对每个 ii 重新完整求解两次非线性方程(t=±10−5t=\pm10^{-5}),中心差商与 −ψi-\psi_i 的最大相对差为 9.4×10−119.4\times10^{-11}。加在单元 1、2 的源项影响最大:它们向下游影响几乎所有单元,而 JhJ_h 对整个区间加权求和。加在单元 0 的源项影响反而较小。一个启发式的解释:一部分扰动经入口面离开——N=8N=8 时主要通过入口面通量的对流(Rusanov)部分 cR(0)=U0/2−1=−0.488c_R(0)=U_0/2-1=−0.488,黏性部分 −2ν/h=−0.16-2\nu/h=−0.16 较小;在连续问题里 λ(0)=0\lambda(0)=0,紧贴入口的源项完全不起作用。

So −ψi-\psi_i is how much JhJ_h grows when cell ii receives one more unit of source; ψi<0\psi_i<0 means that a source added in any cell raises JhJ_h. Figure 37 measures this relation without the adjoint: for every ii it solves the full nonlinear equations twice (t=±10−5t=\pm10^{-5}), and the central difference agrees with −ψi-\psi_i to a relative 9.4×10−119.4\times10^{-11}. Sources in cells 1 and 2 act most: they influence nearly every cell downstream, and JhJ_h sums over the whole interval. A source in cell 0 acts less. A heuristic reading: part of the disturbance leaves through the inlet face, at N=8N=8 mainly through the convective (Rusanov) part of the inlet flux, cR(0)=U0/2−1=−0.488c_R(0)=U_0/2-1=−0.488, rather than through its viscous part, −2ν/h=−0.16-2\nu/h=−0.16; in the continuous problem λ(0)=0\lambda(0)=0, and a source right at the inlet has no effect at all.

图 37 · ψ_i 的含义(N=8,无限制器线性)。柱:-ψ_i;圈:在单元 i 加源项 t 后两次完整非线性重解得到的 dJ_h/ dt,不用伴随。两者的最大相对差 9.4 × 10^(-11),与这个步长下中心差商的截断与舍入误差同一量级。00.20.40.60.811.21.400.51x柱:−ψi​;圈:在单元 i 加源项 t 后重新求解两次的中心差商 dJh​/dt(t = 1e−5)0.92431.23081.19691.01780.82750.60520.35560.1632
图 37 · ψi\psi_i 的含义(N=8N=8,无限制器线性)。柱:−ψi-\psi_i;圈:在单元 ii 加源项 tt 后两次完整非线性重解得到的 dJh/dt\mathrm dJ_h/\mathrm dt,不用伴随。两者的最大相对差 9.4×10−119.4\times10^{-11},与这个步长下中心差商的截断与舍入误差同一量级。
Figure 37 · What ψ_i means (N=8, unlimited linear). Bars: -ψ_i; rings: dJ_h/ dt from two full nonlinear re-solves with an extra source t in cell i, without the adjoint. They agree to a relative 9.4 × 10^(-11), of the size expected from the truncation and round-off errors of a central difference with this step.00.20.40.60.811.21.400.51xbars: −ψi​; rings: dJh​/dt from two full re-solves with an extra source t in cell i (t = 1e−5)0.92431.23081.19691.01780.82750.60520.35560.1632
Figure 37 · What ψi\psi_i means (N=8N=8, unlimited linear). Bars: −ψi-\psi_i; rings: dJh/dt\mathrm dJ_h/\mathrm dt from two full nonlinear re-solves with an extra source tt in cell ii, without the adjoint. They agree to a relative 9.4×10−119.4\times10^{-11}, of the size expected from the truncation and round-off errors of a central difference with this step.

图 32 的影响矩阵给出同一件事的另一种读法:−ψi=wTA−1ei-\psi_i=w^TA^{-1}e_i 是第 ii 列——单元 ii 的源项在各单元引起的变化——按目标权重 wjw_j 加起来。切线解把扰动向下游送,伴随把下游的权重收集回来。在面板里换一个单元试试:

The influence matrix of Figure 32 gives a second reading of the same fact: −ψi=wTA−1ei-\psi_i=w^TA^{-1}e_i is column ii, the change that a source in cell ii causes in every cell, summed with the objective weights wjw_j. The tangent sends a disturbance downstream; the adjoint gathers the downstream weights back. Try another cell in the panel:

与连续伴随比较

Comparison with the continuous adjoint

连续伴随在 x=0x=0 有一个宽约 ν/uin\nu/u_{\rm in} 的层:λ\lambda 从 00 陡降,λx(0)=−142.66\lambda_x(0)=−142.66。N=8N=8 的单元 0 比整个层宽十倍以上,所以 ψ0\psi_0 无法“看到”层的形状。ψ0/(h/2)\psi_0/(h/2) 是 λx(0)\lambda_x(0) 的单侧差商估计(λ(0)=0\lambda(0)=0):图 38 与下表显示,它在 N=8N=8 时只有 −14.8−14.8,N=256N=256 时 −111.1−111.1,N=4096N=4096 时 −140.2−140.2。要 h≪ν/uinh\ll\nu/u_{\rm in},即 NN 上千,层才被分辨。这个标准比第 3 节分辨率面板用的标准严:那里层宽内有三个单元(h≤ν/(3uin)h\le\nu/(3u_{\rm in}),本例 N≥275N\ge275)就算分辨;ψ0/(h/2)\psi_0/(h/2) 要到 N=2048N=2048 才与 λx(0)\lambda_x(0) 相差不到 5%。离开层(x>0.1x>0.1),ψ\psi 收敛到 λ\lambda;观测阶要到 NN 上千才接近 2(最后三对网格为 1.86、1.93、1.96)。第 16 节系统地研究这种一致性。

The continuous adjoint has a thin layer of width about ν/uin\nu/u_{\rm in} at x=0x=0: λ\lambda drops steeply from 00, with λx(0)=−142.66\lambda_x(0)=−142.66. Cell 0 of the N=8N=8 mesh is more than ten times wider than the whole layer, so ψ0\psi_0 cannot see its shape. ψ0/(h/2)\psi_0/(h/2) is the one-sided estimate of λx(0)\lambda_x(0) (since λ(0)=0\lambda(0)=0): Figure 38 and the table show that it is only −14.8−14.8 at N=8N=8, −111.1−111.1 at N=256N=256 and −140.2−140.2 at N=4096N=4096. The layer is resolved only when h≪ν/uinh\ll\nu/u_{\rm in}, with NN in the thousands. This criterion is stricter than that of the resolution panel of Section 3, which counts the layer resolved when three cells fit into its width (h≤ν/(3uin)h\le\nu/(3u_{\rm in}), N≥275N\ge275 here); ψ0/(h/2)\psi_0/(h/2) comes within 5% of λx(0)\lambda_x(0) only from N=2048N=2048 on. Away from the layer (x>0.1x>0.1) ψ\psi converges to λ\lambda; the observed order approaches 2 only for NN in the thousands (1.86, 1.93, 1.96 for the last three pairs of meshes). Section 16 studies this consistency systematically.

图 38 · ψ 与 λ(无限制器线性,默认设计),N=8,16,32,64。上排:整个区间;下排:x[0,0.1] 的层。虚线从 (0,0) 连到 (h/2,ψ_0),斜率是 ψ_0/(h/2);点线的斜率是 λ_x(0)=−142.7。网格加密时层外的点落到曲线上;单元 0 的斜率虽在变陡,却仍与 λ_x(0) 相差很远。λ(x)ψi​斜率 ψ0​/(h/2)斜率 λx​(0) = −142.7−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 8−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 16−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 32−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 64−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −14.8−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −26.4−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −44.1−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −67.0
图 38 · ψ\psi 与 λ\lambda(无限制器线性,默认设计),N=8,16,32,64N=8,16,32,64。上排:整个区间;下排:x∈[0,0.1]x\in[0,0.1] 的层。虚线从 (0,0)(0,0) 连到 (h/2,ψ0)(h/2,\psi_0),斜率是 ψ0/(h/2)\psi_0/(h/2);点线的斜率是 λx(0)=−142.7\lambda_x(0)=−142.7。网格加密时层外的点落到曲线上;单元 0 的斜率虽在变陡,却仍与 λx(0)\lambda_x(0) 相差很远。
Figure 38 · ψ against λ (unlimited linear, default design) for N=8,16,32,64. Top: the whole interval; bottom: the layer, x[0,0.1]. The dashed segment joins (0,0) to (h/2,ψ_0); its slope is ψ_0/(h/2). The dotted line has the slope λ_x(0)=−142.7. Under refinement the points away from the layer settle on the curve, while the slope of cell 0, though steepening, stays far from λ_x(0).λ(x)ψi​slope ψ0​/(h/2)slope λx​(0) = −142.7−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 8−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 16−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 32−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.51xN = 64−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −14.8−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −26.4−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −44.1−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.050.1xψ0​/(h/2) = −67.0
Figure 38 · ψ\psi against λ\lambda (unlimited linear, default design) for N=8,16,32,64N=8,16,32,64. Top: the whole interval; bottom: the layer, x∈[0,0.1]x\in[0,0.1]. The dashed segment joins (0,0)(0,0) to (h/2,ψ0)(h/2,\psi_0); its slope is ψ0/(h/2)\psi_0/(h/2). The dotted line has the slope λx(0)=−142.7\lambda_x(0)=−142.7. Under refinement the points away from the layer settle on the curve, while the slope of cell 0, though steepening, stays far from λx(0)\lambda_x(0).
两端的单侧差商与连续伴随的斜率;层外的误差(无限制器线性;带状求解器)One-sided slopes at the two ends against the slopes of the continuous adjoint; the error away from the layer (unlimited linear; banded solver)
Nψ0/(h/2)\psi_0/(h/2)λx(0)\lambda_x(0)−ψN−1/(h/2)-\psi_{N-1}/(h/2)λx(1)\lambda_x(1)max⁡xi>0.1∣ψi−λ(xi)∣\max_{x_i>0.1}|\psi_i-\lambda(x_i)|
8−14.79−142.662.6122.2031.2e−1
16−26.42−142.662.4862.2034.4e−2
32−44.10−142.662.3682.2032.3e−2
64−67.02−142.662.2342.2031.0e−2
256−111.08−142.662.1122.2031.4e−3
1024−133.18−142.662.1572.2031.2e−4
4096−140.16−142.662.1902.2038.1e−6

不要从粗网格的 ψ0/(h/2)\psi_0/(h/2) 读 λx(0)\lambda_x(0):层没被分辨时这个差商的绝对值小得多,N=8N=8 时只有真值的十分之一。但这并不意味着梯度错了:第 12 节说明,进入梯度的是边界值的伴随 uˉin=−(cL(0)+2ν/h) ψ0\bar u_{\rm in}=-(c_L(0)+2\nu/h)\,\psi_0,它在 N=8N=8 时已在连续值 −νλx(0)-\nu\lambda_x(0) 的 5% 以内。

Do not read λx(0)\lambda_x(0) off ψ0/(h/2)\psi_0/(h/2) on a coarse mesh: while the layer is unresolved this quotient is far too small in magnitude, a tenth of the true slope at N=8N=8. That does not make the gradient wrong: Section 12 shows that what enters the gradient is the adjoint of the boundary value, uˉin=−(cL(0)+2ν/h) ψ0\bar u_{\rm in}=-(c_L(0)+2\nu/h)\,\psi_0, which at N=8N=8 is already within 5% of its continuous value −νλx(0)-\nu\lambda_x(0).

组装梯度:谁的贡献

Assembling the gradient: who contributes

dJh/dDk=∑iψi(RD)ik\mathrm dJ_h/\mathrm dD_k=\sum_i\psi_i(R_D)_{ik} 是逐单元的和。图 39 画出每个单元的贡献 ψi(RD)ik\psi_i(R_D)_{ik} 和累加和。N=8N=8 时 aa 的梯度几乎全来自内部单元(首末两个单元合计 0.0620.062),φ\varphi 的梯度是两个大数之差:首末两个单元贡献 −2.211−2.211,内部单元贡献 2.1502.150,合计只有 −0.061−0.061。加密后首末两个单元承载边界值的贡献,内部单元承载源项的贡献:N=128N=128 时 aa 的这两部分是 −0.606−0.606 与 0.4420.442,φ\varphi 是 −1.667−1.667 与 1.7661.766。梯度是 O(1)O(1) 的两部分之差,第 12 节把它们与连续梯度的两项一一对应。

dJh/dDk=∑iψi(RD)ik\mathrm dJ_h/\mathrm dD_k=\sum_i\psi_i(R_D)_{ik} is a sum over the cells. Figure 39 draws the contribution ψi(RD)ik\psi_i(R_D)_{ik} of every cell and the running sum. At N=8N=8 the aa-gradient comes almost entirely from the interior cells (the first and last cell together give 0.0620.062), while the φ\varphi-gradient is the difference of two large numbers: the first and last cell contribute −2.211−2.211, the interior cells 2.1502.150, together only −0.061−0.061. On finer meshes the end cells carry the contribution of the boundary values and the interior cells that of the source: at N=128N=128 the two parts are −0.606−0.606 and 0.4420.442 for aa, −1.667−1.667 and 1.7661.766 for φ\varphi. The gradient is a difference of two parts of order one; Section 12 matches them with the two terms of the continuous gradient.

图 39 · 谁的贡献(N=8,无限制器线性,默认设计)。柱:每个单元的贡献 ψ_i(R_D)_ik;圆点:到该单元右面为止的累加和;紫虚线:总和,即梯度分量 dJ_h/ dD_k。φ 与 ν 的单元 0 贡献最大,但被其余单元抵消了大半。贡献 ψi​ (RD​)ik​累加和(到单元右面为止)总和 = 梯度分量−0.500.5100.51xk = 0:振幅 adJh​/da = −0.4866−2−10100.51xk = 1:相位 φdJh​/dφ = −0.0610−1−0.500.500.51xk = 2:黏性 νdJh​/dν = −0.3099
图 39 · 谁的贡献(N=8N=8,无限制器线性,默认设计)。柱:每个单元的贡献 ψi(RD)ik\psi_i(R_D)_{ik};圆点:到该单元右面为止的累加和;紫虚线:总和,即梯度分量 dJh/dDk\mathrm dJ_h/\mathrm dD_k。φ\varphi 与 ν\nu 的单元 0 贡献最大,但被其余单元抵消了大半。
Figure 39 · Who contributes (N=8, unlimited linear, default design). Bars: the contribution ψ_i(R_D)_ik of each cell; dots: the running sum up to the right face of the cell; violet dashed line: the total, the gradient component dJ_h/ dD_k. For φ and ν cell 0 contributes most, but the other cells cancel most of it.contribution ψi​ (RD​)ik​running sum (up to the right face of the cell)total = gradient component−0.500.5100.51xk = 0: amplitude adJh​/da = −0.4866−2−10100.51xk = 1: phase φdJh​/dφ = −0.0610−1−0.500.500.51xk = 2: viscosity νdJh​/dν = −0.3099
Figure 39 · Who contributes (N=8N=8, unlimited linear, default design). Bars: the contribution ψi(RD)ik\psi_i(R_D)_{ik} of each cell; dots: the running sum up to the right face of the cell; violet dashed line: the total, the gradient component dJh/dDk\mathrm dJ_h/\mathrm dD_k. For φ\varphi and ν\nu cell 0 contributes most, but the other cells cancel most of it.

下面的面板把本节的内容放在一起,网格、重构与黏性都可以改(带状求解器,NN 到 10241024):ψ\psi 与 λ\lambda、各单元的贡献,以及梯度的四种算法——前向、伴随、两次完整重解的中心差商和连续问题的精确梯度。

The panel below puts this section together, with the mesh, the reconstruction and the viscosity of your choice (banded solver, NN up to 10241024): ψ\psi against λ\lambda, the contribution of each cell, and the gradient by four routes: tangent, adjoint, central differences of two full re-solves, and the exact gradient of the continuous problem.

一次求解得到全部分量:代价

One solve for every component: the cost

两条路线的代价可以直接数。用不加预处理的 GMRES 解每个线性方程组,不形成矩阵,矩阵–向量乘积只由代码给出:前向路线的每次迭代调用一次 residual_d(第 8 节),伴随路线的每次迭代调用一次 residual_b(第 9 节)。图 40 数出调用次数:设计只有 a,φ,νa,\varphi,\nu 三个分量时(nD=3n_D=3),前向路线的调用约是伴随路线的三倍;若再给每个单元一个源项分量(nD=N+3n_D=N+3,上面“ψi\psi_i 的含义”里的 tt),前向路线的调用随 NN 增长得快得多,而伴随路线的调用次数与 nDn_D 无关:N=64N=64 时是 3279 次对 64 次。a,φ,νa,\varphi,\nu 的求解与伴随求解每次约用 NN 次迭代(N=64N=64 时为 64、64、63、64),单元源项的求解在较大的网格上用得少些(N=64N=64 时 31–64 次,平均 48),所以 nD=N+3n_D=N+3 时调用次数之比是 51,而不是 nD=67n_D=67。两条路线的梯度最大相差 1.8×10−121.8\times10^{-12}。与直接求解相比,这个差全在前向路线的单元源项分量上(最多差 1.8×10−121.8\times10^{-12});两条路线的 a,φ,νa,\varphi,\nu 分量以及伴随路线的单元分量与直接求解相差约 10−1410^{-14}(舍入误差)。

The cost of the two routes can be counted directly. Solve every linear system with unpreconditioned GMRES, without forming the matrix (the matrix–vector products come from the code): each iteration of the tangent route calls residual_d once (Section 8), each iteration of the adjoint route calls residual_b once (Section 9). Figure 40 counts the calls. With the three design components a,φ,νa,\varphi,\nu (nD=3n_D=3) the tangent route makes about three times as many calls as the adjoint route. Give every cell one more source component as well (nD=N+3n_D=N+3, the tt of “What ψi\psi_i means” above), and the calls of the tangent route grow much faster with NN, while the calls of the adjoint route do not depend on nDn_D: 3279 calls against 64 at N=64N=64. The solves for a,φ,νa,\varphi,\nu and the adjoint solve take about NN iterations each (64, 64, 63, 64 at N=64N=64), while the solves for the extra cell sources take fewer on the larger meshes (31–64, 48 on average, at N=64N=64), so with nD=N+3n_D=N+3 the ratio of the calls is 51 rather than nD=67n_D=67. The gradients of the two routes differ by at most 1.8×10−121.8\times10^{-12}. Against a direct solve, all of it sits in the cell-source components of the tangent route (off by up to 1.8×10−121.8\times10^{-12}); the components a,φ,νa,\varphi,\nu of both routes and the cell components of the adjoint route agree with the direct solve to about 10−1410^{-14} (round-off).

图 40 · 两条路线的代价(无限制器线性,默认设计;纵轴为对数刻度):不加预处理的 GMRES 求解所调用的 residual_d(前向)与 residual_b(伴随)次数。a,φ,ν 与伴随的求解每次约用 N 次迭代,单元源项的求解在较大网格上少一些。预处理()能减少每次求解的迭代次数,但前向路线仍要 n_D 次求解,伴随路线一次。110100103​104​24888N = 84830416N = 1696102732N = 32191327964N = 64前向或反向代码的调用次数前向路线,nD​ = 3前向路线,nD​ = N + 3伴随路线(两种 nD​ 相同)
图 40 · 两条路线的代价(无限制器线性,默认设计;纵轴为对数刻度):不加预处理的 GMRES 求解所调用的 residual_d(前向)与 residual_b(伴随)次数。a,φ,νa,\varphi,\nu 与伴随的求解每次约用 NN 次迭代,单元源项的求解在较大网格上少一些。预处理(第 17 节)能减少每次求解的迭代次数,但前向路线仍要 nDn_D 次求解,伴随路线一次。
Figure 40 · The cost of the two routes (unlimited linear, default design; logarithmic vertical axis): the calls of residual_d (tangent) and residual_b (adjoint) made by unpreconditioned GMRES. The solves for a,φ,ν and the adjoint solve take about N iterations each, the solves for the cell sources somewhat fewer on the larger meshes. Preconditioning () reduces the iterations of each solve, but the tangent route still needs n_D solves and the adjoint route one.110100103​104​24888N = 84830416N = 1696102732N = 32191327964N = 64calls of the tangent or reverse codetangent route, nD​ = 3tangent route, nD​ = N + 3adjoint route (either nD​)
Figure 40 · The cost of the two routes (unlimited linear, default design; logarithmic vertical axis): the calls of residual_d (tangent) and residual_b (adjoint) made by unpreconditioned GMRES. The solves for a,φ,νa,\varphi,\nu and the adjoint solve take about NN iterations each, the solves for the cell sources somewhat fewer on the larger meshes. Preconditioning (Section 17) reduces the iterations of each solve, but the tangent route still needs nDn_D solves and the adjoint route one.

用 LU 分解直接求解时情况不同:AA 分解一次后(部分选主元:PA=LUPA=LU),nDn_D 个前向右端项与一个伴随右端项(AT=UTLTPA^T=U^TL^TP 用同一组因子)都只需三角求解(前代与回代),差别小得多。伴随的优势在矩阵不显式形成、每次求解都要迭代的大问题里才显著——这正是 CFD 的常态。若有 nJn_J 个目标,伴随路线要解 nJn_J 次,前向路线仍是 nDn_D 次:哪条路线便宜取决于 nDn_D 与 nJn_J 谁大。

With a direct LU solve the picture is different: once AA is factored (with partial pivoting, PA=LUPA=LU), the nDn_D tangent right-hand sides and the one adjoint right-hand side (AT=UTLTPA^T=U^TL^TP reuses the same factors) each cost only triangular solves, and the difference is small. The adjoint pays off in large problems where the matrix is never formed and every solve is an iteration, which is the normal case in CFD. With nJn_J objectives the adjoint route needs nJn_J solves and the tangent route still nDn_D: which route is cheaper depends on whether nDn_D or nJn_J is larger.

第 12 节Section 12

设计导数:设计从哪里进入残差

The design derivatives: where the design enters the residual

本节实验:先预测振幅的梯度 dJh/da\mathrm dJ_h/\mathrm da 主要来自源项行还是两个边界面;再想一想:连续问题的 dJ/dν=0\mathrm dJ/\mathrm d\nu=0 是精确的,为什么 N=8N=8 时 dJh/dν=−0.3099\mathrm dJ_h/\mathrm d\nu=−0.3099?

Experiment: Predict first: where does the amplitude gradient dJh/da\mathrm dJ_h/\mathrm da come from, the source rows or the two boundary faces? And why is dJh/dν=−0.3099\mathrm dJ_h/\mathrm d\nu=−0.3099 at N=8N=8, when the continuous dJ/dν=0\mathrm dJ/\mathrm d\nu=0 exactly?

第 10 节与第 11 节把 RDR_D 当作一个整体使用。本节把它打开:每个设计分量从哪里进入残差,每条进入路径对梯度贡献多少,以及这些部分怎样收敛到连续梯度的两项。

Section 10 and Section 11 used RDR_D as a whole. This section opens it: where each design component enters the residual, how much each path contributes to the gradient, and how the pieces converge to the two terms of the continuous gradient.

每个设计变量改变什么

What each design variable changes

构造解的公式(第 1 节)给出每个量对每个设计变量的精确导数。下表列出它们,最后一列是连续目标的精确梯度:

The formulas of the manufactured solution (Section 1) give the exact derivative of every quantity with respect to every design variable. The table lists them; the last column is the exact gradient of the continuous objective:

设计变量Design variable∂u∗/∂Dk\partial u^*/\partial D_k∂uin/∂Dk=∂uout/∂Dk\partial u_{\rm in}/\partial D_k=\partial u_{\rm out}/\partial D_k∂Qf/∂Dk\partial Q_f/\partial D_k(Qf=q∗(xf)Q_f=q^*(x_f))∂Qf/∂Dk\partial Q_f/\partial D_k, Qf=q∗(xf)Q_f=q^*(x_f)通量 HfH_fFlux HfH_f∂J∗/∂Dk\partial J^*/\partial D_k
aasin⁡ z\sin\,z−sin⁡ 2πφ-\sin\,2\pi\varphiu∗ sin⁡ z−2πν cos⁡ zu^*\,\sin\,z-2\pi\nu\,\cos\,z只经边界面 00、NN 上的边界值only through the boundary values at faces 00 and NN−cos⁡ 2πφ/(2π)-\cos\,2\pi\varphi/(2\pi)
φ\varphi−2πa cos⁡ z-2\pi a\,\cos\,z−2πa cos⁡ 2πφ-2\pi a\,\cos\,2\pi\varphi−2πa u∗ cos⁡ z−4π2νa sin⁡ z-2\pi a\,u^*\,\cos\,z-4\pi^2\nu a\,\sin\,z同上likewisea sin⁡ 2πφa\,\sin\,2\pi\varphi
ν\nu0000−2πa cos⁡ z=−ux∗-2\pi a\,\cos\,z=-u^*_x每个面:∂Hf/∂ν=−(UR−UL)/df\partial H_f/\partial\nu=-(U_R-U_L)/d_fevery face: ∂Hf/∂ν=−(UR−UL)/df\partial H_f/\partial\nu=-(U_R-U_L)/d_f00

默认设计下精确梯度是 (−0.144008, 0.085156, 0.000000)(−0.144008,\ 0.085156,\ 0.000000)。ν\nu 的一行最特别:解与目标都不依赖 ν\nu,但源项的精确通量 QfQ_f 依赖(−νux∗-\nu u^*_x 是源项必须补上的扩散),离散通量也依赖。

At the default design the exact gradient is (−0.144008, 0.085156, 0.000000)(−0.144008,\ 0.085156,\ 0.000000). The ν\nu row is the special one: neither the solution nor the objective depends on ν\nu, but the exact flux QfQ_f of the source does (−νux∗-\nu u^*_x is the diffusion the source has to supply), and so does the discrete flux.

矩阵 RDR_D

The matrix RDR_D

RDR_D 是 N×3N\times3 矩阵,每列是第 10 节的一个右端项(差一个负号)。下表是 N=8N=8 的 RDR_D。aa 与 φ\varphi 两列不含状态:它们只来自精确通量 QfQ_f 和边界面上的 cL(0)=uin/2+1c_L(0)=u_{\rm in}/2+1、cR(N)=uout/2−1c_R(N)=u_{\rm out}/2-1、2ν/h2\nu/h,所以三种重构的这两列完全相同(最大差 00);ν\nu 列含 UR−ULU_R-U_L,随重构而变。

RDR_D is an N×3N\times3 matrix; each column is one right-hand side of Section 10 (up to the sign). The table shows RDR_D for N=8N=8. The aa and φ\varphi columns contain no state: they come only from the exact flux QfQ_f and from cL(0)=uin/2+1c_L(0)=u_{\rm in}/2+1, cR(N)=uout/2−1c_R(N)=u_{\rm out}/2-1 and 2ν/h2\nu/h on the boundary faces, so they are the same for the three reconstructions (largest difference 00). The ν\nu column contains UR−ULU_R-U_L and changes with the reconstruction.

RDR_D(N=8N=8,无限制器线性,默认设计)RDR_D (N=8N=8, unlimited linear, default design)
单元 iiCell ii(RD)i0(R_D)_{i0}(aa)(RD)i0(R_D)_{i0} (aa)(RD)i1(R_D)_{i1}(φ\varphi)(RD)i1(R_D)_{i1} (φ\varphi)(RD)i2(R_D)_{i2}(ν\nu)(RD)i2(R_D)_{i2} (ν\nu)
0−0.0602782.1216691.181870
1−0.739248−0.585875−0.320041
2−0.097399−1.134801−0.103733
30.620327−0.768764−0.065025
40.7755610.071256−0.186947
50.4576600.619323−0.327502
60.0707810.7809470.091534
7−0.0395961.5341740.748130

每一列的四个部分

The four pieces of a column

取 𝐔˙=0\dot{\mathbf U}=0、D˙=ek\dot D=e_k,第 8 节的前向面语句是下式第一行。只有两个边界面上 q˙\dot q、U˙\dot U 不为零(面 00 上 q˙L=U˙L=u˙in\dot q_L=\dot U_L=\dot u_{\rm in},面 NN 上 q˙R=U˙R=u˙out\dot q_R=\dot U_R=\dot u_{\rm out}),ν˙=1\dot\nu=1 只在 k=2k=2 时出现。三项按残差的分发方式(Rf−1R_{f-1} 加、RfR_f 减)进入各行,源项语句再加上第四部分:

With 𝐔˙=0\dot{\mathbf U}=0 and D˙=ek\dot D=e_k, the tangent face statement of Section 8 is the first line below. Only on the two boundary faces are q˙\dot q and U˙\dot U nonzero (q˙L=U˙L=u˙in\dot q_L=\dot U_L=\dot u_{\rm in} on face 00, q˙R=U˙R=u˙out\dot q_R=\dot U_R=\dot u_{\rm out} on face NN), and ν˙=1\dot\nu=1 occurs only for k=2k=2. The three terms enter the rows the way the residual is scattered (added to Rf−1R_{f-1}, subtracted from RfR_f), and the source statement adds the fourth piece:

H˙f=cL q˙L+cR q˙R−ν U˙R−U˙Ldf−ν˙ UR−ULdf,RDek=RDsrcek+RDconvek+RDviscek+RDfluxek,(RDsrc)ik=−(∂Qi+1∂Dk−∂Qi∂Dk),(RDconv)0k=−cL(0) ∂uin∂Dk,(RDconv)N−1,k=cR(N) ∂uout∂Dk,(RDvisc)0k=−2νh ∂uin∂Dk,(RDvisc)N−1,k=−2νh ∂uout∂Dk,(RDflux)i2=∂Hi+1∂ν−∂Hi∂ν,∂Hf∂ν=−UR−ULdf.\begin{aligned}\dot H_f&=c_L\,\dot q_L+c_R\,\dot q_R-\nu\,\frac{\dot U_R-\dot U_L}{d_f}-\dot\nu\,\frac{U_R-U_L}{d_f},\\R_De_k&=R_D^{\rm src}e_k+R_D^{\rm conv}e_k+R_D^{\rm visc}e_k+R_D^{\rm flux}e_k,\\(R_D^{\rm src})_{ik}&=-\Bigl(\frac{\partial Q_{i+1}}{\partial D_k}-\frac{\partial Q_i}{\partial D_k}\Bigr),\\(R_D^{\rm conv})_{0k}&=-c_L(0)\,\frac{\partial u_{\rm in}}{\partial D_k},\qquad(R_D^{\rm conv})_{N-1,k}=c_R(N)\,\frac{\partial u_{\rm out}}{\partial D_k},\\(R_D^{\rm visc})_{0k}&=-\frac{2\nu}{h}\,\frac{\partial u_{\rm in}}{\partial D_k},\qquad(R_D^{\rm visc})_{N-1,k}=-\frac{2\nu}{h}\,\frac{\partial u_{\rm out}}{\partial D_k},\\(R_D^{\rm flux})_{i2}&=\frac{\partial H_{i+1}}{\partial\nu}-\frac{\partial H_i}{\partial\nu},\qquad\frac{\partial H_f}{\partial\nu}=-\frac{U_R-U_L}{d_f}.\end{aligned}

边界部分只出现在第一行和最后一行,其余行为零;2ν/h2\nu/h 就是边界面的 κf=ν/df\kappa_f=\nu/d_f(df=h/2d_f=h/2)。RDfluxR_D^{\rm flux} 只有 ν\nu 一列,而且每个面都有,包括两个边界面(那里 UL=uinU_L=u_{\rm in} 或 UR=uoutU_R=u_{\rm out},df=h/2d_f=h/2)。本页从前向代码自己的中间量读出这四部分;四部分之和与前向代码算出的 RDR_D 相差不到 10−1510^{-15};check_d.js 还用独立的复数步长实现逐项核对了每一部分。图 41 把它们画成堆叠柱。

The boundary pieces occur in the first and the last row only; 2ν/h2\nu/h is the κf=ν/df\kappa_f=\nu/d_f of a boundary face (df=h/2d_f=h/2). RDfluxR_D^{\rm flux} has only the ν\nu column, and it has an entry from every face, the two boundary faces included (there UL=uinU_L=u_{\rm in} or UR=uoutU_R=u_{\rm out} and df=h/2d_f=h/2). The page reads the four pieces off the intermediate values of the tangent code; their sum differs from the RDR_D of the tangent code by less than 10−1510^{-15}, and check_d.js holds each piece separately to an independent complex-step implementation. Figure 41 draws them as stacked bars.

图 41 · R_D 每一列的四个部分(N=8,无限制器线性,默认设计):源项行(橙黄)、边界面的对流部分(紫)与黏性部分(绿)、通量中的 ν(蓝);圆点是它们的和,即 R_De_k。a、φ 列的边界部分只在首末两行。ν 列的两部分只在面上导数近似准确的行里几乎抵消(第 2、3、6 行,约抵消到 10%;第 1、5 行只部分抵消);边界旁和 u*_xx ≈ 0 的行并不抵消(第 0、4、7 行两者同号)。源项行边界面:对流边界面:黏性通量中的 ν和−0.500.500.51xk = 0:振幅 a,RD​ e0​−101200.51xk = 1:相位 φ,RD​ e1​−1−0.500.5100.51xk = 2:黏性 ν,RD​ e2​
图 41 · RDR_D 每一列的四个部分(N=8N=8,无限制器线性,默认设计):源项行(橙黄)、边界面的对流部分(紫)与黏性部分(绿)、通量中的 ν\nu(蓝);圆点是它们的和,即 RDekR_De_k。aa、φ\varphi 列的边界部分只在首末两行。ν\nu 列的两部分只在面上导数近似准确的行里几乎抵消(第 2、3、6 行,约抵消到 10%;第 1、5 行只部分抵消);边界旁和 uxx∗≈0u^*_{xx}\approx0 的行并不抵消(第 0、4、7 行两者同号)。
Figure 41 · The four pieces of each column of R_D (N=8, unlimited linear, default design): source rows (amber), the convective (violet) and the viscous (green) part of the boundary faces, and the ν of the flux (blue); the dots are their sum, R_De_k. In the a and φ columns the boundary pieces sit in the first and the last row. In the ν column the two pieces nearly cancel only where the face derivative is accurate (rows 2, 3, 6, to about 10%; rows 1 and 5 only partly); next to the boundaries and where u*_xx ≈ 0 they do not (in rows 0, 4, 7 they have the same sign).source rowsboundary faces: convectiveboundary faces: viscousν in the fluxsum−0.500.500.51xk = 0: amplitude a: RD​ e0​−101200.51xk = 1: phase φ: RD​ e1​−1−0.500.5100.51xk = 2: viscosity ν: RD​ e2​
Figure 41 · The four pieces of each column of RDR_D (N=8N=8, unlimited linear, default design): source rows (amber), the convective (violet) and the viscous (green) part of the boundary faces, and the ν\nu of the flux (blue); the dots are their sum, RDekR_De_k. In the aa and φ\varphi columns the boundary pieces sit in the first and the last row. In the ν\nu column the two pieces nearly cancel only where the face derivative is accurate (rows 2, 3, 6, to about 10%; rows 1 and 5 only partly); next to the boundaries and where uxx∗≈0u^*_{xx}\approx0 they do not (in rows 0, 4, 7 they have the same sign).

梯度从哪里来

Where the gradient comes from

把伴随与每一部分做内积,梯度 dJh/dDk\mathrm dJ_h/\mathrm dD_k 就被分成同样的四部分 ψTRDsrcek\psi^TR_D^{\rm src}e_k、ψTRDconvek\psi^TR_D^{\rm conv}e_k、ψTRDviscek\psi^TR_D^{\rm visc}e_k、ψTRDfluxek\psi^TR_D^{\rm flux}e_k。两个边界部分合起来有一个简单的形式。第 9 节的反向语句在面 00 上把 qˉL+UˉL\bar q_L+\bar U_L 累加到 uˉin\bar u_{\rm in},在面 NN 上把 qˉR+UˉR\bar q_R+\bar U_R 累加到 uˉout\bar u_{\rm out};以 Rˉ=ψ\bar R=\psi 为种子,Hˉ0=−ψ0\bar H_0=-\psi_0、HˉN=ψN−1\bar H_N=\psi_{N-1},于是

Dotting the adjoint with every piece splits the gradient dJh/dDk\mathrm dJ_h/\mathrm dD_k into the same four parts, ψTRDsrcek\psi^TR_D^{\rm src}e_k, ψTRDconvek\psi^TR_D^{\rm conv}e_k, ψTRDviscek\psi^TR_D^{\rm visc}e_k and ψTRDfluxek\psi^TR_D^{\rm flux}e_k. The two boundary parts together take a simple form. The reverse statements of Section 9 accumulate qˉL+UˉL\bar q_L+\bar U_L into uˉin\bar u_{\rm in} on face 00 and qˉR+UˉR\bar q_R+\bar U_R into uˉout\bar u_{\rm out} on face NN; with the seed Rˉ=ψ\bar R=\psi, Hˉ0=−ψ0\bar H_0=-\psi_0 and HˉN=ψN−1\bar H_N=\psi_{N-1}, so

uˉin=−(cL(0)+2νh)ψ0,uˉout=(cR(N)−2νh)ψN−1,ψT(RDconv+RDvisc)ek=∂uin∂Dk uˉin+∂uout∂Dk uˉout.\bar u_{\rm in}=-\Bigl(c_L(0)+\frac{2\nu}{h}\Bigr)\psi_0,\qquad \bar u_{\rm out}=\Bigl(c_R(N)-\frac{2\nu}{h}\Bigr)\psi_{N-1},\qquad \psi^T\bigl(R_D^{\rm conv}+R_D^{\rm visc}\bigr)e_k=\frac{\partial u_{\rm in}}{\partial D_k}\,\bar u_{\rm in}+\frac{\partial u_{\rm out}}{\partial D_k}\,\bar u_{\rm out}.

uˉin\bar u_{\rm in} 是 JhJ_h 对入口值的导数(源项与出口值不变)。默认设计下 uˉin=1.4949\bar u_{\rm in}=1.4949、uˉout=0.1147\bar u_{\rm out}=0.1147,由反向代码算出,与上面三个式子都相差不到 10−1510^{-15}(三种重构)。下表与图 42 给出梯度的四部分。

uˉin\bar u_{\rm in} is the derivative of JhJ_h with respect to the inlet value (with the source and the outlet value fixed). At the default design the reverse code gives uˉin=1.4949\bar u_{\rm in}=1.4949 and uˉout=0.1147\bar u_{\rm out}=0.1147, in agreement with all three formulas above to within 10−1510^{-15} (three reconstructions). The table and Figure 42 give the four parts of the gradient.

梯度的四部分(N=8N=8,默认设计)The four parts of the gradient (N=8N=8, default design)
重构Reconstruction分量ComponentψTRDsrcek\psi^TR_D^{\rm src}e_kψTRDconvek\psi^TR_D^{\rm conv}e_kψTRDviscek\psi^TR_D^{\rm visc}e_kψTRDfluxek\psi^TR_D^{\rm flux}e_k梯度Gradient
一阶first orderaa−0.03053−0.63467−0.080780.00000−0.745986
一阶first orderφ\varphi1.55327−1.69488−0.215730.00000−0.357342
一阶first orderν\nu1.574000.000000.00000−1.81948−0.245484
无限制器线性unlimited linearaa0.19868−0.61124−0.074080.00000−0.486650
无限制器线性unlimited linearφ\varphi1.76912−1.63232−0.197840.00000−0.061039
无限制器线性unlimited linearν\nu1.816770.000000.00000−2.12664−0.309871
光滑限制器smooth limiteraa0.06174−0.63979−0.078480.00000−0.656527
光滑限制器smooth limiterφ\varphi1.75002−1.70854−0.209580.00000−0.168097
光滑限制器smooth limiterν\nu1.826070.000000.00000−2.11685−0.290780

实验的第一问有了答案:N=8N=8、无限制器线性时,aa 的梯度 −0.4866−0.4866 主要来自边界部分 −0.6853−0.6853(绝对值比梯度本身还大),符号相反的源项部分 0.19870.1987 抵消了其中约 29%;φ\varphi 更极端:1.76911.7691 与 −1.8302−1.8302 相加只剩 −0.0610−0.0610。边界部分几乎全是对流部分,黏性部分只占一小份。N=8N=8 时,这和第 11 节逐单元的“谁的贡献”图看起来不同:单元 0 里源项部分(+0.692+0.692)与边界部分(−0.637−0.637)几乎抵消,首末两个单元合计只有 0.0620.062;只有更细的网格上首末单元才承载边界部分(N=128N=128:−0.606−0.606 对 −0.619−0.619)。

The first question of the experiment has its answer: at N=8N=8 with unlimited linear reconstruction, the aa-gradient −0.4866−0.4866 comes mainly from the boundary part −0.6853−0.6853, which is larger in magnitude than the gradient itself; the source part 0.19870.1987 has the opposite sign and cancels about 29% of it. φ\varphi is more extreme: 1.76911.7691 and −1.8302−1.8302 add up to only −0.0610−0.0610. The boundary part is almost entirely convective; the viscous part is a small share. At N=8N=8 this differs from the per-cell picture of Section 11: in cell 0 the source piece (+0.692+0.692) and the boundary piece (−0.637−0.637) nearly cancel, so the first and the last cell together show only 0.0620.062. Only on finer meshes do the end cells carry the boundary part (N=128N=128: −0.606−0.606 against −0.619−0.619).

图 42 · 梯度的四部分:N=8、N=512(无限制器线性,默认设计)与连续梯度的两项。颜色同,圆点是总和。加密时边界部分从对流(紫)转到黏性(绿),总量只变了 10%(a:从 −0.685 到 −0.617);连续问题里只剩黏性边界项 νλ_x(1) ∂ u_out/∂ D_k-νλ_x(0) ∂ u_in/∂ D_k 和源项积分。源项行边界面:对流边界面:黏性通量中的 ν和−0.8−0.6−0.4−0.200.20.4k = 0:振幅 aN = 8N = 512连续−2−1012k = 1:相位 φN = 8N = 512连续−2−1012k = 2:黏性 νN = 8N = 512连续
图 42 · 梯度的四部分:N=8N=8、N=512N=512(无限制器线性,默认设计)与连续梯度的两项。颜色同图 41,圆点是总和。加密时边界部分从对流(紫)转到黏性(绿),总量只变了 10%(aa:从 −0.685−0.685 到 −0.617−0.617);连续问题里只剩黏性边界项 νλx(1) ∂uout/∂Dk−νλx(0) ∂uin/∂Dk\nu\lambda_x(1)\,\partial u_{\rm out}/\partial D_k-\nu\lambda_x(0)\,\partial u_{\rm in}/\partial D_k 和源项积分。
Figure 42 · The four parts of the gradient at N=8 and N=512 (unlimited linear, default design) and the two terms of the continuous gradient. Colours as in ; the dots are the totals. Under refinement the boundary part moves from the convective (violet) to the viscous (green) piece while its total changes by only 10% (a: from −0.685 to −0.617); in the continuous problem only the viscous boundary term νλ_x(1) ∂ u_out/∂ D_k-νλ_x(0) ∂ u_in/∂ D_k and the source integral remain.source rowsboundary faces: convectiveboundary faces: viscousν in the fluxsum−0.8−0.6−0.4−0.200.20.4k = 0: amplitude aN = 8N = 512continuous−2−1012k = 1: phase φN = 8N = 512continuous−2−1012k = 2: viscosity νN = 8N = 512continuous
Figure 42 · The four parts of the gradient at N=8N=8 and N=512N=512 (unlimited linear, default design) and the two terms of the continuous gradient. Colours as in Figure 41; the dots are the totals. Under refinement the boundary part moves from the convective (violet) to the viscous (green) piece while its total changes by only 10% (aa: from −0.685−0.685 to −0.617−0.617); in the continuous problem only the viscous boundary term νλx(1) ∂uout/∂Dk−νλx(0) ∂uin/∂Dk\nu\lambda_x(1)\,\partial u_{\rm out}/\partial D_k-\nu\lambda_x(0)\,\partial u_{\rm in}/\partial D_k and the source integral remain.

连续梯度:两个相互抵消的大项

The continuous gradient: two large terms that cancel

对连续问题做同样的分解。附录 A 由连续伴随 λ\lambda(−uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x),λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0)推出梯度公式;它也有一个源项部分和一个边界部分,后者只有黏性:

The continuous problem splits the same way. Appendix A derives the gradient formula from the continuous adjoint λ\lambda (−uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x), λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0); it too has a source part and a boundary part, and the latter is purely viscous:

dJdDk=−∫01λ sDk dx+ν λx(1) ∂uout∂Dk−ν λx(0) ∂uin∂Dk(Dk=a,φ),dJdν=−∫01λ (sν+uxx∗) dx=0.\frac{\mathrm dJ}{\mathrm dD_k}=-\int_0^1\lambda\,s_{D_k}\,\mathrm dx+\nu\,\lambda_x(1)\,\frac{\partial u_{\rm out}}{\partial D_k}-\nu\,\lambda_x(0)\,\frac{\partial u_{\rm in}}{\partial D_k}\quad(D_k=a,\varphi),\qquad \frac{\mathrm dJ}{\mathrm d\nu}=-\int_0^1\lambda\,\bigl(s_\nu+u^*_{xx}\bigr)\,\mathrm dx=0.

用独立求出的 λ\lambda(Chebyshev 配点,M=200M=200)计算两项:aa 的源项积分 0.47280.4728 与边界项 −0.6168−0.6168,φ\varphi 的 1.73231.7323 与 −1.6471−1.6471——各自都是 O(1)O(1),相加才得到小的精确梯度 (−0.144008, 0.085156)(−0.144008,\ 0.085156)(与闭式相差不到 10−1210^{-12})。边界项几乎全来自 x=0x=0:−νλx(0) ∂uin/∂Dk-\nu\lambda_x(0)\,\partial u_{\rm in}/\partial D_k 对 aa、φ\varphi 分别是 −0.6074−0.6074 与 −1.6221−1.6221,x=1x=1 只贡献 −0.0094−0.0094 与 −0.0251−0.0251。ν\nu 的两部分 −∫λsν=1.8769-\int\lambda s_\nu=1.8769 与 −∫λuxx∗=−1.8769-\int\lambda u^*_{xx}=−1.8769 逐点抵消:sν=4π2a sin⁡ z=−uxx∗s_\nu=4\pi^2a\,\sin\,z=-u^*_{xx},源项补上的扩散恰好是通量里 ν\nu 的作用。

With an independently computed λ\lambda (Chebyshev collocation, M=200M=200) the two terms are: for aa the source integral 0.47280.4728 and the boundary term −0.6168−0.6168, for φ\varphi 1.73231.7323 and −1.6471−1.6471: each of order one, and only their sum is the small exact gradient (−0.144008, 0.085156)(−0.144008,\ 0.085156) (within 10−1210^{-12} of the closed form). The boundary term comes almost entirely from x=0x=0: −νλx(0) ∂uin/∂Dk-\nu\lambda_x(0)\,\partial u_{\rm in}/\partial D_k is −0.6074−0.6074 for aa and −1.6221−1.6221 for φ\varphi, while x=1x=1 adds only −0.0094−0.0094 and −0.0251−0.0251. The two parts of ν\nu, −∫λsν=1.8769-\int\lambda s_\nu=1.8769 and −∫λuxx∗=−1.8769-\int\lambda u^*_{xx}=−1.8769, cancel at every point: sν=4π2a sin⁡ z=−uxx∗s_\nu=4\pi^2a\,\sin\,z=-u^*_{xx}, the diffusion that the source supplies is exactly what ν\nu does in the flux.

离散的两部分怎样收敛

How the discrete parts converge

离散梯度的源项部分是 −∑iψi∫cellsDk dx-\sum_i\psi_i\int_{\rm cell}s_{D_k}\,\mathrm dx,在 ψi→λ(xi)\psi_i\to\lambda(x_i) 时收敛到 −∫λsDk dx-\int\lambda s_{D_k}\,\mathrm dx;边界部分的黏性项是 −ν ψ0h/2 ∂uin∂Dk+ν −ψN−1h/2 ∂uout∂Dk-\nu\,\frac{\psi_0}{h/2}\,\frac{\partial u_{\rm in}}{\partial D_k}+\nu\,\frac{-\psi_{N-1}}{h/2}\,\frac{\partial u_{\rm out}}{\partial D_k},在单侧差商趋于 λx(0)\lambda_x(0)、λx(1)\lambda_x(1) 时收敛到连续边界项,对流项 −cL(0)ψ0 ∂uin/∂Dk+…-c_L(0)\psi_0\,\partial u_{\rm in}/\partial D_k+\dots 随 ψ0→0\psi_0\to0 消失。图 43 用带状求解器从 N=8N=8 测到 40964096:两部分分别趋向连续的两项。

The source part of the discrete gradient is −∑iψi∫cellsDk dx-\sum_i\psi_i\int_{\rm cell}s_{D_k}\,\mathrm dx, which tends to −∫λsDk dx-\int\lambda s_{D_k}\,\mathrm dx as ψi→λ(xi)\psi_i\to\lambda(x_i); the viscous boundary piece is −ν ψ0h/2 ∂uin∂Dk+ν −ψN−1h/2 ∂uout∂Dk-\nu\,\frac{\psi_0}{h/2}\,\frac{\partial u_{\rm in}}{\partial D_k}+\nu\,\frac{-\psi_{N-1}}{h/2}\,\frac{\partial u_{\rm out}}{\partial D_k}, which tends to the continuous boundary term as the one-sided quotients tend to λx(0)\lambda_x(0) and λx(1)\lambda_x(1), and the convective piece −cL(0)ψ0 ∂uin/∂Dk+…-c_L(0)\psi_0\,\partial u_{\rm in}/\partial D_k+\dots vanishes as ψ0→0\psi_0\to0. Figure 43 measures it with the banded solver from N=8N=8 to 40964096: each part approaches its continuous term.

图 43 · 离散梯度的两部分随网格加密的变化(无限制器线性,默认设计;带状求解器)。橙黄:源项部分;紫:边界部分(对流 + 黏性);深色:梯度;虚线是连续的源项积分、边界项与精确梯度。N=4096 时两部分与连续值分别相差 3.6 × 10^(-5) 与 3.2 × 10^(-6)(a)。源项部分 ψT​ RD​src​ ek​边界部分(对流 + 黏性)梯度虚线:连续值−0.6−0.4−0.200.20.48645124096Nk = 0:振幅 a−2−10128645124096Nk = 1:相位 φ
图 43 · 离散梯度的两部分随网格加密的变化(无限制器线性,默认设计;带状求解器)。橙黄:源项部分;紫:边界部分(对流 + 黏性);深色:梯度;虚线是连续的源项积分、边界项与精确梯度。N=4096N=4096 时两部分与连续值分别相差 3.6×10−53.6\times10^{-5} 与 3.2×10−63.2\times10^{-6}(aa)。
Figure 43 · The two parts of the discrete gradient under refinement (unlimited linear, default design; banded solver). Amber: source part; violet: boundary part (convective + viscous); dark: the gradient; dashed: the continuous source integral, boundary term and exact gradient. At N=4096 the two parts are within 3.6 × 10^(-5) and 3.2 × 10^(-6) of their continuous values (a).source part ψT​ RD​src​ ek​boundary part (convective + viscous)gradientdashed: continuous−0.6−0.4−0.200.20.48645124096Nk = 0: amplitude a−2−10128645124096Nk = 1: phase φ
Figure 43 · The two parts of the discrete gradient under refinement (unlimited linear, default design; banded solver). Amber: source part; violet: boundary part (convective + viscous); dark: the gradient; dashed: the continuous source integral, boundary term and exact gradient. At N=4096N=4096 the two parts are within 3.6×10−53.6\times10^{-5} and 3.2×10−63.2\times10^{-6} of their continuous values (aa).

边界部分与连续边界项的相对差在 N=8N=8 时是 11%,N=64N=64 时 1.1%,可它内部的组成变化很大。图 44 跟踪入口值的伴随 uˉin\bar u_{\rm in}:N=8N=8 时它已是 1.49491.4949,与 −νλx(0)=1.4266-\nu\lambda_x(0)=1.4266 相差 4.8%;N=512N=512 时两者相差 6.3×10−56.3\times10^{-5},N=1024N=1024 时 9.4×10−69.4\times10^{-6}——而 N=512N=512 时 ψ0/(h/2)\psi_0/(h/2) 仍是 −124.9−124.9,离 λx(0)\lambda_x(0) 还差 12%。粗网格上是对流部分 −cL(0)ψ0-c_L(0)\psi_0 在承担它(N=8N=8 时占 90%),细网格上换成黏性部分 −(2ν/h)ψ0-(2\nu/h)\psi_0(N=4096N=4096 时占 98%)。出口值的伴随没有这么准:uˉout\bar u_{\rm out} 是 νλx(1)=0.0220\nu\lambda_x(1)=0.0220 的 5.2 倍(N=8N=8)、3.0 倍(N=16N=16)、2.0 倍(N=32N=32)和 1.44 倍(N=64N=64);N=8N=8 到 256256 时,边界部分的误差有 58%、52%、54%、59%、68%、78% 来自出口面。φ\varphi 的边界部分大,所以 N=8N=8 时边界部分的误差是 φ\varphi 的主要误差(参见第 16 节)。

The boundary part differs from the continuous boundary term by 11% at N=8N=8 and by 1.1% at N=64N=64, yet its make-up changes a lot. Figure 44 follows the adjoint of the inlet value, uˉin\bar u_{\rm in}: at N=8N=8 it is already 1.49491.4949, 4.8% from −νλx(0)=1.4266-\nu\lambda_x(0)=1.4266; at N=512N=512 the two differ by 6.3×10−56.3\times10^{-5} and at N=1024N=1024 by 9.4×10−69.4\times10^{-6}, while at N=512N=512 the quotient ψ0/(h/2)\psi_0/(h/2) is still −124.9−124.9, 12% short of λx(0)\lambda_x(0). On coarse meshes the convective piece −cL(0)ψ0-c_L(0)\psi_0 carries it (90% at N=8N=8); on fine meshes the viscous piece −(2ν/h)ψ0-(2\nu/h)\psi_0 takes over (98% at N=4096N=4096). The adjoint of the outlet value is less accurate: uˉout\bar u_{\rm out} is 5.2 times νλx(1)=0.0220\nu\lambda_x(1)=0.0220 at N=8N=8, 3.0 times at N=16N=16, 2.0 at N=32N=32 and 1.44 at N=64N=64, and for N=8N=8 to 256256 the outlet face carries 58%, 52%, 54%, 59%, 68%, 78% of the error of the boundary part. The boundary part of φ\varphi is large, so at N=8N=8 the error of the boundary part is the dominant error of φ\varphi (compare Section 16).

图 44 · 入口值的伴随(无限制器线性,默认设计)。左:u-bar_in=-(c_L(0)+2ν/h)ψ_0 的对流部分(紫)与黏性部分(绿),圆点是和,虚线是连续值 -νλ_x(0)。右:单侧差商 ψ_0/(h/2) 与 λ_x(0)。梯度需要的 u-bar_in 在粗网格上已接近连续值;层的形状(右图)要到 N 上千才被分辨。对流部分 −cL​(0) ψ0​黏性部分 −(2ν/h) ψ0​连续值00.20.40.60.811.21.41.68645124096Nūin​ = −(cL​(0) + 2ν/h) ψ0​−ν λx​(0) = 1.4266−140−120−100−80−60−40−2008645124096Nψ0​/(h/2) 与 λx​(0)
图 44 · 入口值的伴随(无限制器线性,默认设计)。左:uˉin=−(cL(0)+2ν/h)ψ0\bar u_{\rm in}=-(c_L(0)+2\nu/h)\psi_0 的对流部分(紫)与黏性部分(绿),圆点是和,虚线是连续值 −νλx(0)-\nu\lambda_x(0)。右:单侧差商 ψ0/(h/2)\psi_0/(h/2) 与 λx(0)\lambda_x(0)。梯度需要的 uˉin\bar u_{\rm in} 在粗网格上已接近连续值;层的形状(右图)要到 NN 上千才被分辨。
Figure 44 · The adjoint of the inlet value (unlimited linear, default design). Left: the convective (violet) and the viscous (green) piece of u-bar_in=-(c_L(0)+2ν/h)ψ_0; the dots are the sum, the dashed line the continuous value -νλ_x(0). Right: the one-sided quotient ψ_0/(h/2) against λ_x(0). The u-bar_in that the gradient needs is close to its continuous value on coarse meshes already; the shape of the layer (right) is resolved only with N in the thousands.convective part −cL​(0) ψ0​viscous part −(2ν/h) ψ0​continuous00.20.40.60.811.21.41.68645124096Nūin​ = −(cL​(0) + 2ν/h) ψ0​−ν λx​(0) = 1.4266−140−120−100−80−60−40−2008645124096Nψ0​/(h/2) against λx​(0)
Figure 44 · The adjoint of the inlet value (unlimited linear, default design). Left: the convective (violet) and the viscous (green) piece of uˉin=−(cL(0)+2ν/h)ψ0\bar u_{\rm in}=-(c_L(0)+2\nu/h)\psi_0; the dots are the sum, the dashed line the continuous value −νλx(0)-\nu\lambda_x(0). Right: the one-sided quotient ψ0/(h/2)\psi_0/(h/2) against λx(0)\lambda_x(0). The uˉin\bar u_{\rm in} that the gradient needs is close to its continuous value on coarse meshes already; the shape of the layer (right) is resolved only with NN in the thousands.

为什么层没被分辨时边界值的伴随仍然对?把连续伴随方程跨过入口层积分,从 00 积到层外几个层宽处:λ(0)=0\lambda(0)=0,右端 −(1+x)-(1+x) 只贡献与区间长度同阶的一小份,于是 νλx(0)\nu\lambda_x(0) 约等于层外的 uλu\lambda——入口的灵敏度等于层外伴随的对流“通量”。事实上 λx(0)≈uinλout(0)/ν\lambda_x(0)\approx u_{\rm in}\lambda_{\rm out}(0)/\nu,其中外解在入口的值是 λout(0)=−∫01(1+t)/u dt\lambda_{\rm out}(0)=-\int_0^1(1+t)/u\,\mathrm dt,等于 −1.5619−1.5619,给出 −uinλout(0)=1.4289-u_{\rm in}\lambda_{\rm out}(0)=1.4289,与 −νλx(0)=1.4266-\nu\lambda_x(0)=1.4266 相近。梯度需要的是这个积分量,不是层的形状;离散伴随在单元 0 里守恒地传递同样的通量,所以粗网格上 uˉin\bar u_{\rm in} 已经接近它。这是一个启发式的解释,上面的数字才是证据。

Why is the adjoint of the boundary value right before the layer is resolved? Integrate the continuous adjoint equation across the inlet layer, from 00 to a point a few layer widths in: λ(0)=0\lambda(0)=0 and the right-hand side −(1+x)-(1+x) contributes only in proportion to the length of that interval, so νλx(0)\nu\lambda_x(0) is close to uλu\lambda just outside the layer: the sensitivity to the inlet value equals the convective flux of the adjoint outside the layer. Indeed λx(0)≈uinλout(0)/ν\lambda_x(0)\approx u_{\rm in}\lambda_{\rm out}(0)/\nu, where the outer solution has λout(0)=−∫01(1+t)/u dt\lambda_{\rm out}(0)=-\int_0^1(1+t)/u\,\mathrm dt, here −1.5619−1.5619, which gives −uinλout(0)=1.4289-u_{\rm in}\lambda_{\rm out}(0)=1.4289, close to −νλx(0)=1.4266-\nu\lambda_x(0)=1.4266. The gradient needs this integrated quantity, not the shape of the layer; the discrete adjoint carries the same flux conservatively through the first cell, so uˉin\bar u_{\rm in} is near it on coarse meshes already. This is a heuristic reading; the numbers above are the evidence.

离散梯度两部分的收敛(无限制器线性,默认设计;带状求解器)Convergence of the two parts of the discrete gradient (unlimited linear, default design; banded solver)
NψTRDsrce0\psi^TR_D^{\rm src}e_0ψT(RDconv+RDvisc)e0\psi^T(R_D^{\rm conv}+R_D^{\rm visc})e_0ψTRDsrce1\psi^TR_D^{\rm src}e_1ψT(RDconv+RDvisc)e1\psi^T(R_D^{\rm conv}+R_D^{\rm visc})e_1uˉin\bar u_{\rm in}对流占比Convective shareψ0/(h/2)\psi_0/(h/2)
80.1987−0.68531.7691−1.83021.494990%−14.8
320.3828−0.63401.8216−1.69301.445269%−44.1
1280.4554−0.61921.7523−1.65361.428436%−91.0
5120.4709−0.61701.7345−1.64761.426612%−124.9
20480.4726−0.61681.7324−1.64721.42663%−137.8
40960.4727−0.61681.7323−1.64711.42662%−140.2
连续continuous0.4728−0.61681.7323−1.64711.42660%−142.7

黏性导数

The viscosity derivative

连续的 dJ/dν\mathrm dJ/\mathrm d\nu 精确为零,离散的却不为零。RDR_D 的 ν\nu 列有一个精确的形式。源项部分是 −(∂Qi+1/∂ν−∂Qi/∂ν)-(\partial Q_{i+1}/\partial\nu-\partial Q_i/\partial\nu),即 ux∗(xi+1)−ux∗(xi)u^*_x(x_{i+1})-u^*_x(x_i),通量部分是 −(UR−UL)/df-(U_R-U_L)/d_f 的差;记面上导数近似的误差

The continuous dJ/dν\mathrm dJ/\mathrm d\nu is exactly zero; the discrete one is not. The ν\nu column of RDR_D has an exact form. Its source piece is −(∂Qi+1/∂ν−∂Qi/∂ν)-(\partial Q_{i+1}/\partial\nu-\partial Q_i/\partial\nu), that is ux∗(xi+1)−ux∗(xi)u^*_x(x_{i+1})-u^*_x(x_i), its flux piece the difference of −(UR−UL)/df-(U_R-U_L)/d_f; with the error of the face gradient

Ef=UR−ULdf−ux∗(xf),(RD)i2=−(Ei+1−Ei),dJhdν=ψTRDe2=∑f=0NEf (ψf−ψf−1)(ψ−1=ψN=0).E_f=\frac{U_R-U_L}{d_f}-u^*_x(x_f),\qquad (R_D)_{i2}=-\bigl(E_{i+1}-E_i\bigr),\qquad \frac{\mathrm dJ_h}{\mathrm d\nu}=\psi^TR_De_2=\sum_{f=0}^{N}E_f\,\bigl(\psi_f-\psi_{f-1}\bigr)\quad(\psi_{-1}=\psi_N=0).

(这里的 EfE_f 与第 6 节的误差传播矩阵 EE 无关。对 N=8N=8 逐行核对,差不到 10−1610^{-16}。)若面上的导数近似等于精确导数,ν\nu 列就是零。dJh/dν\mathrm dJ_h/\mathrm d\nu 是面上导数近似的误差按伴随在该面的跳跃加权求和;伴随在入口层里跳得最厉害,所以从 N=64N=64 起几乎全部来自层:x≤0.05x\le0.05 的面在 N=64N=64 时贡献 93%,N=128N=128 时 96%,N=512N=512 时 98%;更粗的网格上并非如此(N=32N=32 时 49%,N=8N=8 时层旁的面贡献 −0.573−0.573,总和只有 −0.310−0.310)。连续问题里只有一个类比,不能算作印证:通量部分写成 ∫λxux∗ dx\int\lambda_xu^*_x\,\mathrm dx 时,−1.877−1.877 中有 −1.729−1.729 来自 x≤0.05x\le0.05;写成 −∫λuxx∗ dx-\int\lambda u^*_{xx}\,\mathrm dx 时,同一区间只给 +0.120+0.120——积分“来自哪里”取决于它的写法。图 45 显示两部分的收敛:源项部分从 N=128N=128 起与 1.8771.877 相差不到 1%(0.76%0.76\%),通量部分要到 N=1024N=1024 才如此(0.53%0.53\%);dJh/dν\mathrm dJ_h/\mathrm d\nu 先变号,在 N=64N=64 附近达到 0.1810.181,最后以趋近 2 的观测阶趋于零(最后三对网格为 1.66、1.82、1.91;N=4096N=4096 时 7.9×10−47.9\times10^{-4})。

(Here EfE_f has nothing to do with the error propagator EE of Section 6. Checked row by row for N=8N=8: the difference is below 10−1610^{-16}.) If the discrete face gradients were exact, the ν\nu column would vanish. dJh/dν\mathrm dJ_h/\mathrm d\nu is the sum of the face-gradient errors weighted by the jump of the adjoint across the face, and the adjoint jumps most inside the inlet layer, so from N=64N=64 on almost everything comes from the layer: the faces with x≤0.05x\le0.05 give 93% at N=64N=64, 96% at N=128N=128 and 98% at N=512N=512. On coarser meshes they do not (49% at N=32N=32; at N=8N=8 the faces near the inlet give −0.573−0.573 of a total of only −0.310−0.310). The continuous problem offers an analogy, not an agreement: written as ∫λxux∗ dx\int\lambda_xu^*_x\,\mathrm dx, the flux part takes −1.729−1.729 of its −1.877−1.877 from x≤0.05x\le0.05; written as −∫λuxx∗ dx-\int\lambda u^*_{xx}\,\mathrm dx, the same interval gives +0.120+0.120: where an integral comes from depends on how it is written. Figure 45 shows the convergence of the two parts: the source part is within 1% of 1.8771.877 from N=128N=128 on (0.76%0.76\%), the flux part only from N=1024N=1024 on (0.53%0.53\%); dJh/dν\mathrm dJ_h/\mathrm d\nu changes sign, peaks at 0.1810.181 near N=64N=64 and finally decays with an observed order approaching 2 (1.66, 1.82, 1.91 for the last three pairs of meshes; 7.9×10−47.9\times10^{-4} at N=4096N=4096).

图 45 · 黏性导数的两部分(无限制器线性,默认设计)。左:通量部分(蓝)与源项部分(橙黄)趋向连续的 ∓ 1.877(虚线),圆点是它们的和 dJ_h/ dν。右:| dJ_h/ dν| 的双对数图,圈表示负值;最细的网格上斜率趋近 -2(N=2048 到 4096 之间为 −1.91),虚线是斜率 -2 的参考线。通量部分 ψT​ RD​flux​ e2​源项部分 ψT​ RD​src​ e2​dJh​/dν虚线:连续值 ∓1.877−2−10128645124096N两部分:通量(蓝)与源项(橙黄)10-4​10-3​10-2​10-1​18645124096N|dJh​/dν|:点为正,圈为负斜率 −2
图 45 · 黏性导数的两部分(无限制器线性,默认设计)。左:通量部分(蓝)与源项部分(橙黄)趋向连续的 ∓1.877\mp1.877(虚线),圆点是它们的和 dJh/dν\mathrm dJ_h/\mathrm d\nu。右:∣dJh/dν∣|\mathrm dJ_h/\mathrm d\nu| 的双对数图,圈表示负值;最细的网格上斜率趋近 −2-2(N=2048N=2048 到 40964096 之间为 −1.91−1.91),虚线是斜率 −2-2 的参考线。
Figure 45 · The two parts of the viscosity derivative (unlimited linear, default design). Left: the flux part (blue) and the source part (amber) approach the continuous ∓ 1.877 (dashed); the dots are their sum dJ_h/ dν. Right: | dJ_h/ dν| on log–log axes, rings for negative values; on the finest meshes the slope approaches -2 (−1.91 between N=2048 and 4096); the dashed line is a slope -2 guide.flux part ψT​ RD​flux​ e2​source part ψT​ RD​src​ e2​dJh​/dνdashed: continuous ∓1.877−2−10128645124096Nthe two parts: flux (blue) and source (amber)10-4​10-3​10-2​10-1​18645124096N|dJh​/dν|: dots positive, rings negativeslope −2
Figure 45 · The two parts of the viscosity derivative (unlimited linear, default design). Left: the flux part (blue) and the source part (amber) approach the continuous ∓1.877\mp1.877 (dashed); the dots are their sum dJh/dν\mathrm dJ_h/\mathrm d\nu. Right: ∣dJh/dν∣|\mathrm dJ_h/\mathrm d\nu| on log–log axes, rings for negative values; on the finest meshes the slope approaches −2-2 (−1.91−1.91 between N=2048N=2048 and 40964096); the dashed line is a slope −2-2 guide.

误差集中在入口旁的面上:未重构端单元的一阶迹(第 16 节)与伴随在层内的大跳跃在那里相遇,所以图 46 把 7 种网格、6 种黏性的 dJh/dν\mathrm dJ_h/\mathrm d\nu 对网格 Péclet 数 uinh/νu_{\rm in}h/\nu(层宽 ν/uin\nu/u_{\rm in} 内单元数的倒数)作图。ν≤0.02\nu\le0.02 时,在小于 1 的同一个 Péclet 数下,各网格的值相差约 1%(例如 Péclet 数 0.179 时 N=256,512,1024N=256,512,1024 给出 0.0333, 0.0331, 0.03300.0333,\ 0.0331,\ 0.0330),Péclet 数为 1.43 时相差 4%;ν=0.05\nu=0.05 与 0.10.1 的点在同一 Péclet 数下相差 4–12%;Péclet 数明显大于 1 时,粗网格的值互相分开(2.86 时相差 60%)。这是数值观察,不是定理,也不说明层是原因:按第 16 节的端单元实验重构端单元后(那里没有列出这个分量),N=64N=64 时 dJh/dν\mathrm dJ_h/\mathrm d\nu 从 0.1810.181 变为 −0.010−0.010,Péclet 数不变。

The error sits at the faces next to the inlet, where the first-order traces of the unreconstructed end cell (Section 16) meet the large jumps of the adjoint in its layer, so Figure 46 plots dJh/dν\mathrm dJ_h/\mathrm d\nu for 7 meshes and 6 viscosities against the cell Péclet number uinh/νu_{\rm in}h/\nu (the inverse of the number of cells per layer width ν/uin\nu/u_{\rm in}). For ν≤0.02\nu\le0.02, at equal Péclet numbers below 1, the meshes agree to about 1% (at 0.179, for example, N=256,512,1024N=256,512,1024 give 0.0333, 0.0331, 0.03300.0333,\ 0.0331,\ 0.0330), and at a Péclet number of 1.43 to 4%; the points with ν=0.05\nu=0.05 and 0.10.1 differ by 4–12% at equal Péclet numbers; clearly above 1 the coarse meshes split apart (60% apart at 2.86). This is a numerical observation, not a theorem, and it does not make the layer the cause: with the end cells reconstructed (the experiment of Section 16, which does not tabulate this component) dJh/dν\mathrm dJ_h/\mathrm d\nu at N=64N=64 changes from 0.1810.181 to −0.010−0.010, at the same Péclet number.

图 46 · dJ_h/ dν 随网格 Péclet 数 u_inh/ν 的变化(无限制器线性,a=0.2,φ=0.07;ν 取 0.002 到 0.1,每条线是一种网格)。连续值处处为零,所以纵轴就是误差。Péclet 数小于 1 时,ν ≤ 0.02 的各网格在同一 Péclet 数下相差约 1%;ν=0.05 与 0.1 的点相差 4–12%。N = 16N = 32N = 64N = 128N = 256N = 512N = 1024−0.3−0.2−0.100.10.20.010.1110网格 Péclet 数 uin​ h/νdJh​/dν
图 46 · dJh/dν\mathrm dJ_h/\mathrm d\nu 随网格 Péclet 数 uinh/νu_{\rm in}h/\nu 的变化(无限制器线性,a=0.2a=0.2,φ=0.07\varphi=0.07;ν\nu 取 0.0020.002 到 0.10.1,每条线是一种网格)。连续值处处为零,所以纵轴就是误差。Péclet 数小于 1 时,ν≤0.02\nu\le0.02 的各网格在同一 Péclet 数下相差约 1%;ν=0.05\nu=0.05 与 0.10.1 的点相差 4–12%。
Figure 46 · dJ_h/ dν against the cell Péclet number u_inh/ν (unlimited linear, a=0.2, φ=0.07; ν from 0.002 to 0.1, one line per mesh). The continuous value is zero everywhere, so the vertical axis is the error. Below a Péclet number of 1 the meshes with ν ≤ 0.02 agree to about 1% at equal Péclet numbers; those with ν=0.05 and 0.1 differ by 4–12%.N = 16N = 32N = 64N = 128N = 256N = 512N = 1024−0.3−0.2−0.100.10.20.010.1110cell Péclet number uin​ h/νdJh​/dν
Figure 46 · dJh/dν\mathrm dJ_h/\mathrm d\nu against the cell Péclet number uinh/νu_{\rm in}h/\nu (unlimited linear, a=0.2a=0.2, φ=0.07\varphi=0.07; ν\nu from 0.0020.002 to 0.10.1, one line per mesh). The continuous value is zero everywhere, so the vertical axis is the error. Below a Péclet number of 1 the meshes with ν≤0.02\nu\le0.02 agree to about 1% at equal Péclet numbers; those with ν=0.05\nu=0.05 and 0.10.1 differ by 4–12%.

误差分解

The error budget

把梯度的误差 dJh/dDk−dJ/dDk\mathrm dJ_h/\mathrm dD_k-\mathrm dJ/\mathrm dD_k 拆成两部分各自的误差(源项部分减源项积分,边界部分减边界项;ν\nu 则是源项部分与通量部分)。图 47 显示了三件事。aa 的误差在每个网格上都主要来自源项部分(N=512N=512 时 −1.9×10−3−1.9\times10^{-3} 对 −2×10−4−2\times10^{-4})。φ\varphi 的两部分误差在每个网格上都符号相反、部分抵消:N=8N=8 时边界部分的误差较大(−1.8×10−1−1.8\times10^{-1}),从 N=16N=16 起源项部分的误差较大。ν\nu 的误差从 N=64N=64 起主要来自通量部分(N=512N=512 时 3.1×10−23.1\times10^{-2} 对 1.6×10−31.6\times10^{-3}),也就是来自入口旁的面。

Split the error of the gradient, dJh/dDk−dJ/dDk\mathrm dJ_h/\mathrm dD_k-\mathrm dJ/\mathrm dD_k, into the errors of its two parts (the source part minus the source integral, the boundary part minus the boundary term; for ν\nu the source part and the flux part). Figure 47 shows: the error of aa comes mainly from the source part on every mesh (−1.9×10−3−1.9\times10^{-3} against −2×10−4−2\times10^{-4} at N=512N=512); for φ\varphi the two errors have opposite signs on every mesh and partly cancel, the boundary part's being the larger at N=8N=8 (−1.8×10−1−1.8\times10^{-1}) and the source part's from N=16N=16 on; the error of ν\nu comes mainly from the flux part from N=64N=64 on (3.1×10−23.1\times10^{-2} against 1.6×10−31.6\times10^{-3} at N=512N=512), that is from the faces next to the inlet.

图 47 · 梯度误差的分解(无限制器线性,默认设计,双对数图,画的是绝对值):源项部分的误差(橙黄)、边界部分(紫,a,φ)或通量部分(蓝,ν)的误差,以及梯度本身的误差(圈)。曲线上的凹口是误差变号的地方。源项部分边界部分(a、φ)通量部分(ν)梯度10-6​10-5​10-4​10-3​10-2​10-1​18645124096Nk = 0:振幅 a10-6​10-5​10-4​10-3​10-2​10-1​18645124096Nk = 1:相位 φ10-5​10-4​10-3​10-2​10-1​18645124096Nk = 2:黏性 ν
图 47 · 梯度误差的分解(无限制器线性,默认设计,双对数图,画的是绝对值):源项部分的误差(橙黄)、边界部分(紫,a,φa,\varphi)或通量部分(蓝,ν\nu)的误差,以及梯度本身的误差(圈)。曲线上的凹口是误差变号的地方。
Figure 47 · The error budget of the gradient (unlimited linear, default design, log axes, absolute values): the error of the source part (amber), of the boundary part (violet, a,φ) or of the flux part (blue, ν), and the error of the gradient itself (rings). The notches are where an error changes sign.source partboundary part (a, φ)flux part (ν)gradient10-6​10-5​10-4​10-3​10-2​10-1​18645124096Nk = 0: amplitude a10-6​10-5​10-4​10-3​10-2​10-1​18645124096Nk = 1: phase φ10-5​10-4​10-3​10-2​10-1​18645124096Nk = 2: viscosity ν
Figure 47 · The error budget of the gradient (unlimited linear, default design, log axes, absolute values): the error of the source part (amber), of the boundary part (violet, a,φa,\varphi) or of the flux part (blue, ν\nu), and the error of the gradient itself (rings). The notches are where an error changes sign.

离散梯度 dJh/dD\mathrm dJ_h/\mathrm dD 是离散目标的精确导数——前向、伴随、复数步长与差分在本页检验过的每个网格上都一致(第 13、14 节)。它与连续梯度的差是离散化误差,不是求导错误。本节说明了这个误差来自哪里:主要出在入口旁的几个单元。第 16 节说明了原因:两个端单元不做重构(σ0=σN−1=0\sigma_0=\sigma_{N-1}=0),面 0、1 与 N−1N-1、NN 的迹只有一阶精度;重构端单元后,λ\lambda 的层同样没被分辨,aa 的梯度误差却从 0.343 降到 0.030(N=8N=8),从 0.107 降到 3.9×10−43.9\times10^{-4}(N=32N=32)。aa、φ\varphi 的误差经由源项部分:xi≤0.05x_i\le0.05 的单元承担了 aa 的源项部分误差的 115%、107%、103%、102%(N=32N=32、6464、128128、512512,其余单元部分抵消),以及 φ\varphi 的约四分之三(77%、76%、76%、76%)。ν\nu 的误差经由通量部分。最粗的网格上还有边界部分:N=8N=8 时 φ\varphi 的最大误差项 −0.18−0.18 一半以上来自出口面。

The discrete gradient dJh/dD\mathrm dJ_h/\mathrm dD is the exact derivative of the discrete objective: tangent, adjoint, complex step and differences agree on every mesh tested on this page (Sections 13 and 14). Its difference from the continuous gradient is a discretisation error, not a differentiation error. This section showed where that error comes from: mostly the cells next to the inlet. Section 16 shows why: the two end cells are not reconstructed (σ0=σN−1=0\sigma_0=\sigma_{N-1}=0), so the traces of faces 0, 1 and N−1N-1, NN are only first-order accurate; with the end cells reconstructed the aa-gradient error drops from 0.343 to 0.030 at N=8N=8 and from 0.107 to 3.9×10−43.9\times10^{-4} at N=32N=32, although the layer of λ\lambda is just as unresolved. For aa and φ\varphi it comes through the source part: the cells with xi≤0.05x_i\le0.05 carry 115%, 107%, 103%, 102% of the source-part error of aa (N=32,64,128,512N=32, 64, 128, 512; the other cells partly compensate) and about three quarters of that of φ\varphi (77%, 76%, 76%, 76%). For ν\nu it comes through the flux part. On the coarsest meshes the boundary part adds to it: at N=8N=8 more than half of the largest φ\varphi error term, −0.18−0.18, comes from the outlet face.

第 13 节Section 13

有限差分验证:每个扰动都重新求解

Finite-difference check: re-solve at every perturbed design

本节实验:先猜一猜,把步长 τ\tau 从 10−110^{-1} 一路缩到 10−1210^{-12},中心差分会不会越来越接近伴随梯度?在哪个 τ\tau 最准、能有几位有效数字一致?然后用本节的步长扫描实验检验。

Experiment: guess first: as the step τ\tau shrinks from 10−110^{-1} to 10−1210^{-12}, does the central difference keep getting closer to the adjoint gradient? At which τ\tau is it most accurate, and how many significant digits agree? Then test the guess with the step-scan lab of this section.

第 10、11 节用两种方法算出了离散目标的梯度:三个前向求解 Avk=−RDekAv_k=-R_De_k 给出 J˙=wTvk\dot J=w^Tv_k,一个伴随求解 ATψ=−gA^T\psi=-g 给出 Dˉ=RDTψ\bar D=R_D^T\psi;默认设计下三种重构的两组结果相差不超过 7.3×10−167.3\times10^{-16}。但这两条路都用到求导代码(第 8 节的前向语句和第 9 节的反向语句)。有限差分不用任何求导代码:它只在附近的设计上重新运行原始求解器,所以是对第 8–12 节的一次独立检验。

Sections 10 and 11 computed the gradient of the discrete objective in two ways: three tangent solves Avk=−RDekAv_k=-R_De_k give J˙=wTvk\dot J=w^Tv_k, and one adjoint solve ATψ=−gA^T\psi=-g gives Dˉ=RDTψ\bar D=R_D^T\psi; at the defaults the two differ by at most 7.3×10−167.3\times10^{-16} for all three reconstructions. Both paths use derivative code (the tangent statements of Section 8 and the reverse statements of Section 9). A finite difference uses no derivative code at all: it only runs the primal solver again at nearby designs, which makes it an independent check of Sections 8–12.

Jh(D)=wT𝐔(D),R(𝐔(D),D)=0.J_h(D)=w^T\mathbf U(D),\qquad R\bigl(\mathbf U(D),D\bigr)=0.

被求导的函数是 Jh(D)J_h(D),即这套网格、这种重构下离散解的目标值。差分验证的是 ∂Jh/∂Dk\partial J_h/\partial D_k,不是连续问题的精确梯度。默认网格上两者相差很远:无限制器线性重构的伴随梯度是 (−0.486650, −0.061039, −0.309871)(-0.486650,\ -0.061039,\ -0.309871),精确梯度是 (−0.144008, 0.085156, 0)(-0.144008,\ 0.085156,\ 0)。这个差别是离散误差,第 15、16 节才讨论;本节只问一件事:伴随算出的数是不是 JhJ_h 的导数。

The function being differentiated is Jh(D)J_h(D), the objective of the discrete solution on this mesh with this reconstruction. The finite difference checks ∂Jh/∂Dk\partial J_h/\partial D_k, not the exact gradient of the continuous problem. On the default mesh the two are far apart: the adjoint gradient with unlimited linear reconstruction is (−0.486650, −0.061039, −0.309871)(-0.486650,\ -0.061039,\ -0.309871), the exact gradient (−0.144008, 0.085156, 0)(-0.144008,\ 0.085156,\ 0). That difference is discretisation error, the subject of Sections 15 and 16; this section asks one thing only: is the number the adjoint computes the derivative of JhJ_h?

两个差商

Two difference quotients

记 ∂k=∂/∂Dk\partial_k=\partial/\partial D_k(第 13 至 15 节里下标 aa、φ\varphi、ν\nu 对应 k=0,1,2k=0,1,2:ea=e0e_a=e_0,va=v0v_a=v_0,Dˉa=Dˉ0\bar D_a=\bar D_0)。把 Jh(D±τek)J_h(D\pm\tau e_k) 在 DD 处做 Taylor 展开,单侧差商和中心差商分别是

Write ∂k=∂/∂Dk\partial_k=\partial/\partial D_k (in Sections 13 to 15 the subscripts aa, φ\varphi, ν\nu stand for k=0,1,2k=0,1,2: ea=e0e_a=e_0, va=v0v_a=v_0, Dˉa=Dˉ0\bar D_a=\bar D_0). Expanding Jh(D±τek)J_h(D\pm\tau e_k) in a Taylor series about DD gives the one-sided and the central quotient:

FDτ+=Jh(D+τek)−Jh(D)τ=∂kJh+τ2 ∂k2Jh+O(τ2),FDτc=Jh(D+τek)−Jh(D−τek)2τ=∂kJh+τ26 ∂k3Jh+O(τ4).\begin{aligned}\mathrm{FD}_\tau^+&=\frac{J_h(D+\tau e_k)-J_h(D)}{\tau}=\partial_kJ_h+\frac\tau2\,\partial_k^2J_h+O(\tau^2),\\ \mathrm{FD}_\tau^{\rm c}&=\frac{J_h(D+\tau e_k)-J_h(D-\tau e_k)}{2\tau}=\partial_kJ_h+\frac{\tau^2}6\,\partial_k^3J_h+O(\tau^4).\end{aligned}

中心差商里偶次项相减抵消,所以它的截断误差是二阶的。步长 τ\tau 只是一个数:它不是网格宽度 hh,也不是导数记号。

In the central quotient the even powers cancel, so its truncation error is second order. The step τ\tau is just a number: it is neither the mesh width hh nor a derivative symbol.

每个扰动设计都要完整重算

Every perturbed design needs a full re-solve

Jh=wT𝐔J_h=w^T\mathbf U 本身不含 DD(第 7 节:JD=0J_D=0),设计只通过状态影响目标。所以只改 DD、不重新求解,差商就是 JD=0J_D=0,这就是“冻结状态”的错误。每个扰动设计 D±τekD\pm\tau e_k 都需要自己收敛的状态 𝐔(D±τek)\mathbf U(D\pm\tau e_k),网格、重构和 Newton 迭代都与基准求解相同(初值是扰动设计下 u∗u^* 在单元中心的值,修正量不超过 10−1310^{-13} 时停止)。图 48 上图是改变振幅后的状态;下图说明状态差商 [𝐔(D+τea)−𝐔(D)]/τ[\mathbf U(D+\tau e_a)-\mathbf U(D)]/\tau 随 τ→0\tau\to0 趋向第 10 节的切线解 va=𝐔˙v_a=\dot{\mathbf U}:τ=0.1\tau=0.1、0.010.01、0.0010.001 时最大偏差为 5.7×10−25.7\times10^{-2}、5.2×10−35.2\times10^{-3}、5.1×10−45.1\times10^{-4},相邻两次之比为 11.0 和 10.1,约 10 倍(一阶)。

Jh=wT𝐔J_h=w^T\mathbf U contains no DD of its own (Section 7: JD=0J_D=0); the design acts on the objective only through the state. Change DD without solving again and the quotient is JD=0J_D=0: the "frozen state" bug. Every perturbed design D±τekD\pm\tau e_k needs its own converged state 𝐔(D±τek)\mathbf U(D\pm\tau e_k), with the mesh, the reconstruction and the Newton iteration of the base solve (started from the values of u∗u^* at the cell centres of the perturbed design, stopped when the correction is at most 10−1310^{-13}). The top panel of Figure 48 shows the state after a change of the amplitude; the bottom panel shows the state quotient [𝐔(D+τea)−𝐔(D)]/τ[\mathbf U(D+\tau e_a)-\mathbf U(D)]/\tau approaching the tangent solution va=𝐔˙v_a=\dot{\mathbf U} of Section 10 as τ→0\tau\to0: the largest deviation is 5.7×10−25.7\times10^{-2}, 5.2×10−35.2\times10^{-3} and 5.1×10−45.1\times10^{-4} for τ=0.1\tau=0.1, 0.010.01 and 0.0010.001, smaller by factors of 11.0 and 10.1: about 10 each time (first order).

图 48 · 扰动设计必须重新求解(默认设计,N=8,无限制器线性)。上:U(D)(点)与 U(D+0.1 e_a)(圈)——整个状态都变了。下:状态差商(τ=0.1 圈,τ=0.01 方块)趋向切线解 v_a(实线);差分在目标上看到的变化 w^Tv_a 就来自这里。0.70.80.911.11.200.20.40.60.81xUi​U(D)U(D + τ ea​),τ = 0.1−1−0.500.500.20.40.60.81x状态差商[U(D + τea​) − U(D)]/τ, τ = 0.1τ = 0.01切线解 va​(第 10 节)
图 48 · 扰动设计必须重新求解(默认设计,N=8N=8,无限制器线性)。上:𝐔(D)\mathbf U(D)(点)与 𝐔(D+0.1 ea)\mathbf U(D+0.1\,e_a)(圈)——整个状态都变了。下:状态差商(τ=0.1\tau=0.1 圈,τ=0.01\tau=0.01 方块)趋向切线解 vav_a(实线);差分在目标上看到的变化 wTvaw^Tv_a 就来自这里。
Figure 48 · A perturbed design must be solved again (default design, N=8, unlimited linear). Top: U(D) (dots) and U(D+0.1 e_a) (rings): the whole state changes. Bottom: the state quotients (τ=0.1 rings, τ=0.01 squares) approach the tangent solution v_a (solid line), the source of the change w^Tv_a that the difference quotient sees in the objective.0.70.80.911.11.200.20.40.60.81xUi​U(D)U(D + τ ea​), τ = 0.1−1−0.500.500.20.40.60.81xstate quotient[U(D + τea​) − U(D)]/τ, τ = 0.1τ = 0.01tangent solution va​ (Section 10)
Figure 48 · A perturbed design must be solved again (default design, N=8N=8, unlimited linear). Top: 𝐔(D)\mathbf U(D) (dots) and 𝐔(D+0.1 ea)\mathbf U(D+0.1\,e_a) (rings): the whole state changes. Bottom: the state quotients (τ=0.1\tau=0.1 rings, τ=0.01\tau=0.01 squares) approach the tangent solution vav_a (solid line), the source of the change wTvaw^Tv_a that the difference quotient sees in the objective.

完整的验证流程如下(伪代码;本页的扫描实验就是这样算的):

The complete check reads (pseudocode; the step-scan lab of this page computes exactly this):

U0 = solve(D)                          # Newton: initial guess u*(x_i; D), stop when |dU| <= 1e-13
J0 = w . U0
for k in (a, phi, nu):
    for tau in 1e-1, 1e-2, ..., 1e-12:
        Up = solve(D + tau e_k)        # a full re-solve: the state changes
        Um = solve(D - tau e_k)        # for nu only if nu - tau > 0
        FD_f = (w . Up - J0) / tau
        FD_c = (w . Up - w . Um) / (2 tau)
        compare with Dbar_k = (R_D^T psi)_k     # the adjoint gradient of Section 11

一次中心差分要 2 次非线性求解,三个分量 6 次;扫描 12 个步长最多 72 次(ν−τ≤0\nu-\tau\le0 的点不算),再加 1 次基准求解。伴随只要 1 次线性求解就给出全部三个分量(第 11 节)。这里设计只有 3 个分量,差分的负担不重;设计有成千上万个分量时,差分只能抽查少数几个方向。

One central difference costs 2 nonlinear solves, 6 for the three components; a scan over 12 steps costs up to 72 (the points with ν−τ≤0\nu-\tau\le0 are skipped), plus the base solve. The adjoint gives all three components with one linear solve (Section 11). With 3 design components the finite differences are affordable here; with thousands of components they can only spot-check a few directions.

截断误差与舍入误差:V 形

Truncation against rounding: the V

两种误差相互竞争。截断误差随 τ\tau 减小(单侧差商斜率 1,中心差商斜率 2)。舍入误差正相反:JhJ_h 只有约 16 位有效数字,它的舍入误差 εJ≈εmach∣Jh∣\varepsilon_J\approx\varepsilon_{\rm mach}|J_h| 不随 τ\tau 变小,差商却要把它除以 τ\tau:

Two errors compete. The truncation error shrinks with τ\tau (slope 1 for the one-sided quotient, slope 2 for the central one). The rounding error does the opposite: JhJ_h carries about 16 significant digits, its rounding error εJ≈εmach∣Jh∣\varepsilon_J\approx\varepsilon_{\rm mach}|J_h| does not shrink with τ\tau, and the quotient divides it by τ\tau:

∣FDτc−∂kJh∣≈τ26 ∣∂k3Jh∣+εJτ,εJ≈εmach∣Jh∣,εmach=2.2×10−16.\bigl|\mathrm{FD}_\tau^{\rm c}-\partial_kJ_h\bigr|\approx\frac{\tau^2}6\,\bigl|\partial_k^3J_h\bigr|+\frac{\varepsilon_J}\tau,\qquad \varepsilon_J\approx\varepsilon_{\rm mach}|J_h|,\quad \varepsilon_{\rm mach}=2.2\times10^{-16}.

在双对数图上右支是斜率 2 的直线,左支是斜率 −1-1 的直线,合起来是一个 V 形。令两项之和对 τ\tau 的导数为零,得到最佳步长 τopt=(3εJ/∣∂k3Jh∣)1/3\tau_{\rm opt}=(3\varepsilon_J/|\partial_k^3J_h|)^{1/3}。这些高阶导数可以由伴随梯度差分得到:在 DD 两侧各做一次伴随求解(aa、φ\varphi 的步长是 10−310^{-3},ν\nu 是 10−410^{-4};差分的是精确导数,不是目标值),两侧梯度的中心差分是 ∂k2Jh\partial_k^2J_h,再用上 DD 处的梯度做二阶差分得到 ∂k3Jh\partial_k^3J_h。默认设计下对 aa 得 ∂a2Jh=−0.3581\partial_a^2J_h=-0.3581、∂a3Jh=−1.5680\partial_a^3J_h=-1.5680,于是 τopt≈8.4×10−6\tau_{\rm opt}\approx8.4\times10^{-6},最小误差约 5.6×10−115.6\times10^{-11}。扫描中实际最好的是 τ=10−5\tau=10^{-5},误差约 3.5×10−113.5\times10^{-11}。

On log-log axes the right branch is a line of slope 2 and the left branch a line of slope −1-1: together they form a V. Setting the derivative of the sum to zero gives the best step τopt=(3εJ/∣∂k3Jh∣)1/3\tau_{\rm opt}=(3\varepsilon_J/|\partial_k^3J_h|)^{1/3}. The higher derivatives come from differencing the adjoint gradient: one adjoint solve on each side of DD (with the step 10−310^{-3} for aa and φ\varphi, 10−410^{-4} for ν\nu; what is differenced is an exact derivative, not the objective); the central difference of the two gradients is ∂k2Jh\partial_k^2J_h, and the second difference with the gradient at DD is ∂k3Jh\partial_k^3J_h. At the defaults this gives ∂a2Jh=−0.3581\partial_a^2J_h=-0.3581 and ∂a3Jh=−1.5680\partial_a^3J_h=-1.5680 for the amplitude, so τopt≈8.4×10−6\tau_{\rm opt}\approx8.4\times10^{-6} and a smallest error of about 5.6×10−115.6\times10^{-11}. The best point of the actual scan is τ=10−5\tau=10^{-5}, with an error of about 3.5×10−113.5\times10^{-11}.

图 49 · V 形是可以预测的(分量 a,默认设计,无限制器线性)。方块和圈是实测的中心与单侧差分误差;两条虚线是 Taylor 预测的截断误差 τ^2|∂_a^3J_h|/6 与 τ|∂_a^2J_h|/2(导数由伴随梯度再差分得到);灰色点线是舍入线 ε_mach|J_h|/τ。τ=10^(-3) 时,实测与预测之比为 1.0000(中心)和 1.0015(单侧)。10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​10-12​10-10​10-8​10-6​10-4​10-2​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ分量 a:实测误差与两条预测线单侧差分 FD+​中心差分 FDc​
图 49 · V 形是可以预测的(分量 aa,默认设计,无限制器线性)。方块和圈是实测的中心与单侧差分误差;两条虚线是 Taylor 预测的截断误差 τ2∣∂a3Jh∣/6\tau^2|\partial_a^3J_h|/6 与 τ∣∂a2Jh∣/2\tau|\partial_a^2J_h|/2(导数由伴随梯度再差分得到);灰色点线是舍入线 εmach∣Jh∣/τ\varepsilon_{\rm mach}|J_h|/\tau。τ=10−3\tau=10^{-3} 时,实测与预测之比为 1.0000(中心)和 1.0015(单侧)。
Figure 49 · The V can be predicted (component a, default design, unlimited linear). Squares and rings are the measured central and one-sided errors; the two dashed lines are the Taylor predictions of the truncation error, τ^2|∂_a^3J_h|/6 and τ|∂_a^2J_h|/2 (the derivatives from differencing the adjoint gradient); the dotted grey line is the rounding line ε_mach|J_h|/τ. At τ=10^(-3) measured over predicted is 1.0000 (central) and 1.0015 (one-sided).10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​10-12​10-10​10-8​10-6​10-4​10-2​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τcomponent a: measured errors and the two predicted linesone-sided FD+​central FDc​
Figure 49 · The V can be predicted (component aa, default design, unlimited linear). Squares and rings are the measured central and one-sided errors; the two dashed lines are the Taylor predictions of the truncation error, τ2∣∂a3Jh∣/6\tau^2|\partial_a^3J_h|/6 and τ∣∂a2Jh∣/2\tau|\partial_a^2J_h|/2 (the derivatives from differencing the adjoint gradient); the dotted grey line is the rounding line εmach∣Jh∣/τ\varepsilon_{\rm mach}|J_h|/\tau. At τ=10−3\tau=10^{-3} measured over predicted is 1.0000 (central) and 1.0015 (one-sided).

图 50 对三个分量各做一次扫描。右支都贴着斜率 1、2 的参考线:τ=10−3\tau=10^{-3} 时,实测中心差分误差与预测 τ2∣∂k3Jh∣/6\tau^2|\partial_k^3J_h|/6 之比是 1.0000、1.0000、1.0001(aa、φ\varphi、ν\nu)。左支沿着舍入线上升:τ≤10−8\tau\le10^{-8} 的所有中心差分点都在舍入线之下(最多是它的 0.80 倍);ν\nu 的单侧差分在 τ=10−8\tau=10^{-8} 处仍以截断误差为主(实测 1.2×10−71.2\times10^{-7},τ∣∂ν2Jh∣/2=1.0×10−7\tau|\partial_\nu^2J_h|/2=1.0\times10^{-7})。ν\nu 分量的右支高得多:ν=0.01\nu=0.01 很小,JhJ_h 对 ν\nu 的高阶导数很大(∂ν3Jh=−726.6\partial_\nu^3J_h=-726.6),τ\tau 一旦不比 ν\nu 小很多,截断误差就很大。按相对步长 τ/Dk\tau/D_k 衡量,ν\nu 与 aa 两个分量其实相近:ν2∣∂ν3Jh∣/6=0.012\nu^2|\partial_\nu^3J_h|/6=0.012,a2∣∂a3Jh∣/6=0.010a^2|\partial_a^3J_h|/6=0.010。τ≥ν\tau\ge\nu 时 ν−τ≤0\nu-\tau\le0,中心差分根本不能用,图和表里没有这些点。

Figure 50 scans each of the three components. All right branches follow the reference lines of slopes 1 and 2: at τ=10−3\tau=10^{-3} the measured central error over the prediction τ2∣∂k3Jh∣/6\tau^2|\partial_k^3J_h|/6 is 1.0000, 1.0000, 1.0001 for aa, φ\varphi, ν\nu. The left branches rise along the rounding line: every central-difference point with τ≤10−8\tau\le10^{-8} lies below it (at most 0.80 of it); the one-sided ν\nu point at τ=10−8\tau=10^{-8} is still truncation (measured 1.2×10−71.2\times10^{-7}, τ∣∂ν2Jh∣/2=1.0×10−7\tau|\partial_\nu^2J_h|/2=1.0\times10^{-7}). The right branch of ν\nu lies much higher: ν=0.01\nu=0.01 is small, the derivatives of JhJ_h with respect to ν\nu are large (∂ν3Jh=−726.6\partial_\nu^3J_h=-726.6), and as soon as τ\tau is not much smaller than ν\nu the truncation error is large. Measured in the relative step τ/Dk\tau/D_k the two components are in fact alike: ν2∣∂ν3Jh∣/6=0.012\nu^2|\partial_\nu^3J_h|/6=0.012 and a2∣∂a3Jh∣/6=0.010a^2|\partial_a^3J_h|/6=0.010. For τ≥ν\tau\ge\nu the central difference cannot even be formed (ν−τ≤0\nu-\tau\le0), so those points are missing from the figure and the tables.

图 50 · 三个分量的步长扫描(默认设计,N=8,无限制器线性)。圈:单侧差分;方块:中心差分;虚线:斜率 1、2 的参考线;点线:舍入线 ε_mach|J_h|/τ。每个分量的 V 形谷底不同:中心差分的最佳步长分别是 10^(-5)、10^(-6)、10^(-6),误差约为 3.5 × 10^(-11)、6.9 × 10^(-11)、1.9 × 10^(-10)。10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​10-12​10-10​10-8​10-6​10-4​10-2​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ21分量 a:∂Jh​/∂a = −0.486650单侧差分 FD+​中心差分 FDc​10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​110-12​10-10​10-8​10-6​10-4​10-2​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ21分量 φ:∂Jh​/∂φ = −0.061039单侧差分 FD+​中心差分 FDc​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​110-12​10-10​10-8​10-6​10-4​10-2​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ分量 ν:∂Jh​/∂ν = −0.309871单侧差分 FD+​中心差分 FDc​
图 50 · 三个分量的步长扫描(默认设计,N=8N=8,无限制器线性)。圈:单侧差分;方块:中心差分;虚线:斜率 1、2 的参考线;点线:舍入线 εmach∣Jh∣/τ\varepsilon_{\rm mach}|J_h|/\tau。每个分量的 V 形谷底不同:中心差分的最佳步长分别是 10−510^{-5}、10−610^{-6}、10−610^{-6},误差约为 3.5×10−113.5\times10^{-11}、6.9×10−116.9\times10^{-11}、1.9×10−101.9\times10^{-10}。
Figure 50 · The step scans of the three components (default design, N=8, unlimited linear). Rings: one-sided differences; squares: central differences; dashed: reference lines of slopes 1 and 2; dotted: the rounding line ε_mach|J_h|/τ. The bottom of the V differs from component to component: the best central steps are 10^(-5), 10^(-6), 10^(-6), with errors of about 3.5 × 10^(-11), 6.9 × 10^(-11), 1.9 × 10^(-10).10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​10-12​10-10​10-8​10-6​10-4​10-2​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τ21component a: ∂Jh​/∂a = −0.486650one-sided FD+​central FDc​10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​110-12​10-10​10-8​10-6​10-4​10-2​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τ21component φ: ∂Jh​/∂φ = −0.061039one-sided FD+​central FDc​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​110-12​10-10​10-8​10-6​10-4​10-2​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τcomponent ν: ∂Jh​/∂ν = −0.309871one-sided FD+​central FDc​
Figure 50 · The step scans of the three components (default design, N=8N=8, unlimited linear). Rings: one-sided differences; squares: central differences; dashed: reference lines of slopes 1 and 2; dotted: the rounding line εmach∣Jh∣/τ\varepsilon_{\rm mach}|J_h|/\tau. The bottom of the V differs from component to component: the best central steps are 10−510^{-5}, 10−610^{-6}, 10−610^{-6}, with errors of about 3.5×10−113.5\times10^{-11}, 6.9×10−116.9\times10^{-11}, 1.9×10−101.9\times10^{-10}.

下表是三种重构、三个分量的中心差分误差 ∣FDτc−Dˉk∣|\mathrm{FD}_\tau^{\rm c}-\bar D_k|(Dˉk\bar D_k 是第 11 节的伴随梯度),粗体是每一列的最小值:

The table lists the central-difference errors ∣FDτc−Dˉk∣|\mathrm{FD}_\tau^{\rm c}-\bar D_k| for the three reconstructions and components (Dˉk\bar D_k is the adjoint gradient of Section 11); bold is the smallest value of each column:

一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
τ\tauaaφ\varphiν\nuaaφ\varphiν\nuaaφ\varphiν\nu
10−110^{-1}1.7e−33.9e−2—2.7e−38.1e−3—5.4e−37.6e−2—
10−210^{-2}1.7e−54.1e−4—2.6e−58.6e−5—5.4e−59.9e−3—
10−310^{-3}1.7e−74.1e−61.6e−42.6e−78.6e−71.2e−45.4e−79.2e−51.4e−4
10−410^{-4}1.7e−94.1e−81.6e−62.6e−98.6e−91.2e−65.4e−99.2e−71.4e−6
10−510^{-5}2.0e−114.0e−101.6e−83.5e−119.2e−111.2e−87.0e−119.2e−91.4e−8
10−610^{-6}8.0e−117.6e−113.0e−105.4e−116.9e−111.9e−102.6e−101.5e−101.3e−10
10−710^{-7}9.7e−105.9e−105.2e−105.7e−117.4e−101.2e−98.1e−104.1e−101.3e−9
10−810^{-8}2.1e−92.2e−87.3e−91.1e−92.5e−84.4e−93.6e−91.8e−99.1e−10
10−910^{-9}3.1e−86.6e−81.5e−81.5e−73.6e−81.1e−78.1e−81.3e−84.4e−8
10−1010^{-10}4.8e−71.4e−62.2e−61.0e−61.1e−61.4e−67.0e−74.6e−71.9e−6
重构Reconstruction分量Component伴随梯度 Dˉk\bar D_kAdjoint gradient Dˉk\bar D_k中心差分最佳 τ\tauBest central τ\tau误差Error单侧差分最佳 τ\tauBest one-sided τ\tau误差Error
一阶first orderaa−0.74598610−510^{-5}2.0e−1110−810^{-8}9.0e−9
一阶first orderφ\varphi−0.35734210−610^{-6}7.6e−1110−810^{-8}5.9e−10
一阶first orderν\nu−0.24548410−610^{-6}3.0e−1010−910^{-9}1.5e−8
无限制器线性unlimited linearaa−0.48665010−510^{-5}3.5e−1110−810^{-8}1.1e−9
无限制器线性unlimited linearφ\varphi−0.06103910−610^{-6}6.9e−1110−810^{-8}1.4e−8
无限制器线性unlimited linearν\nu−0.30987110−610^{-6}1.9e−1010−810^{-8}1.2e−7
光滑限制器smooth limiteraa−0.65652710−510^{-5}7.0e−1110−810^{-8}7.5e−9
光滑限制器smooth limiterφ\varphi−0.16809710−610^{-6}1.5e−1010−810^{-8}5.4e−8
光滑限制器smooth limiterν\nu−0.29078010−610^{-6}1.3e−1010−910^{-9}6.8e−8

读表:中心差分在最佳步长处与伴随梯度相差 2.0×10−112.0\times10^{-11} 到 3.0×10−103.0\times10^{-10},这些梯度有 8 到 10 位有效数字一致;单侧差分的最佳误差是 5.9×10−105.9\times10^{-10} 到 1.2×10−71.2\times10^{-7}。最佳步长因分量和重构而异,事先并不知道,所以只算一个 τ\tau 的差分不够,要扫描。常用的折中 τ=10−5\tau=10^{-5} 对 aa 很好,对一阶与无限制器线性的 φ\varphi 也很好;但对 ν\nu 由截断误差主导(1.2×10−81.2\times10^{-8},因为这一步长的 τ/ν=10−3\tau/\nu=10^{-3}),对光滑限制器的 φ\varphi 也是(9.2×10−99.2\times10^{-9},光滑限制器的 ∂φ3Jh≈5.5×102\partial_\varphi^3J_h\approx5.5\times10^{2})。

Reading the tables: at its best step the central difference differs from the adjoint gradient by 2.0×10−112.0\times10^{-11} to 3.0×10−103.0\times10^{-10}, so 8 to 10 significant digits of these gradients agree; the best one-sided errors are 5.9×10−105.9\times10^{-10} to 1.2×10−71.2\times10^{-7}. The best step differs by component and reconstruction and is not known in advance, so a difference at one τ\tau is not enough: scan. The common compromise τ=10−5\tau=10^{-5} is excellent for aa, and for φ\varphi with the first-order and unlimited linear schemes; but for ν\nu the truncation error dominates (1.2×10−81.2\times10^{-8}; for ν\nu that step is τ/ν=10−3\tau/\nu=10^{-3}), and so it does for φ\varphi with the smooth limiter (9.2×10−99.2\times10^{-9}, where ∂φ3Jh≈5.5×102\partial_\varphi^3J_h\approx5.5\times10^{2}).

自己扫一遍:改变上方的网格、重构或设计(点“求解并更新”),选一个分量,看 V 形怎样移动。

Scan it yourself: change the mesh, the reconstruction or the design above (press Solve & update), pick a component and watch the V move.

割线如何变成切线

How the secant turns into the tangent

单侧差商 FDτ+\mathrm{FD}_\tau^+ 有一个几何意义:它是曲线 t↦Jh(D+tek)t\mapsto J_h(D+te_k) 上过 t=0t=0 与 t=τt=\tau 两点的割线的斜率;切线的斜率是 ∂kJh\partial_kJ_h,也就是伴随给出的 Dˉk\bar D_k。下面的播放器把 τ\tau 每步缩小 10 倍:前两步割线与切线还看得出区别,之后在图上已经重合,差别只留在数字里——看一致的有效数字位数先增后减。

The one-sided quotient FDτ+\mathrm{FD}_\tau^+ has a geometric meaning: it is the slope of the secant through the points t=0t=0 and t=τt=\tau of the curve t↦Jh(D+tek)t\mapsto J_h(D+te_k); the slope of the tangent is ∂kJh\partial_kJ_h, the Dˉk\bar D_k of the adjoint. The player below divides τ\tau by 10 at every step: for the first two steps the secant and the tangent can be told apart, after that they coincide on the drawing and the difference lives only in the digits: watch the number of agreeing significant digits rise and then fall.

误差下限由谁决定:Newton 迭代的停止准则

What sets the error floor: the Newton stopping criterion

两个 JhJ_h 都不是由精确离散解算出的:Newton 迭代在修正量不超过 10−1310^{-13} 时停止,最后一个修正量并不加上去。这个容差会不会就是误差下限?量一量。默认设计下基准求解的修正量依次是 8.8×10−28.8\times10^{-2}、4.1×10−34.1\times10^{-3}、7.2×10−67.2\times10^{-6}、2.8×10−112.8\times10^{-11}、2.0×10−162.0\times10^{-16}:二次收敛一步就越过了容差,返回的状态已经准确到舍入水平。所以默认容差 10−1310^{-13} 并不决定误差下限,舍入才决定(左支贴着舍入线,见上)。

Neither value of JhJ_h comes from the exact discrete solution: Newton stops when the correction is at most 10−1310^{-13}, and the last correction is not added. Is that tolerance the error floor? Measure it. At the defaults the corrections of the base solve are 8.8×10−28.8\times10^{-2}, 4.1×10−34.1\times10^{-3}, 7.2×10−67.2\times10^{-6}, 2.8×10−112.8\times10^{-11}, 2.0×10−162.0\times10^{-16}: quadratic convergence jumps past the tolerance in one step, and the state returned is already accurate to rounding. So the default tolerance 10−1310^{-13} does not set the error floor; rounding does (the left branch follows the rounding line, see above).

放宽容差,情形就变了(图 51,分量 aa)。容差 10−410^{-4} 时只加上两个修正量(第三个 7.2×10−67.2\times10^{-6} 已低于容差),误差在 τ=10−5\tau=10^{-5} 到 10−910^{-9} 之间停在 8.3×10−58.3\times10^{-5} 到 8.4×10−58.4\times10^{-5},不再随 τ\tau 变化。原因是:只要两次求解的迭代步数相同,只迭代 mm 步的 Newton 迭代值 𝐔(m)(D)\mathbf U^{(m)}(D)(这里 mm 数迭代步;第 5 节记作 𝐔k\mathbf U^k)本身就是 DD 的光滑函数,差商算出的是它的导数,偏差是一个固定的量,而不是被 1/τ1/\tau 放大的噪声。这里 m=2m=2:沿 Newton 迭代逐步求导,wT𝐔(2)w^T\mathbf U^{(2)} 的导数与 ∂aJh\partial_aJ_h 相差 8.36×10−58.36\times10^{-5}。容差 10−810^{-8} 时加上三个修正量,wT𝐔(3)w^T\mathbf U^{(3)} 的导数只差 5.5×10−105.5\times10^{-10}:τ=10−5\tau=10^{-5} 时的实测误差 5×10−105\times10^{-10} 就是这个偏差;τ\tau 再小,舍入又占了上风。

Loosen the tolerance and the picture changes (Figure 51, component aa). With the tolerance 10−410^{-4} only two corrections are added (the third, 7.2×10−67.2\times10^{-6}, is below the tolerance), and from τ=10−5\tau=10^{-5} to 10−910^{-9} the error stays at 8.3×10−58.3\times10^{-5} to 8.4×10−58.4\times10^{-5}, no longer depending on τ\tau. The reason: as long as both solves take the same number of steps, the Newton iterate 𝐔(m)(D)\mathbf U^{(m)}(D) after mm steps (mm counts steps here; Section 5 writes 𝐔k\mathbf U^k) is itself a smooth function of DD; the quotient computes its derivative, and the deviation is a fixed bias, not noise amplified by 1/τ1/\tau. Here m=2m=2: differentiating along the Newton iteration, the derivative of wT𝐔(2)w^T\mathbf U^{(2)} differs from ∂aJh\partial_aJ_h by 8.36×10−58.36\times10^{-5}. With the tolerance 10−810^{-8} three corrections are added, and the derivative of wT𝐔(3)w^T\mathbf U^{(3)} differs by only 5.5×10−105.5\times10^{-10}: the measured error 5×10−105\times10^{-10} at τ=10−5\tau=10^{-5} is this bias; at smaller τ\tau rounding takes over again.

热启动(以扰动前的解为初值)加一个绝对容差最危险:第一个修正量约为 τ∣vk∣\tau|v_k|,它一旦小于容差,求解器就原样返回初值,两个 JhJ_h 完全相等,差商为 0。容差 10−810^{-8} 时 τ≤10−9\tau\le10^{-9} 的点全是这样,误差就是梯度本身。

The most dangerous combination is a warm start (from the solution before the perturbation) with an absolute tolerance: the first correction is about τ∣vk∣\tau|v_k|, and once it is below the tolerance the solver returns its initial value unchanged, the two values of JhJ_h are identical and the quotient is 0. With the tolerance 10−810^{-8} this happens at every τ≤10−9\tau\le10^{-9}: the error is the gradient itself.

图 51 · 停止准则改变误差下限(分量 a,默认设计,N=8,无限制器线性,中心差分)。默认容差 10^(-13)(方块):V 形,噪声来自舍入;容差 10^(-4)(圈):与 τ 无关的平台,即 w^TU^((2)) 的导数与 ∂_aJ_h 之差;容差 10^(-8)(点):τ=10^(-5) 处只剩 U^((3)) 的小偏差;热启动加容差 10^(-8)(虚线):小 τ 时求解器不动,差商为 0,误差等于 |D-bar_a|=0.4866。10-12​10-10​10-8​10-6​10-4​10-2​110-12​10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​步长 τ|FDc​ − 伴随梯度|冷启动,容差 10-13​(默认)冷启动,容差 10-4​冷启动,容差 10-8​热启动,容差 10-8​
图 51 · 停止准则改变误差下限(分量 aa,默认设计,N=8N=8,无限制器线性,中心差分)。默认容差 10−1310^{-13}(方块):V 形,噪声来自舍入;容差 10−410^{-4}(圈):与 τ\tau 无关的平台,即 wT𝐔(2)w^T\mathbf U^{(2)} 的导数与 ∂aJh\partial_aJ_h 之差;容差 10−810^{-8}(点):τ=10−5\tau=10^{-5} 处只剩 𝐔(3)\mathbf U^{(3)} 的小偏差;热启动加容差 10−810^{-8}(虚线):小 τ\tau 时求解器不动,差商为 0,误差等于 ∣Dˉa∣=0.4866|\bar D_a|=0.4866。
Figure 51 · The stopping criterion moves the error floor (component a, default design, N=8, unlimited linear, central differences). Default tolerance 10^(-13) (squares): the V, with rounding as the noise; tolerance 10^(-4) (rings): a plateau independent of τ, the bias of the derivative of w^TU^((2)); tolerance 10^(-8) (dots): at τ=10^(-5) only the small bias of U^((3)) is left; warm start with the tolerance 10^(-8) (dashed): for small τ the solver does not move, the quotient is 0 and the error equals |D-bar_a|=0.4866.10-12​10-10​10-8​10-6​10-4​10-2​110-12​10-11​10-10​10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​step τ|FDc​ − adjoint gradient|cold start, tolerance 10-13​ (default)cold start, tolerance 10-4​cold start, tolerance 10-8​warm start, tolerance 10-8​
Figure 51 · The stopping criterion moves the error floor (component aa, default design, N=8N=8, unlimited linear, central differences). Default tolerance 10−1310^{-13} (squares): the V, with rounding as the noise; tolerance 10−410^{-4} (rings): a plateau independent of τ\tau, the bias of the derivative of wT𝐔(2)w^T\mathbf U^{(2)}; tolerance 10−810^{-8} (dots): at τ=10−5\tau=10^{-5} only the small bias of 𝐔(3)\mathbf U^{(3)} is left; warm start with the tolerance 10−810^{-8} (dashed): for small τ\tau the solver does not move, the quotient is 0 and the error equals ∣Dˉa∣=0.4866|\bar D_a|=0.4866.

差分验证的四个陷阱:(1)不重新求解,差商是 JD=0J_D=0;(2)容差太松,差商趋向只迭代 mm 步的迭代值的导数,而不是 JhJ_h 的导数,误差停在一个与 τ\tau 无关的平台上;(3)热启动加绝对容差,小 τ\tau 时求解器不动,差商为 0;(4)热启动只走一步时,𝐔(1)=𝐔−A−1R(𝐔,D±τek)\mathbf U^{(1)}=\mathbf U-A^{-1}R(\mathbf U,D\pm\tau e_k) 的差商(当 AA 与 DkD_k 无关时)就是把 RDekR_De_k 换成它的中心差分近似 [R(𝐔,D+τek)−R(𝐔,D−τek)]/(2τ)[R(\mathbf U,D+\tau e_k)-R(\mathbf U,D-\tau e_k)]/(2\tau) 后的切线结果。对 aa(RR 是 aa 的二次函数,AA 与 aa 无关),它就是切线结果本身(τ=10−4\tau=10^{-4}、容差 10−810^{-8} 时与 wTvaw^Tv_a 只差 1.9×10−131.9\times10^{-13});对 φ\varphi 差 5.9×10−95.9\times10^{-9};对 ν\nu 连 AA 都变了(差 1.2×10−61.2\times10^{-6})。这时差分已不独立,Jacobian 里的错误会被它原样复制。可靠的做法:每个扰动点冷启动、收敛到舍入水平、扫描多个 τ\tau。另外 ν\nu 的步长必须小于 ν\nu 本身。

Four traps of the finite-difference check: (1) without a re-solve the quotient is JD=0J_D=0; (2) with a loose tolerance the quotient tends to the derivative of the iterate after mm Newton steps, not to the derivative of JhJ_h, and the error stays on a plateau independent of τ\tau; (3) with a warm start and an absolute tolerance the solver does not move for small τ\tau and the quotient is 0; (4) when a warm start takes a single step, the quotient of 𝐔(1)=𝐔−A−1R(𝐔,D±τek)\mathbf U^{(1)}=\mathbf U-A^{-1}R(\mathbf U,D\pm\tau e_k) is (when AA does not depend on DkD_k) the tangent result with RDekR_De_k replaced by its central difference [R(𝐔,D+τek)−R(𝐔,D−τek)]/(2τ)[R(\mathbf U,D+\tau e_k)-R(\mathbf U,D-\tau e_k)]/(2\tau). For aa (RR is quadratic in aa and AA does not depend on aa) that is the tangent result itself (at τ=10−4\tau=10^{-4} and the tolerance 10−810^{-8} it differs from wTvaw^Tv_a by only 1.9×10−131.9\times10^{-13}); for φ\varphi the difference is 5.9×10−95.9\times10^{-9}; for ν\nu even AA changes (difference 1.2×10−61.2\times10^{-6}). Then the difference is no longer independent and copies any error of the Jacobian. The safe recipe: a cold start at every perturbed design, convergence to rounding, a scan over many τ\tau. And the step in ν\nu must be smaller than ν\nu itself.

差分能做什么、不能做什么

What finite differences can and cannot do

  • 能:只用原始求解器就检验整条链——前向语句、反向语句、RDR_D、转置和线性求解。例如漏掉第 8 节通量对 ν\nu 的显式导数 −(UR−UL)/df-(U_R-U_L)/d_f,伴随梯度的 ν\nu 分量会变成 1.8167651.816765,差分却给出 −0.309871-0.309871:差别远大于差分误差。Can: check the whole chain with the primal solver only: tangent statements, reverse statements, RDR_D, the transpose and the linear solves. Leave out the explicit ν\nu-derivative of the flux, −(UR−UL)/df-(U_R-U_L)/d_f of Section 8, and the ν\nu-component of the adjoint gradient becomes 1.8167651.816765 while the difference gives −0.309871-0.309871: a gap far larger than any difference error.
  • 不能:给出超过约 10 位的数字,而且只有扫描之后才知道哪个 τ\tau 可信;最佳 τ\tau 随分量、网格和重构变化。Cannot: deliver more than about 10 digits, and only a scan tells which τ\tau to trust; the best τ\tau changes with the component, the mesh and the reconstruction.
  • 不划算:每个分量 2 次非线性求解;伴随 1 次线性求解给出全部分量。Not cheap: 2 nonlinear solves per component; the adjoint gives all components with one linear solve.
  • 不回答离散误差的问题:差分与伴随都是 JhJ_h 的导数,它们离精确梯度多远是第 15、16 节的事。第 14 节的复数步长去掉了 V 形的舍入支。Does not answer the question of discretisation error: the difference and the adjoint are both derivatives of JhJ_h; how far they are from the exact gradient is the business of Sections 15 and 16. The complex step of Section 14 removes the rounding branch of the V.
第 14 节Section 14

复数步长验证:没有相减的差商

Complex-step check: a quotient without subtraction

本节实验:先算一算,在双精度里 a+10−30a+10^{-30} 等于多少?那么 τ=10−30\tau=10^{-30} 时第 13 节的中心差分给出什么?复数步长 Im⁡ Jh(D+iτek)/τ\operatorname{Im}\,J_h(D+i\tau e_k)/\tau 又给出什么?读完本节,用复数步长实验验证。

Experiment: work it out first: what is a+10−30a+10^{-30} in double precision? Then what does the central difference of Section 13 return at τ=10−30\tau=10^{-30}? And what does the complex step Im⁡ Jh(D+iτek)/τ\operatorname{Im}\,J_h(D+i\tau e_k)/\tau return? After the section, check with the complex-step lab.

第 13 节的差分受步长两头夹击:τ\tau 大时截断误差大;τ\tau 小时两个几乎相等的 JhJ_h 相减,舍入被 1/τ1/\tau 放大。双精度里 0.2+10−300.2+10^{-30} 就等于 0.20.2 本身,所以 τ=10−30\tau=10^{-30} 的差分是 0/(2τ)=00/(2\tau)=0。复数步长去掉了相减这一步。

The differences of Section 13 are squeezed from both ends of the step: at large τ\tau the truncation error is large; at small τ\tau two nearly equal values of JhJ_h are subtracted and the rounding is amplified by 1/τ1/\tau. In double precision 0.2+10−300.2+10^{-30} is 0.20.2 itself, so the difference at τ=10−30\tau=10^{-30} is 0/(2τ)=00/(2\tau)=0. The complex step removes the subtraction.

虚数方向上的一步

A step in the imaginary direction

设 JhJ_h 作为 DkD_k 的函数可以解析延拓到复平面(下一小节说明为什么可以)。把实的步长换成虚的 iτi\tau,在 DD 处展开:

Suppose JhJ_h, as a function of DkD_k, extends analytically into the complex plane (the next subsection says why it does). Replace the real step by the imaginary step iτi\tau and expand about DD:

Jh(D+iτek)=Jh+iτ ∂kJh−τ22 ∂k2Jh−i τ36 ∂k3Jh+O(τ4).J_h(D+i\tau e_k)=J_h+i\tau\,\partial_kJ_h-\frac{\tau^2}2\,\partial_k^2J_h-i\,\frac{\tau^3}6\,\partial_k^3J_h+O(\tau^4).

虚部与实部分开:

Separate the imaginary and the real parts:

CSτ=Im⁡ Jh(D+iτek)τ=∂kJh−τ26 ∂k3Jh+O(τ4),Re⁡ Jh(D+iτek)=Jh−τ22 ∂k2Jh+O(τ4).\mathrm{CS}_\tau=\frac{\operatorname{Im}\,J_h(D+i\tau e_k)}{\tau}=\partial_kJ_h-\frac{\tau^2}6\,\partial_k^3J_h+O(\tau^4),\qquad \operatorname{Re}\,J_h(D+i\tau e_k)=J_h-\frac{\tau^2}2\,\partial_k^2J_h+O(\tau^4).

导数直接从虚部读出,不需要两个相近的数相减,舍入不再被 1/τ1/\tau 放大。函数里含有求解器时,这个舍入就是前向求解的舍入,约为 εmach∑i∣wivk,i∣\varepsilon_{\rm mach}\sum_i|w_iv_{k,i}| 的若干倍:这里 ∑i∣wivk,i∣\sum_i|w_iv_{k,i}| 在 0.44 到 1.20 之间,而 ∣∂φJh∣|\partial_\varphi J_h| 只有 0.061;后面表中复数步长与伴随、切线梯度之差在 00 到 1.2×10−151.2\times10^{-15} 之间。截断误差 −τ2∂k3Jh/6-\tau^2\partial_k^3J_h/6 与中心差分的大小相同、符号相反。τ=10−30\tau=10^{-30} 时,无限制器线性的三个分量的截断误差都不超过 1.3×10−581.3\times10^{-58},完全看不见。图 52 用一个看得见的 τ\tau 画出这一步。

The derivative is read off the imaginary part directly; nothing nearly equal is subtracted, so the rounding is no longer amplified by 1/τ1/\tau. When the function contains a solver, the rounding is that of the tangent solve, a modest multiple of εmach∑i∣wivk,i∣\varepsilon_{\rm mach}\sum_i|w_iv_{k,i}|: here ∑i∣wivk,i∣\sum_i|w_iv_{k,i}| lies between 0.44 and 1.20, while ∣∂φJh∣|\partial_\varphi J_h| is only 0.061; in the table below the complex step differs from the adjoint and the tangent gradients by 00 to 1.2×10−151.2\times10^{-15}. The truncation error −τ2∂k3Jh/6-\tau^2\partial_k^3J_h/6 has the size of the central difference's, with the opposite sign. At τ=10−30\tau=10^{-30} it is at most 1.3×10−581.3\times10^{-58} for the three components of the unlimited linear scheme: invisible. Figure 52 draws the step with a visible τ\tau.

图 52 · 复平面上的一步(分量 a,默认设计,无限制器线性;为了看得见取 τ=0.05)。左:设计 a 在实轴上,a+iτ 在它正上方。右:求解复数残差得到复数状态,目标 J_h(D+iτ e_a) 几乎正好落在 J_h 的正下方:虚部 -2.430 × 10^(-2) ≈ τ ∂_aJ_h(∂_aJ_h<0,所以向下),实部只偏了 4.5 × 10^(-4) ≈ -τ^22∂_a^2J_h。ReIma = 0.200a + iττ = 0.05输入:设计 a求解ReImJh​ = 1.40811Jh​(D + iτea​)Im = −0.02430输出:目标 Jh​Im Jh​ / τ = −0.485999;伴随梯度 = −0.486650
图 52 · 复平面上的一步(分量 aa,默认设计,无限制器线性;为了看得见取 τ=0.05\tau=0.05)。左:设计 aa 在实轴上,a+iτa+i\tau 在它正上方。右:求解复数残差得到复数状态,目标 Jh(D+iτea)J_h(D+i\tau e_a) 几乎正好落在 JhJ_h 的正下方:虚部 −2.430×10−2≈τ ∂aJh-2.430\times10^{-2}\approx\tau\,\partial_aJ_h(∂aJh<0\partial_aJ_h<0,所以向下),实部只偏了 4.5×10−4≈−τ22∂a2Jh4.5\times10^{-4}\approx-\tfrac{\tau^2}2\partial_a^2J_h。
Figure 52 · One step in the complex plane (component a, default design, unlimited linear; τ=0.05 so that it can be seen). Left: the design a on the real axis and a+iτ straight above it. Right: solving the complex residual gives a complex state, and the objective J_h(D+iτ e_a) lands almost straight below J_h: the imaginary part -2.430 × 10^(-2) ≈ τ ∂_aJ_h (negative, since ∂_aJ_h<0), while the real part moved only by 4.5 × 10^(-4) ≈ -τ^22∂_a^2J_h.ReIma = 0.200a + iττ = 0.05input: the design asolveReImJh​ = 1.40811Jh​(D + iτea​)Im = −0.02430output: the objective Jh​Im Jh​ / τ = −0.485999; adjoint gradient = −0.486650
Figure 52 · One step in the complex plane (component aa, default design, unlimited linear; τ=0.05\tau=0.05 so that it can be seen). Left: the design aa on the real axis and a+iτa+i\tau straight above it. Right: solving the complex residual gives a complex state, and the objective Jh(D+iτea)J_h(D+i\tau e_a) lands almost straight below JhJ_h: the imaginary part −2.430×10−2≈τ ∂aJh-2.430\times10^{-2}\approx\tau\,\partial_aJ_h (negative, since ∂aJh<0\partial_aJ_h<0), while the real part moved only by 4.5×10−4≈−τ22∂a2Jh4.5\times10^{-4}\approx-\tfrac{\tau^2}2\partial_a^2J_h.

对代码的要求:只用解析运算

What the code must be: analytic operations only

复数步长要求程序的每一步都是某个解析函数在实轴上的限制。加、减、乘、除和 sin⁡\sin、cos⁡\cos 都是;绝对值、max⁡\max、min⁡\min、按符号分支的 if 都不是。第 5 节的残差只用了加减乘除,设计里的 sin⁡\sin、cos⁡\cos 通过 u∗u^* 和 q∗q^* 进入:Rusanov 速度是常数 α=2\alpha=2,没有 ∣u∣|u|;三种斜率是 00、(l+r)/2(l+r)/2 和光滑限制器 lr(l+r)/(l2+r2+ϵ2)lr(l+r)/(l^2+r^2+\epsilon^2)。光滑限制器的分母在实轴上不小于 ϵ2>0\epsilon^2>0,所以它在每个实状态附近都是解析的,没有开关:三种重构都可以做复数步长。AA 可逆时,由隐函数定理,离散解随设计解析地变化,JhJ_h 也就可以解析延拓。minmod 之类的限制器在开关处不可导,复数步长会默默地跟着实部选中的分支走。

The complex step needs every operation of the program to be the restriction of an analytic function to the real axis. Addition, subtraction, multiplication, division, sin⁡\sin and cos⁡\cos are; an absolute value, max⁡\max, min⁡\min and an if on a sign are not. The residual of Section 5 uses only the four operations, and the sin⁡\sin and cos⁡\cos of the design enter through u∗u^* and q∗q^*: the Rusanov speed is the constant α=2\alpha=2, there is no ∣u∣|u|, and the three slopes are 00, (l+r)/2(l+r)/2 and the smooth limiter lr(l+r)/(l2+r2+ϵ2)lr(l+r)/(l^2+r^2+\epsilon^2). The denominator of the smooth limiter is at least ϵ2>0\epsilon^2>0 on the real axis, so it is analytic near every real state and has no switch: all three reconstructions can be complex-stepped. Where AA is invertible, the implicit function theorem makes the discrete solution an analytic function of the design, and with it JhJ_h. A limiter such as minmod is not differentiable at its switch, and the complex step would silently follow the branch the real parts select.

model.js 的 residualComplex 就是第 5 节的残差代码,只把算术换成复数:实部和虚部各存一个数组,语句一条不改;sin⁡(x+iy)=sin⁡ x cosh⁡ y+i cos⁡ x sinh⁡ y\sin(x+iy)=\sin\,x\,\cosh\,y+i\,\cos\,x\,\sinh\,y,cos⁡(x+iy)=cos⁡ x cosh⁡ y−i sin⁡ x sinh⁡ y\cos(x+iy)=\cos\,x\,\cosh\,y-i\,\sin\,x\,\sinh\,y。其中没有一行是手工求导的,所以它是对第 8 节前向语句的独立检验。

The function residualComplex of model.js is the residual code of Section 5 with the arithmetic replaced: the real and the imaginary parts are two arrays, and not one statement changes; sin⁡(x+iy)=sin⁡ x cosh⁡ y+i cos⁡ x sinh⁡ y\sin(x+iy)=\sin\,x\,\cosh\,y+i\,\cos\,x\,\sinh\,y and cos⁡(x+iy)=cos⁡ x cosh⁡ y−i sin⁡ x sinh⁡ y\cos(x+iy)=\cos\,x\,\cosh\,y-i\,\sin\,x\,\sinh\,y. Not one line of it is differentiated by hand, which makes it an independent check of the tangent statements of Section 8.

复数版本必须用代数平方 z⋅zz\cdot z,不能用模的平方 ∣z∣2=z conj⁡(z)|z|^2=z\,\operatorname{conj}(z):共轭会把虚部消掉。目标 Jh=wT𝐔J_h=w^T\mathbf U 是线性的,所以 Im⁡ Jh=wTIm⁡ 𝐔\operatorname{Im}\,J_h=w^T\operatorname{Im}\,\mathbf U。

The complex version must use the algebraic square z⋅zz\cdot z, never the squared modulus ∣z∣2=z conj⁡(z)|z|^2=z\,\operatorname{conj}(z): the conjugate cancels the imaginary part. The objective Jh=wT𝐔J_h=w^T\mathbf U is linear, so Im⁡ Jh=wTIm⁡ 𝐔\operatorname{Im}\,J_h=w^T\operatorname{Im}\,\mathbf U.

状态也变成复数

The state becomes complex

设计 D+iτekD+i\tau e_k 让残差变成复数,离散解也随之是复数。在 τ=0\tau=0 处展开:

The design D+iτekD+i\tau e_k makes the residual complex, and with it the discrete solution. Expand about τ=0\tau=0:

𝐔(D+iτek)=𝐔(D)+iτ vk+O(τ2),vk=𝐔˙=∂𝐔∂Dk.\mathbf U(D+i\tau e_k)=\mathbf U(D)+i\tau\,v_k+O(\tau^2),\qquad v_k=\dot{\mathbf U}=\frac{\partial\mathbf U}{\partial D_k}.

虚部除以 τ\tau 就是第 10 节的切线解。函数里含有求解器时,复数步长本身就是一次复数求解:要解复数残差 R(𝐔,D+iτek)=0R(\mathbf U,D+i\tau e_k)=0。用 Newton 法,Jacobian 取实部的 AA:不动点 R(𝐔,D+iτek)=0R(\mathbf U,D+i\tau e_k)=0 与所用矩阵无关,舍去复 Jacobian 的 O(τ)O(\tau) 虚部不改变结果;但它使修正量的虚部改变 O(τ∥R∥)O(\tau\|R\|)(只有接近收敛时才可忽略),并使虚部晚一步收敛。把残差的虚部展开:

Its imaginary part over τ\tau is the tangent solution of Section 10. When the function contains a solver, the complex step is itself a complex solve: the complex residual R(𝐔,D+iτek)=0R(\mathbf U,D+i\tau e_k)=0 must be solved. Use Newton with the real Jacobian AA: the fixed point R(𝐔,D+iτek)=0R(\mathbf U,D+i\tau e_k)=0 does not depend on the matrix, so dropping the O(τ)O(\tau) imaginary part of the complex Jacobian leaves the result unchanged; it changes the imaginary part of a correction by O(τ∥R∥)O(\tau\|R\|) (negligible only near convergence) and makes the imaginary part lag one step. Expand the imaginary part of the residual:

Im⁡ R(𝐔+iτv, D+iτek)=τ (Av+RDek)+O(τ3).\operatorname{Im}\,R\bigl(\mathbf U+i\tau v,\ D+i\tau e_k\bigr)=\tau\,\bigl(Av+R_De_k\bigr)+O(\tau^3).

令它为零,正是第 10 节的切线方程 Av=−RDekAv=-R_De_k:虚部的一次 Newton 修正就是一次前向求解(乘以 τ\tau)。于是

Setting it to zero is exactly the tangent equation Av=−RDekAv=-R_De_k of Section 10: one Newton correction of the imaginary part is one tangent solve (times τ\tau). Hence

CSτ=Im⁡ Jh(D+iτek)τ=wTIm⁡ 𝐔τ=wTvk+O(τ2)=J˙+O(τ2).\mathrm{CS}_\tau=\frac{\operatorname{Im}\,J_h(D+i\tau e_k)}{\tau}=\frac{w^T\operatorname{Im}\,\mathbf U}{\tau}=w^Tv_k+O(\tau^2)=\dot J+O(\tau^2).

下面的播放器从页面的初值 u∗(xi;D+iτek)u^*(x_i;D+i\tau e_k) 出发做复数 Newton 迭代(τ=10−30\tau=10^{-30}),每一步用当前实部的 Jacobian。τ=10−30\tau=10^{-30} 时实部与第 5 节的原始迭代逐位相同(Re⁡ R=R−τ22(⋯ )\operatorname{Re}\,R=R-\tfrac{\tau^2}2(\cdots);τ=10−30\tau=10^{-30} 时 τ2\tau^2 项约为 10−6010^{-60},远小于 O(1)O(1) 实部的最后一位)。虚部晚一步:Im⁡ 𝐔(m+1)/τ\operatorname{Im}\,\mathbf U^{(m+1)}/\tau 恰好是在实部迭代值 𝐔(m)\mathbf U^{(m)} 处求得的切线解(每一步都取整步时成立,默认设计下正是如此;差不超过 6.7×10−166.7\times10^{-16})。残差实部在 4 次修正后到达舍入水平,虚部在 5 次修正后(图 53)。

The player below runs the complex Newton iteration from the page's initial guess u∗(xi;D+iτek)u^*(x_i;D+i\tau e_k) (τ=10−30\tau=10^{-30}), with the Jacobian of the current real part at every step. At τ=10−30\tau=10^{-30} the real part is the primal iteration of Section 5 bit for bit (Re⁡ R=R−τ22(⋯ )\operatorname{Re}\,R=R-\tfrac{\tau^2}2(\cdots); at τ=10−30\tau=10^{-30} the τ2\tau^2 terms, about 10−6010^{-60}, are far below the last bit of the O(1)O(1) real parts). The imaginary part lags one step: Im⁡ 𝐔(m+1)/τ\operatorname{Im}\,\mathbf U^{(m+1)}/\tau is exactly the tangent solution at the real iterate 𝐔(m)\mathbf U^{(m)} (as long as every step is a full step, as at the defaults; to 6.7×10−166.7\times10^{-16} or better). The real residual reaches rounding after 4 corrections, the imaginary one after 5 (Figure 53).

图 53 · 复数 Newton 迭代的收敛(分量 a,τ=10^(-30),默认设计,无限制器线性)。方块:残差实部;点:残差虚部除以 τ;圈:w^TIm U^((m))/τ 与伴随梯度之差。实部二次收敛,4 次修正后到达舍入水平;虚部晚一步,5 次修正后到达;最后与伴随梯度之差约为 4.4 × 10^(-16)(舍入量级;下表给出收敛求解的值)。10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​1012345Newton 迭代 m范数|Re R(U(m)​)||Im R(U(m)​)| / τ|wT​ Im U(m)​/τ − 伴随梯度|
图 53 · 复数 Newton 迭代的收敛(分量 aa,τ=10−30\tau=10^{-30},默认设计,无限制器线性)。方块:残差实部;点:残差虚部除以 τ\tau;圈:wTIm⁡ 𝐔(m)/τw^T\operatorname{Im}\,\mathbf U^{(m)}/\tau 与伴随梯度之差。实部二次收敛,4 次修正后到达舍入水平;虚部晚一步,5 次修正后到达;最后与伴随梯度之差约为 4.4×10−164.4\times10^{-16}(舍入量级;下表给出收敛求解的值)。
Figure 53 · Convergence of the complex Newton iteration (component a, τ=10^(-30), default design, unlimited linear). Squares: the real part of the residual; dots: its imaginary part over τ; rings: w^TIm U^((m))/τ minus the adjoint gradient. The real part converges quadratically and reaches rounding after 4 corrections; the imaginary part lags one step and gets there after 5; at the end the difference from the adjoint gradient is about 4.4 × 10^(-16) (rounding level; the table below gives the value of the converged solve).10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​1012345Newton iteration mnorm|Re R(U(m)​)||Im R(U(m)​)| / τ|wT​ Im U(m)​/τ − adjoint gradient|
Figure 53 · Convergence of the complex Newton iteration (component aa, τ=10−30\tau=10^{-30}, default design, unlimited linear). Squares: the real part of the residual; dots: its imaginary part over τ\tau; rings: wTIm⁡ 𝐔(m)/τw^T\operatorname{Im}\,\mathbf U^{(m)}/\tau minus the adjoint gradient. The real part converges quadratically and reaches rounding after 4 corrections; the imaginary part lags one step and gets there after 5; at the end the difference from the adjoint gradient is about 4.4×10−164.4\times10^{-16} (rounding level; the table below gives the value of the converged solve).

图 54 把收敛后的虚部除以 τ\tau 与第 10 节的切线解画在一起:三个分量的最大差约为 2.2×10−162.2\times10^{-16}、6.7×10−166.7\times10^{-16}、1.2×10−151.2\times10^{-15}。表中是三种重构下 τ=10−30\tau=10^{-30} 的复数步长梯度,与伴随梯度、切线梯度相差都不超过 1.2×10−151.2\times10^{-15},而第 13 节的中心差分即使在最佳步长处,误差也有 2.0×10−112.0\times10^{-11} 到 3.0×10−103.0\times10^{-10}。

Figure 54 draws the converged imaginary part over τ\tau over the tangent solution of Section 10: the largest differences for the three components are about 2.2×10−162.2\times10^{-16}, 6.7×10−166.7\times10^{-16}, 1.2×10−151.2\times10^{-15}. The table lists the complex-step gradients at τ=10−30\tau=10^{-30} for the three reconstructions: they differ from the adjoint and the tangent gradients by at most 1.2×10−151.2\times10^{-15}, while the central difference of Section 13 gets only to 2.0×10−112.0\times10^{-11} to 3.0×10−103.0\times10^{-10} at its best step.

图 54 · 状态虚部除以 τ 就是切线解(τ=10^(-30),默认设计,无限制器线性)。实线:第 10 节的切线解 v_a,v_φ,v_ν;圈:复数求解得到的 Im U/τ。两者重合到舍入水平。−1−0.500.5100.20.40.60.81xIm Ui​ / τ 与 vi​切线解 va​切线解 vφ​切线解 vν​
图 54 · 状态虚部除以 τ\tau 就是切线解(τ=10−30\tau=10^{-30},默认设计,无限制器线性)。实线:第 10 节的切线解 va,vφ,vνv_a,v_\varphi,v_\nu;圈:复数求解得到的 Im⁡ 𝐔/τ\operatorname{Im}\,\mathbf U/\tau。两者重合到舍入水平。
Figure 54 · The imaginary part of the state over τ is the tangent solution (τ=10^(-30), default design, unlimited linear). Lines: the tangent solutions v_a,v_φ,v_ν of Section 10; rings: Im U/τ from the complex solve. They coincide to rounding.−1−0.500.5100.20.40.60.81xIm Ui​ / τ and vi​tangent solution va​tangent solution vφ​tangent solution vν​
Figure 54 · The imaginary part of the state over τ\tau is the tangent solution (τ=10−30\tau=10^{-30}, default design, unlimited linear). Lines: the tangent solutions va,vφ,vνv_a,v_\varphi,v_\nu of Section 10; rings: Im⁡ 𝐔/τ\operatorname{Im}\,\mathbf U/\tau from the complex solve. They coincide to rounding.
重构Reconstruction分量ComponentCSτ\mathrm{CS}_\tau(τ=10−30\tau=10^{-30})CSτ\mathrm{CS}_\tau at τ=10−30\tau=10^{-30}与伴随之差Minus adjoint与切线之差Minus tangent中心差分最佳误差Best central FD
一阶first orderaa−0.7459861305033.3e−166.7e−162.0e−11
一阶first orderφ\varphi−0.3573416457542.2e−164.4e−167.6e−11
一阶first orderν\nu−0.2454836184675.6e−164.2e−163.0e−10
无限制器线性unlimited linearaa−0.4866496771662.8e−1603.5e−11
无限制器线性unlimited linearφ\varphi−0.0610389157691.0e−153.2e−166.9e−11
无限制器线性unlimited linearν\nu−0.3098713551627.8e−165.0e−161.9e−10
光滑限制器smooth limiteraa−0.6565274693535.6e−166.7e−167.0e−11
光滑限制器smooth limiterφ\varphi−0.1680973009318.0e−165.6e−161.5e−10
光滑限制器smooth limiterν\nu−0.2907804432625.6e−161.2e−151.3e−10

步长扫描:没有 V 形

The step scan: no V

把第 13 节的扫描延长到 τ=10−30\tau=10^{-30}(图 55)。τ\tau 大时复数步长与中心差分的误差大小相同、符号相反:τ=10−2\tau=10^{-2} 时 aa、φ\varphi 分量的比值是 −0.9997-0.9997、−1.0012-1.0012;τ=10−3\tau=10^{-3} 时是 −1.0000-1.0000、−1.0000-1.0000。τ≤10−7\tau\le10^{-7} 时,分量 aa 的复数步长误差一直低于 10−1410^{-14};ν\nu 分量(以及光滑限制器的 φ\varphi 分量)在 τ=10−8\tau=10^{-8} 时截断误差仍然可见:一阶、无限制器线性、光滑限制器的 ν\nu 分量与光滑限制器的 φ\varphi 分量,实测误差依次为 1.82、1.26、1.32、1.00,Taylor 预测 τ2∣∂k3Jh∣/6\tau^2|\partial_k^3J_h|/6 依次为 1.59、1.21、1.37、0.92(单位 10−1410^{-14})。两者相差不超过 2.3×10−152.3\times10^{-15},这是舍入:τ=10−8\tau=10^{-8} 时截断项由实部的 O(τ2)O(\tau^2) 偏移带出(光滑限制器的 φ\varphi 分量还有一部分来自残差虚部的 O(τ3)O(\tau^3) 项,它们同样处在舍入水平),而这个偏移只有 εmachmax⁡i∣Ui∣\varepsilon_{\rm mach}\max_i|U_i| 的 3.9 到 7.7 倍,只占 𝐔\mathbf U 的最后几位。三种重构在 τ≤10−9\tau\le10^{-9} 的所有点都停在舍入水平(不超过 1.3×10−151.3\times10^{-15}),直到 τ=10−30\tau=10^{-30}。中心差分则在 τ=10−5\tau=10^{-5} 到 10−610^{-6} 见底后又回升。

Extend the scan of Section 13 down to τ=10−30\tau=10^{-30} (Figure 55). At large τ\tau the complex step and the central difference have errors of the same size and opposite sign: at τ=10−2\tau=10^{-2} their ratio is −0.9997-0.9997 and −1.0012-1.0012 for aa and φ\varphi, at τ=10−3\tau=10^{-3} −1.0000-1.0000 and −1.0000-1.0000. For τ≤10−7\tau\le10^{-7} the complex-step error of component aa stays below 10−1410^{-14}; for ν\nu (and for the smooth limiter's φ\varphi) the truncation is still visible at τ=10−8\tau=10^{-8}: for the ν\nu-components of first order, unlimited linear and the smooth limiter and for the smooth limiter's φ\varphi-component the measured errors are 1.82, 1.26, 1.32, 1.00 and the Taylor predictions τ2∣∂k3Jh∣/6\tau^2|\partial_k^3J_h|/6 are 1.59, 1.21, 1.37, 0.92 (in units of 10−1410^{-14}). The two differ by at most 2.3×10−152.3\times10^{-15}, which is rounding: at τ=10−8\tau=10^{-8} the truncation is carried by the O(τ2)O(\tau^2) shift of the real part (for the smooth limiter's φ\varphi-component partly by the O(τ3)O(\tau^3) terms of the imaginary part of the residual, which are at rounding level too), and that shift is only 3.9 to 7.7 times εmachmax⁡i∣Ui∣\varepsilon_{\rm mach}\max_i|U_i|, the last few bits of 𝐔\mathbf U. Every point of the three reconstructions with τ≤10−9\tau\le10^{-9} stays at rounding level (at most 1.3×10−151.3\times10^{-15}), down to τ=10−30\tau=10^{-30}. The central difference instead bottoms out at τ=10−5\tau=10^{-5} to 10−610^{-6} and rises again.

图 55 · 复数步长与中心差分的步长扫描(默认设计,N=8,无限制器线性)。方块:中心差分;实心点:复数步长,每个 τ 都是一次复数求解。复数步长在 τ 大时与中心差分重合(截断误差 τ^2|∂_k^3J_h|/6),之后停在舍入水平,一直到 10^(-30);没有 V 形。ν 分量在 τ=0.1 时复数 Newton 迭代不收敛,那一点没有画;中心差分要求 τ<ν。10-18​10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-30​10-25​10-20​10-15​10-10​10-5​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ分量 a:∂Jh​/∂a = −0.486650中心差分 FDc​复数步长 CS10-18​10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-30​10-25​10-20​10-15​10-10​10-5​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ分量 φ:∂Jh​/∂φ = −0.061039中心差分 FDc​复数步长 CS10-18​10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-30​10-25​10-20​10-15​10-10​10-5​步长 τ|差商 − 伴随梯度|舍入线 εmach​|Jh​|/τ分量 ν:∂Jh​/∂ν = −0.309871中心差分 FDc​复数步长 CS
图 55 · 复数步长与中心差分的步长扫描(默认设计,N=8N=8,无限制器线性)。方块:中心差分;实心点:复数步长,每个 τ\tau 都是一次复数求解。复数步长在 τ\tau 大时与中心差分重合(截断误差 τ2∣∂k3Jh∣/6\tau^2|\partial_k^3J_h|/6),之后停在舍入水平,一直到 10−3010^{-30};没有 V 形。ν\nu 分量在 τ=0.1\tau=0.1 时复数 Newton 迭代不收敛,那一点没有画;中心差分要求 τ<ν\tau<\nu。
Figure 55 · Step scans of the complex step and the central difference (default design, N=8, unlimited linear). Squares: central differences; dots: the complex step, one complex solve per τ. At large τ the complex step coincides with the central difference (truncation τ^2|∂_k^3J_h|/6), then it stays at rounding level all the way down to 10^(-30): no V. For ν the complex Newton iteration does not converge at τ=0.1, so that point is not drawn; the central difference needs τ<ν.10-18​10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-30​10-25​10-20​10-15​10-10​10-5​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τcomponent a: ∂Jh​/∂a = −0.486650central FDc​complex step CS10-18​10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-30​10-25​10-20​10-15​10-10​10-5​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τcomponent φ: ∂Jh​/∂φ = −0.061039central FDc​complex step CS10-18​10-16​10-14​10-12​10-10​10-8​10-6​10-4​10-2​110-30​10-25​10-20​10-15​10-10​10-5​step τ|quotient − adjoint gradient|rounding εmach​|Jh​|/τcomponent ν: ∂Jh​/∂ν = −0.309871central FDc​complex step CS
Figure 55 · Step scans of the complex step and the central difference (default design, N=8N=8, unlimited linear). Squares: central differences; dots: the complex step, one complex solve per τ\tau. At large τ\tau the complex step coincides with the central difference (truncation τ2∣∂k3Jh∣/6\tau^2|\partial_k^3J_h|/6), then it stays at rounding level all the way down to 10−3010^{-30}: no V. For ν\nu the complex Newton iteration does not converge at τ=0.1\tau=0.1, so that point is not drawn; the central difference needs τ<ν\tau<\nu.

用复数步长检验 Jacobian 的每一列

Every column of the Jacobians by the complex step

同一个复数程序还能给出 Jacobian 的列。给状态分量 jj 一个虚扰动:Im⁡ R(𝐔+iτej,D)/τ=Aej+O(τ2)\operatorname{Im}\,R(\mathbf U+i\tau e_j,D)/\tau=Ae_j+O(\tau^2),这就是 AA 的列 jj,没有用到任何前向语句;给设计虚扰动则得到 RDekR_De_k。默认设计下,所有列与第 8 节前向语句算出的列的最大差:

The same complex program also gives the columns of the Jacobians. An imaginary perturbation of state component jj gives Im⁡ R(𝐔+iτej,D)/τ=Aej+O(τ2)\operatorname{Im}\,R(\mathbf U+i\tau e_j,D)/\tau=Ae_j+O(\tau^2), column jj of AA, without any tangent statement; an imaginary perturbation of the design gives RDekR_De_k. At the defaults, the largest differences from the columns computed by the tangent statements of Section 8 are:

重构Reconstructionmax⁡∣ACS−A∣\max|A_{\rm CS}-A|(NN 列)max⁡∣ACS−A∣\max|A_{\rm CS}-A| (NN columns)max⁡∣RD,CS−RD∣\max|R_{D,\rm CS}-R_D|(3 列)max⁡∣RD,CS−RD∣\max|R_{D,\rm CS}-R_D| (3 columns)
一阶first order4.4e−164.4e−16
无限制器线性unlimited linear4.4e−164.4e−16
光滑限制器smooth limiter8.9e−164.4e−16

这是对第 8、9 节的又一项独立检验:前向语句给出的 A,RDA,R_D 与“只换算术”的程序一致;第 9 节的反向语句又是它们的转置(点积检验)。选一列看看:

This is one more independent check of Sections 8 and 9: the AA and RDR_D of the tangent statements agree with the program whose only change is its arithmetic, and the reverse statements of Section 9 are their transpose (the dot-product test). Pick a column:

代价与局限

Cost and limits

  • 每个分量一次复数求解(中心差分要两次实数求解);复数运算比实数贵几倍(一次复数乘法是 4 次实数乘法);不用调步长,τ=10−30\tau=10^{-30} 永远可用。One complex solve per component (the central difference needs two real ones); complex arithmetic costs a few times more than real (one complex multiplication is 4 real ones); no step to tune: τ=10−30\tau=10^{-30} always works.
  • 要求代码是解析的,并且要有一个复数版本的残差;遇到 ∣u∣|u|、max⁡\max、限制器开关要逐个分析。It needs the code to be analytic and a complex version of the residual; an ∣u∣|u|, a max⁡\max or a limiter switch must be analysed one by one.
  • 和差分一样,求解次数随设计分量数增长,而伴随一次求解给出全部分量;它验证的也是 JhJ_h 的导数,不回答离散误差的问题(第 15 节)。Like the difference, its number of solves grows with the number of design components, where the adjoint gives all of them with one solve; and it too verifies the derivative of JhJ_h, not the discretisation error (Section 15).
第 15 节Section 15

精度阶:网格加密下的误差

Order of accuracy: the errors under refinement

本节实验:先预测,网格加密一倍(N→2NN\to2N),无限制器线性格式的误差缩小几倍?一阶格式呢?从 N=16N=16 到 3232 就能看到吗?然后用收敛实验和加密播放器检验。

Experiment: predict first: when the mesh is refined once (N→2NN\to2N), by what factor does the error of the unlimited linear scheme shrink, and that of the first-order scheme? Can you see it already from N=16N=16 to 3232? Then check with the convergence lab and the refinement player.

第 13、14 节检验了导数:伴随梯度就是 JhJ_h 的导数(差分验证到误差不超过 3.0×10−103.0\times10^{-10},复数步长到舍入水平)。本节问另一个问题:网格加密时,离散解、离散目标和离散梯度是否趋向构造解的精确值,趋向得多快。不同网格上的 JhJ_h 是不同的函数,所以必须先在每个网格上把非线性方程解到舍入水平,再看离散误差。

Sections 13 and 14 checked the derivatives: the adjoint gradient is the derivative of JhJ_h (to 3.0×10−103.0\times10^{-10} or better by differences, to rounding by the complex step). This section asks a different question: as the mesh is refined, do the discrete solution, objective and gradient approach the exact values of the manufactured solution, and how fast? JhJ_h on different meshes are different functions, so on every mesh the nonlinear equations are first solved to rounding and only then is the discretisation error measured.

量什么、和什么比

What is measured, against what

单元平均 UiU_i 与精确单元平均 ⟨u∗⟩i\langle u^*\rangle_i 比较(第 2 节的闭式),目标与 J∗J^* 比较,梯度与第 1 节的精确梯度比较;观测阶是相邻两套网格的误差之比以 2 为底的对数(errN\mathrm{err}_N 是 NN 个单元的网格上的某个误差):

The cell averages UiU_i are compared with the exact cell averages ⟨u∗⟩i\langle u^*\rangle_i (the closed form of Section 2), the objective with J∗J^*, the gradient with the exact gradient of Section 1; the observed order is the base-2 logarithm of the ratio of the errors on two successive meshes (errN\mathrm{err}_N is one of these errors on the mesh with NN cells):

∥𝐔−⟨u∗⟩∥1=h∑i∣Ui−⟨u∗⟩i∣,∥𝐔−⟨u∗⟩∥∞=max⁡i∣Ui−⟨u∗⟩i∣,∣Jh−J∗∣,∣Dˉk−∂kJ∗∣,ord=log⁡2errNerr2N.\|\mathbf U-\langle u^*\rangle\|_1=h\sum_i|U_i-\langle u^*\rangle_i|,\quad \|\mathbf U-\langle u^*\rangle\|_\infty=\max_i|U_i-\langle u^*\rangle_i|,\quad |J_h-J^*|,\quad |\bar D_k-\partial_kJ^*|,\qquad \mathrm{ord}=\log_2\frac{\mathrm{err}_N}{\mathrm{err}_{2N}}.

两条事实让这些量互相联系。第一,Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^* 精确成立:对每个 N≥2N\ge2,∑icos⁡ 2π(xi−φ)=0\sum_i\cos\,2\pi(x_i-\varphi)=0,因此各单元的一阶矩 ∫(x−xi) u∗ dx\int(x-x_i)\,u^*\,\mathrm dx 加起来恰好为零(本页在 N=8N=8 到 40964096 实测 ∣Jh(⟨u∗⟩)−J∗∣≤3.2×10−15|J_h(\langle u^*\rangle)-J^*|\le3.2\times10^{-15})。所以 Jh−J∗=wT(𝐔−⟨u∗⟩)J_h-J^*=w^T(\mathbf U-\langle u^*\rangle),目标误差是状态误差的加权和(权重之和为 3/23/2)。第二,对设计求导,∂kJ∗=wT⟨∂ku∗⟩\partial_kJ^*=w^T\langle\partial_ku^*\rangle(⟨∂ku∗⟩i\langle\partial_ku^*\rangle_i 是 ∂u∗/∂Dk\partial u^*/\partial D_k 的单元平均),所以梯度误差 Dˉk−∂kJ∗=wT(vk−⟨∂ku∗⟩)\bar D_k-\partial_kJ^*=w^T(v_k-\langle\partial_ku^*\rangle) 是切线解误差的加权和。u∗u^* 不依赖 ν\nu,所以 ⟨∂νu∗⟩=0\langle\partial_\nu u^*\rangle=0,ν\nu 分量的误差就是离散梯度 ∂νJh\partial_\nu J_h 本身。

Two facts tie these quantities together. First, Jh(⟨u∗⟩)=J∗J_h(\langle u^*\rangle)=J^* holds exactly: for every N≥2N\ge2, ∑icos⁡ 2π(xi−φ)=0\sum_i\cos\,2\pi(x_i-\varphi)=0, so the first moments ∫(x−xi) u∗ dx\int(x-x_i)\,u^*\,\mathrm dx of the cells add up to exactly zero (measured for N=8N=8 to 40964096: ∣Jh(⟨u∗⟩)−J∗∣≤3.2×10−15|J_h(\langle u^*\rangle)-J^*|\le3.2\times10^{-15}). Hence Jh−J∗=wT(𝐔−⟨u∗⟩)J_h-J^*=w^T(\mathbf U-\langle u^*\rangle): the objective error is a weighted sum of the state error (the weights add up to 3/23/2). Second, differentiating with respect to the design, ∂kJ∗=wT⟨∂ku∗⟩\partial_kJ^*=w^T\langle\partial_ku^*\rangle (⟨∂ku∗⟩i\langle\partial_ku^*\rangle_i is the cell average of ∂u∗/∂Dk\partial u^*/\partial D_k), so the gradient error Dˉk−∂kJ∗=wT(vk−⟨∂ku∗⟩)\bar D_k-\partial_kJ^*=w^T(v_k-\langle\partial_ku^*\rangle) is a weighted sum of the error of the tangent solution. As u∗u^* does not depend on ν\nu, ⟨∂νu∗⟩=0\langle\partial_\nu u^*\rangle=0: the error of the ν\nu-component is the discrete gradient ∂νJh\partial_\nu J_h itself.

内部的格式:一阶就是多了黏性 hh

The scheme in the interior: first order is extra viscosity hh

先回顾第 3 节的两个精确恒等式,它们解释了下面看到的阶。一阶重构(迹等于单元平均)时,内部行 1≤j≤N−21\le j\le N-2 是

First recall the two exact identities of Section 3; they explain the orders seen below. With first-order reconstruction (the traces are the cell averages) an interior row 1≤j≤N−21\le j\le N-2 is

Rj=14(Uj+12−Uj−12)−(1+νh)(Uj+1−2Uj+Uj−1)−(Qj+1−Qj).R_j=\tfrac14\bigl(U_{j+1}^2-U_{j-1}^2\bigr)-\Bigl(1+\frac{\nu}{h}\Bigr)\bigl(U_{j+1}-2U_j+U_{j-1}\bigr)-\bigl(Q_{j+1}-Q_j\bigr).

除以 hh,这正是 (12u2)x−(ν+h) uxx=s(\tfrac12u^2)_x-(\nu+h)\,u_{xx}=s 的中心差分格式:Rusanov 耗散 α/2=1\alpha/2=1 等于在物理黏性上加了一个数值黏性 hh。格式求解的是一个黏性错了 hh 的问题,所以误差是 O(h)O(h);而且 h>νh>\nu 时数值黏性比物理黏性还大(默认 N=8N=8:h=12.5νh=12.5\nu;N=100N=100 时两者相等)。无限制器线性重构时,内部面 2≤f≤N−22\le f\le N-2 的耗散项是一个三阶差分,

Divided by hh, this is the central-difference scheme for (12u2)x−(ν+h) uxx=s(\tfrac12u^2)_x-(\nu+h)\,u_{xx}=s: the Rusanov dissipation α/2=1\alpha/2=1 adds a numerical viscosity hh to the physical one. The scheme solves a problem whose viscosity is wrong by hh, so its error is O(h)O(h); and for h>νh>\nu the numerical viscosity is larger than the physical one (default N=8N=8: h=12.5νh=12.5\nu; the two are equal at N=100N=100). With unlimited linear reconstruction the dissipation term of an interior face 2≤f≤N−22\le f\le N-2 is a third difference,

−(qR−qL)=14(Uf+1−3Uf+3Uf−1−Uf−2),-(q_R-q_L)=\tfrac14\bigl(U_{f+1}-3U_f+3U_{f-1}-U_{f-2}\bigr),

两个面相减,一行得到 14\tfrac14 倍的四阶差分(超黏性),没有二阶导数形式的人工黏性,内部是二阶格式。这两个恒等式第 3 节已经给出并验算过(那里的面板“数值耗散的真面目”在当前状态上再算一遍),伴随方面的推论见第 16 节。本节测量它们对误差的影响。

so a row receives 14\tfrac14 times a fourth difference (a hyperviscosity): no artificial viscosity of second-derivative form, and the interior scheme is second order. Section 3 states both identities and checks them (its panel "What the numerical dissipation really is" recomputes them on the current state); their consequences for the adjoint are in Section 16. This section measures their effect on the errors.

三种重构,N=8N=8 到 40964096

Three reconstructions, N=8N=8 to 40964096

图 56 与下面两张表是本页的模型在 N=8,16,…,4096N=8,16,\dots,4096 上的结果(默认设计;每个网格都用与上方控件相同的 Newton 迭代解到舍入水平,线性方程用带状 LU 求解)。读法:

Figure 56 and the two tables below are the results of this page's model on N=8,16,…,4096N=8,16,\dots,4096 (default design; every mesh solved to rounding by the Newton iteration of the controls above, the linear systems by a banded LU). How to read them:

  • 一阶:状态误差的观测阶从 0.71、0.86、0.90 稳步升到 0.99(N=4096N=4096),趋向 1。First order: the observed order of the state error climbs steadily from 0.71, 0.86, 0.90 to 0.99 (N=4096N=4096): it approaches 1.
  • 无限制器线性:粗网格上的阶只有 0.94、1.00(N=16N=16、3232),像一阶格式;从 N=64N=64 起逐渐升高(1.11、1.29、1.51、1.70、1.84、1.91、1.96),二阶要到 N≥1024N\ge1024 才显现(从这里起观测阶不低于 1.83)。原因见下面的 Péclet 数和端单元两小节。Unlimited linear: on coarse meshes the order is only 0.94, 1.00 (N=16N=16, 3232), like a first-order scheme; from N=64N=64 on it rises (1.11, 1.29, 1.51, 1.70, 1.84, 1.91, 1.96), and second order shows only for N≥1024N\ge1024 (from there on the observed order is at least 1.83). The two subsections on the Péclet number and the end cells explain why.
  • 光滑限制器:中等网格上接近无限制器线性,之后反而变慢,N=4096N=4096 时阶为 0.99,误差与一阶格式只差 0.2%:它在细网格上退化为一阶格式(见本节末)。Smooth limiter: close to unlimited linear on intermediate meshes, then slower; at N=4096N=4096 its order is 0.99 and its error differs from the first-order one by only 0.2%: on fine meshes it degenerates to the first-order scheme (end of this section).
图 56 · 三种重构的加密(本页模型,默认设计,N=8 到 4096)。上:状态误差 ‖U-⟨u*⟩‖_1;下:梯度 a 分量的误差 |D-bar_a-∂_aJ*|。圈:一阶;方块:无限制器线性;点:光滑限制器;三角形标出斜率 1 和 2。无限制器线性从 N=1024 起才进入二阶;光滑限制器从 N=1024 起贴到一阶的线上(两个误差与一阶相差都不到 7%)。10-6​10-5​10-4​10-3​10-2​10-1​单元数 N‖U − ⟨u*⟩‖1​832128512204821状态误差一阶无限制器线性光滑限制器10-5​10-4​10-3​10-2​10-1​1单元数 N梯度 a 分量的误差832128512204821梯度 a 分量的误差一阶无限制器线性光滑限制器
图 56 · 三种重构的加密(本页模型,默认设计,N=8N=8 到 40964096)。上:状态误差 ∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1;下:梯度 aa 分量的误差 ∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|。圈:一阶;方块:无限制器线性;点:光滑限制器;三角形标出斜率 1 和 2。无限制器线性从 N=1024N=1024 起才进入二阶;光滑限制器从 N=1024N=1024 起贴到一阶的线上(两个误差与一阶相差都不到 7%)。
Figure 56 · Refinement of the three reconstructions (this page's model, default design, N=8 to 4096). Top: the state error ‖U-⟨u*⟩‖_1; bottom: the error of the gradient component a, |D-bar_a-∂_aJ*|. Rings: first order; squares: unlimited linear; dots: smooth limiter; the triangles mark slopes 1 and 2. Unlimited linear enters second order only from N=1024 on; from N=1024 on the smooth limiter lies on the first-order line (both errors within 7% of first order's).10-6​10-5​10-4​10-3​10-2​10-1​cells N‖U − ⟨u*⟩‖1​832128512204821state errorfirst orderunlimited linearsmooth limiter10-5​10-4​10-3​10-2​10-1​1cells Ngradient error, a832128512204821gradient error, afirst orderunlimited linearsmooth limiter
Figure 56 · Refinement of the three reconstructions (this page's model, default design, N=8N=8 to 40964096). Top: the state error ∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1; bottom: the error of the gradient component aa, ∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|. Rings: first order; squares: unlimited linear; dots: smooth limiter; the triangles mark slopes 1 and 2. Unlimited linear enters second order only from N=1024N=1024 on; from N=1024N=1024 on the smooth limiter lies on the first-order line (both errors within 7% of first order's).
一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
NN∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1ord\mathrm{ord}∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1ord\mathrm{ord}∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1ord\mathrm{ord}
88.8e−2—5.2e−2—7.0e−2—
165.4e−20.712.7e−20.942.8e−21.32
323.0e−20.861.4e−21.001.4e−20.96
641.6e−20.906.3e−31.117.5e−30.95
1288.4e−30.922.6e−31.294.5e−30.73
2564.4e−30.949.1e−41.513.2e−30.49
5122.2e−30.962.8e−41.702.0e−30.66
10241.1e−30.977.8e−51.841.1e−30.87
20485.8e−40.992.1e−51.915.7e−40.96
40962.9e−40.995.3e−61.962.9e−40.99
一阶first order无限制器线性unlimited linear光滑限制器smooth limiter
NN∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|ord\mathrm{ord}∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|ord\mathrm{ord}∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|ord\mathrm{ord}
86.0e−1—3.4e−1—5.1e−1—
163.8e−10.652.1e−10.732.1e−11.27
322.2e−10.801.1e−10.951.1e−11.00
641.2e−10.854.9e−21.124.6e−21.23
1286.7e−20.882.0e−21.321.8e−21.36
2563.5e−20.916.8e−31.541.5e−20.20
5121.8e−20.942.1e−31.721.4e−20.13
10249.4e−30.975.8e−41.858.7e−30.69
20484.8e−30.981.5e−41.924.7e−30.91
40962.4e−30.993.9e−51.962.4e−30.97

自己做一遍:选重构和误差量,网格从 N=8N=8 加密到 40964096(当前设计,在浏览器里计算;带状 LU 使每个网格的求解只需几毫秒)。

Do it yourself: pick a reconstruction and an error, refine from N=8N=8 to 40964096 (the current design, computed in the browser; the banded LU keeps every solve to milliseconds).

加密播放器一次只显示一个网格:离散解与精确单元平均、误差的分布,以及到这一步为止的收敛曲线。

The refinement player shows one mesh at a time: the discrete solution against the exact cell averages, the distribution of the error, and the convergence curve up to this step.

Python 程序算到 65536 个单元

The Python runs to 65536 cells

发布仓库里的独立 Python 程序(python/burgers_viscous/solve.py,稀疏 Jacobian、SciPy 的 LU)把无限制器线性算到 N=16384N=16384 和 6553665536,一阶算到 40964096(图 57)。在共同的网格 N=32N=32 到 40964096 上,本页模型与 Python 程序的状态误差相差不超过 8.5×10−128.5\times10^{-12},梯度误差相差不超过 3.9×10−113.9\times10^{-11}(Python 的 Newton 迭代在修正量 ≤2×10−11\le2\times10^{-11} 时停止,这就是差别的来源)。对状态和梯度 aa 分量而言,这证实了预期的阶(无限制器线性趋于 2,一阶趋于 1):无限制器线性格式中,梯度 aa 分量误差的观测阶在 N=16384N=16384 达到 1.99,状态误差的观测阶为 1.99;从 1638416384 到 6553665536 的平均阶是 2.00;一阶格式在 N=4096N=4096 达到 0.99(梯度)和 0.99(状态)。

The independent Python program of the publish repository (python/burgers_viscous/solve.py, a sparse Jacobian, SciPy's LU) ran unlimited linear to N=16384N=16384 and 6553665536 and first order to 40964096 (Figure 57). On the common meshes N=32N=32 to 40964096 this page's model and the Python program differ by at most 8.5×10−128.5\times10^{-12} in the state errors and 3.9×10−113.9\times10^{-11} in the gradient errors (the Python Newton iteration stops at a correction of 2×10−112\times10^{-11}; that is where the differences come from). For the state and the gradient component aa this confirms the expected orders (unlimited linear tends to 2, first order to 1): the observed order of the error of the gradient component aa of unlimited linear reaches 1.99 at N=16384N=16384 and that of the state error 1.99; from 1638416384 to 6553665536 the mean order is 2.00; first order reaches 0.99 (gradient) and 0.99 (state) at N=4096N=4096.

Python 程序自己的梯度检验(JSON 中的 gradient_check)用的正是第 13 节说的最危险的组合:以扰动前的解为初值热启动,加绝对容差 2×10−112\times10^{-11}。本页在 N=32N=32 到 40964096 上重算:每次都加上了 2 个修正量,第二个是 3.8×10−113.8\times10^{-11} 到 7.1×10−117.1\times10^{-11},只比容差大一点。所以那个检验仍然独立,但余量很小。

The Python program's own gradient check (gradient_check in the JSON) uses exactly the combination Section 13 calls the most dangerous: a warm start from the unperturbed solution with the absolute tolerance 2×10−112\times10^{-11}. Recomputed here for N=32N=32 to 40964096: every solve added 2 corrections, the second of 3.8×10−113.8\times10^{-11} to 7.1×10−117.1\times10^{-11}, just above the tolerance. So that check is still independent, but narrowly.

图 57 · Python 程序的加密数据(默认设计,读自经哈希校验的 JSON)。上:无限制器线性,N=32 到 65536;下:一阶,N=32 到 4096。方块:状态误差;实心点:梯度 a 分量与 ν 分量的误差;圈:梯度 φ 分量的误差。梯度 ν 分量的误差(无限制器线性)与梯度 φ 分量的误差(一阶)在粗网格上不单调;无限制器线性中 ν 分量(精确值 0)的误差从 N=64 起一直最大。10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1单元数 N误差3212851220488192327682无限制器线性:N = 32 … 65536(Python)状态误差梯度 a 分量的误差梯度 φ 分量的误差梯度 ν 分量的误差10-4​10-3​10-2​10-1​1单元数 N误差3212851220481一阶:N = 32 … 4096(Python)状态误差梯度 a 分量的误差梯度 φ 分量的误差梯度 ν 分量的误差
图 57 · Python 程序的加密数据(默认设计,读自经哈希校验的 JSON)。上:无限制器线性,N=32N=32 到 6553665536;下:一阶,N=32N=32 到 40964096。方块:状态误差;实心点:梯度 aa 分量与 ν\nu 分量的误差;圈:梯度 φ\varphi 分量的误差。梯度 ν\nu 分量的误差(无限制器线性)与梯度 φ\varphi 分量的误差(一阶)在粗网格上不单调;无限制器线性中 ν\nu 分量(精确值 0)的误差从 N=64N=64 起一直最大。
Figure 57 · The refinement data of the Python program (default design, read from the hash-checked JSON). Top: unlimited linear, N=32 to 65536; bottom: first order, N=32 to 4096. Squares: the state error; dots: the errors of the gradient components a and ν; rings: the error of the gradient component φ. The error of the gradient component ν (unlimited linear) and the error of the gradient component φ (first order) are not monotone on coarse meshes; for unlimited linear the ν-component (exact value 0) has the largest error from N=64 on.10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1cells Nerror3212851220488192327682unlimited linear: N = 32 … 65536 (Python)state errorgradient error, agradient error, φgradient error, ν10-4​10-3​10-2​10-1​1cells Nerror3212851220481first order: N = 32 … 4096 (Python)state errorgradient error, agradient error, φgradient error, ν
Figure 57 · The refinement data of the Python program (default design, read from the hash-checked JSON). Top: unlimited linear, N=32N=32 to 6553665536; bottom: first order, N=32N=32 to 40964096. Squares: the state error; dots: the errors of the gradient components aa and ν\nu; rings: the error of the gradient component φ\varphi. The error of the gradient component ν\nu (unlimited linear) and the error of the gradient component φ\varphi (first order) are not monotone on coarse meshes; for unlimited linear the ν\nu-component (exact value 0) has the largest error from N=64N=64 on.
状态State目标Objective梯度 aa 分量Gradient component aa梯度 φ\varphi 分量Gradient component φ\varphi梯度 ν\nu 分量Gradient component ν\nu求解Solve
NN∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1ord\mathrm{ord}∣Jh−J∗∣|J_h-J^*|∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|ord\mathrm{ord}∣Dˉφ−∂φJ∗∣|\bar D_\varphi-\partial_\varphi J^*|ord\mathrm{ord}∣Dˉν∣|\bar D_\nu|ord\mathrm{ord}Newton 修正Newton corr.秒seconds
321.4e−2—2.0e−21.1e−1—4.3e−2—9.5e−2—2.4e−160.0604
646.3e−31.119.5e−34.9e−21.122.8e−20.641.8e−1−0.933.2e−160.0082
1282.6e−31.293.9e−32.0e−21.321.4e−21.041.6e−10.208.6e−120.0088
2569.1e−41.511.4e−36.8e−31.545.3e−31.368.5e−20.897.9e−140.0090
5122.8e−41.704.2e−42.1e−31.721.7e−31.623.3e−21.375.2e−160.0105
10247.8e−51.841.2e−45.8e−41.854.9e−41.791.0e−21.662.1e−160.0127
20482.1e−51.913.1e−51.5e−41.921.3e−41.893.0e−31.821.9e−160.0176
40965.3e−61.968.1e−63.9e−51.963.5e−51.947.9e−41.911.1e−110.0240
81921.4e−61.982.0e−69.9e−61.988.8e−61.972.0e−41.957.0e−130.0433
163843.4e−71.995.2e−72.5e−61.992.2e−61.995.2e−51.984.5e−140.0781
655362.1e−82.003.2e−81.6e−72.001.4e−71.993.3e−61.992.4e−160.2993
状态State目标Objective梯度 aa 分量Gradient component aa梯度 φ\varphi 分量Gradient component φ\varphi梯度 ν\nu 分量Gradient component ν\nu求解Solve
NN∥𝐔−⟨u∗⟩∥1\|\mathbf U-\langle u^*\rangle\|_1ord\mathrm{ord}∣Jh−J∗∣|J_h-J^*|∣Dˉa−∂aJ∗∣|\bar D_a-\partial_aJ^*|ord\mathrm{ord}∣Dˉφ−∂φJ∗∣|\bar D_\varphi-\partial_\varphi J^*|ord\mathrm{ord}∣Dˉν∣|\bar D_\nu|ord\mathrm{ord}Newton 修正Newton corr.秒seconds
323.0e−2—4.1e−22.2e−1—2.3e−2—5.2e−1—2.0e−120.0074
641.6e−20.902.3e−21.2e−10.856.8e−31.763.2e−10.691.9e−140.0081
1288.4e−30.921.2e−26.7e−20.881.1e−2−0.701.5e−11.082.1e−160.0077
2564.4e−30.946.7e−33.5e−20.918.4e−30.405.8e−21.381.8e−160.0093
5122.2e−30.963.5e−31.8e−20.945.2e−30.711.9e−21.591.5e−160.0099
10241.1e−30.971.8e−39.4e−30.972.9e−30.856.0e−31.685.4e−120.0123
20485.8e−40.999.0e−44.8e−30.981.5e−30.931.9e−31.663.5e−130.0133
40962.9e−40.994.5e−42.4e−30.997.7e−40.966.4e−41.562.2e−140.0203

上表:无限制器线性(含 6553665536 单元的一行,阶按两次加密平均);下表:一阶。误差经过零点的地方,阶没有意义(见本节末)。二阶收敛不只是范数的性质:把误差分布乘以 N2N^2,四套网格的曲线逐渐重合(图 58:N2max⁡i∣Ui−⟨u∗⟩i∣N^2\max_i|U_i-\langle u^*\rangle_i| 依次为 101.0、110.5、113.2、113.8)。

Top table: unlimited linear (with the row of 6553665536 cells, its orders averaged over two refinements); bottom: first order. Where an error passes through zero, its order means nothing (end of this section). Second-order convergence is not only a property of the norms: multiplied by N2N^2, the error profiles of four meshes come together (Figure 58: N2max⁡i∣Ui−⟨u∗⟩i∣N^2\max_i|U_i-\langle u^*\rangle_i| is 101.0, 110.5, 113.2 and 113.8).

图 58 · 误差分布乘以 N^2(无限制器线性,Python 数据,每套网格均匀抽取 161 个单元):N=1024(虚线)、4096、16384、65536(粗线)的 N^2(U_i-⟨u*⟩_i) 逐渐重合,说明误差逐点以 h^2 收敛。N=65536 时绝对值最大的值 -113.8 位于内部 x ≈ 0.81 处;第一个和最后一个单元各有一个窄尖峰(-15.9 与 40.8),出口前一小段内误差迅速变化(见 Péclet 数一小节)。后面的端单元实验说明,状态误差的整条曲线主要来自两个不重构的端单元。−120−100−80−60−40−200204000.20.40.60.81xN² (Ui​ − ⟨u*⟩i​)N = 1024N = 4096N = 16384N = 65536
图 58 · 误差分布乘以 N2N^2(无限制器线性,Python 数据,每套网格均匀抽取 161 个单元):N=1024N=1024(虚线)、40964096、1638416384、6553665536(粗线)的 N2(Ui−⟨u∗⟩i)N^2(U_i-\langle u^*\rangle_i) 逐渐重合,说明误差逐点以 h2h^2 收敛。N=65536N=65536 时绝对值最大的值 −113.8-113.8 位于内部 x≈0.81x\approx0.81 处;第一个和最后一个单元各有一个窄尖峰(−15.9-15.9 与 40.840.8),出口前一小段内误差迅速变化(见 Péclet 数一小节)。后面的端单元实验说明,状态误差的整条曲线主要来自两个不重构的端单元。
Figure 58 · Error profiles multiplied by N^2 (unlimited linear, Python data, 161 cells sampled evenly from each mesh): N^2(U_i-⟨u*⟩_i) for N=1024 (dashed), 4096, 16384 and 65536 (thick) come together, so the error converges pointwise like h^2. At N=65536 the value of largest magnitude, -113.8, sits in the interior at x ≈ 0.81; the first and the last cell show narrow spikes (-15.9 and 40.8), and just before the outlet the error changes quickly (see the subsection on the Péclet number). The end-cell experiment below shows that the whole profile of the state error comes mainly from the two end cells that are not reconstructed.−120−100−80−60−40−200204000.20.40.60.81xN² (Ui​ − ⟨u*⟩i​)N = 1024N = 4096N = 16384N = 65536
Figure 58 · Error profiles multiplied by N2N^2 (unlimited linear, Python data, 161 cells sampled evenly from each mesh): N2(Ui−⟨u∗⟩i)N^2(U_i-\langle u^*\rangle_i) for N=1024N=1024 (dashed), 40964096, 1638416384 and 6553665536 (thick) come together, so the error converges pointwise like h2h^2. At N=65536N=65536 the value of largest magnitude, −113.8-113.8, sits in the interior at x≈0.81x\approx0.81; the first and the last cell show narrow spikes (−15.9-15.9 and 40.840.8), and just before the outlet the error changes quickly (see the subsection on the Péclet number). The end-cell experiment below shows that the whole profile of the state error comes mainly from the two end cells that are not reconstructed.

图 59 是程序在 JSON 里记录的每个网格的耗时(记录的平台字符串 macOS-26.6.2-arm64-arm-64bit-Mach-O 只写了操作系统和处理器架构,不是机器型号)。一个网格的耗时包括 Newton 求解、三个前向求解与一个伴随求解、两次差分检验的求解;无限制器线性的各个网格(refinement_none.json)还包括与连续伴随的比较(在单元中心求连续伴随的值,加两个数值积分),其中 N=32N=32 这个网格还包括一次连续伴随边值问题的求解;6553665536 个单元的那次单独运行和一阶的各个网格都不含这些。稀疏 LU 使耗时大致随 NN 线性增长:6553665536 个单元 0.30 秒。

Figure 59 shows the time per mesh that the program recorded in the JSON (the recorded platform string, macOS-26.6.2-arm64-arm-64bit-Mach-O, names the operating system and the architecture, not the machine). The time of a mesh includes the Newton solve, three tangent solves and one adjoint solve, and the two solves of the difference check; the unlimited-linear rows (refinement_none.json) also include the comparison with the continuous adjoint (evaluating it at the cell centres and two quadratures), and the row N=32N=32 the solution of the continuous-adjoint boundary-value problem; the row of 6553665536 cells (a separate run) and the first-order rows include none of this. The sparse LU keeps the time roughly linear in NN: 0.30 seconds for 6553665536 cells.

图 59 · Python 程序记录的每个网格的耗时(在记录的平台上实测,不是本页浏览器的耗时;无限制器线性 N ≤ 16384 的各点含与连续伴随的比较)。三角形标出斜率 1(线性增长)。粗网格的耗时由固定开销决定。0.0010.010.11单元数 N每个网格的耗时(秒)3212851220488192327681无限制器线性一阶
图 59 · Python 程序记录的每个网格的耗时(在记录的平台上实测,不是本页浏览器的耗时;无限制器线性 N≤16384N\le16384 的各点含与连续伴随的比较)。三角形标出斜率 1(线性增长)。粗网格的耗时由固定开销决定。
Figure 59 · Seconds per mesh recorded by the Python program (measured on the recorded platform, not in this browser; the unlimited-linear points with N ≤ 16384 include the comparison with the continuous adjoint). The triangle marks slope 1 (linear growth). On coarse meshes fixed overheads dominate.0.0010.010.11cells Nseconds per mesh3212851220488192327681unlimited linearfirst order
Figure 59 · Seconds per mesh recorded by the Python program (measured on the recorded platform, not in this browser; the unlimited-linear points with N≤16384N\le16384 include the comparison with the continuous adjoint). The triangle marks slope 1 (linear growth). On coarse meshes fixed overheads dominate.

观测阶如何依赖网格 Péclet 数

How the observed order depends on the cell Péclet number

单元宽度与黏性长度 ν/u\nu/u 之比就是网格 Péclet 数 Peh=uinh/ν\mathrm{Pe}_h=u_{\rm in}h/\nu(默认 ν/uin≈0.0109\nu/u_{\rm in}\approx0.0109,N=8N=8 时 Peh=11.44\mathrm{Pe}_h=11.44)。把六个黏性 ν=0.0025, 0.005, 0.01, 0.02, 0.04, 0.08\nu=0.0025,\ 0.005,\ 0.01,\ 0.02,\ 0.04,\ 0.08 的加密以 Peh\mathrm{Pe}_h 为横轴画在一起(图 60,无限制器线性):误差本身随 ν\nu 不同,但观测阶几乎只是 Peh\mathrm{Pe}_h 的函数。除去每个黏性最粗的一对网格(N=8→16N=8\to16,这些点落在共同曲线之下),同一个 Peh\mathrm{Pe}_h 处六个黏性的阶最多相差 0.07(Peh≤1\mathrm{Pe}_h\le1)和 0.09(Peh>1\mathrm{Pe}_h>1)。Peh≈2.9\mathrm{Pe}_h\approx2.9 时阶为 0.94 到 1.04,Peh≈0.36\mathrm{Pe}_h\approx0.36 时为 1.49 到 1.54,Peh≤0.05\mathrm{Pe}_h\le0.05 时至少 1.91;默认 ν=0.01\nu=0.01 时网格序列要到 N=2048N=2048 才满足 Peh≤0.05\mathrm{Pe}_h\le0.05。

The ratio of the cell width to the viscous length ν/u\nu/u is the cell Péclet number Peh=uinh/ν\mathrm{Pe}_h=u_{\rm in}h/\nu (at the defaults ν/uin≈0.0109\nu/u_{\rm in}\approx0.0109, and Peh=11.44\mathrm{Pe}_h=11.44 at N=8N=8). Draw the refinements of six viscosities ν=0.0025, 0.005, 0.01, 0.02, 0.04, 0.08\nu=0.0025,\ 0.005,\ 0.01,\ 0.02,\ 0.04,\ 0.08 with Peh\mathrm{Pe}_h as the horizontal axis (Figure 60, unlimited linear): the errors themselves differ with ν\nu, but the observed order is almost a function of Peh\mathrm{Pe}_h alone. Leaving out the coarsest pair of each viscosity (N=8→16N=8\to16, whose points lie below the common curve), at the same Peh\mathrm{Pe}_h the orders of the six viscosities differ by at most 0.07 (Peh≤1\mathrm{Pe}_h\le1) and 0.09 (Peh>1\mathrm{Pe}_h>1). The order is 0.94 to 1.04 at Peh≈2.9\mathrm{Pe}_h\approx2.9, 1.49 to 1.54 at Peh≈0.36\mathrm{Pe}_h\approx0.36, and at least 1.91 for Peh≤0.05\mathrm{Pe}_h\le0.05; with the default ν=0.01\nu=0.01 the mesh sequence reaches Peh≤0.05\mathrm{Pe}_h\le0.05 only at N=2048N=2048.

起作用的不是解的边界层(u∗u^* 是一个正弦波,没有层),而是离散误差在出口处宽度约 ν/u\nu/u 的层:N=4096N=4096 时 N2(Ui−⟨u∗⟩i)N^2(U_i-\langle u^*\rangle_i) 从 x≈0.978x\approx0.978 处(1−2ν/uin1-2\nu/u_{\rm in})的 −75-75 升到 x≈0.9996x\approx0.9996 处的 6666。这个层由端单元产生:端单元重构后,同一段上的 N2(Ui−⟨u∗⟩i)N^2(U_i-\langle u^*\rangle_i) 只在 −0.56-0.56 到 −0.48-0.48 之间。对状态误差而言,阶对 Peh\mathrm{Pe}_h 的依赖来自端单元:端单元重构后(下一小节),ν=0.0025\nu=0.0025 时状态误差在 Peh\mathrm{Pe}_h 为 22.9、11.4、5.7、2.9、1.4 处的观测阶依次是 2.56、2.31、2.13、2.09、2.02,Peh≈23\mathrm{Pe}_h\approx23 时已是二阶。端单元重构后,梯度误差的阶仍然上升得很慢(见下一小节);原因本页不作推断。

The layer that matters is not one of the solution (u∗u^* is a sine wave and has none) but one of the discrete error, at the outlet, with a width of about ν/u\nu/u: at N=4096N=4096, N2(Ui−⟨u∗⟩i)N^2(U_i-\langle u^*\rangle_i) rises from −75-75 at x≈0.978x\approx0.978 (1−2ν/uin1-2\nu/u_{\rm in}) to 6666 at x≈0.9996x\approx0.9996. The end cells produce it: with them reconstructed, N2(Ui−⟨u∗⟩i)N^2(U_i-\langle u^*\rangle_i) stays between −0.56-0.56 and −0.48-0.48 on the same stretch. For the state error, the dependence of the order on Peh\mathrm{Pe}_h comes from the end cells: with the end cells reconstructed (next subsection), the observed orders of the state error at ν=0.0025\nu=0.0025 are 2.56, 2.31, 2.13, 2.09, 2.02 at Peh\mathrm{Pe}_h of 22.9, 11.4, 5.7, 2.9, 1.4, second order already at Peh≈23\mathrm{Pe}_h\approx23. With the end cells reconstructed, the order of the gradient error still rises slowly (next subsection); the page claims no cause for that.

图 60 · 观测阶几乎只是网格 Péclet 数的函数(无限制器线性,a=0.2,φ=0.07,六个黏性,每个 N=8 到 4096)。上:梯度 a 分量的误差随 Pe_h 的变化;下:相邻网格的观测阶,画在细网格的 Pe_h 处。六条曲线落在同一条线上(每条曲线最右边的一点,即 N=8 → 16,在它下面):Pe_h>1 时阶约为 1,Pe_h → 0 时趋于 2。10-6​10-5​10-4​10-3​10-2​10-1​10.010.1110网格 Péclet 数 Peh​ = uin​ h / ν梯度 a 分量的误差ν = 0.0025ν = 0.005ν = 0.01ν = 0.02ν = 0.04ν = 0.0800.511.520.010.1110细网格的 Peh​观测阶 ordPeh​ = 1
图 60 · 观测阶几乎只是网格 Péclet 数的函数(无限制器线性,a=0.2a=0.2,φ=0.07\varphi=0.07,六个黏性,每个 N=8N=8 到 40964096)。上:梯度 aa 分量的误差随 Peh\mathrm{Pe}_h 的变化;下:相邻网格的观测阶,画在细网格的 Peh\mathrm{Pe}_h 处。六条曲线落在同一条线上(每条曲线最右边的一点,即 N=8→16N=8\to16,在它下面):Peh>1\mathrm{Pe}_h>1 时阶约为 1,Peh→0\mathrm{Pe}_h\to0 时趋于 2。
Figure 60 · The observed order is almost a function of the cell Péclet number alone (unlimited linear, a=0.2, φ=0.07, six viscosities, each with N=8 to 4096). Top: the error of the gradient component a against Pe_h; bottom: the observed order of successive meshes, drawn at the Pe_h of the finer one. The six curves fall onto one (the rightmost point of each curve, N=8 → 16, lies below it): the order is about 1 for Pe_h>1 and tends to 2 as Pe_h → 0.10-6​10-5​10-4​10-3​10-2​10-1​10.010.1110cell Péclet number Peh​ = uin​ h / νgradient error, aν = 0.0025ν = 0.005ν = 0.01ν = 0.02ν = 0.04ν = 0.0800.511.520.010.1110Peh​ of the finer meshobserved order ordPeh​ = 1
Figure 60 · The observed order is almost a function of the cell Péclet number alone (unlimited linear, a=0.2a=0.2, φ=0.07\varphi=0.07, six viscosities, each with N=8N=8 to 40964096). Top: the error of the gradient component aa against Peh\mathrm{Pe}_h; bottom: the observed order of successive meshes, drawn at the Peh\mathrm{Pe}_h of the finer one. The six curves fall onto one (the rightmost point of each curve, N=8→16N=8\to16, lies below it): the order is about 1 for Peh>1\mathrm{Pe}_h>1 and tends to 2 as Peh→0\mathrm{Pe}_h\to0.

一阶格式没有这样的过渡:它的误差由数值黏性 hh 决定,几乎与 ν\nu 无关——N=4096N=4096 时六个黏性的梯度 aa 分量误差都在 2.0×10−32.0\times10^{-3} 到 2.4×10−32.4\times10^{-3} 之间。

The first-order scheme shows no such transition: its error is set by the numerical viscosity hh and hardly depends on ν\nu: at N=4096N=4096 the errors of the gradient component aa for the six viscosities all lie between 2.0×10−32.0\times10^{-3} and 2.4×10−32.4\times10^{-3}.

自己选几个黏性:当前的 a,φa,\varphi,每个 ν\nu 从 N=8N=8 加密到 40964096(在浏览器里计算)。

Pick some viscosities: the current a,φa,\varphi, every ν\nu refined from N=8N=8 to 40964096 (computed in the browser).

两个不重构的端单元

The two end cells that are not reconstructed

第 3 节规定 σ0=σN−1=0\sigma_0=\sigma_{N-1}=0:两端的单元不重构,面 00、11 和 N−1N-1、NN 用的迹只有一阶精度,这四个面的通量误差是 O(h)O(h)。它们对误差贡献多大?做一个实验(只是本节的实验,不是本页的格式):用虚单元值 U−1=2uin−U0U_{-1}=2u_{\rm in}-U_0、UN=2uout−UN−1U_N=2u_{\rm out}-U_{N-1}(过边界值的直线)按内部公式给端单元一个斜率,其他一切不变;这个变体的 Jacobian 用复数步长得到,所以它的切线与伴随梯度也是精确的。结果(图 61):状态误差小了 44 到 127127 倍,从 N=16N=16 起状态误差的观测阶就在 1.76 到 2.54 之间;N=4096N=4096 时 N2max⁡i∣Ui−⟨u∗⟩i∣N^2\max_i|U_i-\langle u^*\rangle_i| 从 110.5 降到 1.23,内部的误差也一起变小。所以无限制器线性格式的状态误差在粗网格上表现为一阶、数值偏大,主要是这两个端单元造成的。梯度 aa 分量的误差在 N≥128N\ge128 时小 124124 到 137137 倍,比值几乎不变,所以从 N=256N=256 起它的观测阶与本页格式相差不到 0.05;更粗的网格上变体的阶忽高忽低(N=16N=16 到 128128:4.17、2.11、0.28、1.03,本页格式为 0.73、0.95、1.12、1.32),也不是二阶。端单元决定梯度误差的大小,而不是它迟迟才到二阶。

Section 3 sets σ0=σN−1=0\sigma_0=\sigma_{N-1}=0: the two end cells are not reconstructed, the traces used by faces 00, 11 and N−1N-1, NN are only first-order accurate, and the fluxes of these four faces carry O(h)O(h) errors. How much do they contribute? An experiment (an experiment of this section only, not the page's scheme): give the end cells a slope by the interior formula with the ghost values U−1=2uin−U0U_{-1}=2u_{\rm in}-U_0 and UN=2uout−UN−1U_N=2u_{\rm out}-U_{N-1} (the line through the boundary value), with everything else unchanged; the Jacobians of this variant come from the complex step, so its tangent and adjoint gradients are exact too. The result (Figure 61): the state error is 44 to 127127 times smaller, and the observed order of the state error lies between 1.76 and 2.54 from N=16N=16 on; at N=4096N=4096, N2max⁡i∣Ui−⟨u∗⟩i∣N^2\max_i|U_i-\langle u^*\rangle_i| drops from 110.5 to 1.23, the interior error with it. So the first-order look of the state error of the unlimited linear scheme on coarse meshes, and its size, come mainly from these two end cells. The error of the gradient component aa is 124124 to 137137 times smaller for N≥128N\ge128, an almost constant ratio, so from N=256N=256 on its observed order equals the page scheme's to within 0.05; on coarser meshes the variant's order is erratic (N=16N=16 to 128128: 4.17, 2.11, 0.28, 1.03, against 0.73, 0.95, 1.12, 1.32) and not second order. The end cells set the size of the gradient error, not its slow approach to second order.

图 61 · 端单元的作用(无限制器线性,默认设计)。实线方块:本页格式;虚线圈:端单元用虚单元值重构的实验变体。蓝:状态误差;橙:梯度 a 分量的误差。变体的误差大多小一到两个数量级(N=8 时只小 4 倍和 11 倍)。变体的状态误差从 N=16 起是二阶;梯度 a 分量的误差在 N ≥ 128 时小 124 到 137 倍;它的观测阶在粗网格上不是二阶(N=64、128、256 时为 0.28、1.03、1.51),从 N=256 起与本页格式相差不到 0.05。10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1单元数 N误差83212851220482本页格式:状态误差端单元重构:状态误差本页格式:梯度 a 分量的误差端单元重构:梯度 a 分量的误差
图 61 · 端单元的作用(无限制器线性,默认设计)。实线方块:本页格式;虚线圈:端单元用虚单元值重构的实验变体。蓝:状态误差;橙:梯度 aa 分量的误差。变体的误差大多小一到两个数量级(N=8N=8 时只小 4 倍和 11 倍)。变体的状态误差从 N=16N=16 起是二阶;梯度 aa 分量的误差在 N≥128N\ge128 时小 124124 到 137137 倍;它的观测阶在粗网格上不是二阶(N=64N=64、128128、256256 时为 0.28、1.03、1.51),从 N=256N=256 起与本页格式相差不到 0.05。
Figure 61 · What the end cells do (unlimited linear, default design). Solid squares: the page's scheme; dashed rings: the experimental variant with the end cells reconstructed through ghost values. Blue: the state error; orange: the error of the gradient component a. The variant's errors are mostly one to two orders of magnitude smaller (at N=8 only 4 and 11 times). The variant's state error is second order from N=16; its error of the gradient component a is 124 to 137 times smaller for N ≥ 128; its observed order is not second order on coarse meshes (0.28, 1.03, 1.51 at N=64, 128, 256) and from N=256 on equals the page scheme's to within 0.05.10-9​10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1cells Nerror83212851220482page scheme: state errorend cells reconstructed: state errorpage scheme: gradient error, aend cells reconstructed: gradient error, a
Figure 61 · What the end cells do (unlimited linear, default design). Solid squares: the page's scheme; dashed rings: the experimental variant with the end cells reconstructed through ghost values. Blue: the state error; orange: the error of the gradient component aa. The variant's errors are mostly one to two orders of magnitude smaller (at N=8N=8 only 4 and 11 times). The variant's state error is second order from N=16N=16; its error of the gradient component aa is 124124 to 137137 times smaller for N≥128N\ge128; its observed order is not second order on coarse meshes (0.28, 1.03, 1.51 at N=64N=64, 128128, 256256) and from N=256N=256 on equals the page scheme's to within 0.05.

这个变体只用于说明误差的来源。本页其他各节(以及 Python 程序)用的都是不重构端单元的格式,第 13、14 节验证的也是它的导数。

The variant only serves to locate the error. Every other section of this page (and the Python program) uses the scheme without end-cell reconstruction, and Sections 13 and 14 verified its derivatives.

固定 ϵ\epsilon 的光滑限制器在细网格上是一阶的

With a fixed ϵ\epsilon the smooth limiter is first order on fine meshes

光滑限制器的分母里有一个固定的 ϵ=0.01\epsilon=0.01。网格加密时单侧差 li,ri≈h uxl_i,r_i\approx h\,u_x 越来越小,一旦比 ϵ\epsilon 小,就有

The denominator of the smooth limiter contains a fixed ϵ=0.01\epsilon=0.01. Under refinement the one-sided differences li,ri≈h uxl_i,r_i\approx h\,u_x keep shrinking, and once they are smaller than ϵ\epsilon,

∣σi∣=∣li ri (li+ri)∣li2+ri2+ϵ2≤∣li ri (li+ri)∣ϵ2=O(h3).|\sigma_i|=\frac{|l_i\,r_i\,(l_i+r_i)|}{l_i^2+r_i^2+\epsilon^2}\le\frac{|l_i\,r_i\,(l_i+r_i)|}{\epsilon^2}=O(h^3).

斜率修正 σi/2\sigma_i/2 变成 O(h3)O(h^3),迹与一阶格式的迹只差 O(h3)O(h^3),格式的主误差就是一阶格式的 O(h)O(h)。转折发生在 ∣ux∣h≈ϵ|u_x|h\approx\epsilon,即 N≈2πa/ϵ≈126N\approx2\pi a/\epsilon\approx126。图 62 在每个网格的解上量光滑斜率与中心斜率之比(内部单元的中位数):N=8N=8 时 0.63,先升到 N=32N=32 的 0.92,然后一路降到 N=4096N=4096 的 9.4×10−49.4\times10^{-4}。反过来,若 h∣ux∣≫ϵh|u_x|\gg\epsilon,由 σi\sigma_i 的公式(取 li=ril_i=r_i),迹与无限制器线性的迹之差约为 ϵ2/(4h∣ux∣)\epsilon^2/(4h|u_x|);要保持二阶,ϵ\epsilon 不仅要比 hh 缩小得更快,还要满足 ϵ=O(h3/2)\epsilon=O(h^{3/2})。本页不讨论这种做法。

The slope correction σi/2\sigma_i/2 becomes O(h3)O(h^3), the traces differ from the first-order ones by O(h3)O(h^3), and the leading error of the scheme is the O(h)O(h) error of the first-order scheme. The switch happens at ∣ux∣h≈ϵ|u_x|h\approx\epsilon, i.e. N≈2πa/ϵ≈126N\approx2\pi a/\epsilon\approx126. Figure 62 measures the ratio of the smooth slope to the central slope on the solution of every mesh (the median over the interior cells): 0.63 at N=8N=8, it first rises to 0.92 at N=32N=32, then falls all the way to 9.4×10−49.4\times10^{-4} at N=4096N=4096. Conversely, where h∣ux∣≫ϵh|u_x|\gg\epsilon the formula of σi\sigma_i (with li=ril_i=r_i) puts the traces about ϵ2/(4h∣ux∣)\epsilon^2/(4h|u_x|) away from the unlimited linear ones; to stay second order, ϵ\epsilon must not only shrink faster than hh but satisfy ϵ=O(h3/2)\epsilon=O(h^{3/2}). This page does not pursue that.

图 62 · 光滑限制器自动“关掉”重构(默认设计,各网格自己的解)。纵轴:光滑斜率与中心斜率 (l_i+r_i)/2 之比的中位数。竖线 N=2π a/ε 处单侧差与 ε 同量级;更细的网格上这个比值迅速下降(N=256 时为 0.19,512 时为 0.056,从 1024 起低于 0.015),格式退化为一阶。00.250.50.7518321285122048单元数 Nσ光​滑 / σ中​心(中位数)N = 2πa/ϵ ≈ 126光滑限制器的斜率 / 中心斜率
图 62 · 光滑限制器自动“关掉”重构(默认设计,各网格自己的解)。纵轴:光滑斜率与中心斜率 (li+ri)/2(l_i+r_i)/2 之比的中位数。竖线 N=2πa/ϵN=2\pi a/\epsilon 处单侧差与 ϵ\epsilon 同量级;更细的网格上这个比值迅速下降(N=256N=256 时为 0.19,512512 时为 0.056,从 10241024 起低于 0.015),格式退化为一阶。
Figure 62 · The smooth limiter switches the reconstruction off by itself (default design, the solution of each mesh). Vertical axis: the median ratio of the smooth slope to the central slope (l_i+r_i)/2. At the vertical line N=2π a/ε the one-sided differences are of the size of ε; on finer meshes the slope ratio falls quickly (0.19 at N=256, 0.056 at 512, below 0.015 from 1024 on) and the scheme degenerates to first order.00.250.50.7518321285122048cells Nσsmooth​ / σcentral​ (median)N = 2πa/ϵ ≈ 126smooth-limiter slope / central slope
Figure 62 · The smooth limiter switches the reconstruction off by itself (default design, the solution of each mesh). Vertical axis: the median ratio of the smooth slope to the central slope (li+ri)/2(l_i+r_i)/2. At the vertical line N=2πa/ϵN=2\pi a/\epsilon the one-sided differences are of the size of ϵ\epsilon; on finer meshes the slope ratio falls quickly (0.19 at N=256N=256, 0.056 at 512512, below 0.015 from 10241024 on) and the scheme degenerates to first order.

观测阶说明了什么,没有说明什么

What the observed orders show, and what they do not

  • 证实:对状态和梯度 aa 分量而言,无限制器线性的阶趋于 2(Python,N=16384N=16384:1.99、1.99),一阶趋于 1(N=4096N=4096:0.99、0.99);本页模型在 N=32N=32 到 40964096 上重现了这些数据(状态误差相差不超过 8.5×10−128.5\times10^{-12},梯度误差相差不超过 3.9×10−113.9\times10^{-11})。Confirmed: for the state and the gradient component aa, the orders of unlimited linear tend to 2 (Python, N=16384N=16384: 1.99, 1.99) and those of first order to 1 (N=4096N=4096: 0.99, 0.99); this page's model reproduces these data on N=32N=32 to 40964096 (to at most 8.5×10−128.5\times10^{-12} in the state errors and 3.9×10−113.9\times10^{-11} in the gradient errors).
  • 梯度误差不单调。有符号的梯度误差会变号:一阶格式的 φ\varphi 分量在 N=32N=32 与 6464 之间变号;无限制器线性格式的 φ\varphi 分量在 N=8N=8 与 1616 之间变号;无限制器线性格式的 ν\nu 分量在 N=16N=16 与 3232 之间变号;光滑限制器的 φ\varphi 分量在 N=16N=16 与 3232 之间变号;光滑限制器的 ν\nu 分量在 N=16N=16 与 3232、N=128N=128 与 256256 之间变号。变号处误差经过零点,相邻网格的“阶”可以是负数或大于 2,没有意义。The gradient errors are not monotone. The signed gradient errors change sign: the φ\varphi-component of the first-order scheme between N=32N=32 and 6464; the φ\varphi-component of the unlimited linear scheme between N=8N=8 and 1616; the ν\nu-component of the unlimited linear scheme between N=16N=16 and 3232; the φ\varphi-component of the smooth limiter between N=16N=16 and 3232; the ν\nu-component of the smooth limiter between N=16N=16 and 3232, N=128N=128 and 256256. Where they do, the error passes through zero and the "order" of two successive meshes can be negative or larger than 2; it means nothing there.
  • 一阶格式的 ν\nu 分量还没有进入渐近区。N=64N=64 到 40964096 的观测阶依次是 0.69、1.08、1.38、1.59、1.68、1.66、1.56;本页用同一格式继续加密,阶降为 1.42、1.27、1.16、1.09(N=8192N=8192 到 6553665536),趋向 1,到 N=65536N=65536 仍是 1.09。The ν\nu-component of first order is not yet asymptotic. Its observed orders from N=64N=64 to 40964096 are 0.69, 1.08, 1.38, 1.59, 1.68, 1.66, 1.56; continued with the same scheme on this page, they fall to 1.42, 1.27, 1.16, 1.09 (N=8192N=8192 to 6553665536), towards the order 1, and are still 1.09 at N=65536N=65536.
  • 光滑限制器不是二阶格式。ϵ\epsilon 固定时它在细网格上退化为一阶(上一小节)。The smooth limiter is not a second-order scheme. With a fixed ϵ\epsilon it degenerates to first order on fine meshes (previous subsection).
  • 无限制器线性的状态误差在粗网格上表现为一阶,这主要来自两个不重构的端单元;端单元也使梯度误差在 N≥16N\ge16 时大 123 到 275 倍(N=8N=8 时 11 倍),但从 N=256N=256 起不改变它的阶。The state error of unlimited linear looks first order on coarse meshes; comes mainly from the two end cells that are not reconstructed; the end cells also make the gradient error 123 to 275 times larger for N≥16N\ge16 (11 times at N=8N=8), but from N=256N=256 on they do not change its order.

数据的来源

Where the data come from

本节的 Python 数字都读自下列文件;构建页面时检查每个文件记录的实现哈希与当前的 solve.py(SHA-256 0d36ac3febcd7e74…)一致,并且标明 mathematical_proof = false。它们和本页的计算一样是数值证据,不是数学证明。

The Python numbers of this section are read from the files below; when the page is built, the implementation hash recorded in every file is checked against the current solve.py (SHA-256 0d36ac3febcd7e74…), and every file must say mathematical_proof = false. Like this page's own computations, they are numerical evidence, not mathematical proof.

文件File命令Command版本 · 生成时间Version · generated环境Environment文件 SHA-256File SHA-256数学证明Mathematical proof
examples/refinement_first.jsonpython3 solve.py --grids 32,64,128,256,512,1024,2048,4096 --nu .01 --reconstruction first --gradient-check --output examples/refinement_first.json1.0.0 · 2026-10-02T08:35:51ZPython 3.14.3 · NumPy 2.4.6 · SciPy 1.18.1
macOS-26.6.2-arm64-arm-64bit-Mach-O
867fa572cfd79723…否(false)false
examples/refinement_none.jsonpython3 solve.py --grids 32,64,128,256,512,1024,2048,4096,8192,16384 --nu .01 --reconstruction none --gradient-check --continuous-adjoint --output examples/refinement_none.json1.0.0 · 2026-10-02T08:35:50ZPython 3.14.3 · NumPy 2.4.6 · SciPy 1.18.1
macOS-26.6.2-arm64-arm-64bit-Mach-O
1bfc1b10868196bf…否(false)false
examples/large_65536.jsonpython3 solve.py --cells 65536 --nu .01 --reconstruction none --gradient-check --output examples/large_65536.json1.0.0 · 2026-10-02T08:35:53ZPython 3.14.3 · NumPy 2.4.6 · SciPy 1.18.1
macOS-26.6.2-arm64-arm-64bit-Mach-O
1241daca39fb2433…否(false)false

本节的结论都是在一个设计(a=0.2a=0.2,φ=0.07\varphi=0.07,ν=0.01\nu=0.01;Péclet 研究另有五个 ν\nu)上的数值观察。本页没有证明一般的收敛定理,也不声称这些阶对别的设计、别的源项或 ν→0\nu\to0 成立。

The conclusions of this section are numerical observations at one design (a=0.2a=0.2, φ=0.07\varphi=0.07, ν=0.01\nu=0.01; five more values of ν\nu in the Péclet study). The page proves no general convergence theorem and does not claim these orders for other designs, other sources, or ν→0\nu\to0.

第 16 节Section 16

伴随一致性:离散伴随会趋于连续伴随吗?

Adjoint consistency: does the discrete adjoint approach the continuous one?

本节实验:先估计一下,N=8N=8 时第一个单元里的 ψ0\psi_0 离 λ(x0)\lambda(x_0) 大约有多远?要多少个单元,ψ0/(h/2)\psi_0/(h/2) 与 λx(0)=−142.7\lambda_x(0)=−142.7 的相对差才不到 10%——一百个左右,还是一千个左右?然后用本节的加密播放器验证。

Experiment: Estimate first how far ψ0\psi_0 is from λ(x0)\lambda(x_0) in the first cell at N=8N=8, and how many cells ψ0/(h/2)\psi_0/(h/2) needs to come within 10% of λx(0)=−142.7\lambda_x(0)=−142.7, about a hundred or about a thousand. Then check with the refinement player of this section.

第 11 节解出了伴随 ψ\psi(ATψ=−gA^T\psi=-g),第 12 节用它给出离散目标 Jh(D)J_h(D) 的梯度 Dˉ=RDTψ\bar D=R_D^T\psi(精确到舍入误差)。附录 A 则从微分方程出发,推出连续伴随 λ\lambda 和连续梯度公式。两者回答不同的问题:ψ\psi 是有限网格上那段程序的导数,λ\lambda 是连续问题的导数。本节把它们放在一起比较:随网格加密,ψi\psi_i 是否趋于 λ(xi)\lambda(x_i)?离散梯度(包括边界项)是否趋于连续梯度?粗网格上的差别从哪里来?

Section 11 solved for the adjoint ψ\psi (ATψ=−gA^T\psi=-g) and Section 12 used it for the gradient Dˉ=RDTψ\bar D=R_D^T\psi of the discrete objective Jh(D)J_h(D), exact up to rounding. Appendix A starts from the differential equation and derives the continuous adjoint λ\lambda and the continuous gradient formula. The two answer different questions: ψ\psi is a derivative of the program on a finite mesh, λ\lambda a derivative of the continuous problem. This section puts them side by side: does ψi\psi_i approach λ(xi)\lambda(x_i) as the mesh is refined? Does the discrete gradient, boundary term included, approach the continuous one? Where do the differences on coarse meshes come from?

连续伴随与连续梯度

The continuous adjoint and the continuous gradient

连续伴随(附录 A 用变分逐步推出)是一个线性两点边值问题。连续梯度有两部分:源项积分和边界项。这里 u=u∗u=u^*,∂Dku∗\partial_{D_k}u^* 在 x=0x=0、x=1x=1 处就是边界值 uinu_{\rm in}、uoutu_{\rm out} 的导数:

The continuous adjoint (derived step by step with variations in Appendix A) solves a linear two-point boundary-value problem. The continuous gradient has two parts, a source integral and a boundary term. Here u=u∗u=u^*, and ∂Dku∗\partial_{D_k}u^* at x=0x=0 and x=1x=1 is the derivative of the boundary values uinu_{\rm in}, uoutu_{\rm out}:

−u λx−ν λxx=−(1+x),λ(0)=λ(1)=0;dJdDk=−∫01λ ∂Dks dx+ν[λx ∂Dku∗]01(k=0,1).-u\,\lambda_x-\nu\,\lambda_{xx}=-(1+x),\quad \lambda(0)=\lambda(1)=0;\qquad \frac{\mathrm dJ}{\mathrm dD_k}=-\int_0^1\lambda\,\partial_{D_k}s\,\mathrm dx+\nu\Bigl[\lambda_x\,\partial_{D_k}u^*\Bigr]_0^1\quad(k=0,1).

对 D2=νD_2=\nu,通量本身含 ν\nu,公式变为 −∫01λ (∂νs+uxx∗) dx-\int_0^1\lambda\,(\partial_\nu s+u^*_{xx})\,\mathrm dx;对这一族构造解它等于零。伴随方程的对流项 −uλx-u\lambda_x 与原方程符号相反:λ\lambda 从 x=1x=1 向 x=0x=0 传播,所以 λ(0)=0\lambda(0)=0 要靠 x=0x=0 处宽约 ν/uin=0.0109\nu/u_{\rm in}=0.0109 的边界层来满足。默认设计下(201 个点的 Chebyshev 配点),λx(0)=−142.657\lambda_x(0)=−142.657,λx(1)=2.2035\lambda_x(1)=2.2035;源项积分为 (0.4728, 1.7323)(0.4728,\ 1.7323),边界项为 (−0.6168, −1.6471)(−0.6168,\ −1.6471),两者之和与精确梯度 (−0.1440, 0.0852)(−0.1440,\ 0.0852) 相差 10−1310^{-13} 量级(本页和 Python 审计都核对过)。注意两部分都是 O(1)O(1),梯度却小得多:它是两个大数之差。

For D2=νD_2=\nu the flux itself contains ν\nu and the formula becomes −∫01λ (∂νs+uxx∗) dx-\int_0^1\lambda\,(\partial_\nu s+u^*_{xx})\,\mathrm dx, which is zero for this family. The convection term −uλx-u\lambda_x of the adjoint equation has the opposite sign of the primal one: λ\lambda travels from x=1x=1 towards x=0x=0, so λ(0)=0\lambda(0)=0 is met by a boundary layer at x=0x=0 of width about ν/uin=0.0109\nu/u_{\rm in}=0.0109. At the defaults (Chebyshev collocation on 201 points) λx(0)=−142.657\lambda_x(0)=−142.657 and λx(1)=2.2035\lambda_x(1)=2.2035; the source integral is (0.4728, 1.7323)(0.4728,\ 1.7323), the boundary term (−0.6168, −1.6471)(−0.6168,\ −1.6471), and their sum differs from the exact gradient (−0.1440, 0.0852)(−0.1440,\ 0.0852) by about 10−1310^{-13} (checked by this page and by the Python audit). Note that both parts are O(1)O(1) while the gradient is much smaller: it is the difference of two large numbers.

“一致”在这里指什么,哪些只是证据

What “consistent” means here, and what is only evidence

本节说离散伴随与连续伴随一致,指的是固定设计、加密网格时测到三件事:(1) 逐点误差 max⁡i∣ψi−λ(xi)∣\max_i|\psi_i-\lambda(x_i)| 和单元 L1 范数 h∑i∣ψi−λ(xi)∣h\sum_i|\psi_i-\lambda(x_i)| 趋于零;(2) 离散梯度 RDTψR_D^T\psi 趋于连续梯度;(3) 离散梯度的源项部分和边界部分分别趋于源项积分和边界项。本节的测量用模型算到 N=4096N=4096,用 Python 数据算到 N=16384N=16384。这只是本问题上的数值证据,不是定理:本页不给出一般数据下的收敛定理。

In this section the discrete adjoint is called consistent with the continuous one when three things are measured at a fixed design under mesh refinement: (1) the pointwise error max⁡i∣ψi−λ(xi)∣\max_i|\psi_i-\lambda(x_i)| and the cell L1 norm h∑i∣ψi−λ(xi)∣h\sum_i|\psi_i-\lambda(x_i)| tend to zero; (2) the discrete gradient RDTψR_D^T\psi tends to the continuous gradient; (3) its source part and its boundary part tend to the source integral and the boundary term separately. The measurements go to N=4096N=4096 with the model and to N=16384N=16384 with the Python data. This is numerical evidence for this one problem, not a theorem: the page gives no convergence theorem for general data.

为什么可以直接拿 ψi\psi_i 和 λ(xi)\lambda(x_i) 比——同号,也不差一个网格宽度的因子?比较两个拉格朗日函数:

Why can ψi\psi_i be compared with λ(xi)\lambda(x_i) directly, with the same sign and without a factor of the mesh width? Compare the two Lagrangians:

ℒh=Jh(𝐔)+ψTR(𝐔,D)=∑iwiUi+∑iψi[Hi+1−Hi−(Qi+1−Qi)],ℒ=J(u)+∫01λ (qx−s) dx.\mathcal L_h=J_h(\mathbf U)+\psi^TR(\mathbf U,D)=\sum_iw_iU_i+\sum_i\psi_i\bigl[H_{i+1}-H_i-(Q_{i+1}-Q_i)\bigr],\qquad \mathcal L=J(u)+\int_0^1\lambda\,(q_x-s)\,\mathrm dx.

RiR_i 是积分形式的残差:Ri≈∫xi−h/2xi+h/2(qx−s) dxR_i\approx\int_{x_i-h/2}^{x_i+h/2}(q_x-s)\,\mathrm dx;同样 wiUi≈∫xi−h/2xi+h/2(1+x) u dxw_iU_i\approx\int_{x_i-h/2}^{x_i+h/2}(1+x)\,u\,\mathrm dx。所以当 ψi≈λ(xi)\psi_i\approx\lambda(x_i) 时 ψTR≈∫λ (qx−s) dx\psi^TR\approx\int\lambda\,(q_x-s)\,\mathrm dx:同号,没有因子 hh。伴随方程也对得上:(ATψ)i≈h (−uλx−νλxx)(xi)(A^T\psi)_i\approx h\,(-u\lambda_x-\nu\lambda_{xx})(x_i),右端项 −gi=−h(1+xi)-g_i=-h(1+x_i)。如果残差除以单元宽度(“密度”形式),乘子就会变成 hλh\lambda;比较之前要先确认这种约定。

RiR_i is an integrated residual, Ri≈∫xi−h/2xi+h/2(qx−s) dxR_i\approx\int_{x_i-h/2}^{x_i+h/2}(q_x-s)\,\mathrm dx, and likewise wiUi≈∫xi−h/2xi+h/2(1+x) u dxw_iU_i\approx\int_{x_i-h/2}^{x_i+h/2}(1+x)\,u\,\mathrm dx. So ψTR≈∫λ (qx−s) dx\psi^TR\approx\int\lambda\,(q_x-s)\,\mathrm dx when ψi≈λ(xi)\psi_i\approx\lambda(x_i): the same sign and no factor hh. The adjoint equations match too: (ATψ)i≈h (−uλx−νλxx)(xi)(A^T\psi)_i\approx h\,(-u\lambda_x-\nu\lambda_{xx})(x_i) and the right-hand side is −gi=−h(1+xi)-g_i=-h(1+x_i). Had the residual been divided by the cell width (a density), the multiplier would be hλh\lambda; check this convention before comparing.

图 63 · 离散伴随 ψ_i(无限制器线性重构,N=8、32、128)与连续伴随 λ(x)(默认设计)。(a) 远离入口处,点落在曲线上;(b) 入口附近:λ 在宽约 ν/u_in 的层里从 0 降到 λ_out(0),N=8 时第一个单元的中心 x_0=h/2 远在层外;(c) 误差 ψ_i-λ(x_i):在默认设计下,最大值总在头两个单元里,N=8 时为 0.554,N=128 时仍有 0.194。λ(x)ψi​,N = 8ψi​,N = 32ψi​,N = 128−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81x伴随(a) 整个区间−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.010.020.030.040.050.06x(b) 入口附近 x < 0.06ν/uin​−0.100.10.20.30.40.50.600.20.40.60.81xψi​ − λ(xi​)(c) 误差:最大值在头两个单元(伴随的入口层所在处)
图 63 · 离散伴随 ψi\psi_i(无限制器线性重构,N=8N=8、32、128)与连续伴随 λ(x)\lambda(x)(默认设计)。(a) 远离入口处,点落在曲线上;(b) 入口附近:λ\lambda 在宽约 ν/uin\nu/u_{\rm in} 的层里从 0 降到 λout(0)\lambda_{\rm out}(0),N=8N=8 时第一个单元的中心 x0=h/2x_0=h/2 远在层外;(c) 误差 ψi−λ(xi)\psi_i-\lambda(x_i):在默认设计下,最大值总在头两个单元里,N=8N=8 时为 0.554,N=128N=128 时仍有 0.194。
Figure 63 · The discrete adjoint ψ_i (unlimited linear reconstruction, N=8, 32, 128) and the continuous adjoint λ(x) (default design). (a) Away from the inlet the points lie on the curve; (b) near the inlet λ drops from 0 to λ_out(0) inside a layer of width about ν/u_in, and at N=8 the centre x_0=h/2 of the first cell is far outside it; (c) the error ψ_i-λ(x_i): at the default design its maximum is always in one of the first two cells, 0.554 at N=8 and still 0.194 at N=128.λ(x)ψi​, N = 8ψi​, N = 32ψi​, N = 128−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xadjoint(a) the whole interval−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.010.020.030.040.050.06x(b) near the inlet, x < 0.06ν/uin​−0.100.10.20.30.40.50.600.20.40.60.81xψi​ − λ(xi​)(c) the error: its maximum is in one of the first two cells, where the adjoint's inlet layer lies
Figure 63 · The discrete adjoint ψi\psi_i (unlimited linear reconstruction, N=8N=8, 32, 128) and the continuous adjoint λ(x)\lambda(x) (default design). (a) Away from the inlet the points lie on the curve; (b) near the inlet λ\lambda drops from 0 to λout(0)\lambda_{\rm out}(0) inside a layer of width about ν/uin\nu/u_{\rm in}, and at N=8N=8 the centre x0=h/2x_0=h/2 of the first cell is far outside it; (c) the error ψi−λ(xi)\psi_i-\lambda(x_i): at the default design its maximum is always in one of the first two cells, 0.554 at N=8N=8 and still 0.194 at N=128N=128.

读图:N=8N=8 时 ψ0=−0.9243\psi_0=−0.9243,而 λ(x0)=−1.4786\lambda(x_0)=−1.4786。单元宽 h=0.125h=0.125 是伴随层宽的 11.4 倍,第一个单元根本“看不见” λ\lambda 的这个层。远离入口处误差小得多:x>0.1x>0.1 时只有 0.119,不到最大值的 1/4。在下面的面板里换 NN、重构和设计,看误差的位置和大小怎样变:

Reading the figure: at N=8N=8, ψ0=−0.9243\psi_0=−0.9243 while λ(x0)=−1.4786\lambda(x_0)=−1.4786. The cell width h=0.125h=0.125 is 11.4 times the width of the adjoint's layer; the first cell simply does not see the layer of λ\lambda. Away from the inlet the error is much smaller: 0.119 for x>0.1x>0.1, less than 1/4 of the maximum. Change NN, the reconstruction and the design in the panel below and watch where the error sits and how large it is:

加密:误差与收敛阶

Refinement: the errors and their orders

表中是 ψi−λ(xi)\psi_i-\lambda(x_i) 的单元 L1 范数和最大值(模型算到 N=4096N=4096;最后一列是 Python 数据 adjoint_l1_reference_error,它的 λ\lambda 由 SciPy 的 solve_bvp 独立求得,在共同网格上与本页至少有 4 位有效数字相同)。“阶”是相邻两层的观测阶 log⁡2(eN/2/eN)\log_2(e_{N/2}/e_N)。

The table lists the cell L1 norm and the maximum of ψi−λ(xi)\psi_i-\lambda(x_i) (the model up to N=4096N=4096; the last column is the Python field adjoint_l1_reference_error, whose λ\lambda comes independently from SciPy's solve_bvp and shares at least 4 significant digits with this page on the common meshes). “Order” is the observed order log⁡2(eN/2/eN)\log_2(e_{N/2}/e_N) between neighbouring levels.

N一阶 L1first L1阶order一阶最大值first max无限制器 L1none L1阶order无限制器最大值none maxPython L1(无限制器)Python L1 (none)
81.36e−15.53e−11.25e−15.54e−1—
169.21e−20.575.86e−17.05e−20.836.10e−1—
325.34e−20.794.69e−13.37e−21.074.85e−13.37e−2
642.89e−20.883.72e−11.41e−21.262.94e−11.41e−2
1281.52e−20.932.57e−15.40e−31.381.94e−15.40e−3
2567.86e−30.951.65e−11.82e−31.578.56e−21.82e−3
5124.01e−30.979.36e−25.47e−41.742.92e−25.47e−4
10242.03e−30.985.03e−21.51e−41.858.60e−31.51e−4
20481.02e−30.992.61e−23.99e−51.922.34e−33.99e−5
40965.11e−41.001.33e−21.03e−51.966.10e−41.03e−5
8192————2.60e−6
16384————6.54e−7
图 64 · ψ_i-λ(x_i) 随网格加密(默认设计)。实线 L1、虚线最大值;圆圈是 Python 数据(无限制器,到 N=16384)。紫色竖线是 h=ν/u_in:竖线左侧的网格分辨不出伴随的这个层。最细两层之间的阶:无限制器 L1 1.96、最大值 1.94,Python 数据 1.99;一阶 1.00 与 0.97。一阶最大值一阶 L1无限制器最大值无限制器 L1Python 数据 L110-7​10-6​10-5​10-4​10-3​10-2​10-1​110102​103​104​单元数 N|ψi​ − λ(xi​)| 的范数h = ν/uin​hh2​
图 64 · ψi−λ(xi)\psi_i-\lambda(x_i) 随网格加密(默认设计)。实线 L1、虚线最大值;圆圈是 Python 数据(无限制器,到 N=16384N=16384)。紫色竖线是 h=ν/uinh=\nu/u_{\rm in}:竖线左侧的网格分辨不出伴随的这个层。最细两层之间的阶:无限制器 L1 1.96、最大值 1.94,Python 数据 1.99;一阶 1.00 与 0.97。
Figure 64 · ψ_i-λ(x_i) under mesh refinement (default design). Solid: L1, dashed: maximum; rings: the Python data (unlimited linear, to N=16384). The violet line marks h=ν/u_in: the meshes to its left do not resolve the adjoint's layer. Orders between the two finest levels: unlimited linear L1 1.96, maximum 1.94, Python data 1.99; first order 1.00 and 0.97.first maxfirst L1none maxnone L1Python data L110-7​10-6​10-5​10-4​10-3​10-2​10-1​110102​103​104​cells Nnorm of ψi​ − λ(xi​)h = ν/uin​hh2​
Figure 64 · ψi−λ(xi)\psi_i-\lambda(x_i) under mesh refinement (default design). Solid: L1, dashed: maximum; rings: the Python data (unlimited linear, to N=16384N=16384). The violet line marks h=ν/uinh=\nu/u_{\rm in}: the meshes to its left do not resolve the adjoint's layer. Orders between the two finest levels: unlimited linear L1 1.96, maximum 1.94, Python data 1.99; first order 1.00 and 0.97.

结论(测量):两种格式的离散伴随都收敛到连续伴随,无限制器线性二阶、一阶格式一阶,最大误差和 L1 误差同阶。粗网格上情形不同:无限制器线性格式的最大误差在默认设计下停在头两个单元里,N=8N=8 时 0.554,N=16N=16 时反而升到 0.610,N=64N=64 时仍有 0.294。这些网格都分辨不出伴随在入口处的层(N<uin/ν≈91N<u_{\rm in}/\nu\approx91),但误差主要并非来自伴随的入口层,下一小节的实验说明了这一点。

Conclusion (measured): for both schemes the discrete adjoint converges to the continuous one, at second order for unlimited linear reconstruction and at first order for the first-order scheme, with the same order in the maximum and the L1 norm. Coarse meshes are different: at the default design the maximum error of the unlimited linear scheme stays in the first two cells, 0.554 at N=8N=8, even rising to 0.610 at N=16N=16, and still 0.294 at N=64N=64. None of these meshes resolves the adjoint's layer at the inlet (N<uin/ν≈91N<u_{\rm in}/\nu\approx91), but the error does not come mainly from the layer: the experiment of the next subsection shows it.

粗网格上的误差从哪里来:两个端单元

Where the coarse-mesh error comes from: the two end cells

第 3 节规定 σ0=σN−1=0\sigma_0=\sigma_{N-1}=0:两端的单元不重构。第 15 节用一个实验测过它们对状态误差的影响:用虚单元值 U−1=2uin−U0U_{-1}=2u_{\rm in}-U_0、UN=2uout−UN−1U_N=2u_{\rm out}-U_{N-1} 按内部公式给两个端单元一个斜率,其他一切不变(这只是实验,不是本页的格式)。这里用同一段代码(第 15 节的变体,Jacobian 由复数步长得到)看伴随和梯度。网格分辨伴随层的能力完全没变,伴随的最大误差和 aa 分量的梯度误差却大幅下降:

Section 3 sets σ0=σN−1=0\sigma_0=\sigma_{N-1}=0: the two end cells are not reconstructed. Section 15 measured what this does to the state error with an experiment: give the two end cells a slope by the interior formula with the ghost values U−1=2uin−U0U_{-1}=2u_{\rm in}-U_0 and UN=2uout−UN−1U_N=2u_{\rm out}-U_{N-1}, with everything else unchanged (an experiment only, not the page's scheme). Here the same code (the variant of Section 15, whose Jacobians come from the complex step) is used for the adjoint and the gradient. The mesh resolves the adjoint's layer no better than before, yet the largest adjoint error and the aa-gradient error drop sharply:

Nmax⁡∣ψ−λ∣\max|\psi-\lambda|(本页)max⁡∣ψ−λ∣\max|\psi-\lambda| (page)max⁡∣ψ−λ∣\max|\psi-\lambda|(端单元重构)max⁡∣ψ−λ∣\max|\psi-\lambda| (end cells reconstructed)dJh/da\mathrm dJ_h/\mathrm da 的误差(本页)aa-gradient error (page)dJh/da\mathrm dJ_h/\mathrm da 的误差(端单元重构)aa-gradient error (end cells reconstructed)
80.5540.238−3.43e−1−3.03e−2
160.6100.261−2.07e−1−1.68e−3
320.4850.182−1.07e−1−3.90e−4
640.2940.049−4.94e−2−3.22e−4

重构端单元后,伴随的层同样没被分辨,aa 分量的梯度误差却从 N=8N=8 时的 0.343 降到 0.030,N=32N=32 时从 0.107 降到 3.9×10−43.9\times10^{-4};max⁡i∣ψi−λ(xi)∣\max_i|\psi_i-\lambda(x_i)| 在 N=8N=8 时从 0.554 降到 0.238,N=64N=64 时从 0.294 降到 0.049。N=8N=8 时 ψ0\psi_0 变为 −1.313,接近 λ\lambda 在第一个单元上的平均 −1.351,而斜率比 ψ0/(h/2)÷λx(0)\psi_0/(h/2)\div\lambda_x(0) 仍只有 0.147。所以粗网格上,无限制器线性重构的伴随最大误差 max⁡i∣ψi−λ(xi)∣\max_i|\psi_i-\lambda(x_i)| 和 aa 分量的梯度误差主要来自两个只有一阶精度的端单元,而不是伴随的层没被分辨本身。光滑限制器的情形相近:N≤64N\le64 时重构端单元后,aa 分量的梯度误差降到原来的 1/5.6 至 1/28,伴随最大误差降到原来的 1/1.9 至 1/7.2。对无限制器线性重构,ψ−λ\psi-\lambda 的 L1 误差并非如此:N=8N=8 时重构端单元后反而略大(0.141,本页格式为 0.125);φ\varphi 与 ν\nu 分量的梯度误差在 N=8N=8 时也只分别降为 1/2.2 与 1/1.4(光滑限制器的 ν\nu 分量梯度误差甚至从 0.291 增大到 0.412)。

With the end cells reconstructed the adjoint's layer is just as unresolved, but the aa-gradient error drops from 0.343 to 0.030 at N=8N=8 and from 0.107 to 3.9×10−43.9\times10^{-4} at N=32N=32; max⁡i∣ψi−λ(xi)∣\max_i|\psi_i-\lambda(x_i)| drops from 0.554 to 0.238 at N=8N=8 and from 0.294 to 0.049 at N=64N=64. At N=8N=8, ψ0\psi_0 becomes −1.313, close to the mean of λ\lambda over the first cell, −1.351, while the slope ratio ψ0/(h/2)÷λx(0)\psi_0/(h/2)\div\lambda_x(0) is still only 0.147. So on coarse meshes the largest adjoint error, max⁡i∣ψi−λ(xi)∣\max_i|\psi_i-\lambda(x_i)|, and the aa-gradient error of unlimited linear reconstruction come mainly from the two end cells, which are only first-order accurate, not from the adjoint's unresolved layer itself. The smooth limiter behaves similarly: for N≤64N\le64 reconstructing its end cells makes the aa-gradient error 5.6 to 28 times and the largest adjoint error 1.9 to 7.2 times smaller. For unlimited linear reconstruction the L1 error of ψ−λ\psi-\lambda does not: at N=8N=8 it is even slightly larger with the end cells reconstructed (0.141 against 0.125), and the φ\varphi- and ν\nu-gradient errors fall only by factors of 2.2 and 1.4 at N=8N=8 (with the smooth limiter the ν\nu-gradient error even grows, from 0.291 to 0.412).

图 65 · 端单元实验(无限制器线性,默认设计)。(a) N=8 时入口附近的 ψ_i:本页格式(圆圈)与端单元经虚单元值重构后(实心点);虚线是 λ 在第一个单元上的平均 −1.351。(b) 两种格式的 max|ψ-λ|(实线)和 a 分量的梯度误差(虚线):紫线左侧的网格(N ≤ 64)都分辨不出伴随的层;重构端单元后,max|ψ-λ| 仍降到本页格式的 1/2.3 至 1/6.0,a 分量的梯度误差降到 1/11 至 1/275。λ(x)本页格式(端单元不重构)第 15 节的实验(端单元经虚单元值重构)−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.30.40.5x伴随(a) N = 8,入口附近10-5​10-4​10-3​10-2​10-1​110100N误差h = ν/uin​(b) 实线 max|ψ − λ|,虚线 |dJh​/da − dJ/da|
图 65 · 端单元实验(无限制器线性,默认设计)。(a) N=8N=8 时入口附近的 ψi\psi_i:本页格式(圆圈)与端单元经虚单元值重构后(实心点);虚线是 λ\lambda 在第一个单元上的平均 −1.351。(b) 两种格式的 max⁡∣ψ−λ∣\max|\psi-\lambda|(实线)和 aa 分量的梯度误差(虚线):紫线左侧的网格(N≤64N\le64)都分辨不出伴随的层;重构端单元后,max⁡∣ψ−λ∣\max|\psi-\lambda| 仍降到本页格式的 1/2.3 至 1/6.0,aa 分量的梯度误差降到 1/11 至 1/275。
Figure 65 · The end-cell experiment (unlimited linear, default design). (a) ψ_i near the inlet at N=8: the page's scheme (rings) and the end cells reconstructed through ghost values (dots); dashed: the mean of λ over the first cell, −1.351. (b) max|ψ-λ| (solid) and the a-gradient error (dashed) of the two schemes: no mesh left of the violet line (N ≤ 64) resolves the adjoint's layer, yet reconstructing the end cells makes max|ψ-λ| 2.3 to 6.0 times smaller and the a-gradient error 11 to 275 times smaller.λ(x)the page (end cells not reconstructed)the experiment of Section 15 (end cells reconstructed)−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.30.40.5xadjoint(a) N = 8, near the inlet10-5​10-4​10-3​10-2​10-1​110100Nerrorh = ν/uin​(b) solid max|ψ − λ|, dashed |dJh​/da − dJ/da|
Figure 65 · The end-cell experiment (unlimited linear, default design). (a) ψi\psi_i near the inlet at N=8N=8: the page's scheme (rings) and the end cells reconstructed through ghost values (dots); dashed: the mean of λ\lambda over the first cell, −1.351. (b) max⁡∣ψ−λ∣\max|\psi-\lambda| (solid) and the aa-gradient error (dashed) of the two schemes: no mesh left of the violet line (N≤64N\le64) resolves the adjoint's layer, yet reconstructing the end cells makes max⁡∣ψ−λ∣\max|\psi-\lambda| 2.3 to 6.0 times smaller and the aa-gradient error 11 to 275 times smaller.

播放器逐层演示加密过程,可以在本页格式、端单元重构的实验和本节最后要讲的错误版本之间切换:

The player shows the refinement level by level; it switches between the page's scheme, the end-cell experiment and the wrong version of the last part of this section:

一阶格式就是黏性为 ν + h 的中心格式

First order is the central scheme with viscosity ν + h

为什么一阶离散伴随的层那么宽?看一阶格式(σi=0\sigma_i=0,qL=Uf−1q_L=U_{f-1},qR=Ufq_R=U_f)的一个内部单元 jj(1≤j≤N−21\le j\le N-2)。它的两个面都是内部面(df=hd_f=h),代入第 3 节的通量:

Why is the layer of the first-order discrete adjoint so wide? Take the first-order scheme (σi=0\sigma_i=0, qL=Uf−1q_L=U_{f-1}, qR=Ufq_R=U_f) and an interior cell jj (1≤j≤N−21\le j\le N-2). Both of its faces are interior faces (df=hd_f=h); insert the flux of Section 3:

Hj+1−Hj=14(Uj2+Uj+12)−(Uj+1−Uj)−νh(Uj+1−Uj)−14(Uj−12+Uj2)+(Uj−Uj−1)+νh(Uj−Uj−1).H_{j+1}-H_j=\tfrac14\bigl(U_j^2+U_{j+1}^2\bigr)-(U_{j+1}-U_j)-\tfrac{\nu}{h}(U_{j+1}-U_j)-\tfrac14\bigl(U_{j-1}^2+U_j^2\bigr)+(U_j-U_{j-1})+\tfrac{\nu}{h}(U_j-U_{j-1}).

Uj2U_j^2 抵消,两个跳跃合成一个二阶差分,耗散与黏性合并:

The Uj2U_j^2 terms cancel, the two jumps combine into one second difference, and the dissipation joins the viscosity:

Rj=Uj+12−Uj−124−(1+νh)(Uj+1−2Uj+Uj−1)−(Qj+1−Qj)=h[12Uj+12−12Uj−122h−(ν+h) Uj+1−2Uj+Uj−1h2]−(Qj+1−Qj).R_j=\frac{U_{j+1}^2-U_{j-1}^2}{4}-\Bigl(1+\frac{\nu}{h}\Bigr)\bigl(U_{j+1}-2U_j+U_{j-1}\bigr)-(Q_{j+1}-Q_j)=h\Bigl[\frac{\tfrac12U_{j+1}^2-\tfrac12U_{j-1}^2}{2h}-(\nu+h)\,\frac{U_{j+1}-2U_j+U_{j-1}}{h^2}\Bigr]-(Q_{j+1}-Q_j).

方括号正是 u ux−(ν+h) uxxu\,u_x-(\nu+h)\,u_{xx} 的中心差分:Rusanov 耗散系数 α/2=1\alpha/2=1 相当于额外黏性 hh(即 αh/2\alpha h/2)。再看转置:AA 的第 jj 列只有三个非零元,

The bracket is exactly the central difference of u ux−(ν+h) uxxu\,u_x-(\nu+h)\,u_{xx}: the Rusanov dissipation coefficient α/2=1\alpha/2=1 acts as an added viscosity hh (that is αh/2\alpha h/2). Now transpose: column jj of AA has three nonzero entries,

Aj−1,j=Uj2−(1+νh),Ajj=2(1+νh),Aj+1,j=−Uj2−(1+νh),A_{j-1,j}=\frac{U_j}{2}-\Bigl(1+\frac\nu h\Bigr),\qquad A_{jj}=2\Bigl(1+\frac\nu h\Bigr),\qquad A_{j+1,j}=-\frac{U_j}{2}-\Bigl(1+\frac\nu h\Bigr),

所以伴随方程的第 jj 行是

so row jj of the adjoint equation reads

(ATψ)j=−Uj ψj+1−ψj−12−(1+νh)(ψj+1−2ψj+ψj−1)=h[−Uj ψj+1−ψj−12h−(ν+h) ψj+1−2ψj+ψj−1h2]=−h (1+xj).(A^T\psi)_j=-U_j\,\frac{\psi_{j+1}-\psi_{j-1}}{2}-\Bigl(1+\frac\nu h\Bigr)\bigl(\psi_{j+1}-2\psi_j+\psi_{j-1}\bigr)=h\Bigl[-U_j\,\frac{\psi_{j+1}-\psi_{j-1}}{2h}-(\nu+h)\,\frac{\psi_{j+1}-2\psi_j+\psi_{j-1}}{h^2}\Bigr]=-h\,(1+x_j).

除以 hh:一阶离散伴随的内部各行,正是黏性为 ν+h\nu+h 的连续伴随 −uλx−(ν+h)λxx=−(1+x)-u\lambda_x-(\nu+h)\lambda_{xx}=-(1+x) 的中心格式(对流系数取离散状态 UjU_j)。这是恒等式,不是近似:Python 审计用 sympy 符号化简验证,本页在收敛解上逐行核对,差在 1.3×10−151.3\times10^{-15} 以内。所以一阶离散伴随的层宽约 (ν+h)/uin(\nu+h)/u_{\rm in} 而不是 ν/uin\nu/u_{\rm in}:N=8N=8 时前者是后者的 13.5 倍。两个端行含边界面(距离 h/2h/2),不属于这个形式。

Divide by hh: the interior rows of the first-order discrete adjoint are the central scheme for the continuous adjoint with viscosity ν+h\nu+h, −uλx−(ν+h)λxx=−(1+x)-u\lambda_x-(\nu+h)\lambda_{xx}=-(1+x) (with the discrete state UjU_j as the convection coefficient). This is an identity, not an approximation: the Python audit proves it with sympy, and this page checks it row by row on the converged states, to within 1.3×10−151.3\times10^{-15}. The layer of the first-order discrete adjoint is therefore about (ν+h)/uin(\nu+h)/u_{\rm in} wide instead of ν/uin\nu/u_{\rm in}: 13.5 times wider at N=8N=8. The two end rows contain the boundary faces (distance h/2h/2) and are not of this form.

二阶格式在内部没有这一项。无限制器线性重构 σi=(li+ri)/2\sigma_i=(l_i+r_i)/2 时,面 2≤f≤N−22\le f\le N-2 的迹之差是一个三阶差分,行 2≤j≤N−32\le j\le N-3 的耗散是一个四阶差分:

In the interior the second-order scheme has no such term. With unlimited linear reconstruction, σi=(li+ri)/2\sigma_i=(l_i+r_i)/2, the jump of the traces of a face 2≤f≤N−22\le f\le N-2 is a third difference, and the dissipation of a row 2≤j≤N−32\le j\le N-3 is a fourth difference:

qR−qL=−14(Uf+1−3Uf+3Uf−1−Uf−2),−(qR−qL)j+1+(qR−qL)j=14(Uj+2−4Uj+1+6Uj−4Uj−1+Uj−2)=h44 uxxxx+O(h6).q_R-q_L=-\tfrac14\bigl(U_{f+1}-3U_f+3U_{f-1}-U_{f-2}\bigr),\qquad -(q_R-q_L)_{j+1}+(q_R-q_L)_j=\tfrac14\bigl(U_{j+2}-4U_{j+1}+6U_j-4U_{j-1}+U_{j-2}\bigr)=\frac{h^4}{4}\,u_{xxxx}+O(h^6).

这是超黏性:单位长度上为 h34uxxxx\tfrac{h^3}{4}u_{xxxx},没有二阶导数型的人工黏性(sympy 证明;本页在随机状态上核对,差在 2.3×10−162.3\times10^{-16} 以内)。但这两个恒等式只在上述范围内成立。两端的单元不重构(σ0=σN−1=0\sigma_0=\sigma_{N-1}=0),所以面 0,10,1 与 N−1,NN-1,N 的迹只有一阶精度:用精确单元平均代入(N=4096N=4096),(qR−qL)/(h ux∗)(q_R-q_L)/(h\,u^*_x) 在面 0、1、N−1N-1、NN 上分别为 0.5001、0.4998、0.5002、0.4999,在面 2 上只有 5.9×10−75.9\times10^{-7}。也就是 qR−qL≈h2uxq_R-q_L\approx\tfrac h2u_x:无限制器线性重构里这四个面都带额外黏性 h/2h/2;一阶格式里只有面 00 和面 NN 如此,面 11 与 N−1N-1 和每个内部面一样带 hh(N=4096N=4096 时面 1 上的比值为 1.0000);光滑限制器在 h∣ux∣≫ϵh|u_x|\gg\epsilon 时接近无限制器线性,h∣ux∣≪ϵh|u_x|\ll\epsilon 后面 11 与 N−1N-1 也带 hh(N=4096N=4096 时比值为 0.9992)。耗散矩阵仍是对称的(数值上反对称部分为 0.0),但两个端行是 (74, −1, 14)(\tfrac{7}{4},\ -1,\ \tfrac{1}{4}) 和 (−1, 74, −1, 14)(-1,\ \tfrac{7}{4},\ -1,\ \tfrac{1}{4}),不是四阶差分。所以在两端附近,无限制器线性重构的伴随看到的黏性是 ν+h/2\nu+h/2——伴随的入口层正在那里。

This is a hyperviscosity, h34uxxxx\tfrac{h^3}{4}u_{xxxx} per unit length, with no second-derivative artificial viscosity (sympy proof; checked by this page on random states to within 2.3×10−162.3\times10^{-16}). But the two identities hold only in these ranges. The end cells are not reconstructed (σ0=σN−1=0\sigma_0=\sigma_{N-1}=0), so the traces of faces 0,10,1 and N−1,NN-1,N are only first-order accurate: with the exact cell averages (N=4096N=4096), (qR−qL)/(h ux∗)(q_R-q_L)/(h\,u^*_x) is 0.5001, 0.4998, 0.5002 and 0.4999 on faces 0, 1, N−1N-1 and NN, against 5.9×10−75.9\times10^{-7} on face 2. That is qR−qL≈h2uxq_R-q_L\approx\tfrac h2u_x: in unlimited linear reconstruction these four faces carry an added viscosity h/2h/2; in the first-order scheme only faces 00 and NN do, faces 11 and N−1N-1 carry hh like every interior face (ratio 1.0000 on face 1 at N=4096N=4096); the smooth limiter is close to unlimited linear while h∣ux∣≫ϵh|u_x|\gg\epsilon, and once h∣ux∣≪ϵh|u_x|\ll\epsilon it also gives hh on faces 11 and N−1N-1 (ratio 0.9992 at N=4096N=4096). The dissipation matrix is still symmetric (its antisymmetric part is 0.0 numerically), but its two end rows are (74, −1, 14)(\tfrac{7}{4},\ -1,\ \tfrac{1}{4}) and (−1, 74, −1, 14)(-1,\ \tfrac{7}{4},\ -1,\ \tfrac{1}{4}), not fourth differences. Near both ends the adjoint of unlimited linear reconstruction therefore sees the viscosity ν+h/2\nu+h/2, exactly where the adjoint's inlet layer lies.

图 66 · 一阶离散伴随(点)、黏性 ν 的连续伴随 λ_ν(实线)与黏性 ν+h 的连续伴随 λ_(ν+h)(虚线),只画 x ≤ 0.3。离散伴随的层远比 ν/u_in 宽,加密时,点先贴近虚线。在层内(x ≤ 5(ν+h)/u_in),N=4096 时到 λ_(ν+h) 的最大偏差是到 λ_ν 的 1/26。λ(黏性 ν)黏性 ν + h 的连续伴随一阶离散伴随 ψi​−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.3x伴随N = 8,ν + h = 0.135−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.3xN = 32,ν + h = 0.0413−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.3xN = 128,ν + h = 0.0178
图 66 · 一阶离散伴随(点)、黏性 ν\nu 的连续伴随 λν\lambda_\nu(实线)与黏性 ν+h\nu+h 的连续伴随 λν+h\lambda_{\nu+h}(虚线),只画 x≤0.3x\le0.3。离散伴随的层远比 ν/uin\nu/u_{\rm in} 宽,加密时,点先贴近虚线。在层内(x≤5(ν+h)/uinx\le5(\nu+h)/u_{\rm in}),N=4096N=4096 时到 λν+h\lambda_{\nu+h} 的最大偏差是到 λν\lambda_\nu 的 1/26。
Figure 66 · The first-order discrete adjoint (dots), the continuous adjoint λ_ν of viscosity ν (solid) and λ_(ν+h) of viscosity ν+h (dashed), for x ≤ 0.3. The layer of the discrete adjoint is far wider than ν/u_in; under refinement the dots approach the dashed curve first. Inside the layer (x ≤ 5(ν+h)/u_in) the largest deviation from λ_(ν+h) at N=4096 is 1/26 of that from λ_ν.λ (viscosity ν)continuous adjoint with viscosity ν + hfirst-order discrete adjoint ψi​−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.3xadjointN = 8, ν + h = 0.135−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.3xN = 32, ν + h = 0.0413−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.10.20.3xN = 128, ν + h = 0.0178
Figure 66 · The first-order discrete adjoint (dots), the continuous adjoint λν\lambda_\nu of viscosity ν\nu (solid) and λν+h\lambda_{\nu+h} of viscosity ν+h\nu+h (dashed), for x≤0.3x\le0.3. The layer of the discrete adjoint is far wider than ν/uin\nu/u_{\rm in}; under refinement the dots approach the dashed curve first. Inside the layer (x≤5(ν+h)/uinx\le5(\nu+h)/u_{\rm in}) the largest deviation from λν+h\lambda_{\nu+h} at N=4096N=4096 is 1/26 of that from λν\lambda_\nu.

测量结果:N≤2048N\le2048 时两个最大偏差都在伴随的层里;相对 λν+h\lambda_{\nu+h} 的比相对 λν\lambda_\nu 的下降快——N=512N=512 到 1024 的观测阶分别是 1.77 与 0.90。这是过渡阶段:N=2048N=2048 到 4096 两者都约为一阶(1.07 与 0.97),这时到 λν+h\lambda_{\nu+h} 的最大偏差已离开层(N=4096N=4096 时在 x=0.132x=0.132)。在层内,N=4096N=4096 时它只有到 λν\lambda_\nu 的偏差的 1/26:一阶伴随在层里的主要误差来自额外黏性 hh。

Measured: up to N=2048N=2048 both largest deviations sit in the adjoint's layer, and the one from λν+h\lambda_{\nu+h} falls faster than the one from λν\lambda_\nu, with observed orders 1.77 and 0.90 from N=512N=512 to 1024. This is a transient: from N=2048N=2048 to 4096 both are about first order (1.07 and 0.97), and the largest deviation from λν+h\lambda_{\nu+h} has left the layer (at x=0.132x=0.132 for N=4096N=4096). Inside the layer it is 1/26 of the deviation from λν\lambda_\nu at N=4096N=4096: the leading error of the first-order adjoint in the layer comes from the added viscosity hh.

等效黏性解释的是一阶离散伴随的层,不是全部误差。N=8N=8 时等效伴随问题的层宽约 0.15,大约一个单元,点离两条曲线都远。在 L1 范数下两个距离相差小得多(N=1024N=1024:0.00203 与 0.00140,之比 1.45;最大偏差之比为 17.1):到 λν+h\lambda_{\nu+h} 的 L1 距离有 90% 在层外,到 λν\lambda_\nu 的却有 71% 在层内(层取 x≤5(ν+h)/uinx\le5(\nu+h)/u_{\rm in})。到 λν+h\lambda_{\nu+h} 的 L1 距离中,O(h)O(h) 的部分来自内部各行的对流系数——离散状态 UjU_j 本身有 O(h)O(h) 误差:把它换成 u∗(xj)u^*(x_j),这个距离从 1.4×10−31.4\times10^{-3} 降到 1.16×10−41.16\times10^{-4}(N=1024N=1024,观测阶 1.91);两个端行只贡献 O(h2)O(h^2)。到 λν\lambda_\nu 的 L1 距离中 O(h)O(h) 的部分则是额外黏性 hh,主要在层里(这个距离的 69% 在层内):换成 u∗(xj)u^*(x_j) 后它并不减小(N=1024N=1024 时为 2.03×10−32.03\times10^{-3} 与 2.22×10−32.22\times10^{-3})。第一个单元的边界面只带额外黏性 h/2h/2;这可以直观地(非严格地)解释 ψ0\psi_0 为什么落在两条曲线之间(N=8N=8 到 4096 的每个网格上都是如此)。

The effective viscosity explains the layer of the first-order discrete adjoint, not every error. At N=8N=8 the layer of the effective adjoint problem is itself about 0.15 wide, about one cell, and the dots are far from both curves. In the L1 norm the two distances differ much less (N=1024N=1024: 0.00203 and 0.00140, a ratio of 1.45, against 17.1 for the largest deviations): 90% of the L1 distance to λν+h\lambda_{\nu+h} lies outside the layer, while 71% of that to λν\lambda_\nu lies inside it (the layer taken as x≤5(ν+h)/uinx\le5(\nu+h)/u_{\rm in}). The O(h)O(h) part of the distance to λν+h\lambda_{\nu+h} comes from the convection coefficient of the interior rows, the discrete state UjU_j, which has its own O(h)O(h) error: with u∗(xj)u^*(x_j) in its place this distance falls from 1.4×10−31.4\times10^{-3} to 1.16×10−41.16\times10^{-4} (N=1024N=1024, observed order 1.91); the two end rows contribute only O(h2)O(h^2). The O(h)O(h) part of the distance to λν\lambda_\nu is the added viscosity hh, mostly in the layer (69% of this distance lies there): with u∗(xj)u^*(x_j) it does not fall (2.03×10−32.03\times10^{-3} and 2.22×10−32.22\times10^{-3} at N=1024N=1024). The boundary face of the first cell carries only the added viscosity h/2h/2; heuristically, this is why ψ0\psi_0 lies between the two curves (as it does on every mesh, N=8N=8 to 4096).

边界项与伴随的入口层

The boundary term and the inlet layer of the adjoint

连续梯度的边界项含 νλx(0) ∂Dkuin\nu\lambda_x(0)\,\partial_{D_k}u_{\rm in},而 ν\nu 越小,∣λx(0)∣|\lambda_x(0)| 越大。先看 λ\lambda 的边界层结构(连续伴随问题的形式渐近分析,不是证明)。层外黏性项可以略去,−uλx≈−(1+x)-u\lambda_x\approx-(1+x),且 λ(1)=0\lambda(1)=0(伴随从 x=1x=1 向上游传):

The boundary term of the continuous gradient contains νλx(0) ∂Dkuin\nu\lambda_x(0)\,\partial_{D_k}u_{\rm in}, while ∣λx(0)∣|\lambda_x(0)| grows as ν\nu decreases. First the structure of the layer of λ\lambda (a formal asymptotic analysis of the continuous adjoint problem, not a proof). Outside the layer the viscous term can be dropped, −uλx≈−(1+x)-u\lambda_x\approx-(1+x), with λ(1)=0\lambda(1)=0 (the adjoint travels upstream from x=1x=1):

λout(x)=−∫x11+tu∗(t) dt,λout(0)=−∫011+tu∗(t) dt=−1.561867.\lambda_{\rm out}(x)=-\int_x^1\frac{1+t}{u^*(t)}\,\mathrm dt,\qquad \lambda_{\rm out}(0)=-\int_0^1\frac{1+t}{u^*(t)}\,\mathrm dt=−1.561867.

λout(0)≠0\lambda_{\rm out}(0)\ne0,而边界条件要求 λ(0)=0\lambda(0)=0,所以 x=0x=0 处必须有层。层内令 ξ=uinx/ν\xi=u_{\rm in}x/\nu,主导项满足 λξξ+λξ=0\lambda_{\xi\xi}+\lambda_\xi=0,解为 C1+C2e−ξC_1+C_2e^{-\xi};由 λ(0)=0\lambda(0)=0 及与 λout\lambda_{\rm out} 的匹配得到

λout(0)≠0\lambda_{\rm out}(0)\ne0 while the boundary condition asks for λ(0)=0\lambda(0)=0, so there must be a layer at x=0x=0. Inside it, with ξ=uinx/ν\xi=u_{\rm in}x/\nu, the leading terms satisfy λξξ+λξ=0\lambda_{\xi\xi}+\lambda_\xi=0, with the solutions C1+C2e−ξC_1+C_2e^{-\xi}; λ(0)=0\lambda(0)=0 and matching with λout\lambda_{\rm out} give

λ(x)≈λout(x)−λout(0) e−ξ,λx(0)≈uin λout(0)ν,ν λx(0)≈uin λout(0)=−1.42887.\lambda(x)\approx\lambda_{\rm out}(x)-\lambda_{\rm out}(0)\,e^{-\xi},\qquad \lambda_x(0)\approx\frac{u_{\rm in}\,\lambda_{\rm out}(0)}{\nu},\qquad \nu\,\lambda_x(0)\approx u_{\rm in}\,\lambda_{\rm out}(0)=−1.42887.

斜率按 1/ν1/\nu 增长,边界项 νλx(0) ∂Dkuin\nu\lambda_x(0)\,\partial_{D_k}u_{\rm in} 却在 ν→0\nu\to0 时保持 O(1)O(1):它等于层两侧的跳跃 λout(0)−0\lambda_{\rm out}(0)-0 乘以 uinu_{\rm in},与黏性无关。数值验证:ν=0.01\nu=0.01 时 Chebyshev 解给出 νλx(0)=−1.42657\nu\lambda_x(0)=−1.42657,渐近值为 −1.42887;ν\nu 较小时差别约与 ν\nu 成正比(下一小节的表)。

The slope grows like 1/ν1/\nu, but the boundary term νλx(0) ∂Dkuin\nu\lambda_x(0)\,\partial_{D_k}u_{\rm in} stays O(1)O(1) as ν→0\nu\to0: it equals the jump λout(0)−0\lambda_{\rm out}(0)-0 across the layer times uinu_{\rm in}, independent of the viscosity. Numerically, at ν=0.01\nu=0.01 the Chebyshev solution gives νλx(0)=−1.42657\nu\lambda_x(0)=−1.42657 against the asymptotic −1.42887; for small ν\nu the difference is roughly proportional to ν\nu (the table of the next subsection).

离散情形:ψ0\psi_0 在 x0=h/2x_0=h/2,而 λ(0)=0\lambda(0)=0,所以 ψ0/(h/2)\psi_0/(h/2) 是 λx(0)\lambda_x(0) 的单侧差商。但梯度用到的不是这个斜率,而是第 12 节的入口值伴随 uˉin\bar u_{\rm in}:uinu_{\rm in} 只进入面 0,∂R/∂uin=−(cL(0)+2νh)e0\partial R/\partial u_{\rm in}=-\bigl(c_L(0)+\tfrac{2\nu}{h}\bigr)e_0,所以

Discretely, ψ0\psi_0 sits at x0=h/2x_0=h/2 and λ(0)=0\lambda(0)=0, so ψ0/(h/2)\psi_0/(h/2) is a one-sided difference quotient for λx(0)\lambda_x(0). But the gradient does not use this slope; it uses the adjoint of the inlet value of Section 12, uˉin\bar u_{\rm in}: uinu_{\rm in} enters face 0 only, ∂R/∂uin=−(cL(0)+2νh)e0\partial R/\partial u_{\rm in}=-\bigl(c_L(0)+\tfrac{2\nu}{h}\bigr)e_0, so

uˉin=ψT∂R∂uin=−ψ0(cL(0)+2νh)=−(ν+h2+uinh4)ψ0h/2=dJhduin,cL(0)=uin2+1.\bar u_{\rm in}=\psi^T\frac{\partial R}{\partial u_{\rm in}}=-\psi_0\Bigl(c_L(0)+\frac{2\nu}{h}\Bigr)=-\Bigl(\nu+\frac h2+\frac{u_{\rm in}h}{4}\Bigr)\frac{\psi_0}{h/2}=\frac{\mathrm dJ_h}{\mathrm du_{\rm in}},\qquad c_L(0)=\frac{u_{\rm in}}{2}+1.

uˉin\bar u_{\rm in} 是 JhJ_h 对入口值的灵敏度;它的连续对应是 dJ/duin=−νλx(0)=1.42657\mathrm dJ/\mathrm du_{\rm in}=-\nu\lambda_x(0)=1.42657(梯度公式的边界项在 x=0x=0 的部分)。同一个数也可以用一次切线求解得到:Avin=(cL(0)+2νh)e0Av_{\rm in}=\bigl(c_L(0)+\tfrac{2\nu}{h}\bigr)e_0,dJh/duin=wTvin\mathrm dJ_h/\mathrm du_{\rm in}=w^Tv_{\rm in}(N=8N=8 时两种算法都给出 1.494909,相差 2×10−162\times10^{-16})。入口值的扰动 vinv_{\rm in} 像状态一样向下游传:它在入口处光滑,边界层在出口(N=4096N=4096 时第一个单元里 0.9999,x=0.977x=0.977 处 0.904,最后一个单元里 0.011)。这解释了为什么粗网格上 uˉin\bar u_{\rm in} 已经很准,而斜率 ψ0/(h/2)\psi_0/(h/2) 还差得很远。看 ψ0/(h/2)\psi_0/(h/2) 前面的系数:物理黏性 ν\nu;面 0 的 Rusanov 耗散跨过距离 h/2h/2 给出的额外黏性 h/2h/2;以及对流导数 uin/2u_{\rm in}/2 给出的 uinh/4u_{\rm in}h/4(第 12 节把 cL(0)=uin/2+1c_L(0)=u_{\rm in}/2+1 整个算作对流部分;这里把其中的耗散 1 单独列出,因为它像黏性一样起作用)。表中两种量并排(无限制器线性,默认设计):

uˉin\bar u_{\rm in} is the sensitivity of JhJ_h to the inlet value; its continuous counterpart is dJ/duin=−νλx(0)=1.42657\mathrm dJ/\mathrm du_{\rm in}=-\nu\lambda_x(0)=1.42657 (the part of the boundary term of the gradient formula at x=0x=0). The same number comes from one tangent solve: Avin=(cL(0)+2νh)e0Av_{\rm in}=\bigl(c_L(0)+\tfrac{2\nu}{h}\bigr)e_0, dJh/duin=wTvin\mathrm dJ_h/\mathrm du_{\rm in}=w^Tv_{\rm in} (at N=8N=8 both give 1.494909, differing by 2×10−162\times10^{-16}). The perturbation vinv_{\rm in} of the inlet value travels downstream like the state: it is smooth at the inlet and has its layer at the outlet (at N=4096N=4096: 0.9999 in the first cell, 0.904 at x=0.977x=0.977, 0.011 in the last cell). This explains why uˉin\bar u_{\rm in} is already accurate on coarse meshes while the slope ψ0/(h/2)\psi_0/(h/2) is still far off. Look at the factor in front of ψ0/(h/2)\psi_0/(h/2): the physical viscosity ν\nu; the added viscosity h/2h/2 of the Rusanov dissipation of face 0 across the distance h/2h/2; and uinh/4u_{\rm in}h/4 from the convective derivative uin/2u_{\rm in}/2 (Section 12 counts all of cL(0)=uin/2+1c_L(0)=u_{\rm in}/2+1 as the convective part; here its dissipation 1 is listed separately because it acts like a viscosity). The table puts the two quantities side by side (unlimited linear, default design):

Nψ0/(h/2)\psi_0/(h/2)与 λx(0)\lambda_x(0) 之比ratio to λx(0)\lambda_x(0)黏性部分 νψ0/(h/2)\nu\psi_0/(h/2)viscous part νψ0/(h/2)\nu\psi_0/(h/2)uˉin\bar u_{\rm in}与 −νλx(0)-\nu\lambda_x(0) 之比ratio to −νλx(0)-\nu\lambda_x(0)
8−14.790.104−0.14791.49491.0479
16−26.420.185−0.26421.46771.0288
32−44.100.309−0.44101.44521.0131
64−67.020.470−0.67021.43331.0047
128−91.020.638−0.91021.42841.0013
256−111.080.779−1.11081.42691.0003
512−124.890.875−1.24891.42661.0000
1024−133.180.934−1.33181.42661.0000
2048−137.760.966−1.37761.42661.0000
4096−140.160.983−1.40161.42661.0000

斜率 ψ0/(h/2)\psi_0/(h/2) 收敛得很慢:N=256N=256 时只有 λx(0)\lambda_x(0) 的 77.9%,要到 N=1024N=1024 才进入 10% 以内(一阶格式也要到 N=1024N=1024);只看黏性部分,N=256N=256 时入口项只再现了 78%。uˉin\bar u_{\rm in} 则在 N=8N=8 时与连续值只差 4.8%,N=256N=256 时差 0.03%。这是默认设计下的结果,不是一般规律:a=0.5a=0.5、φ=0.5\varphi=0.5 时,uˉin\bar u_{\rm in} 与连续值之比在 N=8N=8 时只有 0.706,N=16N=16 时为 0.814。Python 数据(到 N=16384N=16384)给出同样的斜率比。

The slope ψ0/(h/2)\psi_0/(h/2) converges slowly: at N=256N=256 it is only 77.9% of λx(0)\lambda_x(0), and it comes within 10% only at N=1024N=1024 (the first-order scheme also needs N=1024N=1024); the viscous part alone reproduces only 78% of the inlet term at N=256N=256. uˉin\bar u_{\rm in} differs from its continuous value by 4.8% already at N=8N=8 and by 0.03% at N=256N=256. This holds at the default design and is not general: with a=0.5a=0.5 and φ=0.5\varphi=0.5 the ratio of uˉin\bar u_{\rm in} to its continuous value is 0.706 at N=8N=8 and 0.814 at N=16N=16. The Python data (to N=16384N=16384) give the same slope ratios.

图 67 · 两种边界关系随 N 的变化(默认设计)。实线:斜率 ψ_0/(h/2) 与 λ_x(0) 之比,要到远在紫线右侧(h ≪ ν/u_in,N 上千,见)才接近 1;虚线:u-bar_in= dJ_h/ du_in 与 -νλ_x(0) 之比,从 N=8 起就在 1 附近(无限制器 1.048,一阶 1.050)。圆圈:Python 数据的斜率比。ψ0​/(h/2) ÷ λx​(0)(一阶)ψ0​/(h/2) ÷ λx​(0)(无限制器)Python 数据uin​÷ (−ν λx​(0))(一阶)uin​÷ (−ν λx​(0))(无限制器)00.20.40.60.811.110102​103​104​单元数 N与连续值之比h = ν/uin​
图 67 · 两种边界关系随 NN 的变化(默认设计)。实线:斜率 ψ0/(h/2)\psi_0/(h/2) 与 λx(0)\lambda_x(0) 之比,要到远在紫线右侧(h≪ν/uinh\ll\nu/u_{\rm in},NN 上千,见第 11 节)才接近 1;虚线:uˉin=dJh/duin\bar u_{\rm in}=\mathrm dJ_h/\mathrm du_{\rm in} 与 −νλx(0)-\nu\lambda_x(0) 之比,从 N=8N=8 起就在 1 附近(无限制器 1.048,一阶 1.050)。圆圈:Python 数据的斜率比。
Figure 67 · The two boundary relations against N (default design). Solid: the slope ψ_0/(h/2) over λ_x(0), which approaches 1 only well to the right of the violet line (h ≪ ν/u_in, N in the thousands, ); dashed: u-bar_in= dJ_h/ du_in over -νλ_x(0), close to 1 from N=8 on (1.048 unlimited linear, 1.050 first order). Rings: the slope ratio of the Python data.first: ψ0​/(h/2) ÷ λx​(0)none: ψ0​/(h/2) ÷ λx​(0)Python datafirst:uin​÷ (−ν λx​(0))none:uin​÷ (−ν λx​(0))00.20.40.60.811.110102​103​104​cells Nratio to the continuous valueh = ν/uin​
Figure 67 · The two boundary relations against NN (default design). Solid: the slope ψ0/(h/2)\psi_0/(h/2) over λx(0)\lambda_x(0), which approaches 1 only well to the right of the violet line (h≪ν/uinh\ll\nu/u_{\rm in}, NN in the thousands, Section 11); dashed: uˉin=dJh/duin\bar u_{\rm in}=\mathrm dJ_h/\mathrm du_{\rm in} over −νλx(0)-\nu\lambda_x(0), close to 1 from N=8N=8 on (1.048 unlimited linear, 1.050 first order). Rings: the slope ratio of the Python data.

黏性 ν 的作用

The effect of ν

把 ν\nu 从 0.1 减到 0.001(aa、φ\varphi 不变),连续伴随的层越来越薄,∣λx(0)∣|\lambda_x(0)| 按 1/ν1/\nu 增长,νλx(0)\nu\lambda_x(0) 则趋于渐近值 uinλout(0)u_{\rm in}\lambda_{\rm out}(0)。差值除以 ν\nu(表中“差/ν/\nu”一列)从 ν=0.1\nu=0.1 时的 0.758 变到 ν=0.001\nu=0.001 时的 0.188:只有 ν\nu 较小时差值才约与 ν\nu 成正比。源项积分和边界项各自随 ν\nu 变化,它们的和——精确梯度——不变(精确梯度不依赖 ν\nu)。下表用 Chebyshev 解(201 个点;Python 审计 audit_f.py 用 241 与 321 个点比对,差在 10−1210^{-12} 量级),分量 aa:

Decrease ν\nu from 0.1 to 0.001 (aa, φ\varphi fixed): the layer of the continuous adjoint gets thinner, ∣λx(0)∣|\lambda_x(0)| grows like 1/ν1/\nu, and νλx(0)\nu\lambda_x(0) tends to the asymptotic value uinλout(0)u_{\rm in}\lambda_{\rm out}(0). The difference divided by ν\nu (the column “gap/ν/\nu”) goes from 0.758 at ν=0.1\nu=0.1 to 0.188 at ν=0.001\nu=0.001: the difference is roughly proportional to ν\nu only for small ν\nu. The source integral and the boundary term each change with ν\nu; their sum, the exact gradient, does not (the exact gradient does not depend on ν\nu). The table uses the Chebyshev solutions (201 points; the Python audit audit_f.py compares 241 with 321 points and finds differences of order 10−1210^{-12}), component aa:

ν\nuλx(0)\lambda_x(0)νλx(0)\nu\lambda_x(0)uinλout(0)u_{\rm in}\lambda_{\rm out}(0)差/ν/\nugap/ν/\nu源项积分source integral边界项boundary term和 =dJ/da=\mathrm dJ/\mathrm dasum =dJ/da=\mathrm dJ/\mathrm da
0.1−13.530−1.35304−1.428870.7580.5257−0.6697−0.144008
0.05−28.095−1.40474−1.428870.4820.5018−0.6458−0.144008
0.02−71.155−1.42310−1.428870.2880.4808−0.6248−0.144008
0.01−142.657−1.42657−1.428870.2300.4728−0.6168−0.144008
0.005−285.568−1.42784−1.428870.2050.4686−0.6126−0.144008
0.002−714.240−1.42848−1.428870.1920.4661−0.6101−0.144008
0.001−1428.677−1.42868−1.428870.1880.4652−0.6092−0.144008
图 68 · 黏性对连续伴随的作用(a=0.2,φ=0.07)。(a) λ(x):粗线是 ν=0.01;(b) 用层变量 ξ=u_inx/ν 画 (λ-λ_out)/(-λ_out(0)):ν 越小越贴近 e^(-ξ)(点线),即上面的两项近似;(c) ν 减小时,νλ_x(0) 趋于 u_inλ_out(0)=−1.4289;ν → 0 时边界项并不消失。−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xλ(x)(a) λ(x),ν 从 0.1 到 0.00100.20.40.60.81012345678ξ = uin​ x/ν(b) (λ − λout​)/(−λout​(0)) 与 e−ξ​(点线)ν = 0.1ν = 0.05ν = 0.02ν = 0.01ν = 0.005ν = 0.002ν = 0.001ν λx​(0)(Chebyshev)渐近值 uin​ λout​(0)−1.44−1.42−1.4−1.38−1.36−1.340.0010.010.1νν λx​(0)
图 68 · 黏性对连续伴随的作用(a=0.2a=0.2,φ=0.07\varphi=0.07)。(a) λ(x)\lambda(x):粗线是 ν=0.01\nu=0.01;(b) 用层变量 ξ=uinx/ν\xi=u_{\rm in}x/\nu 画 (λ−λout)/(−λout(0))(\lambda-\lambda_{\rm out})/(-\lambda_{\rm out}(0)):ν\nu 越小越贴近 e−ξe^{-\xi}(点线),即上面的两项近似;(c) ν\nu 减小时,νλx(0)\nu\lambda_x(0) 趋于 uinλout(0)=−1.4289u_{\rm in}\lambda_{\rm out}(0)=−1.4289;ν→0\nu\to0 时边界项并不消失。
Figure 68 · The effect of the viscosity on the continuous adjoint (a=0.2, φ=0.07). (a) λ(x), the thick line is ν=0.01; (b) (λ-λ_out)/(-λ_out(0)) against the layer variable ξ=u_inx/ν: the smaller ν, the closer to e^(-ξ) (dotted), the two-term approximation above; (c) as ν decreases, νλ_x(0) tends to u_inλ_out(0)=−1.4289: the boundary term does not vanish as ν → 0.−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xλ(x)(a) λ(x) for ν from 0.1 to 0.00100.20.40.60.81012345678ξ = uin​ x/ν(b) (λ − λout​)/(−λout​(0)) and e−ξ​ (dotted)ν = 0.1ν = 0.05ν = 0.02ν = 0.01ν = 0.005ν = 0.002ν = 0.001ν λx​(0) (Chebyshev)asymptote uin​ λout​(0)−1.44−1.42−1.4−1.38−1.36−1.340.0010.010.1νν λx​(0)
Figure 68 · The effect of the viscosity on the continuous adjoint (a=0.2a=0.2, φ=0.07\varphi=0.07). (a) λ(x)\lambda(x), the thick line is ν=0.01\nu=0.01; (b) (λ−λout)/(−λout(0))(\lambda-\lambda_{\rm out})/(-\lambda_{\rm out}(0)) against the layer variable ξ=uinx/ν\xi=u_{\rm in}x/\nu: the smaller ν\nu, the closer to e−ξe^{-\xi} (dotted), the two-term approximation above; (c) as ν\nu decreases, νλx(0)\nu\lambda_x(0) tends to uinλout(0)=−1.4289u_{\rm in}\lambda_{\rm out}(0)=−1.4289: the boundary term does not vanish as ν→0\nu\to0.

在面板里拖动 ν\nu,同时看离散伴随:固定网格时 ν\nu 越小,层越难分辨,ψ0/(h/2)\psi_0/(h/2) 离 λx(0)\lambda_x(0) 越远;面板同时给出这时的 uˉin\bar u_{\rm in} 与连续值之比。

Drag ν\nu in the panel and watch the discrete adjoint at the same time: on a fixed mesh, the smaller ν\nu, the harder the layer is to resolve and the further ψ0/(h/2)\psi_0/(h/2) is from λx(0)\lambda_x(0); the panel also gives the ratio of uˉin\bar u_{\rm in} to its continuous value.

梯度误差的逐项分解

The gradient error, part by part

第 12 节在固定网格上分清了设计进入残差的三条路径。对 aa 与 φ\varphi(k=0,1k=0,1)只有两条:每一行的积分源项,以及读边界值的面 0 和面 NN。所以离散梯度与连续梯度可以逐项对齐。离散梯度的三部分是 (i) 源项行、(ii) 入口面、(iii) 出口面:

Section 12 separated the three paths by which the design enters the residual, on a fixed mesh. For aa and φ\varphi (k=0,1k=0,1) there are only two: the integrated source of every row, and faces 0 and NN, which read the boundary values. So the discrete and the continuous gradient can be lined up term by term. The three parts of the discrete gradient are (i) the source rows, (ii) the inlet face and (iii) the outlet face:

Dˉk=−∑iψi ∂Dk(Qi+1−Qi)⏟(i) − ψ0(cL(0)+2νh)∂Dkuin⏟(ii) +ψN−1(cR(N)−2νh)∂Dkuout⏟(iii),\bar D_k=\underbrace{-\sum_i\psi_i\,\partial_{D_k}(Q_{i+1}-Q_i)}_{(\mathrm i)}\ \underbrace{-\,\psi_0\Bigl(c_L(0)+\tfrac{2\nu}{h}\Bigr)\partial_{D_k}u_{\rm in}}_{(\mathrm{ii})}\ +\underbrace{\psi_{N-1}\Bigl(c_R(N)-\tfrac{2\nu}{h}\Bigr)\partial_{D_k}u_{\rm out}}_{(\mathrm{iii})},

它们的连续对应是 (i′) 源项积分、(ii′) 入口项、(iii′) 出口项:

Their continuous counterparts are (i′) the source integral, (ii′) the inlet term and (iii′) the outlet term:

dJdDk=−∫01λ ∂Dks dx⏟(i′) − νλx(0) ∂Dkuin⏟(ii′) +νλx(1) ∂Dkuout⏟(iii′).\frac{\mathrm dJ}{\mathrm dD_k}=\underbrace{-\int_0^1\lambda\,\partial_{D_k}s\,\mathrm dx}_{(\mathrm i')}\ \underbrace{-\,\nu\lambda_x(0)\,\partial_{D_k}u_{\rm in}}_{(\mathrm{ii}')}\ +\underbrace{\nu\lambda_x(1)\,\partial_{D_k}u_{\rm out}}_{(\mathrm{iii}')}.

源项行对应源项积分,因为 ∂Dk(Qi+1−Qi)=∫xi−h/2xi+h/2∂Dks dx\partial_{D_k}(Q_{i+1}-Q_i)=\int_{x_i-h/2}^{x_i+h/2}\partial_{D_k}s\,\mathrm dx。下表是分量 aa(无限制器线性);连续值为:源项积分 0.4728,入口项 −0.6074,出口项 −0.0094,梯度 −0.1440。三部分之和与 RDTψR_D^T\psi 相差不到 10−1410^{-14}(本页与审计都核对过)。

The source rows correspond to the source integral because ∂Dk(Qi+1−Qi)=∫xi−h/2xi+h/2∂Dks dx\partial_{D_k}(Q_{i+1}-Q_i)=\int_{x_i-h/2}^{x_i+h/2}\partial_{D_k}s\,\mathrm dx. The table is for component aa (unlimited linear); the continuous values are: source integral 0.4728, inlet term −0.6074, outlet term −0.0094, gradient −0.1440. The three parts add up to RDTψR_D^T\psi to within 10−1410^{-14} (checked by this page and by the audit).

N源项行source rows入口面inlet face其中黏性部分its viscous part出口面outlet faceDˉ0=dJh/da\bar D_0=\mathrm dJ_h/\mathrm daDˉ0=dJh/da\bar D_0=\mathrm dJ_h/\mathrm da与精确值之差minus exact
80.1987−0.6365−0.0630−0.0488−0.4866−3.4e−1
160.3028−0.6249−0.1125−0.0285−0.3506−2.1e−1
320.3828−0.6153−0.1878−0.0186−0.2511−1.1e−1
640.4304−0.6103−0.2854−0.0135−0.1934−4.9e−2
1280.4554−0.6082−0.3876−0.0110−0.1639−2.0e−2
2560.4667−0.6076−0.4729−0.0099−0.1508−6.8e−3
5120.4709−0.6074−0.5317−0.0096−0.1461−2.1e−3
10240.4723−0.6074−0.5671−0.0094−0.1446−5.8e−4

三点观察。(1) 入口面最准:N=8N=8 时为 −0.6365,连续值为 −0.6074(原因见上一小节),虽然其中的黏性部分只有 −0.0630。(2) 粗网格上误差主要在源项行:N=8N=8 时为 0.1987,连续值为 0.4728。逐个单元看 ∫xi−h/2xi+h/2(λ−ψi) ∂as dx\int_{x_i-h/2}^{x_i+h/2}(\lambda-\psi_i)\,\partial_as\,\mathrm dx:第一个单元贡献 −0.335,绝对值比源项总误差 −0.274 还大(其余单元部分抵消)。这个误差主要来自不重构的端单元:在端单元重构的实验里,第一个单元只贡献 −0.044,源项总误差只有 −0.021。对 φ\varphi,出口面的通量只有一阶精度,N=8N=8 时它的误差最大(−0.105;源项行 0.037,入口面 −0.078);细网格上它在梯度中的那部分仍按二阶收敛(最细两层之间的阶为 1.96)。(3) 各部分都是 O(1)O(1),梯度却只有 −0.144:各部分只要差零点几,梯度的相对误差就达到 O(1)O(1)。N=8N=8 时 Dˉ0=−0.4866\bar D_0=−0.4866,是精确值的 3.38 倍。

Three observations. (1) The inlet face is the most accurate part: −0.6365 at N=8N=8 against −0.6074 (the reason is in the previous subsection), although its viscous part is only −0.0630. (2) On coarse meshes the error sits mainly in the source rows: 0.1987 against 0.4728 at N=8N=8. Cell by cell, ∫xi−h/2xi+h/2(λ−ψi) ∂as dx\int_{x_i-h/2}^{x_i+h/2}(\lambda-\psi_i)\,\partial_as\,\mathrm dx is −0.335 in the first cell alone, larger in magnitude than the whole source error −0.274 (the other cells partly cancel). This error comes mainly from the unreconstructed end cell: in the experiment with the end cells reconstructed, the first cell contributes only −0.044 and the whole source error is −0.021. For φ\varphi the outlet face, whose flux is only first-order accurate, has the largest error at N=8N=8 (−0.105, against 0.037 in the source rows and −0.078 at the inlet face); its part of the gradient still converges at second order on fine meshes (order 1.96 between the two finest levels). (3) The parts are O(1)O(1) while the gradient is only −0.144: errors of a few tenths in the parts are O(1)O(1) relative errors of the gradient. At N=8N=8, Dˉ0=−0.4866\bar D_0=−0.4866, 3.38 times the exact value.

图 69 · 梯度误差随 N 的逐项分解(无限制器线性,默认设计):每一部分离散值与连续值之差,以及梯度误差(粗线)。入口面最先收敛;粗网格上,分量 a 的误差主要在源项行(尤其是端单元);对 φ,N=8 时出口面的误差最大。渐近地,各部分约二阶或更快收敛:最细两层之间,源项行 1.96、出口面 1.96、入口面 2.80(刚过紫线(h<ν/u_in)时,N=128 → 256,源项行与出口面只有 1.51 与 1.55)。源项行入口面出口面梯度误差(总和)10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1101001000N|离散部分 − 连续部分|(a) 分量 a10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1101001000N(b) 分量 φ
图 69 · 梯度误差随 NN 的逐项分解(无限制器线性,默认设计):每一部分离散值与连续值之差,以及梯度误差(粗线)。入口面最先收敛;粗网格上,分量 aa 的误差主要在源项行(尤其是端单元);对 φ\varphi,N=8N=8 时出口面的误差最大。渐近地,各部分约二阶或更快收敛:最细两层之间,源项行 1.96、出口面 1.96、入口面 2.80(刚过紫线(h<ν/uinh<\nu/u_{\rm in})时,N=128→256N=128\to256,源项行与出口面只有 1.51 与 1.55)。
Figure 69 · The gradient error part by part against N (unlimited linear, default design): the difference between the discrete and the continuous value of each part, and the gradient error (thick). The inlet face converges first; on coarse meshes the error of component a sits mainly in the source rows (mainly the end cells), and for φ the outlet face has the largest error at N=8. Asymptotically every part converges at about second order or faster: between the two finest levels the source rows at 1.96, the outlet face at 1.96 and the inlet face at 2.80 (just right of the violet line (h<ν/u_in), N=128 → 256, the source rows and the outlet face only at 1.51 and 1.55).source rowsinlet faceoutlet facegradient error (sum)10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1101001000N|discrete part − continuous part|(a) component a10-8​10-7​10-6​10-5​10-4​10-3​10-2​10-1​1101001000N(b) component φ
Figure 69 · The gradient error part by part against NN (unlimited linear, default design): the difference between the discrete and the continuous value of each part, and the gradient error (thick). The inlet face converges first; on coarse meshes the error of component aa sits mainly in the source rows (mainly the end cells), and for φ\varphi the outlet face has the largest error at N=8N=8. Asymptotically every part converges at about second order or faster: between the two finest levels the source rows at 1.96, the outlet face at 1.96 and the inlet face at 2.80 (just right of the violet line (h<ν/uinh<\nu/u_{\rm in}), N=128→256N=128\to256, the source rows and the outlet face only at 1.51 and 1.55).

反面例子:把边界面距离取成 h

A counterexample: the boundary-face distance taken as h

一个看似无害的错误是:把边界面的黏性距离取成 d0=dN=hd_0=d_N=h(“两个状态之间的距离是一个单元”),而不是本页的 h/2h/2(uinu_{\rm in} 在 x=0x=0,U0U_0 在 x=h/2x=h/2)。错误版本的残差记为 R~\tilde R,它只在两个端行不同:

A harmless-looking slip: take the viscous distance of the boundary faces as d0=dN=hd_0=d_N=h (“the distance between the two states is one cell”) instead of the page's h/2h/2 (uinu_{\rm in} is at x=0x=0, U0U_0 at x=h/2x=h/2). The residual of the slip, R~\tilde R, differs only in the two end rows:

R~0=R0−νh (U0−uin),R~N−1=RN−1+νh (uout−UN−1),R~i=Ri(1≤i≤N−2).\tilde R_0=R_0-\frac{\nu}{h}\,(U_0-u_{\rm in}),\qquad \tilde R_{N-1}=R_{N-1}+\frac{\nu}{h}\,(u_{\rm out}-U_{N-1}),\qquad \tilde R_i=R_i\quad(1\le i\le N-2).

错误版本的切线语句和反向语句写在本节的模块里,用点积检验和复数步长核对,误差在 10−1610^{-16} 量级(与模型同样的检查)。Python 审计用原始稀疏求解器、只改它的距离数组,独立地复现了下面的每个数。

Its tangent and reverse statements are written in this section's module and checked like the model's, by the dot test and complex step, to 10−1610^{-16}. The Python audit reproduces every number below independently with the original sparse solver, changing only its distance array.

R~\tilde R 的首行不相容:代入精确单元平均,本页的 R0R_0 是 O(h)O(h)(N=4096N=4096 时 R0/h=−0.509R_0/h=−0.509,第 1 行同样是 O(h)O(h),内部各行是 O(h3)O(h^3)),错误版本的 R~0\tilde R_0 却趋于常数 −νux∗(0)/2=−0.00569-\nu u^*_x(0)/2=−0.00569(N=4096N=4096 时为 −0.00581)。但解仍然收敛:R~0\tilde R_0 对 U0U_0 的导数约为 2ν/h2\nu/h,解只需把 U0−uinU_0-u_{\rm in} 放大一倍——相当于把边界值放到 x=−h/2x=-h/2,一个 O(h)O(h) 的移动。N=4096N=4096 时测得 (U0−uin)/(h ux∗(0))(U_0-u_{\rm in})/(h\,u^*_x(0)):本页 0.497,错误版本 0.977。

The first row of R~\tilde R is inconsistent: with the exact cell averages inserted, the page's R0R_0 is O(h)O(h) (R0/h=−0.509R_0/h=−0.509 at N=4096N=4096; row 1 is O(h)O(h) too, the interior rows O(h3)O(h^3)), while the slip's R~0\tilde R_0 tends to the constant −νux∗(0)/2=−0.00569-\nu u^*_x(0)/2=−0.00569 (−0.00581 at N=4096N=4096). Yet the solution still converges: R~0\tilde R_0 depends on U0U_0 with a derivative of about 2ν/h2\nu/h, and the solution only has to double U0−uinU_0-u_{\rm in}, which amounts to placing the boundary value at x=−h/2x=-h/2, an O(h)O(h) shift. At N=4096N=4096, (U0−uin)/(h ux∗(0))(U_0-u_{\rm in})/(h\,u^*_x(0)) is 0.497 for the page and 0.977 for the slip.

图 70 · 本页(实线)与错误版本(虚线),无限制器线性重构。(a) 状态 L1 误差与 dJ_h/ da 的误差:N ≤ 256 时错误版本的这两项反而更小,之后只按一阶收敛;N=4096 时状态误差是本页的 22.3 倍,a 分量的梯度误差是 22.4 倍。(b) ψ_0/(h/2) 与 λ_x(0) 之比:本页趋于 1,错误版本趋于 2(边界移到了 -h/2);错误版本自己的 u-bar_in(用它自己的 c_L(0)+ν/h)却仍趋于连续值(N=4096 时比值 1.00002)。实线:本页(边界面距离 h/2)虚线:错误版本(边界面距离 h)(a) 状态 L1 误差(a) dJh​/da 的误差;(b) ψ0​/(h/2) ÷ λx​(0)紫:错误版本的uin​÷ (−ν λx​(0))10-6​10-5​10-4​10-3​10-2​10-1​1101001000N误差(a) 状态 L1 误差与 dJh​/da 的误差hh2​00.511.52101001000N(b) 与连续值之比
图 70 · 本页(实线)与错误版本(虚线),无限制器线性重构。(a) 状态 L1 误差与 dJh/da\mathrm dJ_h/\mathrm da 的误差:N≤256N\le256 时错误版本的这两项反而更小,之后只按一阶收敛;N=4096N=4096 时状态误差是本页的 22.3 倍,aa 分量的梯度误差是 22.4 倍。(b) ψ0/(h/2)\psi_0/(h/2) 与 λx(0)\lambda_x(0) 之比:本页趋于 1,错误版本趋于 2(边界移到了 −h/2-h/2);错误版本自己的 uˉin\bar u_{\rm in}(用它自己的 cL(0)+ν/hc_L(0)+\nu/h)却仍趋于连续值(N=4096N=4096 时比值 1.00002)。
Figure 70 · The page (solid) and the slip (dashed), unlimited linear reconstruction. (a) The state L1 error and the error of dJ_h/ da: up to N=256 these two are even smaller for the slip, after that they converge only at first order; at N=4096 the slip's state error is 22.3 times the page's and its a-gradient error 22.4 times. (b) ψ_0/(h/2) over λ_x(0): the page tends to 1, the slip to 2 (the boundary moved to -h/2); the slip's own u-bar_in (with its own c_L(0)+ν/h) still tends to the continuous value (ratio 1.00002 at N=4096).solid: the page (boundary-face distance h/2)dashed: the slip (boundary-face distance h)(a) state L1 error(a) error of dJh​/da; (b) ψ0​/(h/2) ÷ λx​(0)violet: the slip’suin​÷ (−ν λx​(0))10-6​10-5​10-4​10-3​10-2​10-1​1101001000Nerror(a) state L1 error and the error of dJh​/dahh2​00.511.52101001000N(b) ratios to the continuous values
Figure 70 · The page (solid) and the slip (dashed), unlimited linear reconstruction. (a) The state L1 error and the error of dJh/da\mathrm dJ_h/\mathrm da: up to N=256N=256 these two are even smaller for the slip, after that they converge only at first order; at N=4096N=4096 the slip's state error is 22.3 times the page's and its aa-gradient error 22.4 times. (b) ψ0/(h/2)\psi_0/(h/2) over λx(0)\lambda_x(0): the page tends to 1, the slip to 2 (the boundary moved to −h/2-h/2); the slip's own uˉin\bar u_{\rm in} (with its own cL(0)+ν/hc_L(0)+\nu/h) still tends to the continuous value (ratio 1.00002 at N=4096N=4096).

教训有三条。粗网格上的吻合不能证明边界处理正确:N≤256N\le256 时错误版本的状态误差和 aa 分量的梯度误差更小(但它的 ν\nu 分量的梯度误差在每个网格上都更大,N=128N=128 时为 0.285,本页为 0.157;φ\varphi 分量的梯度误差在 N=8N=8 时也更大)。把收敛阶测到伴随的层被分辨之后,错误才显出来:二阶格式降为一阶(最细两层之间状态误差的阶 0.88,梯度 0.88,仍在向 1 增加)。边界关系 ψ0/(h/2)→λx(0)\psi_0/(h/2)\to\lambda_x(0) 是更灵敏的检验:ψ0/(h/2)→2λx(0)\psi_0/(h/2)\to2\lambda_x(0) 直接暴露了边界位置错了半个单元;uˉin\bar u_{\rm in} 却暴露不了,它对错误版本仍趋于连续值。错误版本自己的切线、伴随和点积检验都完全正确——它们检验的是程序的导数,而不检验程序离散的究竟是哪个方程。

Three lessons. Agreement on coarse meshes does not prove a boundary treatment right: for N≤256N\le256 the slip has the smaller state and aa-gradient errors (though its ν\nu-gradient error is larger on every mesh, 0.285 against 0.157 at N=128N=128, and its φ\varphi-gradient error is larger at N=8N=8). Measuring the order beyond the resolution of the adjoint's layer exposes it: the second-order scheme drops to first order (state error order 0.88 and gradient 0.88 between the two finest levels, still rising towards 1). The boundary relation ψ0/(h/2)→λx(0)\psi_0/(h/2)\to\lambda_x(0) is the sharper test: ψ0/(h/2)→2λx(0)\psi_0/(h/2)\to2\lambda_x(0) shows directly that the boundary sits half a cell off; uˉin\bar u_{\rm in} cannot show it, since for the slip it still tends to the continuous value. The slip's own tangent, adjoint and dot test are all perfectly right; they test the derivative of the program, not which equation the program discretises.

本节测到的:离散伴随与连续伴随一致——ψi→λ(xi)\psi_i\to\lambda(x_i)(无限制器线性二阶、一阶格式一阶),离散梯度连同源项部分与边界部分都趋于连续值。但在粗网格上(N<91N<91),本页格式的梯度虽是 Jh(D)J_h(D) 的导数(精确到舍入误差),却离连续梯度很远:N=8N=8 时 dJh/da=−0.487\mathrm dJ_h/\mathrm da=−0.487,连续值为 −0.144。这个误差主要来自两个不重构的端单元(第 15 节),而不是伴随的层没被分辨本身:重构端单元后伴随的层同样没被分辨,aa 分量的梯度误差却从 N=8N=8 时的 0.343 降到 0.030,N=32N=32 时从 0.107 降到 4×10−44\times10^{-4}。这些都只是本问题上的数值证据。

What this section measured: the discrete adjoint is consistent with the continuous one: ψi→λ(xi)\psi_i\to\lambda(x_i) (second order for unlimited linear, first order for the first-order scheme), and the discrete gradient, with its source part and its boundary part, tends to the continuous values. But on coarse meshes (N<91N<91) the gradient of the page's scheme, although it is the derivative of Jh(D)J_h(D), exact up to rounding, is far from the continuous one: dJh/da=−0.487\mathrm dJ_h/\mathrm da=−0.487 against −0.144 at N=8N=8. Most of this error comes from the two unreconstructed end cells (Section 15), not from the adjoint's unresolved layer itself: reconstructing them leaves the adjoint's layer just as unresolved but reduces the aa-gradient error from 0.343 to 0.030 at N=8N=8 and from 0.107 to 4×10−44\times10^{-4} at N=32N=32. All of this is numerical evidence for this one problem.

第 17 节Section 17

GS 与 GMRES:迭代及其转置

GS and GMRES: the iterations and their transposes

本节实验:先估计一下,N=64N=64 时(无限制器线性)切线方程的 GS 要迭代多少次?伴随方程是否一样多?然后用本节的收敛面板验证。

Experiment: Estimate first how many GS iterations the tangent system needs at N=64N=64 (unlimited linear), and whether the adjoint system needs the same number. Then check with the convergence panel of this section.

第 10 节和第 11 节用 LU 解 Avk=−RDekAv_k=-R_De_k 与 ATψ=−gA^T\psi=-g。全局控件的网格很小,模型直接分解稠密矩阵;第 11、12、15–17 节的面板用带状 LU:AA 只有五条带,分解和回代都是 O(N)O(N)。二维、三维问题里直接分解会产生大量填充,迭代法取而代之。本节为本页自己的两个方程构造两种迭代,如实测量它们,并说明对伴随最重要的结构:伴随迭代是切线迭代的转置。

Section 10 and Section 11 solve Avk=−RDekAv_k=-R_De_k and ATψ=−gA^T\psi=-g with LU. The meshes of the global controls are small and the model factors the dense matrix; the panels of Sections 11, 12 and 15–17 use a band LU: AA has only five bands, so factorisation and solution cost O(N)O(N). In two and three dimensions a direct factorisation fills in and iterations take over. This section builds two iterations for the page's own two systems, measures them honestly, and shows the structure that matters most for adjoints: the adjoint iteration is the transpose of the tangent iteration.

两个方程与直接解法

The two systems and the direct solve

两个方程都写成 Kx=bKx=b:切线方程取 K=AK=A、b=−RDekb=-R_De_k、x=vkx=v_k;伴随方程取 K=ATK=A^T、b=−gb=-g、x=ψx=\psi。本节里 xx 只表示这个未知向量,不表示坐标,KK 也与第 8 节的 KfK_f 无关。

Both systems are written Kx=bKx=b: the tangent system has K=AK=A, b=−RDekb=-R_De_k, x=vkx=v_k; the adjoint system K=ATK=A^T, b=−gb=-g, x=ψx=\psi. In this section xx is only this unknown vector, never the coordinate, and KK has nothing to do with the KfK_f of Section 8.

Kx=b,(K, b, x)∈{(A, −RDek, vk), (AT, −g, ψ)}.Kx=b,\qquad (K,\,b,\,x)\in\bigl\{(A,\,-R_De_k,\,v_k),\ (A^T,\,-g,\,\psi)\bigr\}.

AA 有两条下带、两条上带(一阶格式各一条):一个面的通量涉及 Uf−2,…,Uf+1U_{f-2},\dots,U_{f+1},一行用两个面。整条带只要前向代码的五次乘积,而不是 NN 次:每个种子是每隔五列取一列的单位向量 eje_j 之和(按 jj 除以 5 的余数分成五组);同一种子所含各列在任一行中都不会同时有非零元,所以每次乘积给出带的五分之一(核对:与模型逐列求出的 Jacobian 完全相同,差为 0)。部分选主元的 LU 分解仍保持带状(行交换另需两条上带):N=128N=128 时分解加一次回代共 1885 次运算(乘加 1504 次、除法 381 次,行交换 123 次),每个未知量约 14.7 次;伴随方程分解 ATA^T,代价相同。

AA has two sub- and two superdiagonals (one each at first order): the flux of a face involves Uf−2,…,Uf+1U_{f-2},\dots,U_{f+1} and a row uses two faces. The whole band takes five products of the tangent code, not NN: each seed is the sum of the unit vectors eje_j of every fifth column (one seed per residue of jj modulo 5); the columns summed in one seed never both have a nonzero in the same row, so each product delivers a fifth of the band (checked: identical to the model's column-by-column Jacobian, difference 0). LU with partial pivoting keeps the band (the row interchanges need two more superdiagonals): at N=128N=128 factorisation and one solve take 1885 operations (1504 multiply-adds and 381 divisions, with 123 row interchanges), about 14.7 per unknown; the adjoint factorises ATA^T at the same cost.

以一阶 Jacobian 作预处理的 GS 缺陷校正

GS defect correction with the first-order Jacobian

设 PP 是一阶残差在同一状态处的 Jacobian(三条带;一阶格式时 P=AP=A)。在 Pz=rPz=r 上从零出发做一次 GS 扫描,按单元顺序依次求出:

Let PP be the Jacobian of the first-order residual at the same state (three bands; P=AP=A for the first-order scheme). One GS sweep from zero on Pz=rPz=r runs through the cells in order:

zi=1Pii(ri−∑j<iPij zj),i=0,1,…,N−1;z=Br,B=(diag⁡P+LP)−1,z_i=\frac{1}{P_{ii}}\Bigl(r_i-\sum_{j<i}P_{ij}\,z_j\Bigr),\quad i=0,1,\dots,N-1;\qquad z=Br,\qquad B=(\operatorname{diag}P+L_P)^{-1},

LPL_P 是 PP 的严格下三角部分,zz 是扫描的输出(不是第 1 节的相位 zz)。缺陷校正把扫描 BB 作用在精确算子的残差上:

with LPL_P the strictly lower part of PP and zz the output of the sweep (not the phase zz of Section 1). The defect correction applies the sweep BB to the residual of the exact operator:

Δxm=ω B (b−Kxm),xm+1=xm+Δxm,x0=0.\Delta x^m=\omega\,B\,(b-Kx^m),\qquad x^{m+1}=x^m+\Delta x^m,\qquad x^0=0.

减去精确解 xx:误差满足 xm+1−x=(I−ωBA)(xm−x)x^{m+1}-x=(I-\omega BA)(x^m-x)(切线方程)。对任意初值收敛当且仅当误差传播矩阵的谱半径 ρ(I−ωBA)<1\rho(I-\omega BA)<1;进入渐近阶段后,误差每迭代一次约乘以 ρ\rho。迭代只需要 KxKx:按无矩阵(matrix-free)方式实现时,切线方程用第 8 节的 residual_d,伴随方程用第 9 节的 residual_b;需要存储的只有 PP 的三条带。

Subtract the solution xx: the error obeys xm+1−x=(I−ωBA)(xm−x)x^{m+1}-x=(I-\omega BA)(x^m-x) (tangent system). The iteration converges from every start exactly when the spectral radius of the error propagation matrix is below one, ρ(I−ωBA)<1\rho(I-\omega BA)<1; once the asymptotic phase is reached, every iteration multiplies the error by about ρ\rho. The iteration needs only products KxKx: implemented matrix-free, the tangent system uses residual_d of Section 8 and the adjoint system residual_b of Section 9; only the three bands of PP are stored.

伴随迭代是切线迭代的转置

The adjoint iteration is the transpose of the tangent iteration

从零出发做 mm 次切线迭代,结果对 bb 是线性的:

Run the tangent iteration mm times from zero; the result is linear in bb:

xm=ℳm b,ℳm=∑k=0m−1(I−ωBA)k ωB.x^m=\mathcal M_m\,b,\qquad \mathcal M_m=\sum_{k=0}^{m-1}(I-\omega BA)^k\,\omega B.

逐项转置,并把 BTB^T 穿过幂次(BT(ATBT)k=(BTAT)kBTB^T(A^TB^T)^k=(B^TA^T)^kB^T):

Transpose term by term and move BTB^T through the power (BT(ATBT)k=(BTAT)kBTB^T(A^TB^T)^k=(B^TA^T)^kB^T):

ℳmT=∑k=0m−1ωBT(I−ωATBT)k=∑k=0m−1(I−ωBTAT)k ωBT.\mathcal M_m^T=\sum_{k=0}^{m-1}\omega B^T\bigl(I-\omega A^TB^T\bigr)^k=\sum_{k=0}^{m-1}\bigl(I-\omega B^TA^T\bigr)^k\,\omega B^T.

这正是伴随方程迭代 ψm+1=ψm+ωBT(b−ATψm)\psi^{m+1}=\psi^m+\omega B^T(b-A^T\psi^m) 的 mm 步映射。而 BT=(diag⁡P+LPT)−1B^T=(\operatorname{diag}P+L_P^T)^{-1}:解 (diag⁡P+LPT)z=r(\operatorname{diag}P+L_P^T)z=r 从最后一个单元开始,

This is the mm-step map of the adjoint iteration ψm+1=ψm+ωBT(b−ATψm)\psi^{m+1}=\psi^m+\omega B^T(b-A^T\psi^m). And BT=(diag⁡P+LPT)−1B^T=(\operatorname{diag}P+L_P^T)^{-1}: solving (diag⁡P+LPT)z=r(\operatorname{diag}P+L_P^T)z=r starts from the last cell,

zi=1Pii(ri−∑j>iPji zj),i=N−1,…,1,0,z_i=\frac{1}{P_{ii}}\Bigl(r_i-\sum_{j>i}P_{ji}\,z_j\Bigr),\quad i=N-1,\dots,1,0,

即在 PTP^T 上反向扫描。由此得到四个结论,都已测量:

a backward sweep on PTP^T. Four consequences, all measured:

  • 迭代的点积检验。对任意 bb、b′b' 和每个 mm,b′T(ℳmb)=(ℳmTb′)Tbb'^T(\mathcal M_mb)=(\mathcal M_m^Tb')^Tb。随机的 b,b′b,b'(N=16N=16,m=1,…,60m=1,\dots,60)测得最大相对差 4×10−154\times10^{-15};Python 审计显式构造两个 mm 步矩阵(m≤20m\le20,N=8,16,32N=8,16,32,三种重构),差在 10−1510^{-15} 量级。Dot test of the iterations. b′T(ℳmb)=(ℳmTb′)Tbb'^T(\mathcal M_mb)=(\mathcal M_m^Tb')^Tb for all bb, b′b' and every mm. With random b,b′b,b' (N=16N=16, m=1,…,60m=1,\dots,60) the largest relative difference is 4×10−154\times10^{-15}; the Python audit forms both mm-step matrices explicitly (m≤20m\le20, N=8,16,32N=8,16,32, three reconstructions) and finds differences of order 10−1510^{-15}.
  • 截断的梯度在每一步都相等。令 vkm=ℳm(−RDek)v_k^m=\mathcal M_m(-R_De_k)、ψm=ℳmT(−g)\psi^m=\mathcal M_m^T(-g),则 wTvkm=−(ℳmTw)TRDekw^Tv_k^m=-(\mathcal M_m^Tw)^TR_De_k,也就是 (ψm)TRDek(\psi^m)^TR_De_k:切线 GS 与伴随 GS 迭代 mm 次后给出同一个导数,此时两者都还没收敛(图 71,最大差 7×10−167\times10^{-16})。The truncated gradients agree at every step. With vkm=ℳm(−RDek)v_k^m=\mathcal M_m(-R_De_k) and ψm=ℳmT(−g)\psi^m=\mathcal M_m^T(-g), wTvkm=−(ℳmTw)TRDekw^Tv_k^m=-(\mathcal M_m^Tw)^TR_De_k, which is (ψm)TRDek(\psi^m)^TR_De_k: tangent GS and adjoint GS give the same derivative after mm iterations, while neither has converged (Figure 71, largest difference 7×10−167\times10^{-16}).
  • 转置的扫描是反向的。伴随把信息从出口带向入口(第 16 节),反向扫描顺着这个方向。在 PTP^T 上做前向扫描也是伴随方程的一种合法迭代,但它不是切线迭代的转置。粗网格上它慢得多(N=16N=16:246 次,转置迭代 70 次),但网格 Péclet 数 uinh/νu_{\rm in}h/\nu 降到约 2 以下后就不再如此(N=64N=64:前向扫描 267 次,转置迭代 267 次;N=512N=512:前向扫描 7883 次,转置迭代 7517 次;光滑限制器在 N=64N=64 时前向扫描反而更快:278 次,转置迭代 296 次)。The transposed sweep runs backward. The adjoint carries information from the outlet to the inlet (Section 16), and the backward sweep follows that direction. A forward sweep on PTP^T is also a valid iteration for the adjoint system, but it is not the transpose of the tangent iteration. On coarse meshes it is much slower (N=16N=16: 246 iterations against 70 for the transposed one), but not once the cell Péclet number uinh/νu_{\rm in}h/\nu drops below about 2 (N=64N=64: forward sweep 267, transposed 267; N=512N=512: forward sweep 7883, transposed 7517; with the smooth limiter at N=64N=64 the forward sweep is even faster: 278 against 296 for the transposed one).
  • 同样的渐近速度。I−ωBTAT=BT(I−ωBA)TB−TI-\omega B^TA^T=B^T(I-\omega BA)^TB^{-T} 与 (I−ωBA)T(I-\omega BA)^T 相似,所以两个误差传播矩阵的特征值相同;测得的谱半径相差约 2×10−92\times10^{-9}(受舍入误差限制:在双精度下,这类非对称矩阵的特征值只能算到这个精度,numpy 的 LAPACK 给出同类的差别)。迭代次数仍可略有不同(右端项不同,见下表)。The same asymptotic rate. I−ωBTAT=BT(I−ωBA)TB−TI-\omega B^TA^T=B^T(I-\omega BA)^TB^{-T} is similar to (I−ωBA)T(I-\omega BA)^T, so the two error propagation matrices have the same eigenvalues; the measured spectral radii differ by about 2×10−92\times10^{-9} (limited by rounding: in double precision the eigenvalues of such non-symmetric matrices cannot be computed more accurately, and numpy's LAPACK shows differences of the same kind). The iteration counts can still differ a little (different right-hand sides; table below).
图 71 · 迭代 m 次后的导数 dJ_h/ da(无限制器线性,N=16)。切线 GS 的 w^Tv^m(粗线)与伴随 GS 的 (ψ^m)^TR_De_0(点)在每一步重合;切线与伴随 GMRES(虚线)在收敛前不同,只在收敛后一致;点线是收敛值 −0.3506。切线 GS:wT​ vm​伴随 GS:(ψm​)T​ RD​ e0​切线 GMRES伴随 GMRES收敛值−0.7−0.6−0.5−0.4−0.3−0.2−0.100510152025303540迭代次数 mdJh​/da
图 71 · 迭代 mm 次后的导数 dJh/da\mathrm dJ_h/\mathrm da(无限制器线性,N=16N=16)。切线 GS 的 wTvmw^Tv^m(粗线)与伴随 GS 的 (ψm)TRDe0(\psi^m)^TR_De_0(点)在每一步重合;切线与伴随 GMRES(虚线)在收敛前不同,只在收敛后一致;点线是收敛值 −0.3506。
Figure 71 · The derivative dJ_h/ da after m iterations (unlimited linear, N=16). The tangent GS value w^Tv^m (thick) and the adjoint GS value (ψ^m)^TR_De_0 (dots) coincide at every step; the tangent and adjoint GMRES values (dashed) differ before convergence and agree only after it; dotted: the converged value −0.3506.tangent GS: wT​ vm​adjoint GS: (ψm​)T​ RD​ e0​tangent GMRESadjoint GMRESconverged value−0.7−0.6−0.5−0.4−0.3−0.2−0.100510152025303540iterations mdJh​/da
Figure 71 · The derivative dJh/da\mathrm dJ_h/\mathrm da after mm iterations (unlimited linear, N=16N=16). The tangent GS value wTvmw^Tv^m (thick) and the adjoint GS value (ψm)TRDe0(\psi^m)^TR_De_0 (dots) coincide at every step; the tangent and adjoint GMRES values (dashed) differ before convergence and agree only after it; dotted: the converged value −0.3506.

GMRES

GMRES

GMRES 保留已经产生的方向,把它们组合起来。用同一个扫描 BB 作右预处理,第 mm 步的近似解为

GMRES keeps the directions it has generated and combines them. Right-preconditioned with the same sweep BB, the mm-th approximation is

xm=B ym,ym=arg⁡min⁡y∈𝒦m∥b−KBy∥2,𝒦m=span⁡{b, KBb, …, (KB)m−1b},x^m=B\,y^m,\qquad y^m=\arg\min_{y\in\mathcal K_m}\|b-KBy\|_2,\qquad \mathcal K_m=\operatorname{span}\bigl\{b,\,KBb,\,\dots,\,(KB)^{m-1}b\bigr\},

用 Arnoldi 过程(修正 Gram–Schmidt 做两遍)和 Givens 旋转计算;本页每一步都记录真实残差 ∥b−Kxm∥2\|b-Kx^m\|_2。重启版本每走固定步数(5、10 或 30 步)就从当前解重新开始,以限制存储。伴随版本用 K=ATK=A^T 与 BTB^T。由定义可得两点:不重启时 GMRES 至多 NN 步就得到精确解(测量:N=8N=8 时 8 步,N=16N=16 时 16 步);GMRES 对 bb 不是线性的,ymy^m 通过极小化依赖 bb,所以没有 GS 那样的 mm 步转置:切线与伴随 GMRES 的导数在收敛前不同(N=16N=16、m≤6m\le6 时差可达 0.273),收敛后才一致(差 9×10−169\times10^{-16})。

computed with the Arnoldi process (modified Gram–Schmidt, two passes) and Givens rotations; the page records the true residual ∥b−Kxm∥2\|b-Kx^m\|_2 after every step. The restarted versions start again from the current iterate after a fixed number of steps (5, 10 or 30) to bound the storage. The adjoint version uses K=ATK=A^T and BTB^T. Two facts follow from the definition: without restarts GMRES reaches the exact solution in at most NN steps (measured: 8 steps at N=8N=8, 16 at N=16N=16); and GMRES is not linear in bb, since ymy^m depends on bb through the minimisation, so there is no mm-step transposition as for GS: the tangent and adjoint GMRES derivatives differ before convergence (up to 0.273 for m≤6m\le6 at N=16N=16) and agree once both have converged (difference 9×10−169\times10^{-16}).

测量:迭代次数、谱半径、代价

Measurements: iterations, spectral radius, cost

下表数的是使 ∥b−Kxm∥2≤10−10∥b∥2\|b-Kx^m\|_2\le10^{-10}\|b\|_2 的迭代次数(“切线/伴随”,切线方程取 k=0k=0,即振幅 aa),无限制器线性重构,默认设计;GMRES(NN) 即不重启(NN 步内得到精确解),ω=0.65\omega=0.65 的次数见收敛面板;N=256N=256、512 只列重启的 GMRES。ρ\rho 是 I−BAI-BA 的谱半径,ln⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rho 是由它预测的次数。第 6 节的图 18 用另一个标准(缺陷的最大范数降到 10−1210^{-12},对象是第一个 Newton 修正方程),所以同一个 NN 的次数不同。Python 审计用自己的稠密 GS、GMRES(numpy)复现了每一个次数(重启的 GMRES 在 N≥256N\ge256 时相差不超过 2%),用 numpy 的特征值复现了每一个谱半径。

The table counts the iterations until ∥b−Kxm∥2≤10−10∥b∥2\|b-Kx^m\|_2\le10^{-10}\|b\|_2 (“tangent / adjoint”, the tangent system for k=0k=0, the amplitude aa), unlimited linear reconstruction, default design; GMRES(NN) is GMRES without restart (exact within NN steps); the counts for ω=0.65\omega=0.65 are in the convergence panel; for N=256N=256 and 512 only the restarted GMRES is listed. ρ\rho is the spectral radius of I−BAI-BA, and ln⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rho the count it predicts. Figure 18 of Section 6 uses another criterion (the defect in the maximum norm down to 10−1210^{-12}, on the first Newton correction system), so its counts for the same NN differ. The Python audit reproduces every count with its own dense GS and GMRES (numpy; the restarted GMRES within 2% for N≥256N\ge256) and every spectral radius with numpy's eigenvalues.

NGS ω=1\omega=1ω=0.8\omega=0.8ω=0.5\omega=0.5ρ\rholn⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rhoGMRES(5)GMRES(10)GMRES(30)GMRES(NN)
845 / 4560 / 60102 / 1050.57484220 / 238 / 88 / 88 / 8
1670 / 7091 / 92153 / 1550.67865951 / 4239 / 3116 / 1616 / 16
32114 / 117148 / 151248 / 2530.76188564 / 6269 / 5329 / 2929 / 29
64253 / 267321 / 339523 / 5520.8757173100 / 94124 / 12988 / 8647 / 45
128642 / 704806 / 8841300 / 14250.9481432163 / 137211 / 207315 / 44984 / 81
256271 / 272358 / 288614 / 658
5121088 / 895602 / 665920 / 839

三种重构对比(GS,ω=1\omega=1,切线/伴随,以及 ρ\rho):

The three reconstructions side by side (GS, ω=1\omega=1, tangent / adjoint, and ρ\rho):

N一阶first无限制器none光滑smoothρ\rho(一阶)ρ\rho (first)ρ\rho(无限制器)ρ\rho (none)ρ\rho(光滑)ρ\rho (smooth)
875 / 8045 / 4566 / 710.74870.57480.7168
16109 / 12770 / 7087 / 910.82900.67860.7617
32193 / 205114 / 117122 / 1250.88400.76180.7870
64363 / 385253 / 267280 / 2960.93050.87570.9016
128818 / 888642 / 704730 / 7940.96550.94810.9601
图 72 · 迭代次数随 N 的变化(切线方程,分量 a,默认设计)。从 N=32 起(网格 Péclet 数 u_inh/ν ≤ 2.86),GS 的迭代次数增长得比 N 快:无限制器线性从 N=32 的 114 次、N=64 的 253 次到 N=512 的 6206 次;紫线是 h=ν/u_in(网格 Péclet 数为 1);GMRES 次数少得多:N=512 时 GMRES(30) 要 920 次,GS 要 6206 次。点线:带状 LU 的运算次数折合成 GS 迭代,约 1.8 次。GS(一阶)GS(无限制器)GS(光滑)GMRES(30)(无限制器)GMRES 不重启(无限制器)带状 LU 的代价(折合成 GS 迭代)110102​103​104​10100单元数 N迭代次数(切线方程,分量 a)h = ν/uin​NN2​
图 72 · 迭代次数随 NN 的变化(切线方程,分量 aa,默认设计)。从 N=32N=32 起(网格 Péclet 数 uinh/ν≤2.86u_{\rm in}h/\nu\le2.86),GS 的迭代次数增长得比 NN 快:无限制器线性从 N=32N=32 的 114 次、N=64N=64 的 253 次到 N=512N=512 的 6206 次;紫线是 h=ν/uinh=\nu/u_{\rm in}(网格 Péclet 数为 1);GMRES 次数少得多:N=512N=512 时 GMRES(30) 要 920 次,GS 要 6206 次。点线:带状 LU 的运算次数折合成 GS 迭代,约 1.8 次。
Figure 72 · Iterations against N (tangent system, component a, default design). From N=32 on (cell Péclet number u_inh/ν ≤ 2.86) the GS count grows faster than N: from 114 at N=32 and 253 at N=64 to 6206 at N=512 for unlimited linear; the violet line marks h=ν/u_in (cell Péclet number 1); GMRES needs far fewer: 920 for GMRES(30) at N=512 against 6206 for GS. Dotted: the operations of the band LU expressed in GS iterations, about 1.8.GS firstGS noneGS smoothGMRES(30) noneGMRES no restart, nonecost of band LU (in GS iterations)110102​103​104​10100cells Niterations (tangent, component a)h = ν/uin​NN2​
Figure 72 · Iterations against NN (tangent system, component aa, default design). From N=32N=32 on (cell Péclet number uinh/ν≤2.86u_{\rm in}h/\nu\le2.86) the GS count grows faster than NN: from 114 at N=32N=32 and 253 at N=64N=64 to 6206 at N=512N=512 for unlimited linear; the violet line marks h=ν/uinh=\nu/u_{\rm in} (cell Péclet number 1); GMRES needs far fewer: 920 for GMRES(30) at N=512N=512 against 6206 for GS. Dotted: the operations of the band LU expressed in GS iterations, about 1.8.
图 73 · (a) N=32 时 GS 误差传播矩阵 I-BA 的特征值都在单位圆内(无限制器线性:圆点,虚线圆半径 ρ=0.7618;一阶:方块)。(b) 谱半径随 N 增大趋于 1:网格越细,GS 越慢。一阶无限制器光滑单位圆半径 ρ(无限制器)−1−0.500.51−1−0.500.51ReIm(a) I − BA 的特征值,N = 320.50.60.70.80.9110100Nρ(I − BA)(b) 谱半径随 N 的变化
图 73 · (a) N=32N=32 时 GS 误差传播矩阵 I−BAI-BA 的特征值都在单位圆内(无限制器线性:圆点,虚线圆半径 ρ=0.7618\rho=0.7618;一阶:方块)。(b) 谱半径随 NN 增大趋于 1:网格越细,GS 越慢。
Figure 73 · (a) At N=32 every eigenvalue of the GS error propagation matrix I-BA lies inside the unit circle (unlimited linear: dots, dashed circle of radius ρ=0.7618; first order: squares). (b) The spectral radius tends to 1 as N grows: the finer the mesh, the slower GS.firstnonesmoothunit circleradius ρ (none)−1−0.500.51−1−0.500.51ReIm(a) eigenvalues of I − BA, N = 320.50.60.70.80.9110100Nρ(I − BA)(b) spectral radius against N
Figure 73 · (a) At N=32N=32 every eigenvalue of the GS error propagation matrix I−BAI-BA lies inside the unit circle (unlimited linear: dots, dashed circle of radius ρ=0.7618\rho=0.7618; first order: squares). (b) The spectral radius tends to 1 as NN grows: the finer the mesh, the slower GS.

结论(测量,不是定理):(1) GS 在测到的所有情形都收敛,但慢,而且网格越细越慢:无限制器线性 ρ\rho 从 0.575(N=8N=8)升到 0.948(N=128N=128),次数从 45 升到 642。(2) 欠松弛在这里没有帮助:设 μ\mu 是 BABA 中使 ∣1−μ∣|1-\mu| 最大的特征值,若 μ\mu 落在圆盘 ∣μ−12∣<12|\mu-\tfrac12|<\tfrac12 内,则 ∣1−ωμ∣|1-\omega\mu| 随 ω\omega 从 1 减小而增大;测得的所有情形里 ∣μ−12∣≤0.466|\mu-\tfrac12|\le0.466,所以 ρ(ω)\rho(\omega) 随 ω\omega 减小而变大。(3) ln⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rho 给出量级。无限制器线性的实际次数总是更多(N=128N=128:预测 432,实测 642):开始的 300 次迭代里残差平均每次只乘以 0.980,最后 300 次才是 0.951(ρ=0.948\rho=0.948),预测忽略了渐近阶段之前的过渡。在 N=8N=8 时,一阶与光滑限制器的切线方程实测次数反而比预测略少(一阶:实测 75,预测 80;光滑限制器:实测 66,预测 69)。(4) GMRES 次数少得多(不重启时 N=128N=128 伴随 81 次)。重启后的迭代次数随重启长度的变化却不单调:N=128N=128 时伴随 GMRES(30) 要 449 次,比 GMRES(10) 的 207 次和 GMRES(5) 的 137 次都多,N=512N=512 时 GMRES(5) 又最慢(895 次,GMRES(10) 665 次);更长的重启不保证更快,这里只有不重启的 GMRES 稳妥(至多 NN 步)。(5) 代价:一次 GS 迭代约 8.0N8.0N 次运算,带状 LU 分解加回代约 14.7N14.7N;GMRES 每一步再加上正交化,每个已存方向约 4N4N。一维问题里直接求解的代价只相当于约 1.8 次 GS 迭代:这里讲迭代是为了它们的结构,以及二维、三维问题,而不是为了一维里的速度。

Conclusions (measured, not theorems): (1) GS converges in every case measured, but slowly, and the more slowly the finer the mesh: for unlimited linear ρ\rho rises from 0.575 (N=8N=8) to 0.948 (N=128N=128) and the count from 45 to 642. (2) Under-relaxation does not help here: let μ\mu be the eigenvalue of BABA with the largest ∣1−μ∣|1-\mu|; if μ\mu lies in the disk ∣μ−12∣<12|\mu-\tfrac12|<\tfrac12, then ∣1−ωμ∣|1-\omega\mu| grows as ω\omega decreases from 1; in every case measured ∣μ−12∣≤0.466|\mu-\tfrac12|\le0.466, so ρ(ω)\rho(\omega) grows as ω\omega decreases. (3) ln⁡10−10/ln⁡ρ\ln10^{-10}/\ln\rho gives the order of magnitude. For unlimited linear the actual counts are always higher (at N=128N=128: 432 predicted, 642 measured): over the first 300 iterations the residual is multiplied on average by only 0.980 per iteration, over the last 300 by 0.951 (ρ=0.948\rho=0.948); the prediction ignores the transient before the asymptotic phase. For the tangent system at N=8N=8, first order and the smooth limiter need slightly fewer iterations than predicted (first order 75 measured, 80 predicted; smooth 66 measured, 69 predicted). (4) GMRES needs far fewer iterations (81 for the adjoint at N=128N=128 without restart). The restarted counts, however, are not monotone in the restart length: at N=128N=128 the adjoint GMRES(30) needs 449, more than GMRES(10) with 207 and GMRES(5) with 137, and at N=512N=512 GMRES(5) is the slowest (895, GMRES(10) 665); a longer restart guarantees nothing, and only unrestarted GMRES is dependable here (at most NN steps). (5) Cost: a GS iteration takes about 8.0N8.0N operations, the band LU factorisation and solve about 14.7N14.7N; a GMRES step adds the orthogonalisation, about 4N4N per stored direction. In one dimension the direct solve costs about 1.8 GS iterations: the iterations are taught here for their structure and for two and three dimensions, not for speed in one.

Nuinh/νu_{\rm in}h/\nu伴随:反向扫描(转置)adjoint: backward sweep (transpose)伴随:前向扫描adjoint: forward sweep
165.7270246
641.43267267
1280.71704690
2560.3621712289
5120.1875177883

不要把 GS 的“截断导数相等”套用到 GMRES 上:GS 的 mm 步映射是线性的,转置关系在每一步成立;GMRES 不是线性映射,只有收敛后的结果满足对偶关系。用迭代解求梯度时,切线与伴随的结果只能在收敛后比较(GMRES),或在相同 mm、严格转置的迭代之间比较(GS,此时应在舍入误差内一致);这时的差别指向导数代码或转置的错误。

Do not carry the “equal truncated derivatives” of GS over to GMRES: the mm-step map of GS is linear and the transposition holds at every step; GMRES is not a linear map, and only its converged results satisfy the duality. When gradients come from iterative solves, compare the tangent and adjoint values only at convergence (GMRES) or at equal mm with exactly transposed iterations (GS, where they must agree to rounding); a difference there points to an error in the derivative code or the transposition.

第 18 节Section 18

总结:一个网格、一个通量、三个方向

Summary: one mesh, one flux, three directions

本节实验:对三个方向,各说出种子是什么、解哪个方程、得到什么;然后用本节的总览面板核对——它对当前控件把所有计算重做一遍。

Experiment: For each of the three directions, say what is seeded, which equation is solved and what comes out. Then check with the dashboard of this section, which redoes every calculation for the current controls.

本页只算了一件事:离散目标 Jh(D)=wT𝐔(D)J_h(D)=w^T\mathbf U(D) 对设计 D=(a,φ,ν)D=(a,\varphi,\nu) 的导数。它用三种方式计算,三者共用网格、面通量和重构;变化的只是传播的数据和数据流的方向。

The page computed one thing, the derivative of the discrete objective Jh(D)=wT𝐔(D)J_h(D)=w^T\mathbf U(D) with respect to the design D=(a,φ,ν)D=(a,\varphi,\nu), in three ways that share the mesh, the face flux and the reconstruction; only the data that are propagated and the direction of the data flow change.

图 74 · 三个方向的数据流和本页的数字(默认设计,N=8,无限制器线性)。原始:设计 → Newton 法解出 U → J_h=1.408114。切线:每个种子 D-dot=e_k 一次线性求解,得 J-dot_k=w^Tv_k。伴随:从目标的种子出发,一次转置求解得到 ψ,再得 D-bar=R_D^Tψ,三个分量同时得到;切线与伴随的结果相差 7 × 10^(-16)。原始D(0.2,0.07,0.01)R(U, D) = 0Newton 5 次U8 个单元值Jh​ = wT​ U1.408114切线D= ek​k = 0, 1, 2A vk​ = −RD​ ek​3 次线性求解vk​ =U3 × 8 个值Jk​= wT​ vk​(−0.4866,−0.0610,−0.3099)伴随D= RD​T​ ψ(−0.4866,−0.0610,−0.3099)ψ8 个值AT​ ψ = −g1 次线性求解J= 1, g = w目标的种子对偶:maxk​ |wT​ vk​ − ψT​ RD​ ek​| = 7.2e−16(N = 8,无限制器线性,默认设计)同一个网格、同一个面通量、同一个重构;变的只是数据和数据流的方向
图 74 · 三个方向的数据流和本页的数字(默认设计,N=8N=8,无限制器线性)。原始:设计 → Newton 法解出 𝐔\mathbf U → Jh=1.408114J_h=1.408114。切线:每个种子 D˙=ek\dot D=e_k 一次线性求解,得 J˙k=wTvk\dot J_k=w^Tv_k。伴随:从目标的种子出发,一次转置求解得到 ψ\psi,再得 Dˉ=RDTψ\bar D=R_D^T\psi,三个分量同时得到;切线与伴随的结果相差 7×10−167\times10^{-16}。
Figure 74 · The data flow of the three directions with the page's numbers (default design, N=8, unlimited linear). Primal: design → Newton gives U → J_h=1.408114. Tangent: one linear solve per seed D-dot=e_k gives J-dot_k=w^Tv_k. Adjoint: from the seed of the objective, one transposed solve gives ψ and then D-bar=R_D^Tψ, all three components at once; the tangent and adjoint results differ by 7 × 10^(-16).PrimalD(0.2, 0.07, 0.01)R(U, D) = 0Newton, 5 iterationsU8 cell valuesJh​ = wT​ U1.408114TangentD= ek​k = 0, 1, 2A vk​ = −RD​ ek​3 linear solvesvk​ =U3 × 8 valuesJk​= wT​ vk​(−0.4866, −0.0610, −0.3099)AdjointD= RD​T​ ψ(−0.4866, −0.0610, −0.3099)ψ8 valuesAT​ ψ = −g1 linear solveJ= 1, g = wthe seed of the objectiveduality: maxk​ |wT​ vk​ − ψT​ RD​ ek​| = 7.2e−16 (N = 8, unlimited linear, default design)the same mesh, the same face flux, the same reconstruction; only the data and the direction of the data flow change
Figure 74 · The data flow of the three directions with the page's numbers (default design, N=8N=8, unlimited linear). Primal: design → Newton gives 𝐔\mathbf U → Jh=1.408114J_h=1.408114. Tangent: one linear solve per seed D˙=ek\dot D=e_k gives J˙k=wTvk\dot J_k=w^Tv_k. Adjoint: from the seed of the objective, one transposed solve gives ψ\psi and then Dˉ=RDTψ\bar D=R_D^T\psi, all three components at once; the tangent and adjoint results differ by 7×10−167\times10^{-16}.

三个方向

Three directions

原始Primal前向(tangent)Forward (tangent)伴随(adjoint)Reverse (adjoint)
种子SeedDDDDD˙=ek\dot D=e_k(𝐔˙=v\dot{\mathbf U}=v)D˙=ek\dot D=e_k (𝐔˙=v\dot{\mathbf U}=v)Rˉ=ψ\bar R=\psi(来自 Jˉ=1\bar J=1,g=wg=w)Rˉ=ψ\bar R=\psi (from Jˉ=1\bar J=1, g=wg=w)
运行的代码Code that runs残差代码(取值、重构、通量、分发)the residual code (gather, reconstruct, flux, scatter)residual_d,同序residual_d, same orderresidual_b,逆序,累加 +=residual_b, reverse order, accumulating +=
要解的方程Equation solvedR(𝐔,D)=0R(\mathbf U,D)=0(Newton 法)R(𝐔,D)=0R(\mathbf U,D)=0 (Newton)Avk=−RDekAv_k=-R_De_kAvk=−RDekAv_k=-R_De_kATψ=−gA^T\psi=-gATψ=−gA^T\psi=-g
输出Output𝐔\mathbf U,Jh=wT𝐔J_h=w^T\mathbf U𝐔\mathbf U, Jh=wT𝐔J_h=w^T\mathbf UJ˙k=gTvk\dot J_k=g^Tv_kJ˙k=gTvk\dot J_k=g^Tv_kDˉ=RDTψ\bar D=R_D^T\psiDˉ=RDTψ\bar D=R_D^T\psi
每个梯度的求解次数Solves per gradient——每个设计分量一次(3)one per design component (3)1(与分量个数无关)1 (any number of components)
本页位置Where第 5 节Section 5第 8 节、第 10 节Section 8, Section 10第 9 节、第 11 节、第 12 节Section 9, Section 11, Section 12

切线与伴随由对偶恒等式连在一起:对任意种子 RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D(第 9 节的点积检验),在解上它变成 wTvk=ψTRDekw^Tv_k=\psi^TR_De_k。代价的差别也由此而来:切线每个设计分量要一次求解,伴随每个目标要一次求解;本页有 3 个分量、1 个目标。

The tangent and the adjoint are tied by the duality identity: RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D for any seeds (the dot test of Section 9), which at the solution becomes wTvk=ψTRDekw^Tv_k=\psi^TR_De_k. The difference in cost comes from the same place: the tangent needs one solve per design component, the adjoint one solve per objective; this page has 3 components and 1 objective.

图 75 · 同一个面循环的三种用法。原始(蓝):重构面上的迹,算通量,分发到左右两个单元。切线(绿):按同样的顺序传播带点的量,用同样的重构权重和在原始迹处求得的 c_L,c_R,κ_f。伴随(红):从右向左,先从残差的种子取 H-bar_f=R-bar_(f-1)-R-bar_f(分发的转置),再乘 c_L,c_R, ± κ_f,最后经转置的重构权重累加到模板里每个未知量上。原始UUf−2​, …, Uf+1​qL​, qR​, UL​, UR​取值 + 重构Hf​ = Hc​ + Hv​面通量Rf−1​ += Hf​Rf​ −= Hf​σi​H(qL​, qR​)分发切线U,D种子qL​,qR​,UL​,UR​同样的重构权重Hf​cL​qL​+ cR​qR​+ κf​ (UL​−UR​) + …Rf−1​+=Hf​Rf​−=Hf​σl​, σr​cL​, cR​, κf​同序伴随U+= …,D+= …转置的权重qL​= cL​Hf​,qR​= cR​Hf​UL​= κf​Hf​,UR​= −κf​Hf​Hf​=Rf−1​−Rf​取值(分发的转置)R种子 ψ 或 w+=cL​, cR​, κf​逆序三者共用网格、重构权重和在原始迹 qL​、qR​ 处求得的 cL​ = qL​/2 + 1、cR​ = qR​/2 − 1,以及 κf​ = ν/df​
图 75 · 同一个面循环的三种用法。原始(蓝):重构面上的迹,算通量,分发到左右两个单元。切线(绿):按同样的顺序传播带点的量,用同样的重构权重和在原始迹处求得的 cL,cR,κfc_L,c_R,\kappa_f。伴随(红):从右向左,先从残差的种子取 Hˉf=Rˉf−1−Rˉf\bar H_f=\bar R_{f-1}-\bar R_f(分发的转置),再乘 cL,cR,±κfc_L,c_R,\pm\kappa_f,最后经转置的重构权重累加到模板里每个未知量上。
Figure 75 · The same face loop used three ways. Primal (blue): reconstruct the traces on the face, evaluate the flux, scatter it to the two neighbouring cells. Tangent (green): propagate the dotted quantities in the same order, with the same reconstruction weights and the c_L,c_R,κ_f taken at the primal traces. Adjoint (red): from right to left, first gather H-bar_f=R-bar_(f-1)-R-bar_f from the residual seed (the transposed scatter), then multiply by c_L,c_R, ± κ_f, and finally accumulate through the transposed reconstruction weights into every unknown of the stencil.PrimalUUf−2​, …, Uf+1​qL​, qR​, UL​, UR​gather + reconstructHf​ = Hc​ + Hv​face fluxRf−1​ += Hf​Rf​ −= Hf​σi​H(qL​, qR​)scatterTangentU,DseedsqL​,qR​,UL​,UR​the same weightsHf​cL​qL​+ cR​qR​+ κf​ (UL​−UR​) + …Rf−1​+=Hf​Rf​−=Hf​σl​, σr​cL​, cR​, κf​same orderAdjointU+= …,D+= …transposed weightsqL​= cL​Hf​,qR​= cR​Hf​UL​= κf​Hf​,UR​= −κf​Hf​Hf​=Rf−1​−Rf​gather (transposed scatter)Rseed ψ or w+=cL​, cR​, κf​reverse orderall three share the mesh, the reconstruction weights, cL​ = qL​/2 + 1 and cR​ = qR​/2 − 1 taken at the primal traces qL​, qR​, and κf​ = ν/df​
Figure 75 · The same face loop used three ways. Primal (blue): reconstruct the traces on the face, evaluate the flux, scatter it to the two neighbouring cells. Tangent (green): propagate the dotted quantities in the same order, with the same reconstruction weights and the cL,cR,κfc_L,c_R,\kappa_f taken at the primal traces. Adjoint (red): from right to left, first gather Hˉf=Rˉf−1−Rˉf\bar H_f=\bar R_{f-1}-\bar R_f from the residual seed (the transposed scatter), then multiply by cL,cR,±κfc_L,c_R,\pm\kappa_f, and finally accumulate through the transposed reconstruction weights into every unknown of the stencil.

下面的播放器用当前控件,把这条链一步一步走一遍:每一步显示那一刻的数组。

The player below walks the chain step by step with the current controls, showing the arrays of each moment.

验证了什么,怎样验证

What was verified, and how

每一种检查回答一个不同的问题:点积检验问反向代码是不是前向代码的转置;“切线 = 伴随”问的是两个求解是否一致;复数步长和差分问导数是不是这个程序的导数;Python 数据问另一份独立实现是否给出同样的数;连续公式问连续推导本身;收敛阶问离散是否逼近连续。下表的数是本页在构建时运行各项检查所得的最大值,范围见各行所列的网格与种子(除非另注,取默认设计);各节打印的是它们自己的网格上的值,可能更小;“见”一栏给出解释该检查的小节;Python 审计(audit/audit_f.py 与 audit/ 中其他脚本)独立地复现了它们。

Each check answers a different question: the dot test asks whether the reverse code is the transpose of the tangent code; tangent = adjoint asks whether the two solves agree; complex step and finite differences ask whether the derivative is the derivative of this program; the Python data ask whether an independent implementation gives the same numbers; the continuous formula checks the continuous derivation itself; the orders ask whether the discretisation approaches the continuum. The numbers in the table are the largest values found by the checks that this page runs at build time, over the meshes and seeds named in each row (default design unless noted); the sections print the values for their own meshes, which can be smaller, and “See” names the section that explains the check; the Python audit (audit/audit_f.py and the other scripts in audit/) reproduces them independently.

检查Check最大偏差Largest discrepancy见See
点积检验:前向代码与反向代码(随机状态与种子,N=8,16,33N=8,16,33,相对)dot test of the tangent and reverse code (random states and seeds, N=8,16,33N=8,16,33, relative)1.5e−15第 9 节Section 9
切线梯度与伴随梯度之差(三种重构,N≤128N\le128)tangent gradient minus adjoint gradient (3 reconstructions, N≤128N\le128)6.3e−15第 11 节Section 11
贯穿整个求解的复数步长与伴随之差(N=8,16N=8,16)complex step through the solve minus adjoint (N=8,16N=8,16)1.7e−15第 14 节Section 14
扰动解的复残差 Im⁡R/τ\operatorname{Im}R/\taucomplex residual of the perturbed state, Im⁡R/τ\operatorname{Im}R/\tau1.2e−15第 14 节Section 14
GS 的 mm 步转置(相对)mm-step transposition of GS (relative)3.7e−15第 17 节Section 17
中心差分(τ=10−5\tau=10^{-5},完整重算)与伴随之差central differences (τ=10−5\tau=10^{-5}, full re-solves) minus adjoint1.6e−8第 13 节Section 13
与 Python 数据中的梯度之差(N=32,…,4096N=32,\dots,4096)difference from the gradients of the Python data (N=32,…,4096N=32,\dots,4096)3.9e−11第 15 节Section 15
ψ−λ\psi-\lambda 的 L1 范数与 Python 数据之差(相对)L1 norm of ψ−λ\psi-\lambda against the Python data (relative)2.1e−7第 16 节Section 16
连续梯度公式与精确梯度之差continuous gradient formula minus exact gradient1.0e−13附录 AAppendix A

收敛阶(Python 数据中最细的两层):无限制器线性的状态 L1 误差阶 1.99,梯度分量 dJ/da\mathrm dJ/\mathrm da 的误差阶 1.99(N=8192N=8192 到 16384);一阶格式为 0.99 与 0.99(N=2048N=2048 到 4096)。伴随本身:ψ−λ\psi-\lambda 的 L1 误差阶,无限制器线性 1.96(模型,N=4096N=4096),1.99(Python,N=16384N=16384;见第 15、16 节)。

Orders of convergence (between the two finest levels of the Python data): for unlimited linear reconstruction the state L1 error converges at 1.99 and the error of the gradient component dJ/da\mathrm dJ/\mathrm da at 1.99 (N=8192N=8192 to 16384); for the first-order scheme at 0.99 and 0.99 (N=2048N=2048 to 4096). The adjoint itself: the L1 error of ψ−λ\psi-\lambda converges at 1.96 for unlimited linear (model, N=4096N=4096) and 1.99 (Python, N=16384N=16384; see Sections 15 and 16).

图 76 · 验证的阶梯(对数轴)。检验导数代码的各项(点积、切线 = 伴随、复数步长、GS 转置,绿色)都在舍入误差量级,最大 6.3 × 10^(-15)。与参考解的比较(紫色:Python 数据的梯度 4 × 10^(-11) 和 ψ-λ 的 L1 范数 2 × 10^(-7),由求解容差和 solve_bvp 决定;连续公式 1 × 10^(-13))都比导数检验的最大值大十倍以上。中心差分(琥珀色)的 2 × 10^(-8) 是截断误差 (τ^2)/6|∂^3J_h/∂ D_k^3|:它来自一阶格式的 ν 分量(∂^3J_h/∂ ν^3=−956,(τ^2)/6|∂^3J_h|=1.6 × 10^(-8)),远大于舍入误差 ε_mach/τ ≈ 2 × 10^(-11)。对大小为 0.06 到 0.75 的梯度,它约能证实七位有效数字。10-17​10-15​10-13​10-11​10-9​10-7​10-5​点积检验:前向代码与反向代码(随机状态与种子)1.5e−15切线梯度与伴随梯度之差(三种重构,N ≤ 128)6.3e−15贯穿整个求解的复数步长与伴随之差1.7e−15扰动解的复残差 Im R/τ1.2e−15GS 的 m 步转置(相对)3.7e−15中心差分(τ = 10−5​,完整重算)与伴随之差1.6e−8与 Python 数据中的梯度之差(N = 32 … 4096)3.9e−11ψ − λ 的 L1 范数与 Python 数据之差(相对)2.1e−7连续梯度公式与精确梯度之差1.0e−13导数代码的检验中心差分与参考解比较
图 76 · 验证的阶梯(对数轴)。检验导数代码的各项(点积、切线 = 伴随、复数步长、GS 转置,绿色)都在舍入误差量级,最大 6.3×10−156.3\times10^{-15}。与参考解的比较(紫色:Python 数据的梯度 4×10−114\times10^{-11} 和 ψ−λ\psi-\lambda 的 L1 范数 2×10−72\times10^{-7},由求解容差和 solve_bvp 决定;连续公式 1×10−131\times10^{-13})都比导数检验的最大值大十倍以上。中心差分(琥珀色)的 2×10−82\times10^{-8} 是截断误差 τ26∣∂3Jh/∂Dk3∣\tfrac{\tau^2}{6}|\partial^3J_h/\partial D_k^3|:它来自一阶格式的 ν\nu 分量(∂3Jh/∂ν3=−956\partial^3J_h/\partial \nu^3=−956,τ26∣∂3Jh∣=1.6×10−8\tfrac{\tau^2}{6}|\partial^3J_h|=1.6\times10^{-8}),远大于舍入误差 ϵmach/τ≈2×10−11\epsilon_{\rm mach}/\tau\approx2\times10^{-11}。对大小为 0.06 到 0.75 的梯度,它约能证实七位有效数字。
Figure 76 · The verification ladder (logarithmic axis). The checks of the derivative code (dot test, tangent = adjoint, complex step, GS transposition; green) sit at the level of rounding, at most 6.3 × 10^(-15); the comparisons with reference solutions (violet: the gradients of the Python data, 4 × 10^(-11), and the L1 norm of ψ-λ, 2 × 10^(-7), set by solver tolerances and solve_bvp; the continuous formula, 1 × 10^(-13)) are all more than ten times larger; the 2 × 10^(-8) of central differences (amber) is the truncation error (τ^2)/6|∂^3J_h/∂ D_k^3| of the ν component of the first-order scheme (∂^3J_h/∂ ν^3=−956, (τ^2)/6|∂^3J_h|=1.6 × 10^(-8)), far above the rounding error ε_mach/τ ≈ 2 × 10^(-11); on gradients of size 0.06 to 0.75 it confirms about seven significant digits.10-17​10-15​10-13​10-11​10-9​10-7​10-5​dot test of the tangent and reverse code (random states and seeds)1.5e−15tangent gradient minus adjoint gradient (3 reconstructions, N ≤ 128)6.3e−15complex step through the solve minus adjoint1.7e−15complex residual of the perturbed state, Im R/τ1.2e−15m-step transposition of GS (relative)3.7e−15central differences (τ = 10−5​, full re-solves) minus adjoint1.6e−8gradients of the Python data (N = 32 … 4096)3.9e−11L1 norm of ψ − λ against the Python data (relative)2.1e−7continuous gradient formula minus exact gradient1.0e−13checks of the derivative codecentral differencescomparisons with reference solutions
Figure 76 · The verification ladder (logarithmic axis). The checks of the derivative code (dot test, tangent = adjoint, complex step, GS transposition; green) sit at the level of rounding, at most 6.3×10−156.3\times10^{-15}; the comparisons with reference solutions (violet: the gradients of the Python data, 4×10−114\times10^{-11}, and the L1 norm of ψ−λ\psi-\lambda, 2×10−72\times10^{-7}, set by solver tolerances and solve_bvp; the continuous formula, 1×10−131\times10^{-13}) are all more than ten times larger; the 2×10−82\times10^{-8} of central differences (amber) is the truncation error τ26∣∂3Jh/∂Dk3∣\tfrac{\tau^2}{6}|\partial^3J_h/\partial D_k^3| of the ν\nu component of the first-order scheme (∂3Jh/∂ν3=−956\partial^3J_h/\partial \nu^3=−956, τ26∣∂3Jh∣=1.6×10−8\tfrac{\tau^2}{6}|\partial^3J_h|=1.6\times10^{-8}), far above the rounding error ϵmach/τ≈2×10−11\epsilon_{\rm mach}/\tau\approx2\times10^{-11}; on gradients of size 0.06 to 0.75 it confirms about seven significant digits.

总览面板对当前控件把这些检查全部重做:原始解、切线与伴随梯度、对偶、点积检验、复数步长、中心差分、精确梯度和连续公式,放在一张表里。

The dashboard redoes all of these checks for the current controls: the primal solution, the tangent and adjoint gradients, the duality, the dot test, complex step, central differences, the exact gradient and the continuous formula, in one table.

离散梯度是什么,不是什么

What the discrete gradient is, and what it is not

RDTψR_D^T\psi 是离散目标 Jh(D)J_h(D)(即这个网格上这段程序的目标)的梯度,精确到舍入误差(上表)。它不是连续目标 JJ 的梯度,只有加密网格才能逼近后者(第 15 节、第 16 节)。默认设计、N=8N=8 时,离散梯度是 (−0.4866, −0.0610, −0.3099)(−0.4866,\ −0.0610,\ −0.3099),连续梯度(闭式)是 (−0.1440, 0.0852, 0)(−0.1440,\ 0.0852,\ 0)。分量 aa 的差别主要来自两个不重构的端单元(第 15 节、第 16 节),而不是伴随在入口处的层没被分辨:重构端单元后,它的误差从 0.343 降到 0.030;φ\varphi 与 ν\nu 分量改善得少(从 0.146 到 0.068,从 0.310 到 0.225)。用 RDTψR_D^T\psi 的优化器优化的是这个网格上的 JhJ_h;结果是否接近连续最优,取决于离散化在重要的地方是否足够准——这里是两个端单元和入口处伴随的黏性层。

RDTψR_D^T\psi is the gradient of the discrete objective Jh(D)J_h(D), the objective of this program on this mesh, exact up to rounding (table above). It is not the gradient of the continuous objective JJ; that one is approached only as the mesh is refined (Section 15, Section 16). At the defaults with N=8N=8 the discrete gradient is (−0.4866, −0.0610, −0.3099)(−0.4866,\ −0.0610,\ −0.3099) and the continuous one (closed form) (−0.1440, 0.0852, 0)(−0.1440,\ 0.0852,\ 0). The difference in the aa component comes mainly from the two unreconstructed end cells (Section 15, Section 16), not from the unresolved layer of the adjoint at the inlet: with them reconstructed its error falls from 0.343 to 0.030; the φ\varphi and ν\nu components improve less (from 0.146 to 0.068 and from 0.310 to 0.225). An optimiser that uses RDTψR_D^T\psi optimises JhJ_h on that mesh; whether the result is close to the continuous optimum depends on whether the discretisation is accurate where it matters, here the two end cells and the viscous layer of the adjoint at the inlet.

本页的局限

The limits of this page

  • 固定的正黏性(控件中 0.001≤ν≤10.001\le\nu\le1),没有激波。激波属于单元中心的一维 Burgers 页的附录 B,ν→0\nu\to0 与 h→0h\to0 的极限顺序见它的附录 D(D.4);本页每次计算的 ν\nu 都固定(第 16 节只比较几个固定的 ν\nu,渐近分析也只是形式推导)。A fixed positive viscosity (0.001≤ν≤10.001\le\nu\le1 in the controls) and no shocks. Shocks belong to Appendix B of the cell-centred 1-D Burgers page and the orders of the limits ν→0\nu\to0, h→0h\to0 to its Appendix D (D.4); here ν\nu stays fixed in every computation (Section 16 compares several fixed values and gives formal asymptotics only).
  • 一个光滑的构造解(周期的 u∗u^*,所以 uin=uoutu_{\rm in}=u_{\rm out})、一个目标、三个设计分量;Rusanov 速度固定为 α=2\alpha=2,光滑限制器取 ϵ=0.01\epsilon=0.01。One smooth manufactured solution (periodic u∗u^*, so uin=uoutu_{\rm in}=u_{\rm out}), one objective and three design components; the Rusanov speed is fixed at α=2\alpha=2 and the smooth limiter uses ϵ=0.01\epsilon=0.01.
  • 本页不给出非线性问题或格式的存在性、唯一性或收敛定理:每个观测到的收敛阶都只是本问题上的数值证据(第 5–7 节与附录 A 的 A.4 中的证明只针对那里写明的线性方程组、单步估计和恒等式);第 16 节的渐近分析是形式推导。No existence, uniqueness or convergence theorem for the nonlinear problem or the scheme is given: every observed order is numerical evidence for this one problem (the proofs of Sections 5–7 and of A.4 in Appendix A concern the linear systems, one-step estimates and identities named there); the asymptotics of Section 16 are formal.
  • 第 17 节的迭代是为了讲清结构,没有调优;一维里带状 LU 更便宜。The iterations of Section 17 are there to show their structure and are not tuned; in one dimension the band LU is cheaper.

接下来读什么

Where to go next

  • 附录 A:用变分推出连续伴随与梯度公式,以及它的边界项。Appendix A: the continuous adjoint and the gradient formula with its boundary term, derived with variations.
  • 附录 B:格点格式——它与本页的差别,以及两种格式的一组数字对照。Appendix B: the node-centred scheme, where it differs from this page, and one comparison of the numbers of the two schemes.
  • 附录 C:怎样复现本页的数字和 Python 数据。Appendix C: how to reproduce the numbers of this page and the Python data.

要记住的

What to remember

  • 切线与伴随用自动微分的记号:切线是 x˙\dot x、按原顺序;伴随是 xˉ\bar x、按逆序累加 +=\mathrel{\text{+=}};二者由对偶 RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D 连在一起。The tangent and the adjoint use the notation of automatic differentiation: the tangent is x˙\dot x in the original order, the adjoint xˉ\bar x accumulated with +=\mathrel{\text{+=}} in reverse order; the duality RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D ties them together.
  • 核心就是一个面:取值、重构、通量、分发;切线与伴随复用同样的局部导数 cL,cR,κfc_L,c_R,\kappa_f 和重构权重。One face is everything: gather, reconstruct, flux, scatter; the tangent and the adjoint reuse the same local derivatives cL,cR,κfc_L,c_R,\kappa_f and reconstruction weights.
  • 伴随梯度是离散目标的导数,精确到舍入误差:用点积检验、复数步长和差分验证它;用加密和连续伴随检验它离连续梯度多远。The adjoint gradient is the derivative of the discrete objective, exact up to rounding: verify it with the dot test, complex step and finite differences; check how far it is from the continuous gradient with refinement and the continuous adjoint.
  • 积分形式的残差使 ψi≈λ(xi)\psi_i\approx\lambda(x_i),同号、无因子 hh。粗网格上,无限制器线性重构的伴随最大误差和 aa 分量的梯度误差很大,主要因为两端单元不重构(第 15 节、第 16 节);连续伴随在入口有宽 ν/uin\nu/u_{\rm in} 的层,要分辨它还需要 h<ν/uinh<\nu/u_{\rm in}。An integrated residual makes ψi≈λ(xi)\psi_i\approx\lambda(x_i), with the same sign and no factor hh. On coarse meshes the largest adjoint error and the aa-gradient error of unlimited linear reconstruction are large, mainly because the two end cells are not reconstructed (Section 15, Section 16); the continuous adjoint has a layer of width ν/uin\nu/u_{\rm in} at the inlet, and resolving it also needs h<ν/uinh<\nu/u_{\rm in}.
  • 一阶格式等于黏性为 ν+h\nu+h 的中心格式。边界关系 ψ0/(h/2)→λx(0)\psi_0/(h/2)\to\lambda_x(0) 能暴露粗网格吻合所掩盖的边界错误;入口值伴随 uˉin=dJh/duin\bar u_{\rm in}=\mathrm dJ_h/\mathrm du_{\rm in} 不能(对错误版本它仍趋于 −νλx(0)-\nu\lambda_x(0));在默认设计下它在粗网格上就接近连续值,但这不是一般规律(第 16 节)。The first-order scheme is the central scheme with viscosity ν+h\nu+h. The boundary relation ψ0/(h/2)→λx(0)\psi_0/(h/2)\to\lambda_x(0) exposes boundary errors that agreement on coarse meshes hides; the adjoint of the inlet value, uˉin=dJh/duin\bar u_{\rm in}=\mathrm dJ_h/\mathrm du_{\rm in}, does not (for the slip it still tends to −νλx(0)-\nu\lambda_x(0)); at the default design it is already close to its continuous value on coarse meshes, but not in general (Section 16).
  • 伴随迭代应当是切线迭代的转置:GS 转置后反向扫描,截断导数在每一步都相等;GMRES 不是线性的,只有收敛后才满足对偶关系。The adjoint iteration should be the transpose of the tangent iteration: transposed GS sweeps backward and the truncated derivatives agree at every step; GMRES is not linear and satisfies the duality only at convergence.

附录 A:连续伴随

Appendix A: The continuous adjoint

本节实验:ν\nu 越小,连续伴随在 x=0x=0 处的斜率 λx(0)\lambda_x(0) 越陡。梯度公式里的边界项 ν[λxvk]01\nu\bigl[\lambda_x v_k\bigr]_0^1 会随 ν→0\nu\to0 消失吗?先猜,再用图 80 和本附录的 ν\nu 实验台验证。

Experiment: as ν\nu decreases, the slope λx(0)\lambda_x(0) of the continuous adjoint at x=0x=0 steepens. Does the boundary term ν[λxvk]01\nu\bigl[\lambda_x v_k\bigr]_0^1 of the gradient formula vanish as ν→0\nu\to0? Guess first, then check with Figure 80 and the ν\nu lab of this appendix.

正文各节对离散程序求导:前向用点 x˙\dot x,伴随用横线 xˉ\bar x。本附录换一个对象:直接对连续方程求伴随。这样得到的 λ(x)\lambda(x) 正是离散伴随 ψ\psi 在网格加密时应当逼近的函数(第 16 节);推导也说明它的边界条件从哪里来。这里用变分记号:δu\delta u、δs\delta s、δJ\delta J 是连续函数的变分;δ\delta 只出现在本附录(以及明确说“连续”的句子里)。

The main sections differentiate the discrete code: the tangent with dots x˙\dot x, the adjoint with bars xˉ\bar x. This appendix takes a different object, the continuous equation itself, and derives its adjoint. The result is the function λ(x)\lambda(x) that the discrete adjoint ψ\psi should approach under mesh refinement (Section 16), and the derivation shows where its boundary conditions come from. The notation here is variational: δu\delta u, δs\delta s, δJ\delta J are variations of continuous functions; δ\delta appears only in this appendix (and in sentences that say continuous).

A.1 状态方程、目标与变分

A.1 The state equation, the objective and their variations

连续问题就是第 1 节的方程:总通量 q=12u2−νuxq=\tfrac12u^2-\nu u_x,

The continuous problem is the equation of Section 1: with the total flux q=12u2−νuxq=\tfrac12u^2-\nu u_x,

qx=s(x;D)在 (0,1) 上,u(0)=uin(D),u(1)=uout(D),J(u)=∫01(1+x) u dx.q_x=s(x;D)\quad\text{在 }(0,1)\text{ 上},\qquad u(0)=u_{\rm in}(D),\quad u(1)=u_{\rm out}(D),\qquad J(u)=\int_0^1(1+x)\,u\,\mathrm dx.
qx=s(x;D)on (0,1),u(0)=uin(D),u(1)=uout(D),J(u)=∫01(1+x) u dx.q_x=s(x;D)\quad\text{on }(0,1),\qquad u(0)=u_{\rm in}(D),\quad u(1)=u_{\rm out}(D),\qquad J(u)=\int_0^1(1+x)\,u\,\mathrm dx.

设计改变 δD\delta D 时,源项改变 δs\delta s,两端给定值改变 δuin\delta u_{\rm in}、δuout\delta u_{\rm out},状态随之改变 δu\delta u。把通量线性化:δq=u δu−ν δux−ux δν\delta q=u\,\delta u-\nu\,\delta u_x-u_x\,\delta\nu(最后一项只在 ν\nu 本身改变时出现,因为 ν\nu 写在通量里)。于是线性化的状态方程是

When the design changes by δD\delta D, the source changes by δs\delta s, the two prescribed end values by δuin\delta u_{\rm in}, δuout\delta u_{\rm out}, and the state follows with δu\delta u. Linearise the flux: δq=u δu−ν δux−ux δν\delta q=u\,\delta u-\nu\,\delta u_x-u_x\,\delta\nu (the last term appears only when ν\nu itself changes, because ν\nu sits inside the flux). The linearised state equation is therefore

(u δu−ν δux)x=δs+uxx δν,δu(0)=δuin,δu(1)=δuout.\bigl(u\,\delta u-\nu\,\delta u_x\bigr)_x=\delta s+u_{xx}\,\delta\nu,\qquad \delta u(0)=\delta u_{\rm in},\quad \delta u(1)=\delta u_{\rm out}.

每次只改变一个分量 DkD_k,除以 δDk\delta D_k,就得到连续切线解vk=∂u/∂Dkv_k=\partial u/\partial D_k:对 aa、φ\varphi 有 (uvk−νvk,x)x=∂s/∂Dk(u v_k-\nu v_{k,x})_x=\partial s/\partial D_k,vk(0)=∂uin/∂Dkv_k(0)=\partial u_{\rm in}/\partial D_k,vk(1)=∂uout/∂Dkv_k(1)=\partial u_{\rm out}/\partial D_k;对 Dk=νD_k=\nu 有 (uvk−νvk,x)x=sν+uxx(uv_k-\nu v_{k,x})_x=s_\nu+u_{xx},两端 vk=0v_k=0。它是离散切线解 v=𝐔˙v=\dot{\mathbf U} 的连续对应物。

Moving one component DkD_k at a time and dividing by δDk\delta D_k gives the continuous tangent vk=∂u/∂Dkv_k=\partial u/\partial D_k: for aa and φ\varphi, (uvk−νvk,x)x=∂s/∂Dk(u v_k-\nu v_{k,x})_x=\partial s/\partial D_k with vk(0)=∂uin/∂Dkv_k(0)=\partial u_{\rm in}/\partial D_k and vk(1)=∂uout/∂Dkv_k(1)=\partial u_{\rm out}/\partial D_k; for Dk=νD_k=\nu, (uvk−νvk,x)x=sν+uxx(uv_k-\nu v_{k,x})_x=s_\nu+u_{xx} with vk=0v_k=0 at both ends. It is the continuous counterpart of the discrete tangent v=𝐔˙v=\dot{\mathbf U}.

A.2 拉格朗日函数与两次分部积分

A.2 The Lagrangian and two integrations by parts

把方程乘以一个待定的函数 λ(x)\lambda(x),加到目标上:

Multiply the equation by a function λ(x)\lambda(x), still to be chosen, and add it to the objective:

ℒ(u,D,λ)=J(u)+∫01λ [qx−s] dx.\mathcal L(u,D,\lambda)=J(u)+\int_0^1\lambda\,\bigl[q_x-s\bigr]\,\mathrm dx .

对状态方程的任何解,方括号内的量都为零,所以对任意 λ\lambda 都有 ℒ=J\mathcal L=J,变分也相同:δJ=δℒ\delta J=\delta\mathcal L。这正是正文 Jh+ψTRJ_h+\psi^TR 的连续版本,正负号约定一致(第 16 节比较 ψ\psi 与 λ\lambda 时无须变号)。对设计求变分:

On any solution of the state equation the bracket vanishes, so ℒ=J\mathcal L=J for every λ\lambda, and so do their variations: δJ=δℒ\delta J=\delta\mathcal L. This is the continuous version of the main text's Jh+ψTRJ_h+\psi^TR with the same sign convention (Section 16 compares ψ\psi with λ\lambda without a change of sign). Vary the design:

δℒ=∫01(1+x) δu dx+∫01λ [(u δu−ν δux)x−δs−uxx δν]dx.\delta\mathcal L=\int_0^1(1+x)\,\delta u\,\mathrm dx+\int_0^1\lambda\,\Bigl[\bigl(u\,\delta u-\nu\,\delta u_x\bigr)_x-\delta s-u_{xx}\,\delta\nu\Bigr]\mathrm dx .

中间一项含未知的 δu\delta u 的导数。我们要把导数从 δu\delta u 挪到 λ\lambda 上,一步一步来:(1)分部积分一次;(2)展开括号;(3)对 ν∫λx δux\nu\int\lambda_x\,\delta u_x 再分部积分一次:

The middle term contains derivatives of the unknown δu\delta u. Move them from δu\delta u onto λ\lambda, one step at a time: (1) integrate by parts once; (2) expand the bracket; (3) integrate ν∫λx δux\nu\int\lambda_x\,\delta u_x by parts again:

∫01λ (u δu−ν δux)x dx=[λ(u δu−ν δux)]01−∫01λx (u δu−ν δux) dx(1)=[λ(u δu−ν δux)]01−∫01uλx δu dx+ν∫01λx δux dx(2)=[λ(u δu−ν δux)]01+ν[λx δu]01−∫01(uλx+νλxx) δu dx(3)\begin{aligned}\int_0^1\lambda\,(u\,\delta u-\nu\,\delta u_x)_x\,\mathrm dx&=\bigl[\lambda(u\,\delta u-\nu\,\delta u_x)\bigr]_0^1-\int_0^1\lambda_x\,(u\,\delta u-\nu\,\delta u_x)\,\mathrm dx&&\text{(1)}\\&=\bigl[\lambda(u\,\delta u-\nu\,\delta u_x)\bigr]_0^1-\int_0^1u\lambda_x\,\delta u\,\mathrm dx+\nu\int_0^1\lambda_x\,\delta u_x\,\mathrm dx&&\text{(2)}\\&=\bigl[\lambda(u\,\delta u-\nu\,\delta u_x)\bigr]_0^1+\nu\bigl[\lambda_x\,\delta u\bigr]_0^1-\int_0^1\bigl(u\lambda_x+\nu\lambda_{xx}\bigr)\,\delta u\,\mathrm dx&&\text{(3)}\end{aligned}

代回 δℒ\delta\mathcal L,按“内部”和“两端”整理:

Put this back into δℒ\delta\mathcal L and sort it into the interior and the two ends:

δℒ=∫01[(1+x)−uλx−νλxx]δu dx+[λ(u δu−ν δux)]01+ν[λx δu]01−∫01λ (δs+uxx δν) dx.\delta\mathcal L=\int_0^1\Bigl[(1+x)-u\lambda_x-\nu\lambda_{xx}\Bigr]\delta u\,\mathrm dx+\bigl[\lambda(u\,\delta u-\nu\,\delta u_x)\bigr]_0^1+\nu\bigl[\lambda_x\,\delta u\bigr]_0^1-\int_0^1\lambda\,\bigl(\delta s+u_{xx}\,\delta\nu\bigr)\,\mathrm dx .

A.3 选 λ:伴随方程及其边界条件

A.3 Choosing λ: the adjoint equation and its boundary conditions

δu\delta u 只有解完切线问题才知道。我们选 λ\lambda,让所有含 δu\delta u 的项都消失,图 77 画出了这四项:

δu\delta u is known only after solving the tangent problem. Choose λ\lambda so that every term containing δu\delta u disappears; Figure 77 draws the four pieces:

  • 内部。被积函数为零:−uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x)。右端项 −(1+x)-(1+x) 来自目标的权重。Interior. The integrand vanishes: −uλx−νλxx=−(1+x)-u\lambda_x-\nu\lambda_{xx}=-(1+x). The right side −(1+x)-(1+x) comes from the weight of the objective.
  • 两端的第一项 [λ(u δu−ν δux)]01\bigl[\lambda(u\,\delta u-\nu\,\delta u_x)\bigr]_0^1 含扰动状态在两端的斜率 δux(0)\delta u_x(0)、δux(1)\delta u_x(1)——它们是切线问题的输出,事先不知道。唯一的办法是让它们的系数为零:λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0。这样 λu δu\lambda u\,\delta u 也一起消失。The first end term [λ(u δu−ν δux)]01\bigl[\lambda(u\,\delta u-\nu\,\delta u_x)\bigr]_0^1 contains the end slopes δux(0)\delta u_x(0), δux(1)\delta u_x(1) of the perturbed state: they are outputs of the tangent problem, unknown beforehand. The only way out is to make their coefficients zero: λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0. Then λu δu\lambda u\,\delta u disappears as well.
  • 两端的第二项 ν[λx δu]01=νλx(1) δuout−νλx(0) δuin\nu\bigl[\lambda_x\,\delta u\bigr]_0^1=\nu\lambda_x(1)\,\delta u_{\rm out}-\nu\lambda_x(0)\,\delta u_{\rm in} 只含给定端值的变分,是已知的:它留下来,成为梯度的一部分。The second end term ν[λx δu]01=νλx(1) δuout−νλx(0) δuin\nu\bigl[\lambda_x\,\delta u\bigr]_0^1=\nu\lambda_x(1)\,\delta u_{\rm out}-\nu\lambda_x(0)\,\delta u_{\rm in} contains only variations of the prescribed end values, which are known: it stays and becomes part of the gradient.

二阶方程配两个条件,数目正好。若再对 λx\lambda_x 加条件,问题就超定;少一个,就留下一个算不出的项。结果是连续伴随问题与梯度公式:

A second-order equation with two conditions: exactly the right number. One more condition on λx\lambda_x would overdetermine the problem; one fewer would leave a term that cannot be evaluated. The result is the continuous adjoint problem and the gradient formula:

−uλx−νλxx=−(1+x),λ(0)=λ(1)=0,-u\lambda_x-\nu\lambda_{xx}=-(1+x),\qquad \lambda(0)=\lambda(1)=0,
dJdDk=−∫01λ ∂s∂Dk dx+ν(λx(1)∂uout∂Dk−λx(0)∂uin∂Dk)(Dk=a,φ),dJdν=−∫01λ (sν+uxx) dx.\frac{\mathrm dJ}{\mathrm dD_k}=-\int_0^1\lambda\,\frac{\partial s}{\partial D_k}\,\mathrm dx+\nu\Bigl(\lambda_x(1)\frac{\partial u_{\rm out}}{\partial D_k}-\lambda_x(0)\frac{\partial u_{\rm in}}{\partial D_k}\Bigr)\quad(D_k=a,\varphi),\qquad \frac{\mathrm dJ}{\mathrm d\nu}=-\int_0^1\lambda\,\bigl(s_\nu+u_{xx}\bigr)\,\mathrm dx .

ν\nu 分量没有边界项(端值不依赖 ν\nu),但多了物理通量本身的一项 −∫λuxx-\int\lambda u_{xx}。对构造解,源项 s=u∗ux∗−νuxx∗s=u^*u^*_x-\nu u^*_{xx} 给出 sν=−uxx∗s_\nu=-u^*_{xx},所以在 u=u∗u=u^* 上被积函数 sν+uxxs_\nu+u_{xx} 处处为零,dJ/dν=0\mathrm dJ/\mathrm d\nu=0,与 ∂J∗/∂ν=0\partial J^*/\partial\nu=0 一致。

The ν\nu component has no boundary term (the end values do not depend on ν\nu) but one more term from the physical flux itself, −∫λuxx-\int\lambda u_{xx}. For the manufactured solution the source s=u∗ux∗−νuxx∗s=u^*u^*_x-\nu u^*_{xx} gives sν=−uxx∗s_\nu=-u^*_{xx}, so the integrand sν+uxxs_\nu+u_{xx} vanishes identically at u=u∗u=u^* and dJ/dν=0\mathrm dJ/\mathrm d\nu=0, in agreement with ∂J∗/∂ν=0\partial J^*/\partial\nu=0.

常见错误:漏掉通量项,只算 −∫01λsν dx-\int_0^1\lambda s_\nu\,\mathrm dx。默认设计下这个数是 1.8769,而正确答案是 0:通量项 −∫01λuxx dx=−1.8769-\int_0^1\lambda u_{xx}\,\mathrm dx=−1.8769 恰好把它抵消(图 79 右)。离散的情形相同:第 12 节的 ν\nu 路径有一条直接穿过通量 HfH_f。

A common mistake: dropping the flux term and computing only −∫01λsν dx-\int_0^1\lambda s_\nu\,\mathrm dx. At the defaults that number is 1.8769, whereas the correct answer is 0: the flux term −∫01λuxx dx=−1.8769-\int_0^1\lambda u_{xx}\,\mathrm dx=−1.8769 cancels it exactly (Figure 79, right). The discrete case is the same: one of the ν\nu paths of Section 12 runs straight through the flux HfH_f.

图 77 · 两次分部积分之后的 L。三项(灰)由选择 λ 消去:内部靠伴随方程,两端的 λ(u u-ν u_x) 靠 λ(0)=λ(1)=0——因为 u_x 在两端未知。第四项(紫)只含给定端值的变分,留在梯度里。中间是本页默认设计下真实的 λ(x):两端为零,x=0 处斜率 λ_x(0)=−142.66。δℒ 在 [0,1] 上分部积分两次之后的四项本页的 λ(x)(默认设计),两端 λ = 0x = 0x = 1λx​(0) = −142.7(陡:边界层)λx​(1) = 2.20x = 0:[λ(u δu − ν δux​)]δux​(0) 未知 ⇒ λ(0) = 0这一项消失✕内部:∫[(1+x) − uλx​ − νλxx​] δu伴随方程 ⇒ 被积函数 = 0这一项消失✕x = 1:[λ(u δu − ν δux​)]δux​(1) 未知 ⇒ λ(1) = 0这一项消失✕ν[λx​ δu]0​1​ = ν λx​(1) δuout​ − ν λx​(0) δuin​δuin​、δuout​ 是给定数据的变分:这一项留在梯度里✓
图 77 · 两次分部积分之后的 δℒ\delta\mathcal L。三项(灰)由选择 λ\lambda 消去:内部靠伴随方程,两端的 λ(u δu−ν δux)\lambda(u\,\delta u-\nu\,\delta u_x) 靠 λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0——因为 δux\delta u_x 在两端未知。第四项(紫)只含给定端值的变分,留在梯度里。中间是本页默认设计下真实的 λ(x)\lambda(x):两端为零,x=0x=0 处斜率 λx(0)=−142.66\lambda_x(0)=−142.66。
Figure 77 · L after the two integrations by parts. Three pieces (grey) are removed by the choice of λ: the interior by the adjoint equation, the two end terms λ(u u-ν u_x) by λ(0)=λ(1)=0, because u_x is unknown at the ends. The fourth piece (violet) contains only variations of the prescribed end values and stays in the gradient. In the middle, the actual λ(x) of the default design: zero at both ends, with the slope λ_x(0)=−142.66 at x=0.δℒ after integrating by parts twice: four pieces on [0,1]this page’s λ(x) (default design), λ = 0 at both endsx = 0x = 1λx​(0) = −142.7(steep: the layer)λx​(1) = 2.20x = 0: [λ(u δu − ν δux​)]δux​(0) unknown ⇒ λ(0) = 0this term vanishes✕interior: ∫[(1+x) − uλx​ − νλxx​] δuadjoint equation ⇒ integrand = 0this term vanishes✕x = 1: [λ(u δu − ν δux​)]δux​(1) unknown ⇒ λ(1) = 0this term vanishes✕ν[λx​ δu]0​1​ = ν λx​(1) δuout​ − ν λx​(0) δuin​δuin​, δuout​ are variations of given data: this term stays in the gradient✓
Figure 77 · δℒ\delta\mathcal L after the two integrations by parts. Three pieces (grey) are removed by the choice of λ\lambda: the interior by the adjoint equation, the two end terms λ(u δu−ν δux)\lambda(u\,\delta u-\nu\,\delta u_x) by λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0, because δux\delta u_x is unknown at the ends. The fourth piece (violet) contains only variations of the prescribed end values and stays in the gradient. In the middle, the actual λ(x)\lambda(x) of the default design: zero at both ends, with the slope λx(0)=−142.66\lambda_x(0)=−142.66 at x=0x=0.

下面的播放器把这三步逐行算出来:取一个检验函数 vv 代替 δu\delta u,用本页的 λ\lambda 计算每一行的每一项。前六行对任何 vv 都相等(只用到分部积分和伴随方程);第七行还要用切线方程,所以只对真正的切线解成立。

The player below evaluates the three steps line by line: a test function vv stands in for δu\delta u, and every term of every line is computed with this page's λ\lambda. The first six lines agree for any vv (they use only integration by parts and the adjoint equation); the seventh also uses the tangent equation, so it holds only for a true tangent.

A.4 伴随问题适定吗:能证明的部分

A.4 Is the adjoint problem well posed? What can be proved

(A.3–A.4 中 vv 表示一般的函数——检验函数或 𝒜\mathcal A 定义域里的元素;vkv_k 才是切线解。)记状态线性算子 𝒜v=(uv−νvx)x\mathcal A v=(uv-\nu v_x)_x(带齐次端值 v(0)=v(1)=0v(0)=v(1)=0),伴随算子 𝒜∗λ=−uλx−νλxx\mathcal A^*\lambda=-u\lambda_x-\nu\lambda_{xx}(带 λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0)。下面三条中,(1)、(3) 在本页完整证明;(2) 证明一个方向,另一方向引用 Fredholm 择一定理。它们对任何连续的 uu 和任何 ν>0\nu>0 成立,只有第三条要求 u>0u>0。

(In A.3–A.4, vv is a generic function, a test function or an element of the domain of 𝒜\mathcal A; the tangent is vkv_k.) Write the linear state operator 𝒜v=(uv−νvx)x\mathcal A v=(uv-\nu v_x)_x (with homogeneous end values v(0)=v(1)=0v(0)=v(1)=0) and the adjoint operator 𝒜∗λ=−uλx−νλxx\mathcal A^*\lambda=-u\lambda_x-\nu\lambda_{xx} (with λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0). Of the three statements below, (1) and (3) are proved in full here; (2) proves one direction and cites the Fredholm alternative for the other. They hold for every continuous uu and every ν>0\nu>0, and only the third needs u>0u>0.

(1) 唯一可解。伴随方程对 λx\lambda_x 是一阶的:记 Φ(x)=ν−1∫0xu dt\Phi(x)=\nu^{-1}\int_0^xu\,\mathrm dt,则 νλxx+uλx=1+x\nu\lambda_{xx}+u\lambda_x=1+x 等价于 (eΦλx)x=eΦ(1+x)/ν\bigl(e^{\Phi}\lambda_x\bigr)_x=e^{\Phi}(1+x)/\nu。积分两次:

(1) Unique solvability. The adjoint equation is first order in λx\lambda_x: with Φ(x)=ν−1∫0xu dt\Phi(x)=\nu^{-1}\int_0^xu\,\mathrm dt, the equation νλxx+uλx=1+x\nu\lambda_{xx}+u\lambda_x=1+x is the same as (eΦλx)x=eΦ(1+x)/ν\bigl(e^{\Phi}\lambda_x\bigr)_x=e^{\Phi}(1+x)/\nu. Integrate twice:

λx(x)=e−Φ(x)[λx(0)+1ν∫0xeΦ(t)(1+t) dt],λ(x)=∫0xλx dt.\lambda_x(x)=e^{-\Phi(x)}\Bigl[\lambda_x(0)+\frac1\nu\int_0^xe^{\Phi(t)}(1+t)\,\mathrm dt\Bigr],\qquad \lambda(x)=\int_0^x\lambda_x\,\mathrm dt .

λ(0)=0\lambda(0)=0 已经满足;λ(1)=0\lambda(1)=0 是关于 λx(0)\lambda_x(0) 的一个线性方程,系数 ∫01e−Φ dx>0\int_0^1e^{-\Phi}\,\mathrm dx>0,所以 λx(0)\lambda_x(0) 唯一确定,解存在且唯一。右端项为零时同一计算给出 λx(0)=0\lambda_x(0)=0、λ≡0\lambda\equiv0:在这组边界条件下,伴随齐次问题只有零解。对 𝒜v=f\mathcal A v=f 积分一次得 uv−νvx=uv-\nu v_x= 常数 +∫0xf+\int_0^xf,同样的积分因子对任意连续的 ff 解出唯一的 vv(v(1)=0v(1)=0 确定那个常数):状态算子 𝒜\mathcal A 可逆。

λ(0)=0\lambda(0)=0 holds by construction; λ(1)=0\lambda(1)=0 is one linear equation for λx(0)\lambda_x(0) with the coefficient ∫01e−Φ dx>0\int_0^1e^{-\Phi}\,\mathrm dx>0, so λx(0)\lambda_x(0) is determined uniquely and the solution exists and is unique. With a zero right side the same computation gives λx(0)=0\lambda_x(0)=0 and λ≡0\lambda\equiv0: the adjoint operator has no nonzero homogeneous solution under these boundary conditions. Integrating 𝒜v=f\mathcal A v=f once gives uv−νvx=uv-\nu v_x= constant +∫0xf+\int_0^xf, and the same integrating factor solves it uniquely for every continuous ff (v(1)=0v(1)=0 fixes the constant): the state operator 𝒜\mathcal A is invertible.

(2) 为什么两者总是同时可逆(简短论证)。A.2 的分部积分在 v(0)=v(1)=0v(0)=v(1)=0、λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0 时两端项全为零,剩下 Green 恒等式 ∫01λ 𝒜v dx=∫01(𝒜∗λ) v dx\int_0^1\lambda\,\mathcal A v\,\mathrm dx=\int_0^1(\mathcal A^*\lambda)\,v\,\mathrm dx。若 𝒜∗λ0=0\mathcal A^*\lambda_0=0 而 λ0≠0\lambda_0\ne0,则对所有 vv 有 ∫λ0𝒜v=0\int\lambda_0\mathcal Av=0:任何满足 ∫λ0f≠0\int\lambda_0 f\ne0 的右端项 ff 都不在 𝒜\mathcal A 的值域里,𝒜\mathcal A 不可逆。反方向(𝒜\mathcal A 不可逆 ⇒\Rightarrow 伴随有非零齐次解)是正则二阶边值问题的 Fredholm 择一定理,属于标准结论,本页不再证明;对本问题,(1) 已直接证明:状态算子与伴随算子的齐次问题都只有零解。离散的对应物是 AA 与 ATA^T 秩相同。

(2) Why the two are always invertible together (a short argument). With v(0)=v(1)=0v(0)=v(1)=0 and λ(0)=λ(1)=0\lambda(0)=\lambda(1)=0 every end term of the integration by parts of A.2 vanishes, and what is left is Green's identity ∫01λ 𝒜v dx=∫01(𝒜∗λ) v dx\int_0^1\lambda\,\mathcal A v\,\mathrm dx=\int_0^1(\mathcal A^*\lambda)\,v\,\mathrm dx. If 𝒜∗λ0=0\mathcal A^*\lambda_0=0 with λ0≠0\lambda_0\ne0, then ∫λ0𝒜v=0\int\lambda_0\mathcal Av=0 for every vv: no right side ff with ∫λ0f≠0\int\lambda_0 f\ne0 lies in the range of 𝒜\mathcal A, and 𝒜\mathcal A is not invertible. The converse (𝒜\mathcal A not invertible ⇒\Rightarrow a nonzero homogeneous solution of the adjoint problem) is the Fredholm alternative for regular second-order boundary-value problems, a standard result not re-proved here; for this problem (1) has already shown directly that the homogeneous state and adjoint problems have only the zero solution. The discrete counterpart is that AA and ATA^T have the same rank.

(3) 最大值原理(u>0u>0)。(a) 伴随方程的右端项 −(1+x)<0-(1+x)<0。在 λ\lambda 的内部极大点 λx=0\lambda_x=0、λxx≤0\lambda_{xx}\le0,于是 𝒜∗λ=−νλxx≥0\mathcal A^*\lambda=-\nu\lambda_{xx}\ge0,与 𝒜∗λ<0\mathcal A^*\lambda<0 矛盾;所以最大值只在两端取到,λ<0\lambda<0 于 (0,1)(0,1)(这一步不需要 uu 的符号)。(b) 若 u≥umin⁡>0u\ge u_{\min}>0,取常数 C>2/umin⁡C>2/u_{\min},则 𝒜∗(λ+C(1−x))=uC−(1+x)>0\mathcal A^*\bigl(\lambda+C(1-x)\bigr)=uC-(1+x)>0;同样的论证说明 λ+C(1−x)\lambda+C(1-x) 没有内部极小,它的最小值在端点取到:x=0x=0 处是 C>0C>0,x=1x=1 处是 00,所以最小值是 00。令 C→2/umin⁡C\to2/u_{\min}:

(3) The maximum principle (u>0u>0). (a) The right side of the adjoint equation, −(1+x)-(1+x), is negative. At an interior maximum of λ\lambda, λx=0\lambda_x=0 and λxx≤0\lambda_{xx}\le0, so 𝒜∗λ=−νλxx≥0\mathcal A^*\lambda=-\nu\lambda_{xx}\ge0, contradicting 𝒜∗λ<0\mathcal A^*\lambda<0; hence the maximum is attained only at the ends and λ<0\lambda<0 on (0,1)(0,1) (this step needs no sign of uu). (b) If u≥umin⁡>0u\ge u_{\min}>0, take a constant C>2/umin⁡C>2/u_{\min}; then 𝒜∗(λ+C(1−x))=uC−(1+x)>0\mathcal A^*\bigl(\lambda+C(1-x)\bigr)=uC-(1+x)>0, and the same argument shows that λ+C(1−x)\lambda+C(1-x) has no interior minimum: its minimum is attained at an end: the value is C>0C>0 at x=0x=0 and 00 at x=1x=1, so the minimum is 00. Letting C→2/umin⁡C\to2/u_{\min},

−2umin⁡ (1−x)≤λ(x)<0(0<x<1),对每个 ν>0.-\frac{2}{u_{\min}}\,(1-x)\le\lambda(x)<0\qquad(0<x<1),\quad\text{对每个 }\nu>0 .
−2umin⁡ (1−x)≤λ(x)<0(0<x<1),for every ν>0.-\frac{2}{u_{\min}}\,(1-x)\le\lambda(x)<0\qquad(0<x<1),\quad\text{for every }\nu>0 .

默认设计 umin⁡=1−a=0.8u_{\min}=1-a=0.8,下界是 −2.5(1−x)-2.5(1-x),即 ∣λ∣≤2.5(1−x)|\lambda|\le2.5(1-x)。它与 ν\nu 无关:ν→0\nu\to0 时 λ\lambda 本身保持有界,变陡的只是 x=0x=0 处的斜率——那是一个边界层,不是 λ\lambda 的爆破。本附录中各个 ν\nu 的解都满足这两个不等式(check_g.js 逐点检查)。

At the defaults umin⁡=1−a=0.8u_{\min}=1-a=0.8 and the lower bound is −2.5(1−x)-2.5(1-x), i.e. ∣λ∣≤2.5(1−x)|\lambda|\le2.5(1-x). It does not depend on ν\nu: as ν→0\nu\to0 the function λ\lambda itself stays bounded, and only its slope at x=0x=0 steepens. That is a boundary layer, not a blow-up of λ\lambda. Every solution of this appendix, for every ν\nu, satisfies the two inequalities (checked point by point by check_g.js).

本页没有证明的:离散伴随 ψ\psi 收敛到 λ\lambda(第 16 节给的是数值证据);下面 A.6 的渐近展开(形式推导,用数值核对);uu 变号或出现激波时的任何结论。

Not proved on this page: the convergence of the discrete adjoint ψ\psi to λ\lambda (Section 16 gives numerical evidence); the asymptotic expansion of A.6 below (a formal derivation, checked numerically); anything for a uu that changes sign or contains a shock.

A.5 求解:本页的谱方法

A.5 Solving it: the page’s spectral solver

model.js 的 continuousAdjoint(D, M) 用 Chebyshev 配点法解这个两点边值问题:取 M+1M+1 个点 xk=12(1+cos⁡(πk/M))x_k=\tfrac12\bigl(1+\cos(\pi k/M)\bigr)——它们在两端加密,正好落在边界层里;对过这些点的插值多项式求导,得到微分矩阵 𝖣(1)\mathsf D^{(1)} 与 𝖣(2)=(𝖣(1))2\mathsf D^{(2)}=(\mathsf D^{(1)})^2(无衬线的 𝖣\mathsf D 不是设计 DD);在内部点上要求 −u(xk)(𝖣(1)λ)k−ν(𝖣(2)λ)k=−(1+xk)-u(x_k)(\mathsf D^{(1)}\lambda)_k-\nu(\mathsf D^{(2)}\lambda)_k=-(1+x_k),两端点上 λ=0\lambda=0;解一个稠密线性方程组,λx\lambda_x 由 𝖣(1)λ\mathsf D^{(1)}\lambda 给出。它与有限体积模型只共用稠密 LU(experiments/numerics.js)和 u∗u^* 的公式;离散方法(配点)与有限体积、与离散伴随无关。真正独立的核对是下面的积分因子法(不用配点,也不用 LU)、Python 审计 audit/audit_continuous.py 的 NumPy 求解,以及附录 B 的 check_dn.py。

continuousAdjoint(D, M) of model.js solves this two-point boundary-value problem by Chebyshev collocation: take the M+1M+1 points xk=12(1+cos⁡(πk/M))x_k=\tfrac12\bigl(1+\cos(\pi k/M)\bigr), which cluster at both ends, right inside the boundary layer; differentiating the interpolating polynomial through them gives the differentiation matrices 𝖣(1)\mathsf D^{(1)} and 𝖣(2)=(𝖣(1))2\mathsf D^{(2)}=(\mathsf D^{(1)})^2 (the sans-serif 𝖣\mathsf D is not the design DD); require −u(xk)(𝖣(1)λ)k−ν(𝖣(2)λ)k=−(1+xk)-u(x_k)(\mathsf D^{(1)}\lambda)_k-\nu(\mathsf D^{(2)}\lambda)_k=-(1+x_k) at the interior points and λ=0\lambda=0 at the two end points; solve one dense linear system, and read λx\lambda_x from 𝖣(1)λ\mathsf D^{(1)}\lambda. With the finite-volume model it shares only the dense LU (experiments/numerics.js) and the formula of u∗u^*; its discretisation (collocation) has nothing to do with the finite volumes or the discrete adjoint. The truly independent checks are the integrating-factor method below (no collocation, no LU), the NumPy solver of the Python audit audit/audit_continuous.py, and check_dn.py for Appendix B.

收敛性:在 401 个采样点上,M=160M=160 与 M=320M=320 的 λ\lambda 最大相差不到 3e−13,λx(0)\lambda_x(0) 的相对差不到 3e−13。另一条完全独立的路径是 A.4 的积分因子公式,用 Gauss 求积直接计算:它与谱方法的 λx(0)\lambda_x(0) 相对差不到 2e−14。Python 审计 audit/audit_continuous.py 用 NumPy 比较 M=240M=240 与 M=480M=480。本附录正文与图里伴随的数值用 M=240M=240;切线问题用 M=160M=160;第 11–18 节用 M=200M=200(201 个点,model.js 的默认值),打印的数字与本附录在所示位数上一致;实验台按 ν\nu 选 MM(96 到 256,保证边界层被分辨,见 check_g.js)。

Convergence: on 401 sample points, λ\lambda for M=160M=160 and M=320M=320 differs by at most 3e−13, and λx(0)\lambda_x(0) by at most 3e−13 relative. A second, completely independent path is the integrating-factor formula of A.4, evaluated by Gauss quadrature: its λx(0)\lambda_x(0) agrees with the spectral one to within 2e−14 relative. The Python audit audit/audit_continuous.py compares M=240M=240 with M=480M=480 in NumPy. The adjoint numbers in the text and figures of this appendix use M=240M=240; the tangent problems use M=160M=160; Sections 11–18 use M=200M=200 (201 points, the default of model.js), and the numbers printed there agree with this appendix to the digits shown; the labs choose MM from ν\nu (96 to 256, enough to resolve the layer, as check_g.js verifies).

默认设计下 λx(0)=−142.6568\lambda_x(0)=−142.6568、λx(1)=2.2035\lambda_x(1)=2.2035。把梯度公式逐项算出(Clenshaw–Curtis 求积,用同一组点):“源项积分”是 −∫01λ ∂s/∂Dk dx-\int_0^1\lambda\,\partial s/\partial D_k\,\mathrm dx(对 ν\nu 是 −∫01λ sν dx-\int_0^1\lambda\,s_\nu\,\mathrm dx,与图 79 右图相同;这一行的第三列放通量项 −∫01λ uxx dx-\int_0^1\lambda\,u_{xx}\,\mathrm dx),“边界项”是 ν(λx(1) ∂uout/∂Dk−λx(0) ∂uin/∂Dk)\nu\bigl(\lambda_x(1)\,\partial u_{\rm out}/\partial D_k-\lambda_x(0)\,\partial u_{\rm in}/\partial D_k\bigr)。

At the defaults λx(0)=−142.6568\lambda_x(0)=−142.6568 and λx(1)=2.2035\lambda_x(1)=2.2035. The gradient formula term by term (Clenshaw–Curtis quadrature on the same points): the source integral is −∫01λ ∂s/∂Dk dx-\int_0^1\lambda\,\partial s/\partial D_k\,\mathrm dx (for ν\nu, −∫01λ sν dx-\int_0^1\lambda\,s_\nu\,\mathrm dx, as in the right panel of Figure 79, with the flux term −∫01λ uxx dx-\int_0^1\lambda\,u_{xx}\,\mathrm dx in the third column of that row), the boundary term ν(λx(1) ∂uout/∂Dk−λx(0) ∂uin/∂Dk)\nu\bigl(\lambda_x(1)\,\partial u_{\rm out}/\partial D_k-\lambda_x(0)\,\partial u_{\rm in}/\partial D_k\bigr).

分量Component源项积分Source integral边界项Boundary term和Sum精确梯度Exact gradient和与精确之差Sum minus exact
aa0.472777−0.616785−0.144007698−0.144007698−6e−14
φ\varphi1.732274−1.6471180.0851558580.0851558581e−15
ν\nu1.876920−1.876920000

细看这张表。源项积分和边界项各自是 O(1)O(1) 的量,和却小得多:φ\varphi 的两部分(1.73、−1.65)约是和的 20 倍,几乎抵消;aa 的两部分(0.47、−0.62)约是和的 3.3–4.3 倍;和与精确值相差不到 7e−14。所以边界项不能省:省掉它,φ\varphi 分量会错二十倍。

Read the table carefully. The source integral and the boundary term are each of order one while their sum is much smaller: for φ\varphi the two parts (1.73 and −1.65) are about 20 times the sum and nearly cancel; for aa (0.47 and −0.62) they are about 3.3–4.3 times the sum; the sums agree with the exact values to within 7e−14. So the boundary term cannot be dropped: without it the φ\varphi component would be wrong by a factor of twenty.

图 78 · 连续伴随 λ(x),四个黏性系数(谱方法,M=240,a=0.2,φ=0.07)。左:整个区间;虚线是外解 λ_out(νλ_xx 略去,从 x=1 积分)。右:放大 x=0 附近,点线是 ν=0.01 的复合近似 λ_out(x)-λ_out(0)e^-u_inx/ν。ν 每小十倍,层薄十倍、斜率陡十倍;层变薄以后 λ 的大小变化不大:ν=0.1、0.03、0.01、0.003 时最小值为 −1.08、−1.37、−1.48、−1.53,趋于 λ_out(0)=−1.56。ν = 0.1ν = 0.03ν = 0.01ν = 0.003λout​(外解)复合近似(ν = 0.01)−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xλ整个区间−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.010.020.030.040.050.06x放大 x ∈ [0, 0.06]:x = 0 处的层ν = 0.01:λx​(0) = −142.7
图 78 · 连续伴随 λ(x)\lambda(x),四个黏性系数(谱方法,M=240M=240,a=0.2a=0.2,φ=0.07\varphi=0.07)。左:整个区间;虚线是外解 λout\lambda_{\rm out}(νλxx\nu\lambda_{xx} 略去,从 x=1x=1 积分)。右:放大 x=0x=0 附近,点线是 ν=0.01\nu=0.01 的复合近似 λout(x)−λout(0)e−uinx/ν\lambda_{\rm out}(x)-\lambda_{\rm out}(0)e^{-u_{\rm in}x/\nu}。ν\nu 每小十倍,层薄十倍、斜率陡十倍;层变薄以后 λ\lambda 的大小变化不大:ν=0.1\nu=0.1、0.030.03、0.010.01、0.0030.003 时最小值为 −1.08、−1.37、−1.48、−1.53,趋于 λout(0)=−1.56\lambda_{\rm out}(0)=−1.56。
Figure 78 · The continuous adjoint λ(x) for four viscosities (spectral solver, M=240, a=0.2, φ=0.07). Left: the whole interval; dashed, the outer solution λ_out (νλ_xx dropped, integrated from x=1). Right: zoom near x=0; dotted, the composite approximation λ_out(x)-λ_out(0)e^-u_inx/ν for ν=0.01. Each tenfold decrease of ν makes the layer ten times thinner and the slope ten times steeper; the size of λ changes little once the layer is thin: its minimum is −1.08, −1.37, −1.48, −1.53 for ν=0.1, 0.03, 0.01, 0.003, approaching λ_out(0)=−1.56.ν = 0.1ν = 0.03ν = 0.01ν = 0.003λout​ (outer)composite (ν = 0.01)−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.20.40.60.81xλthe whole interval−1.6−1.4−1.2−1−0.8−0.6−0.4−0.2000.010.020.030.040.050.06xzoom x ∈ [0, 0.06]: the layer at x = 0ν = 0.01: λx​(0) = −142.7
Figure 78 · The continuous adjoint λ(x)\lambda(x) for four viscosities (spectral solver, M=240M=240, a=0.2a=0.2, φ=0.07\varphi=0.07). Left: the whole interval; dashed, the outer solution λout\lambda_{\rm out} (νλxx\nu\lambda_{xx} dropped, integrated from x=1x=1). Right: zoom near x=0x=0; dotted, the composite approximation λout(x)−λout(0)e−uinx/ν\lambda_{\rm out}(x)-\lambda_{\rm out}(0)e^{-u_{\rm in}x/\nu} for ν=0.01\nu=0.01. Each tenfold decrease of ν\nu makes the layer ten times thinner and the slope ten times steeper; the size of λ\lambda changes little once the layer is thin: its minimum is −1.08, −1.37, −1.48, −1.53 for ν=0.1\nu=0.1, 0.030.03, 0.010.01, 0.0030.003, approaching λout(0)=−1.56\lambda_{\rm out}(0)=−1.56.
图 79 · 梯度的两部分随 ν 的变化(每个 ν 一次谱方法求解)。左、中:a 与 φ 的源项积分(蓝)与边界项(紫)都是 O(1) 且随 ν 变化,它们的和(橙圈)始终落在与 ν 无关的精确梯度(点线)上。右:ν 分量的源项积分与通量项大小相等、符号相反,和为零。源项积分 −∫λ ∂s/∂Dk​边界项 ν[λx​ ∂ub​/∂Dk​]ν 的通量项 −∫λ uxx​两项之和 = dJ/dDk​点线:精确梯度(与 ν 无关)−0.6−0.4−0.200.20.40.60.0010.010.1νD0​ = a−2−10120.0010.010.1νD1​ = φ−2−10120.0010.010.1νD2​ = ν
图 79 · 梯度的两部分随 ν\nu 的变化(每个 ν\nu 一次谱方法求解)。左、中:aa 与 φ\varphi 的源项积分(蓝)与边界项(紫)都是 O(1)O(1) 且随 ν\nu 变化,它们的和(橙圈)始终落在与 ν\nu 无关的精确梯度(点线)上。右:ν\nu 分量的源项积分与通量项大小相等、符号相反,和为零。
Figure 79 · The two parts of the gradient as ν varies (one spectral solve per ν). Left and middle: for a and φ the source integral (blue) and the boundary term (violet) are both of order one and change with ν, while their sum (orange rings) stays on the exact gradient (dotted), which does not depend on ν. Right: for the ν component the source integral and the flux term are equal and opposite and sum to zero.source integral −∫λ ∂s/∂Dk​boundary term ν[λx​ ∂ub​/∂Dk​]flux term of ν, −∫λ uxx​sum = dJ/dDk​dotted: the exact gradient (independent of ν)−0.6−0.4−0.200.20.40.60.0010.010.1νD0​ = a−2−10120.0010.010.1νD1​ = φ−2−10120.0010.010.1νD2​ = ν
Figure 79 · The two parts of the gradient as ν\nu varies (one spectral solve per ν\nu). Left and middle: for aa and φ\varphi the source integral (blue) and the boundary term (violet) are both of order one and change with ν\nu, while their sum (orange rings) stays on the exact gradient (dotted), which does not depend on ν\nu. Right: for the ν\nu component the source integral and the flux term are equal and opposite and sum to zero.

在任意设计下检查对偶:用本附录自己的配点法解三个连续切线问题,再与伴随公式比较。

Check the duality at any design: solve the three continuous tangent problems with this appendix's own collocation and compare with the adjoint formula.

默认设计下(切线问题取 M=160M=160),切线解与精确导数 ∂u∗/∂Dk\partial u^*/\partial D_k(sin⁡z\sin z、−2πacos⁡z-2\pi a\cos z、00)相差不到 2e−13;两条路径给出同一个导数:

At the defaults (tangent problems with M=160M=160) the tangent solutions agree with the exact derivatives ∂u∗/∂Dk\partial u^*/\partial D_k (sin⁡z\sin z, −2πacos⁡z-2\pi a\cos z, 00) to better than 2e−13, and the two paths give the same derivative:

分量Component切线解 ∫01(1+x) vk dx\int_0^1(1+x)\,v_k\,\mathrm dxTangent ∫01(1+x) vk dx\int_0^1(1+x)\,v_k\,\mathrm dx伴随公式Adjoint formula两者之差Difference切线解的误差Error of the tangent
aa−0.1440076980−0.14400769805e−141e−13
φ\varphi0.08515585830.08515585832e−132e−13
ν\nu0.00000000000.000000000000
∫01(1+x) vk dx=−∫01λ ∂s∂Dk dx+ν[λxvk]01.\int_0^1(1+x)\,v_k\,\mathrm dx=-\int_0^1\lambda\,\frac{\partial s}{\partial D_k}\,\mathrm dx+\nu\bigl[\lambda_x v_k\bigr]_0^1 .

这就是连续层次的对偶恒等式:左边一次切线求解给一个分量,右边一次伴随求解给全部分量。它与离散的 RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D 是同一件事:分部积分扮演了转置的角色。

This is the duality identity at the continuous level: on the left one tangent solve gives one component, on the right one adjoint solve gives all of them. It is the same thing as the discrete RˉTR˙=𝐔ˉT𝐔˙+DˉTD˙\bar R^T\dot R=\bar{\mathbf U}^T\dot{\mathbf U}+\bar D^T\dot D, with integration by parts playing the role of the transpose.

A.6 x = 0 处的边界层

A.6 The boundary layer at x = 0

为什么层在 x=0x=0?伴随的对流项 −uλx-u\lambda_x(u>0u>0)把信息从 x=1x=1 带向 x=0x=0——与流动方向相反。所以 x=1x=1 是伴随的“上游”,x=0x=0 的条件只能靠一个薄层来满足。

Why is the layer at x=0x=0? The adjoint convection term −uλx-u\lambda_x (with u>0u>0) carries information from x=1x=1 towards x=0x=0, against the flow. So x=1x=1 is upstream for the adjoint, and the condition at x=0x=0 can only be met through a thin layer.

外解。略去 νλxx\nu\lambda_{xx},得 −uλx=−(1+x)-u\lambda_x=-(1+x);从上游端 λout(1)=0\lambda_{\rm out}(1)=0 积分,得

Outer solution. Drop νλxx\nu\lambda_{xx}: −uλx=−(1+x)-u\lambda_x=-(1+x), integrated from the upstream end λout(1)=0\lambda_{\rm out}(1)=0:

λout(x)=−∫x11+tu(t) dt,λout(0)=−∫011+tu(t) dt=−1.561867.\lambda_{\rm out}(x)=-\int_x^1\frac{1+t}{u(t)}\,\mathrm dt,\qquad \lambda_{\rm out}(0)=-\int_0^1\frac{1+t}{u(t)}\,\mathrm dt=−1.561867.

内解。在 x=0x=0 附近 u≈uinu\approx u_{\rm in},层内 λ\lambda 变化快、1+x1+x 的作用可略,方程近似为 −uinλx−νλxx=0-u_{\rm in}\lambda_x-\nu\lambda_{xx}=0,解为 C1+C2e−uinx/νC_1+C_2e^{-u_{\rm in}x/\nu}。要求 λ(0)=0\lambda(0)=0、在层外与外解匹配,得复合近似:

Inner solution. Near x=0x=0, u≈uinu\approx u_{\rm in}; inside the layer λ\lambda varies fast and the source 1+x1+x is negligible, so the equation is approximately −uinλx−νλxx=0-u_{\rm in}\lambda_x-\nu\lambda_{xx}=0, whose solutions are C1+C2e−uinx/νC_1+C_2e^{-u_{\rm in}x/\nu}. Requiring λ(0)=0\lambda(0)=0 and a match with the outer solution outside the layer gives the composite approximation:

λ(x)≈λout(x)−λout(0) e−uinx/ν⟹λx(0)≈uinλout(0)ν,νλx(0)→uinλout(0)=−1.428865.\lambda(x)\approx\lambda_{\rm out}(x)-\lambda_{\rm out}(0)\,e^{-u_{\rm in}x/\nu}\quad\Longrightarrow\quad \lambda_x(0)\approx\frac{u_{\rm in}\lambda_{\rm out}(0)}{\nu},\qquad \nu\lambda_x(0)\to u_{\rm in}\lambda_{\rm out}(0)=−1.428865.

实验的答案:νλx(0)\nu\lambda_x(0) 趋于一个非零常数,所以边界项 −νλx(0) ∂uin/∂Dk-\nu\lambda_x(0)\,\partial u_{\rm in}/\partial D_k 在 ν→0\nu\to0 时不消失,而是趋于 −uinλout(0) ∂uin/∂Dk-u_{\rm in}\lambda_{\rm out}(0)\,\partial u_{\rm in}/\partial D_k。这也解释了离散的情形:边界面的黏性项 2ν/h2\nu/h 乘 ψ0\psi_0,只有网格分辨了宽度 ν/uin\nu/u_{\rm in} 的层,乘积 (2ν/h) ψ0(2\nu/h)\,\psi_0 才逼近 νλx(0)\nu\lambda_x(0)(第 16 节)。但进入梯度的是整个入口项 uˉin\bar u_{\rm in};在默认设计下,它在粗得多的网格上就已准确(第 16 节)。

The answer to the experiment: νλx(0)\nu\lambda_x(0) tends to a nonzero constant, so the boundary term −νλx(0) ∂uin/∂Dk-\nu\lambda_x(0)\,\partial u_{\rm in}/\partial D_k does not vanish as ν→0\nu\to0; it tends to −uinλout(0) ∂uin/∂Dk-u_{\rm in}\lambda_{\rm out}(0)\,\partial u_{\rm in}/\partial D_k. This also explains the discrete picture: the viscous boundary term 2ν/h2\nu/h multiplies ψ0\psi_0, and the product (2ν/h) ψ0(2\nu/h)\,\psi_0 approaches νλx(0)\nu\lambda_x(0) only once the mesh resolves the layer of width ν/uin\nu/u_{\rm in} (Section 16). What enters the gradient, however, is the whole inlet term uˉin\bar u_{\rm in}, and at the default design it is accurate on much coarser meshes (Section 16).

误差有多大。由 A.4,λx(0)\lambda_x(0) 的精确表达式为 λx(0)=−∫01Π dx/∫01e−Φ dx\lambda_x(0)=-\int_0^1\Pi\,\mathrm dx\big/\int_0^1e^{-\Phi}\,\mathrm dx(Π\Pi 是 A.4 积分因子公式里 λx(0)=0\lambda_x(0)=0 时的 λx\lambda_x)。对两个积分分别展开——分母用 Laplace 方法,∫01e−Φ=νuin(1−νux(0)/uin2+O(ν2))\int_0^1e^{-\Phi}=\tfrac{\nu}{u_{\rm in}}\bigl(1-\nu u_x(0)/u_{\rm in}^2+O(\nu^2)\bigr);分子用外展开加端点修正——得到两项形式渐近展开

How large is the error. The exact formula is λx(0)=−∫01Π dx/∫01e−Φ dx\lambda_x(0)=-\int_0^1\Pi\,\mathrm dx\big/\int_0^1e^{-\Phi}\,\mathrm dx, where Π\Pi is the λx\lambda_x of the integrating-factor formula of A.4 with λx(0)=0\lambda_x(0)=0. Expanding the two integrals separately (Laplace's method for the denominator, ∫01e−Φ=νuin(1−νux(0)/uin2+O(ν2))\int_0^1e^{-\Phi}=\tfrac{\nu}{u_{\rm in}}\bigl(1-\nu u_x(0)/u_{\rm in}^2+O(\nu^2)\bigr); an outer expansion with an end correction for the numerator) gives the formal two-term expansion

νλx(0)=uinλout(0)+γ1ν+O(ν2),γ1=uin[∫011u(1+xu)xdx+1uin2]+λout(0) ux(0)uin=0.18472.\nu\lambda_x(0)=u_{\rm in}\lambda_{\rm out}(0)+\gamma_1\nu+O(\nu^2),\qquad \gamma_1=u_{\rm in}\Bigl[\int_0^1\frac1u\Bigl(\frac{1+x}{u}\Bigr)_x\mathrm dx+\frac1{u_{\rm in}^2}\Bigr]+\frac{\lambda_{\rm out}(0)\,u_x(0)}{u_{\rm in}}=0.18472.

下表用谱方法核对(每个 ν\nu 一次求解):一项近似的误差除以 ν\nu 趋于 γ1\gamma_1,两项近似的剩余除以 ν2\nu^2 保持有界。默认 ν=0.01\nu=0.01 时一项近似差 2.3e−3(约 0.16%)。

The table checks this against the spectral solver (one solve per ν\nu): the error of the one-term approximation divided by ν\nu tends to γ1\gamma_1, and the remainder of the two-term approximation divided by ν2\nu^2 stays bounded. At the default ν=0.01\nu=0.01 the one-term approximation is off by 2.3e−3 (about 0.16%).

ν\nuλx(0)\lambda_x(0)νλx(0)\nu\lambda_x(0)νλx(0)−uinλout(0)\nu\lambda_x(0)-u_{\rm in}\lambda_{\rm out}(0)误差 /ν/\nuerror /ν/\nu两项后误差 /ν2/\nu^2after two terms /ν2/\nu^2
0.1−13.5304−1.3530427.58e−20.75825.74
0.03−47.2758−1.4182731.06e−20.35315.61
0.01−142.6568−1.4265682.30e−30.22974.50
0.003−476.0922−1.4282775.89e−40.19623.82
0.001−1428.6769−1.4286771.88e−40.18833.59
图 80 · 边界层的渐近核对。左:νλ_x(0)(点)趋于 u_inλ_out(0)=−1.4289(虚线),紫色点线是两项展开 u_inλ_out(0)+γ_1ν。右:一项近似的误差按 ν 下降,两项近似的误差按 ν^2 下降。数值证据,不是证明。−1.45−1.4−1.35−1.3−1.25−1.20.0010.010.1νν λx​(0)边界项的系数保持 O(1)谱方法解uin​ λout​(0)两项展开10-6​10-5​10-4​10-3​10-2​10-1​10.0010.010.1ν误差渐近式的误差一项:∝ ν两项:∝ ν²
图 80 · 边界层的渐近核对。左:νλx(0)\nu\lambda_x(0)(点)趋于 uinλout(0)=−1.4289u_{\rm in}\lambda_{\rm out}(0)=−1.4289(虚线),紫色点线是两项展开 uinλout(0)+γ1νu_{\rm in}\lambda_{\rm out}(0)+\gamma_1\nu。右:一项近似的误差按 ν\nu 下降,两项近似的误差按 ν2\nu^2 下降。数值证据,不是证明。
Figure 80 · The boundary-layer asymptotics checked. Left: νλ_x(0) (dots) tends to u_inλ_out(0)=−1.4289 (dashed); the violet dotted line is the two-term expansion u_inλ_out(0)+γ_1ν. Right: the error of the one-term approximation falls like ν, that of the two-term approximation like ν^2. Numerical evidence, not a proof.−1.45−1.4−1.35−1.3−1.25−1.20.0010.010.1νν λx​(0)the boundary coefficient stays O(1)spectral solveuin​ λout​(0)two terms10-6​10-5​10-4​10-3​10-2​10-1​10.0010.010.1νerrorerror of the asymptoticsone term: ∝ νtwo terms: ∝ ν²
Figure 80 · The boundary-layer asymptotics checked. Left: νλx(0)\nu\lambda_x(0) (dots) tends to uinλout(0)=−1.4289u_{\rm in}\lambda_{\rm out}(0)=−1.4289 (dashed); the violet dotted line is the two-term expansion uinλout(0)+γ1νu_{\rm in}\lambda_{\rm out}(0)+\gamma_1\nu. Right: the error of the one-term approximation falls like ν\nu, that of the two-term approximation like ν2\nu^2. Numerical evidence, not a proof.

自己调 ν\nu:实验台每次用本页的谱方法重新求解,画出 λ\lambda、层内放大与复合近似,并给出 λx(0)\lambda_x(0)、νλx(0)\nu\lambda_x(0) 和梯度的两部分。

Move ν\nu yourself: the lab re-solves with this page's spectral solver each time, draws λ\lambda, the zoom into the layer with the composite approximation, and reports λx(0)\lambda_x(0), νλx(0)\nu\lambda_x(0) and the two parts of the gradient.

播放器把 ν\nu 从 0.2 一步步减到 0.001:看层怎样变薄,νλx(0)\nu\lambda_x(0) 的点怎样落到渐近线上,而梯度的和始终不变。

The player lowers ν\nu step by step from 0.2 to 0.001: watch the layer thin, the points of νλx(0)\nu\lambda_x(0) settle onto the asymptote, and the sum of the gradient stay put.

附录 B:格点格式

Appendix B: The node-centred scheme

本节实验:同一个问题,把未知量从单元移到节点上,离散梯度会更准吗?对三种重构各猜一次,再看 B.2 的表。

Experiment: The same problem with the unknowns moved from the cells to the nodes: is the discrete gradient more accurate? Guess for each of the three reconstructions, then read the table of B.2.

本页的推导和检查针对未知量放在单元里的有限体积格式。同一个问题——同样的方程、构造解、设计 D=(a,φ,ν)D=(a,\varphi,\nu)、目标 JJ、Rusanov 通量、三种重构和自动微分记号——也可以把未知量放在网格节点上:这是格点页的内容。它与本页平行(同样的 18 节和三个附录),每个数字都是针对那个格式重新推导、重新测量的。本附录只说明两种格式在哪里不同,并把两者的一组数字并排放在一起。

The derivations and checks of this page are for the finite-volume scheme with the unknowns in the cells. The same problem — the same equation, manufactured solution, design D=(a,φ,ν)D=(a,\varphi,\nu), objective JJ, Rusanov flux, the three reconstructions and the automatic-differentiation notation — can also be discretised with the unknowns at the mesh nodes; that is the subject of the node-centred page. It runs parallel to this one (the same 18 sections and three appendices), with every number re-derived and re-measured for that scheme. This appendix only says where the two schemes differ and puts one set of numbers side by side.

B.1 两种格式的差别

B.1 Where the two schemes differ

图 81 · 两种格式的网格(N=5 只为画图)。上:本页,未知量是单元平均,边界值进入两个边界面。下:格点页,未知量是节点上的值;两个边界节点的行是约束 U_0=u_in、U_N=u_out,其余每个节点的行是它周围对偶控制体(方框)上的守恒平衡,面在相邻两个节点的中点。格心(本页):未知量是单元平均 Ui​U0​U1​U2​U3​U4​uin​uout​N = 5 个单元、N + 1 = 6 个面;两个边界面读给定值(方块),离最近的单元中心 h/2格点(伙伴页):未知量是节点值 Uj​U1​U2​U3​U4​U0​ = uin​UN​ = uout​N = 5 个区间、N + 1 = 6 个节点、N = 5 个面;节点 0 与 N 的行是约束(方块)其余节点的行平衡它周围的对偶控制体(方框;两端的控制体只有一半宽)
图 81 · 两种格式的网格(N=5N=5 只为画图)。上:本页,未知量是单元平均,边界值进入两个边界面。下:格点页,未知量是节点上的值;两个边界节点的行是约束 U0=uinU_0=u_{\rm in}、UN=uoutU_N=u_{\rm out},其余每个节点的行是它周围对偶控制体(方框)上的守恒平衡,面在相邻两个节点的中点。
Figure 81 · The two meshes (N=5 only for the drawing). Top: this page; the unknowns are cell averages and the boundary values enter the two boundary faces. Bottom: the node-centred page; the unknowns are values at the nodes, the rows of the two boundary nodes are the constraints U_0=u_in, U_N=u_out, and the row of every other node is the conservation balance on the dual interval around it (the box), with the faces at the midpoints between consecutive nodes.Cell-centred (this page): the unknowns are cell averages Ui​U0​U1​U2​U3​U4​uin​uout​N = 5 cells, N + 1 = 6 faces; the two boundary faces read the prescribed values (squares), h/2 from the nearest cell centreNode-centred (the partner page): the unknowns are nodal values Uj​U1​U2​U3​U4​U0​ = uin​UN​ = uout​N = 5 intervals, N + 1 = 6 nodes, N = 5 faces; the rows of nodes 0 and N are constraints (squares)the other rows balance the dual interval around the node (the box; the two end intervals are half as wide)
Figure 81 · The two meshes (N=5N=5 only for the drawing). Top: this page; the unknowns are cell averages and the boundary values enter the two boundary faces. Bottom: the node-centred page; the unknowns are values at the nodes, the rows of the two boundary nodes are the constraints U0=uinU_0=u_{\rm in}, UN=uoutU_N=u_{\rm out}, and the row of every other node is the conservation balance on the dual interval around it (the box), with the faces at the midpoints between consecutive nodes.

图 81 画出两个网格,下表列出两种格式的差别。

Figure 81 draws the two meshes; the table lists where the schemes differ.

方面Aspect格心(本页)Cell-centred (this page)格点(伙伴页)Node-centred (the partner page)
未知量UnknownsNN 个单元平均 UiU_i(i=0,…,N−1i=0,\dots,N-1)NN cell averages UiU_i (i=0,…,N−1i=0,\dots,N-1)N+1N+1 个节点值 Uj≈u(xj)U_j\approx u(x_j)(j=0,…,Nj=0,\dots,N,含两个边界节点)N+1N+1 nodal values Uj≈u(xj)U_j\approx u(x_j) (j=0,…,Nj=0,\dots,N, the two boundary nodes included)
控制体Control volumesNN 个单元,宽 hhthe NN cells, width hh节点周围的对偶控制体:内部宽 hh,两端宽 h/2h/2(两端的控制体只在目标函数的权重里出现)the dual intervals around the nodes: width hh inside, h/2h/2 at the two ends (the end intervals enter only the weights of the objective)
面FacesN+1N+1 个面;面 00 与面 NN 读给定值,离单元中心 h/2h/2(第 4 节)N+1N+1 faces; faces 00 and NN read the prescribed values, h/2h/2 from the cell centre (Section 4)NN 个面,每个面夹在相邻两个节点之间,两侧都有节点NN faces, each between two consecutive nodes, with a node on each side
边界条件Boundary conditions进入两个边界面的通量;两个端单元不重构(斜率取 0)inside the flux of the two boundary faces; the two end cells are not reconstructed (slope 0)两个约束行 R0=U0−uinR_0=U_0-u_{\rm in}、RN=UN−uoutR_N=U_N-u_{\rm out};边界节点的斜率取单侧差分(一阶格式取 0)two constraint rows R0=U0−uinR_0=U_0-u_{\rm in}, RN=UN−uoutR_N=U_N-u_{\rm out}; the slopes at the boundary nodes are one-sided differences (zero for first order)
精确的参照值Exact reference values精确单元平均,带 sinc⁡(h)\operatorname{sinc}(h) 因子(第 2 节)exact cell averages, with the factor sinc⁡(h)\operatorname{sinc}(h) (Section 2)点值 u∗(xj)u^*(x_j)point values u∗(xj)u^*(x_j)
目标函数Objective单元中心的中点和;对周期的 u∗u^* 与它的精确单元平均,当 N≥2N\ge2 时恰好等于 J∗J^*(第 7 节)midpoint sum over the cell averages; for the periodic u∗u^* and its exact cell averages it equals J∗J^* exactly when N≥2N\ge2 (Section 7)梯形和;Jh(u∗)−J∗=h212ux∗(0)+O(h4)J_h(u^*)-J^*=\tfrac{h^2}{12}u^*_x(0)+O(h^4)trapezoid sum; Jh(u∗)−J∗=h212ux∗(0)+O(h4)J_h(u^*)-J^*=\tfrac{h^2}{12}u^*_x(0)+O(h^4)
伴随里的边界数据Boundary data in the adjoint入口值的伴随 uˉin=dJh/duin\bar u_{\rm in}=\mathrm dJ_h/\mathrm du_{\rm in} 来自边界面;斜率 ψ0/(h/2)\psi_0/(h/2) 要到 h≪ν/uinh\ll\nu/u_{\rm in} 才接近 λx(0)\lambda_x(0)(第 16 节)the adjoint of the inlet value, uˉin=dJh/duin\bar u_{\rm in}=\mathrm dJ_h/\mathrm du_{\rm in}, comes from the boundary face; the slope ψ0/(h/2)\psi_0/(h/2) approaches λx(0)\lambda_x(0) only for h≪ν/uinh\ll\nu/u_{\rm in} (Section 16)约束行的乘子 ψ0\psi_0、ψN\psi_N 本身:−ψ0=dJh/duin-\psi_0=\mathrm dJ_h/\mathrm du_{\rm in},它逼近的是 −νλx(0)-\nu\lambda_x(0)the multipliers ψ0\psi_0, ψN\psi_N of the constraint rows themselves: −ψ0=dJh/duin-\psi_0=\mathrm dJ_h/\mathrm du_{\rm in}, aimed at −νλx(0)-\nu\lambda_x(0)

B.2 一个对照:目标与梯度的误差

B.2 One comparison: the errors of the objective and the gradient

下表在默认设计(a=0.2a=0.2,φ=0.07\varphi=0.07,ν=0.01\nu=0.01)下,对两种格式、三种重构和 N=8N=8、6464 两个网格,给出离散目标与精确值之差 ∣Jh−J∗∣|J_h-J^*|(J∗=32−acos⁡2πφ2π=1.471198J^*=\tfrac32-\tfrac{a\cos2\pi\varphi}{2\pi}=1.471198),以及离散梯度 Dˉ=RDTψ\bar D=R_D^T\psi 与精确梯度 dJ/dD=(−0.144008,0.085156,0)\mathrm dJ/\mathrm dD=(-0.144008, 0.085156, 0) 的最大分量误差。两个模型在构建页面时都被运行,数字由 check_g.js 与两个独立的 Python 参考逐项对照。

At the default design (a=0.2a=0.2, φ=0.07\varphi=0.07, ν=0.01\nu=0.01), for both schemes, the three reconstructions and the two meshes N=8N=8 and 6464, the table gives the difference ∣Jh−J∗∣|J_h-J^*| between the discrete objective and its exact value (J∗=32−acos⁡2πφ2π=1.471198J^*=\tfrac32-\tfrac{a\cos2\pi\varphi}{2\pi}=1.471198), and the largest component error of the discrete gradient Dˉ=RDTψ\bar D=R_D^T\psi against the exact gradient dJ/dD=(−0.144008,0.085156,0)\mathrm dJ/\mathrm dD=(-0.144008, 0.085156, 0). Both models are run when the page is built, and check_g.js holds the numbers to the two independent Python references.

重构ReconstructionNN格心 ∣Jh−J∗∣|J_h-J^*|cell ∣Jh−J∗∣|J_h-J^*|格心 ∥Dˉ−dJ/dD∥∞\|\bar D-\mathrm dJ/\mathrm dD\|_\inftycell ∥Dˉ−dJ/dD∥∞\|\bar D-\mathrm dJ/\mathrm dD\|_\infty格点 ∣Jh−J∗∣|J_h-J^*|node ∣Jh−J∗∣|J_h-J^*|格点 ∥Dˉ−dJ/dD∥∞\|\bar D-\mathrm dJ/\mathrm dD\|_\inftynode ∥Dˉ−dJ/dD∥∞\|\bar D-\mathrm dJ/\mathrm dD\|_\infty
一阶first order81.1e−16.0e−11.9e−11.0e0
一阶first order642.3e−23.2e−13.0e−21.6e−1
无限制器线性unlimited linear86.3e−23.4e−17.3e−33.3e−1
无限制器线性unlimited linear649.5e−31.8e−12.4e−41.4e−2
光滑限制器smooth limiter89.1e−25.1e−18.5e−34.7e−1
光滑限制器smooth limiter641.1e−21.3e−11.3e−31.1e−1

在这六行里,无限制器线性与光滑限制器的格点误差都比格心的小;一阶的格点目标误差反而大,梯度误差在 N=8N=8 时更大(1.0e0 对 6.0e−1)、N=64N=64 时则更小(1.6e−1 对 3.2e−1)。这只是对这两个网格的描述:两个网格不构成收敛研究,加密时的行为——每个分量、每种重构随 NN 的变化——在格点页的第 15、16 节测量。

In these six rows the node-centred errors are the smaller ones for unlimited linear and the smooth limiter; for first order the node-centred objective error is the larger one, and the gradient error is larger at N=8N=8 (1.0e0 against 6.0e−1) and smaller at N=64N=64 (1.6e−1 against 3.2e−1). That describes these two meshes only: two meshes are not a convergence study, and the behaviour under refinement — each component, each reconstruction, as a function of NN — is measured in Sections 15 and 16 of the node-centred page.

图 82 · 两种格式的误差随 N 的变化(默认设计,N=8,16,32,64;颜色表示重构)。左:|J_h-J*|;右:梯度的最大分量误差 ‖D-bar- dJ/ dD‖_∞。实心点与实线:格心(本页);空心圈与虚线:格点(伙伴页)。四个网格读不出可靠的收敛阶;加密时的收敛阶在格点页的第 15 节测量。10-4​10-3​10-2​10-1​18163264N目标误差 |Jh​ − J*|一阶无限制器线性光滑限制器0.010.11108163264N梯度误差 max 分量格心(本页)格点(伙伴页)
图 82 · 两种格式的误差随 NN 的变化(默认设计,N=8,16,32,64N=8,16,32,64;颜色表示重构)。左:∣Jh−J∗∣|J_h-J^*|;右:梯度的最大分量误差 ∥Dˉ−dJ/dD∥∞\|\bar D-\mathrm dJ/\mathrm dD\|_\infty。实心点与实线:格心(本页);空心圈与虚线:格点(伙伴页)。四个网格读不出可靠的收敛阶;加密时的收敛阶在格点页的第 15 节测量。
Figure 82 · The errors of the two schemes against N (default design, N=8,16,32,64; the colour is the reconstruction). Left: |J_h-J*|; right: the largest component error of the gradient, ‖D-bar- dJ/ dD‖_∞. Dots and solid lines: cell-centred (this page); rings and dashed lines: node-centred (the partner page). Four meshes do not give a reliable order of convergence; the orders under refinement are measured in Section 15 of the node-centred page.10-4​10-3​10-2​10-1​18163264Nobjective error |Jh​ − J*|first orderunlimited linearsmooth limiter0.010.11108163264Ngradient error, largest componentcell (this page)node (partner page)
Figure 82 · The errors of the two schemes against NN (default design, N=8,16,32,64N=8,16,32,64; the colour is the reconstruction). Left: ∣Jh−J∗∣|J_h-J^*|; right: the largest component error of the gradient, ∥Dˉ−dJ/dD∥∞\|\bar D-\mathrm dJ/\mathrm dD\|_\infty. Dots and solid lines: cell-centred (this page); rings and dashed lines: node-centred (the partner page). Four meshes do not give a reliable order of convergence; the orders under refinement are measured in Section 15 of the node-centred page.

图 82 把表扩展到四个网格;下面的实验台列出同样的数字,并给出三个梯度分量和 Newton 迭代次数。

Figure 82 extends the table to four meshes; the lab below lists the same numbers with the three gradient components and the number of Newton iterations.

边界数据的伴随给出另一个对照(无限制器线性,N=8N=8,默认设计):格点格式里,约束行的乘子给出 −ψ0=1.4061-\psi_0=1.4061,与连续值 −νλx(0)=1.4266-\nu\lambda_x(0)=1.4266 相差 1.4%;本页的 uˉin\bar u_{\rm in}(第 16 节)是 1.4949,相差 4.8%。

The adjoint of the boundary data gives a second comparison (unlimited linear, N=8N=8, default design): on the node-centred scheme the multiplier of the constraint row gives −ψ0=1.4061-\psi_0=1.4061, 1.4% from the continuous value −νλx(0)=1.4266-\nu\lambda_x(0)=1.4266; the uˉin\bar u_{\rm in} of this page (Section 16) is 1.4949, 4.8% from it.

这是数值证据,不是定理:它只对这一个问题、这两个网格成立。格点页的页首与各节说明哪些结论只属于那个格式。

This is numerical evidence, not a theorem: it holds for this one problem and these two meshes. The node-centred page says in its own sections which statements belong to that scheme only.

附录 C:复现与数据

Appendix C: Reproduction and data

本节实验:页面上的一个数字从哪里来?挑一个——比如第 15 节里 N=16384N=16384 的梯度误差——按图 83 追到产生它的程序、记录它的文件和核对它的检查。

Experiment: where does a number on this page come from? Pick one, say the gradient error of Section 15 at N=16384N=16384, and follow Figure 83 to the program that produced it, the file that records it and the check that holds it.

本页的数字有三个来源:浏览器里的模型(model.js,正文各节与附录 A 的连续伴随)、附录的数值(figs_g.js),以及独立的 Python 包算出的大网格数据。三者各有核对;本附录把它们列清楚,并给出复现的命令。

The numbers of this page have three sources: the model in the browser (model.js: the main sections and the continuous adjoint of Appendix A), the numerics of the appendices (figs_g.js), and the large-grid data of an independent Python package. Each is checked; this appendix lists how, and gives the commands to reproduce them.

图 83 · 数字的来路。上排:Python 包写出带出处的 JSON,data.js 在每次构建时核对哈希与标注,构建程序把数字写进页面。中排:浏览器里运行的两份代码(model.js、figs_g.js)与构建程序 build.js。下排:把它们与独立计算核对的检查(箭头指向被核对的对象)。Python 包python/burgers_viscous/solve.py(正文模型)各自的单元测试结果文件(JSON)命令、版本、UTC 时间实现的 SHA-256mathematical_proof = false误差、剖面、Newton 历史data.js每次构建都核对:实现哈希与文件一致标注为数值证据字段齐全、无 NaN/Infmodel.js浏览器里的模型:残差、前向、伴随、求解、连续伴随(谱方法)SHA-256 1c04a44882e0…figs_g.js附录的数值:切线配点法、积分因子、两个模型的对照、SHA-256(λ 取自 model.js)构建 build.jslesson_*.js 写正文与图数字来自模型与数据记入 facts.json→ adjoint_burgers_viscous_cell.html独立的 Python 审计audit/ref_model.py → reference.jsonaudit/audit_*.py连续伴随、求解器、点积检验(NumPy、SciPy)JavaScript 检查check_model.js (--selftest)check_g.js (--selftest)把模型与附录数值与独立计算核对页面上的检查tools/probe.jsexperiments/check_site_widths.js无控制台错误、无空面板、手机宽度不横向滚动
图 83 · 数字的来路。上排:Python 包写出带出处的 JSON,data.js 在每次构建时核对哈希与标注,构建程序把数字写进页面。中排:浏览器里运行的两份代码(model.js、figs_g.js)与构建程序 build.js。下排:把它们与独立计算核对的检查(箭头指向被核对的对象)。
Figure 83 · Where the numbers come from. Top: the Python package writes JSON with its provenance, data.js checks hashes and labels at every build, and the builder writes the numbers into the page. Middle: the two pieces of code that run in the browser (model.js, figs_g.js) and the builder build.js. Bottom: the checks that hold them to independent computations (the arrows point at what is checked).Python packagepython/burgers_viscous/solve.py (main model)their own unit testsresult files (JSON)command, versions, UTC timeSHA-256 of the implementationmathematical_proof = falseerrors, profiles, Newton historydata.jschecked at every build:implementation hash matcheslabelled numerical evidencefields present and finitemodel.jsthe browser model: residual,tangent, adjoint, solves,continuous adjoint (spectral)SHA-256 1c04a44882e0…figs_g.jsappendix numerics: tangentcollocation, integrating factor,the comparison of two models,SHA-256 (λ from model.js)build: build.jslesson_*.js write text, figuresnumbers from model and dataregistered in facts.json→ adjoint_burgers_viscous_cell.htmlindependent Python auditsaudit/ref_model.py → reference.jsonaudit/audit_*.pycontinuous adjoint, solvers, dot tests(NumPy, SciPy)JavaScript gatescheck_model.js (--selftest)check_g.js (--selftest)hold the model and the appendixnumerics to independent onesgates on the pagetools/probe.jsexperiments/check_site_widths.jsno console error, no empty lab,no sideways scroll on phones
Figure 83 · Where the numbers come from. Top: the Python package writes JSON with its provenance, data.js checks hashes and labels at every build, and the builder writes the numbers into the page. Middle: the two pieces of code that run in the browser (model.js, figs_g.js) and the builder build.js. Bottom: the checks that hold them to independent computations (the arrows point at what is checked).

C.1 Python 包

C.1 The Python package

Python 包位于 python/burgers_viscous/,与页面一起发布,只依赖 NumPy 与 SciPy。各文件的作用:

The package lives in python/burgers_viscous/, published with the page; it needs only NumPy and SciPy. What each file does:

文件File作用Role
solve.py正文的单元中心模型(残差、Newton、前向与伴随、加密研究、完整重算的差分核对);写出 examples/ 的数据the cell-centred model of the main text (residual, Newton, tangent and adjoint, refinement study, FD check with full re-solves); writes the data of examples/
fd_scan.py差分步长扫描,每个步长两次完整求解(examples/fd_scan.json)the FD step scan with two full solves per step (examples/fd_scan.json)
test_solver.py单元测试:Jacobian 与复数步长比较、转置、加密、连续伴随的边界配对、原 JavaScript 内核的快照unit tests: Jacobian against complex step, transposes, refinement, the continuous boundary pairing, a snapshot of the original JavaScript kernel
requirements.txt依赖:NumPy、SciPydependencies: NumPy, SciPy
README.md方程、格式、命令与限制equation, scheme, commands and limits
examples/存储的数据 refinement_none.json、refinement_first.json、large_65536.json、fd_scan.json、javascript_reference.json、tests.log;其中三个另有 CSV 版本(refinement_none.csv、refinement_first.csv、large_65536.csv)the stored data refinement_none.json, refinement_first.json, large_65536.json, fd_scan.json, javascript_reference.json, tests.log; three of them also as CSV (refinement_none.csv, refinement_first.csv, large_65536.csv)

C.2 复现:命令与出处

C.2 Reproduction: commands and provenance

每个结果文件都记录了产生它的命令、程序版本、生成时间、Python/NumPy/SciPy 版本、平台和实现文件的 SHA-256,并标注 mathematical_proof = false。下面的命令直接取自这些记录(解释器路径换成 python3);在包的目录里运行:

Every result file records the command that produced it, the program version, the generation time, the Python/NumPy/SciPy versions, the platform and the SHA-256 of the implementation, and is labelled mathematical_proof = false. The commands below are taken from these records (with the interpreter path replaced by python3); run them in the package directory:

# examples/refinement_none.json  (2026-10-02T08:35:50Z)
python3 solve.py --grids 32,64,128,256,512,1024,2048,4096,8192,16384 \
    --nu .01 --reconstruction none --gradient-check \
    --continuous-adjoint --output examples/refinement_none.json

# examples/refinement_first.json  (2026-10-02T08:35:51Z)
python3 solve.py --grids 32,64,128,256,512,1024,2048,4096 --nu .01 \
    --reconstruction first --gradient-check \
    --output examples/refinement_first.json

# examples/large_65536.json  (2026-10-02T08:35:53Z)
python3 solve.py --cells 65536 --nu .01 --reconstruction none \
    --gradient-check --output examples/large_65536.json
文件File页面上的用途Used in生成(UTC)Generated (UTC)版本VersionPython / NumPy / SciPyPython / NumPy / SciPy
examples/refinement_none.json第 7、15、16、18 节,C.2 的实验台与图 84(无限制器线性,N = 32 … 16384)Sections 7, 15, 16, 18, the lab of C.2 and Figure 84 (unlimited linear, N = 32 … 16384)2026-10-02T08:35:50Z1.0.03.14.3 / 2.4.6 / 1.18.1
examples/refinement_first.json第 7、15、16、18 节,C.2 的实验台与图 84(一阶,N = 32 … 4096)Sections 7, 15, 16, 18, the lab of C.2 and Figure 84 (first order, N = 32 … 4096)2026-10-02T08:35:51Z1.0.03.14.3 / 2.4.6 / 1.18.1
examples/large_65536.json第 15 节与图 84(N = 65536)Section 15 and Figure 84 (N = 65536)2026-10-02T08:35:53Z1.0.03.14.3 / 2.4.6 / 1.18.1

SHA-256(构建时计算):实现文件 solve.py 与页面读入的三个结果文件。C.1 列出的 examples/fd_scan.json,本页既不读取,也不计算哈希;它由 fd_scan.py 生成,其 implementation_sha256 是 solve.py 的哈希,source_sha256 另记了 solve.py 与 fd_scan.py 两个文件的哈希。data.js 拒绝实现哈希与当前程序不符的数据,所以页面上的数字一定来自这个程序的当前版本。

SHA-256 (computed at build time): the implementation file solve.py and the three result files the page reads. examples/fd_scan.json, listed in C.1, is neither read nor hashed by the page; it was produced by fd_scan.py, its implementation_sha256 is the hash of solve.py, and its source_sha256 records the hashes of both solve.py and fd_scan.py. data.js refuses data whose implementation hash differs from the current program, so the numbers on this page come from the current version of this program.

文件FileSHA-256SHA-256
examples/large_65536.json1241daca39fb2433ca6510c4edf58fac5475abf88d3a294596f2dc73dac5cd17
examples/refinement_first.json867fa572cfd7972361d20f954bb14905ef2b07bcb00ace4ac12d2fffbf6ff048
examples/refinement_none.json1bfc1b10868196bfd8527baa5b28d758e2505fdc4b21a0d3b5dd2502a78ecdfa
solve.py0d36ac3febcd7e74c8f21cf95a1068554264c0982955dbbd6a7ebf9856586e3e
图 84 · 每次存储计算在生成数据的机器上的用时(JSON 里的 elapsed_seconds)。这些是实测,不是性能保证;本页不依赖它们。0.0010.010.1110102​103​104​105​单元或区间数 N用时(s)每次存储计算在生成数据的机器上的用时(实测,不是性能保证)正文模型,无限制器线性正文模型,一阶N = 65536
图 84 · 每次存储计算在生成数据的机器上的用时(JSON 里的 elapsed_seconds)。这些是实测,不是性能保证;本页不依赖它们。
Figure 84 · The time of every stored run on the recording machine (elapsed_seconds of the JSON). These are measurements, not performance guarantees; nothing on this page depends on them.0.0010.010.1110102​103​104​105​cells or intervals Ntime (s)time of every stored run on the recording machine (measured, not a guarantee)main model, unlimited linearmain model, first orderN = 65536
Figure 84 · The time of every stored run on the recording machine (elapsed_seconds of the JSON). These are measurements, not performance guarantees; nothing on this page depends on them.

在浏览器里复现:选一次存储的计算,实验台用本页的代码重新求解,并逐位比较目标与梯度。

Reproduce in the browser: pick a stored run, the lab re-solves it with this page's code and compares the objective and the gradient digit by digit.

C.3 本页自己的检查

C.3 The page’s own checks

在源码目录 viscous_burgers/ 里运行(Node.js;Python 3 需要 NumPy、SciPy、SymPy):

Run in the source directory viscous_burgers/ (Node.js; Python 3 with NumPy, SciPy and SymPy):

# the page and its data (data.js checks every hash and label)
node build.js
# the browser model against the independent Python reference, and planted faults
node check_model.js
node check_model.js --selftest
# the numerics of the appendices (continuous adjoint, the comparison of Appendix B, SHA-256)
node check_g.js
node check_g.js --selftest
# the independent Python reference and its audits (reference.json is what check_model.js reads)
python3 audit/audit_math.py
python3 audit/audit_solve.py
python3 audit/audit_continuous.py
python3 audit/make_reference.py
# the built page in headless Chrome: console errors, empty labs, both languages
node tools/probe.js
# the tests of the Python package itself (in python/burgers_viscous/)
python3 -m unittest -v test_solver.py

C.4 各项说法如何核对

C.4 What is verified, and how

页面上的说法Claim on the page检查Check方式与容差How, tolerance
残差、Jacobian、前向与伴随语句(正文模型)residual, Jacobians, tangent and reverse statements (main model)check_model.js;audit/audit_math.pycheck_model.js; audit/audit_math.py与独立 Python 参考及复数步长比较,1e−12;点积检验against the independent Python reference and complex step, 1e−12; dot test
前向 = 伴随,与完整重算的差分比较tangent = adjoint, against FD with full re-solvescheck_model.js;audit/audit_solve.pycheck_model.js; audit/audit_solve.py1e−12;差分 1e−71e−12; FD 1e−7
连续伴随(附录 A 的谱方法)continuous adjoint (the spectral solver of Appendix A)check_model.js;check_g.jscheck_model.js; check_g.js与 Python 求解器比较 1e−10;与积分因子法比较 1e−10(相对)against the Python solver 1e−10; against the integrating factor 1e−10 (relative)
梯度公式与边界项、对偶恒等式gradient formula with its boundary term, the duality identitycheck_g.js;audit/audit_continuous.pycheck_g.js; audit/audit_continuous.py与精确梯度比较 1e−12;切线解与伴随之差 1e−11against the exact gradient 1e−12; tangent against adjoint 1e−11
边界层的两项展开the two-term layer expansioncheck_g.jscheck_g.js数值:误差/ν→γ1/\nu\to\gamma_1、剩余/ν2/\nu^2 有界(形式推导,非证明)numerical: error/ν→γ1/\nu\to\gamma_1, remainder/ν2/\nu^2 bounded (formal derivation, not a proof)
附录 B 的对照(两个模型的目标与梯度、−ψ0-\psi_0)the comparison of Appendix B (objective and gradient of the two models, −ψ0-\psi_0)check_g.jscheck_g.js与两个独立的 Python 参考比较,1e−9against the two independent Python references, 1e−9
数据的出处与完整性provenance and integrity of the datadata.js(每次构建)data.js (every build)SHA-256、标注、字段SHA-256, labels, fields
页面能运行、手机上不横向滚动the page runs, no sideways scroll on phonestools/probe.js;experiments/check_site_widths.jstools/probe.js; experiments/check_site_widths.js无控制台错误,375/360/320 pxno console error, 375/360/320 px

这些检查都是数值证据:它们说明代码与公式一致、与独立计算一致、与存储的数据一致,但不证明非线性问题或格式的存在性、唯一性或收敛定理。本页的证明是附录 A.4 以及第 5–7 节的短证明(Newton 的二次余项、一阶 Jacobian 的 M 矩阵性质与 GS 收敛、周期解下 JhJ_h 的精确性);其余标明为“未证明”的地方,就是未证明。

All these checks are numerical evidence: they show that the code agrees with the formulas, with independent computations and with the stored data, but they do not prove existence, uniqueness or convergence theorems for the nonlinear problem or the scheme. The proofs on this page are those of Appendix A.4 and the short proofs of Sections 5–7 (the quadratic remainder of Newton's method, the M-matrix property and the Gauss–Seidel convergence for the first-order Jacobian, the exactness of JhJ_h for the periodic solution); whatever is labelled unproved is unproved.

C.5 浏览器模型的源码

C.5 The source of the browser model

下面是页面运行的 model.js 全文,SHA-256 为 1c04a44882e03bc8f507991db1b4bef536696e352eed3711e9e8aef902e8eb49(构建时计算)。实验台可以在你的浏览器里重新计算这个哈希。

Below is the full model.js the page runs, with SHA-256 1c04a44882e03bc8f507991db1b4bef536696e352eed3711e9e8aef902e8eb49 (computed at build time). The lab can recompute this hash in your browser.

model.js 全文(点击展开)model.js in full (click to open)
'use strict';
/* The cell-centred viscous Burgers model of the page: the residual code, its tangent code and its reverse code, written statement by
   statement exactly as the page prints them (Sections 3, 5, 8, 9), and the solves built on them.  Nothing here is generated by an AD tool:
   viscous_burgers/audit/ (Python, complex step, dot tests, an independent spectral solver) holds every formula of this file to account, and
   check_model.js compares this file with it.

   Problem.  q(u) = u^2/2 - nu u_x,  q_x = s(x; D) on (0,1), u(0) = u_in, u(1) = u_out.  Manufactured: u*(x; D) = 1 + a sin(2 pi (x - phi)),
   D = (a, phi, nu), s = q*_x, u_in = u*(0), u_out = u*(1).  Objective J = int_0^1 (1 + x) u dx = 3/2 - a cos(2 pi phi)/(2 pi).
   Mesh.  N cells of width h = 1/N; face f at x_f = f h (f = 0..N); cell i between faces i and i+1; U_i = the average of u over cell i.
   Face flux  H_f = (qL^2 + qR^2)/4 - (qR - qL) - nu (UR - UL)/d_f        (Rusanov, fixed speed 2, plus the central viscous flux)
   Residual   R_i = H_{i+1} - H_i - (Q_{i+1} - Q_i),   Q_f = q*(x_f; D),   J_h = sum_i w_i U_i,  w_i = h (1 + x_i). */
(function (root) {
  const TWO_PI = 2 * Math.PI;
  const NUM = typeof module !== 'undefined' ? require('../experiments/numerics') : root.EduNumerics;

  /* ---------- the exact functions of the manufactured solution (D = [a, phi, nu]) ---------- */
  const ustar = (x, D) => 1 + D[0] * Math.sin(TWO_PI * (x - D[1]));
  const ustarX = (x, D) => TWO_PI * D[0] * Math.cos(TWO_PI * (x - D[1]));
  const qstar = (x, D) => { const u = ustar(x, D); return 0.5 * u * u - D[2] * ustarX(x, D); };
  /* tangent of Q = q*(x; D) for the seed Dd and its reverse (accumulated into Db) */
  function qstarD(x, D, Dd) {
    const z = TWO_PI * (x - D[1]), s = Math.sin(z), c = Math.cos(z), u = 1 + D[0] * s;
    return (u * s - D[2] * TWO_PI * c) * Dd[0] + (u * (-TWO_PI * D[0] * c) - D[2] * TWO_PI * TWO_PI * D[0] * s) * Dd[1] + (-TWO_PI * D[0] * c) * Dd[2];
  }
  function qstarB(x, D, Qb, Db) {
    const z = TWO_PI * (x - D[1]), s = Math.sin(z), c = Math.cos(z), u = 1 + D[0] * s;
    Db[0] += (u * s - D[2] * TWO_PI * c) * Qb;
    Db[1] += (u * (-TWO_PI * D[0] * c) - D[2] * TWO_PI * TWO_PI * D[0] * s) * Qb;
    Db[2] += (-TWO_PI * D[0] * c) * Qb;
  }
  /* boundary data and their tangents: u_in = u*(0), u_out = u*(1) (equal, u* is periodic) */
  const uin = D => ustar(0, D), uout = D => ustar(1, D);
  const uinD = (D, Dd) => Math.sin(TWO_PI * (0 - D[1])) * Dd[0] + (-TWO_PI * D[0] * Math.cos(TWO_PI * (0 - D[1]))) * Dd[1];
  const uoutD = (D, Dd) => Math.sin(TWO_PI * (1 - D[1])) * Dd[0] + (-TWO_PI * D[0] * Math.cos(TWO_PI * (1 - D[1]))) * Dd[1];
  const exactObjective = D => 1.5 - D[0] * Math.cos(TWO_PI * D[1]) / TWO_PI;
  const exactGradient = D => [-Math.cos(TWO_PI * D[1]) / TWO_PI, D[0] * Math.sin(TWO_PI * D[1]), 0];
  /* the cell average of u*: 1 + a sinc(h) sin(2 pi (x_i - phi)), sinc(h) = sin(pi h)/(pi h) */
  const exactAverage = (x, h, D) => x.map(xi => 1 + D[0] * (Math.sin(Math.PI * h) / (Math.PI * h)) * Math.sin(TWO_PI * (xi - D[1])));

  function make(opts) {
    const N = opts.N, kind = opts.kind || 'none', eps = opts.eps === undefined ? 0.01 : opts.eps;
    if (!Number.isInteger(N) || N < 4 || N > 4096) throw Error('viscous Burgers: N must be an integer in [4, 4096]');
    if (!['first', 'none', 'smooth'].includes(kind)) throw Error('viscous Burgers: the reconstruction is first, none or smooth');
    if (!(eps > 0)) throw Error('viscous Burgers: eps > 0');
    const h = 1 / N, x = Array.from({length: N}, (_, i) => (i + 0.5) * h), xf = Array.from({length: N + 1}, (_, f) => f * h);
    const w = x.map(xi => h * (1 + xi));
    const zeros = n => new Array(n).fill(0);

    /* the slope of cell i from its two one-sided differences m = U_i - U_{i-1}, p = U_{i+1} - U_i, and its partial derivatives */
    function sigma(m, p) {
      if (kind === 'first') return 0;
      if (kind === 'none') return 0.5 * (m + p);
      return m * p * (m + p) / (m * m + p * p + eps * eps);
    }
    function sigmaD(m, p) {
      if (kind === 'first') return [0, 0];
      if (kind === 'none') return [0.5, 0.5];
      const den = m * m + p * p + eps * eps, num = m * p * (m + p);
      return [((2 * m * p + p * p) * den - 2 * m * num) / (den * den), ((m * m + 2 * m * p) * den - 2 * p * num) / (den * den)];
    }
    const dist = f => (f === 0 || f === N ? h / 2 : h);

    /* ---------- gather + reconstruct (statements 5-6 of the residual code of Sections 5, 8 and 9), for every face: the page's arrays ---------- */
    function faces(U, D) {
      const nu = D[2], s = zeros(N), qL = zeros(N + 1), qR = zeros(N + 1), UL = zeros(N + 1), UR = zeros(N + 1), d = zeros(N + 1), H = zeros(N + 1);
      for (let i = 1; i < N - 1; i++) s[i] = sigma(U[i] - U[i - 1], U[i + 1] - U[i]);
      for (let f = 0; f <= N; f++) {
        if (f === 0) { qL[f] = uin(D); UL[f] = uin(D); } else { qL[f] = U[f - 1] + 0.5 * s[f - 1]; UL[f] = U[f - 1]; }
        if (f === N) { qR[f] = uout(D); UR[f] = uout(D); } else { qR[f] = U[f] - 0.5 * s[f]; UR[f] = U[f]; }
        d[f] = dist(f);
        H[f] = 0.25 * (qL[f] * qL[f] + qR[f] * qR[f]) - (qR[f] - qL[f]) - nu * (UR[f] - UL[f]) / d[f];
      }
      return {s, qL, qR, UL, UR, d, H};
    }
    const sourceRows = D => { const S = zeros(N); for (let i = 0; i < N; i++) S[i] = qstar(xf[i + 1], D) - qstar(xf[i], D); return S; };

    /* ---------- PRIMAL: the residual code ---------- */
    function residual(U, D) {
      const F = faces(U, D), S = sourceRows(D), R = zeros(N);
      for (let f = 0; f <= N; f++) { if (f >= 1) R[f - 1] += F.H[f]; if (f <= N - 1) R[f] -= F.H[f]; }
      for (let i = 0; i < N; i++) R[i] -= S[i];
      return R;
    }
    const objective = U => U.reduce((acc, u, i) => acc + w[i] * u, 0);

    /* ---------- TANGENT: residual_d(U, Ud, D, Dd) = A Ud + R_D Dd, in the order of the primal code; tangentFaces returns every intermediate tangent ---------- */
    function tangentFaces(U, Ud, D, Dd) {
      const nu = D[2], nud = Dd[2], uind = uinD(D, Dd), uoutd = uoutD(D, Dd);
      const s = zeros(N), sd = zeros(N);
      for (let i = 1; i < N - 1; i++) {
        const m = U[i] - U[i - 1], p = U[i + 1] - U[i], md = Ud[i] - Ud[i - 1], pd = Ud[i + 1] - Ud[i], g = sigmaD(m, p);
        s[i] = sigma(m, p); sd[i] = g[0] * md + g[1] * pd;
      }
      const T = {s, sd, qL: zeros(N + 1), qLd: zeros(N + 1), qR: zeros(N + 1), qRd: zeros(N + 1), UL: zeros(N + 1), ULd: zeros(N + 1), UR: zeros(N + 1), URd: zeros(N + 1),
        cL: zeros(N + 1), cR: zeros(N + 1), Hd: zeros(N + 1), Qd: zeros(N + 1), Sd: zeros(N), uind, uoutd};
      const Rd = zeros(N);
      for (let f = 0; f <= N; f++) {
        let qL, qLd, UL, ULd, qR, qRd, UR, URd;
        if (f === 0) { qL = uin(D); qLd = uind; UL = qL; ULd = uind; } else { qL = U[f - 1] + 0.5 * s[f - 1]; qLd = Ud[f - 1] + 0.5 * sd[f - 1]; UL = U[f - 1]; ULd = Ud[f - 1]; }
        if (f === N) { qR = uout(D); qRd = uoutd; UR = qR; URd = uoutd; } else { qR = U[f] - 0.5 * s[f]; qRd = Ud[f] - 0.5 * sd[f]; UR = U[f]; URd = Ud[f]; }
        const cL = 0.5 * qL + 1, cR = 0.5 * qR - 1, df = dist(f);
        const Hd = cL * qLd + cR * qRd - nu * (URd - ULd) / df - nud * (UR - UL) / df;
        T.qL[f] = qL; T.qLd[f] = qLd; T.qR[f] = qR; T.qRd[f] = qRd; T.UL[f] = UL; T.ULd[f] = ULd; T.UR[f] = UR; T.URd[f] = URd; T.cL[f] = cL; T.cR[f] = cR; T.Hd[f] = Hd;
        if (f >= 1) Rd[f - 1] += Hd;
        if (f <= N - 1) Rd[f] -= Hd;
      }
      for (let f = 0; f <= N; f++) T.Qd[f] = qstarD(xf[f], D, Dd);
      for (let i = 0; i < N; i++) { T.Sd[i] = T.Qd[i + 1] - T.Qd[i]; Rd[i] -= T.Sd[i]; }
      T.Rd = Rd;
      return T;
    }
    const residualD = (U, Ud, D, Dd) => tangentFaces(U, Ud, D, Dd).Rd;

    /* ---------- REVERSE: residual_b(U, D, Rb) = (A^T Rb, R_D^T Rb), the statements of residual_d in reverse order, accumulating with += ---------- */
    function reverseFaces(U, D, Rb) {
      const nu = D[2], Ub = zeros(N), Db = [0, 0, 0];
      const Qb = zeros(N + 1);                                  // the adjoint of Q_f: statements R_i -= Q_{i+1} - Q_i run first in reverse
      for (let i = N - 1; i >= 0; i--) { Qb[i + 1] += -Rb[i]; Qb[i] += Rb[i]; }
      for (let f = N; f >= 0; f--) qstarB(xf[f], D, Qb[f], Db);
      const s = zeros(N), sm = zeros(N), sp = zeros(N), sb = zeros(N);
      for (let i = 1; i < N - 1; i++) { const m = U[i] - U[i - 1], p = U[i + 1] - U[i], g = sigmaD(m, p); s[i] = sigma(m, p); sm[i] = g[0]; sp[i] = g[1]; }
      const B = {Qb, Hb: zeros(N + 1), qLb: zeros(N + 1), qRb: zeros(N + 1), ULb: zeros(N + 1), URb: zeros(N + 1), sb, nub: zeros(N + 1)};
      let uinb = 0, uoutb = 0;
      for (let f = N; f >= 0; f--) {
        let qL, UL, qR, UR;
        if (f === 0) { qL = uin(D); UL = qL; } else { qL = U[f - 1] + 0.5 * s[f - 1]; UL = U[f - 1]; }
        if (f === N) { qR = uout(D); UR = qR; } else { qR = U[f] - 0.5 * s[f]; UR = U[f]; }
        const df = dist(f), Hb = (f >= 1 ? Rb[f - 1] : 0) - (f <= N - 1 ? Rb[f] : 0);
        const cL = 0.5 * qL + 1, cR = 0.5 * qR - 1, qLb = cL * Hb, qRb = cR * Hb, ULb = nu / df * Hb, URb = -nu / df * Hb;
        B.Hb[f] = Hb; B.qLb[f] = qLb; B.qRb[f] = qRb; B.ULb[f] = ULb; B.URb[f] = URb; B.nub[f] = -(UR - UL) / df * Hb;
        Db[2] += B.nub[f];
        if (f === 0) uinb += qLb + ULb; else { Ub[f - 1] += qLb + ULb; sb[f - 1] += 0.5 * qLb; }
        if (f === N) uoutb += qRb + URb; else { Ub[f] += qRb + URb; sb[f] += -0.5 * qRb; }
      }
      for (let i = N - 2; i >= 1; i--) { const mb = sm[i] * sb[i], pb = sp[i] * sb[i]; Ub[i] += mb - pb; Ub[i - 1] += -mb; Ub[i + 1] += pb; }
      const zin = TWO_PI * (0 - D[1]), zout = TWO_PI * (1 - D[1]);
      Db[0] += Math.sin(zin) * uinb + Math.sin(zout) * uoutb;
      Db[1] += -TWO_PI * D[0] * (Math.cos(zin) * uinb + Math.cos(zout) * uoutb);
      B.Ub = Ub; B.Db = Db; B.uinb = uinb; B.uoutb = uoutb;
      return B;
    }
    const residualB = (U, D, Rb) => { const B = reverseFaces(U, D, Rb); return {Ub: B.Ub, Db: B.Db}; };

    /* ---------- the Jacobians by columns of the tangent code ---------- */
    function jacState(U, D) {
      const A = Array.from({length: N}, () => zeros(N)), z = [0, 0, 0];
      for (let j = 0; j < N; j++) { const e = zeros(N); e[j] = 1; const col = residualD(U, e, D, z); for (let i = 0; i < N; i++) A[i][j] = col[i]; }
      return A;
    }
    function jacDesign(U, D) {
      const z = zeros(N), cols = [0, 1, 2].map(k => residualD(U, z, D, [0, 1, 2].map(m => (m === k ? 1 : 0))));
      return Array.from({length: N}, (_, i) => [cols[0][i], cols[1][i], cols[2][i]]);
    }
    const transpose = A => A[0].map((_, j) => A.map(r => r[j]));
    const infnorm = v => v.reduce((m, z) => Math.max(m, Math.abs(z)), 0);

    /* ---------- the primal solve: Newton with a backtracking line search and the original positive box 0.1 < U < 1.9 ---------- */
    function solve(D, o = {}) {
      let U = o.U0 ? o.U0.slice() : x.map(xi => ustar(xi, D));       // centre samples of u*: an initial guess only
      const history = [], states = [], tol = o.tol === undefined ? 1e-13 : o.tol, maxit = o.maxit || 35;
      for (let it = 0; it < maxit; it++) {
        const R = residual(U, D), A = jacState(U, D), dU = NUM.solve(NUM.factor(A), R.map(v => -v));
        const rn = infnorm(R), dn = infnorm(dU);
        history.push({iteration: it, residual: rn, correction: dn}); states.push(U.slice());
        if (dn <= tol || rn < 1e-15) return {U, history, states, converged: true};
        let step = 1, ok = false;
        for (let k = 0; k < 25; k++) {
          const T = U.map((u, i) => u + step * dU[i]);
          if (Math.min(...T) > 0.1 && Math.max(...T) < 1.9 && infnorm(residual(T, D)) < (1 - 1e-4 * step) * rn) { U = T; ok = true; break; }
          step *= 0.5;
        }
        if (!ok) return {U, history, states, converged: false, reason: 'line search failed'};
      }
      return {U, history, states, converged: false, reason: 'iteration limit'};
    }

    /* ---------- the tangent solves A v_k = -R_D e_k and the adjoint solve A^T psi = -g (g = w) ---------- */
    function sensitivities(U, D) {
      const A = jacState(U, D), RD = jacDesign(U, D), FA = NUM.factor(A), FAT = NUM.factor(transpose(A));
      const v = [0, 1, 2].map(k => NUM.solve(FA, RD.map(r => -r[k])));
      const psi = NUM.solve(FAT, w.map(z => -z));
      const gradTangent = v.map(vk => vk.reduce((acc, z, i) => acc + w[i] * z, 0));
      const gradAdjoint = [0, 1, 2].map(k => RD.reduce((acc, r, i) => acc + psi[i] * r[k], 0));
      return {A, RD, v, psi, gradTangent, gradAdjoint};
    }

    /* ---------- complex step: the SAME residual code with complex arithmetic (real and imaginary parts as two arrays); only the smooth operations the
       residual uses occur: + - * / and sin, cos of a complex argument ---------- */
    function residualComplex(Ure, Uim, Dre, Dim) {
      const C = {add: (a, b) => [a[0] + b[0], a[1] + b[1]], sub: (a, b) => [a[0] - b[0], a[1] - b[1]], mul: (a, b) => [a[0] * b[0] - a[1] * b[1], a[0] * b[1] + a[1] * b[0]],
        div: (a, b) => { const d = b[0] * b[0] + b[1] * b[1]; return [(a[0] * b[0] + a[1] * b[1]) / d, (a[1] * b[0] - a[0] * b[1]) / d]; },
        sc: (t, a) => [t * a[0], t * a[1]], k: t => [t, 0],
        sin: a => [Math.sin(a[0]) * Math.cosh(a[1]), Math.cos(a[0]) * Math.sinh(a[1])], cos: a => [Math.cos(a[0]) * Math.cosh(a[1]), -Math.sin(a[0]) * Math.sinh(a[1])]};
      const U = Ure.map((r, i) => [r, Uim[i]]), a = [Dre[0], Dim[0]], phi = [Dre[1], Dim[1]], nu = [Dre[2], Dim[2]];
      const ustarC = xx => C.add(C.k(1), C.mul(a, C.sin(C.sc(TWO_PI, C.sub(C.k(xx), phi)))));
      const qstarC = xx => { const z = C.sc(TWO_PI, C.sub(C.k(xx), phi)), u = C.add(C.k(1), C.mul(a, C.sin(z))), ux = C.mul(C.sc(TWO_PI, a), C.cos(z)); return C.sub(C.sc(0.5, C.mul(u, u)), C.mul(nu, ux)); };
      const sigmaC = (m, p) => {
        if (kind === 'first') return C.k(0);
        if (kind === 'none') return C.sc(0.5, C.add(m, p));
        return C.div(C.mul(C.mul(m, p), C.add(m, p)), C.add(C.add(C.mul(m, m), C.mul(p, p)), C.k(eps * eps)));
      };
      const s = Array.from({length: N}, () => C.k(0));
      for (let i = 1; i < N - 1; i++) s[i] = sigmaC(C.sub(U[i], U[i - 1]), C.sub(U[i + 1], U[i]));
      const R = Array.from({length: N}, () => C.k(0));
      for (let f = 0; f <= N; f++) {
        const qL = f === 0 ? ustarC(0) : C.add(U[f - 1], C.sc(0.5, s[f - 1])), UL = f === 0 ? ustarC(0) : U[f - 1];
        const qR = f === N ? ustarC(1) : C.sub(U[f], C.sc(0.5, s[f])), UR = f === N ? ustarC(1) : U[f];
        const H = C.sub(C.sub(C.sc(0.25, C.add(C.mul(qL, qL), C.mul(qR, qR))), C.sub(qR, qL)), C.sc(1 / dist(f), C.mul(nu, C.sub(UR, UL))));
        if (f >= 1) R[f - 1] = C.add(R[f - 1], H);
        if (f <= N - 1) R[f] = C.sub(R[f], H);
      }
      for (let i = 0; i < N; i++) R[i] = C.sub(R[i], C.sub(qstarC(xf[i + 1]), qstarC(xf[i])));
      return {re: R.map(z => z[0]), im: R.map(z => z[1])};
    }

    return {N, h, kind, eps, x, xf, w, dist, sigma, sigmaD, faces, sourceRows, residual, residualD, residualB, tangentFaces, reverseFaces, objective, jacState, jacDesign, transpose, solve, sensitivities, residualComplex,
      exactAverage: D => exactAverage(x, h, D), infnorm};
  }

  /* ---------- the continuous adjoint, by an independent method: Chebyshev collocation of  -u lam' - nu lam'' = -(1 + x),  lam(0) = lam(1) = 0 ---------- */
  function continuousAdjoint(D, M = 200) {
    const xc = Array.from({length: M + 1}, (_, k) => Math.cos(Math.PI * k / M)), c = xc.map((_, k) => (k === 0 || k === M ? 2 : 1) * (k % 2 ? -1 : 1));
    const Dm = Array.from({length: M + 1}, () => new Array(M + 1).fill(0));
    for (let i = 0; i <= M; i++) { let row = 0; for (let j = 0; j <= M; j++) if (i !== j) { Dm[i][j] = (c[i] / c[j]) / (xc[i] - xc[j]); row += Dm[i][j]; } Dm[i][i] = -row; }
    const x = xc.map(z => (z + 1) / 2), d1 = Dm.map(r => r.map(z => 2 * z));
    const d2 = d1.map((r, i) => r.map((_, j) => r.reduce((acc, z, k) => acc + z * d1[k][j], 0)));
    const L = d1.map((r, i) => r.map((z, j) => -ustar(x[i], D) * z - D[2] * d2[i][j])), rhs = x.map(z => -(1 + z));
    for (const i of [0, M]) { L[i] = new Array(M + 1).fill(0); L[i][i] = 1; rhs[i] = 0; }
    const lam = NUM.solve(NUM.factor(L), rhs), lamX = d1.map(r => r.reduce((acc, z, j) => acc + z * lam[j], 0));
    /* barycentric interpolation of lam and lam_x at arbitrary points */
    const bw = xc.map((_, k) => (k === 0 || k === M ? 0.5 : 1) * (k % 2 ? -1 : 1));
    const interp = (f, z) => { let num = 0, den = 0; for (let k = 0; k <= M; k++) { const dz = z - x[k]; if (Math.abs(dz) < 1e-15) return f[k]; const t = bw[k] / dz; num += t * f[k]; den += t; } return num / den; };
    return {x, lam, lamX, at: z => interp(lam, z), atX: z => interp(lamX, z)};
  }

  const api = {make, ustar, ustarX, qstar, qstarD, uin, uout, exactObjective, exactGradient, exactAverage, continuousAdjoint, TWO_PI,
    DEFAULT_D: [0.2, 0.07, 0.01], DEFAULTS: {N: 8, kind: 'none'}};
  if (typeof module !== 'undefined') module.exports = api; else root.ViscousBurgers = api;
})(typeof window !== 'undefined' ? window : globalThis);