/* First-order "upwind" scheme for 1-dim. advection. * Uses forward differencing in time and makes a choice of forward * or backward differencing in space based on the direction of the fluid flow. * First-order accurate in space and time. * To verify with CIVL: * civl verify upwindFirstOrder.cvl */ $input int n; // Number of points $assume(n >= 1); $input double h; // Distance between points $assume(0R has 2 continuous derivatives in [-1,1]x[0,100] $abstract $differentiable(2, [-1,1],[0,100]) $real u($real x, $real t); $input int step; // some arbitrary time step $assume(step >= 0); double v[n]; double v_new[n]; void upwindForward() { /*@ loop invariant $forall (int j:1..i-1) v_new[j] == v[j] - dt*a*(v[j+1]-v[j])/h; @ loop invariant 1<=i && i<=n-1; @ loop assigns i, v_new[1..n-2]; @*/ for (int i = 1; i < n-1; i++) { v_new[i] = v[i] - dt*a*(v[i+1] - v[i])/h; } } void upwindBackward() { /*@ loop invariant $forall (int j:1..i-1) v_new[j] == v[j] - dt*a*(v[j]-v[j-1])/h; @ loop invariant 1<=i && i<=n-1; @ loop assigns i, v_new[1..n-2]; @*/ for (int i = 1; i < n-1; i++) { v_new[i] = v[i] - dt*a*(v[i] - v[i-1])/h; } } void upwind() { if (a > 0) upwindBackward(); else upwindForward(); /*@ loop invariant 1<=i && i<=n-1; @ loop invariant $forall (int j:1..i-1) v[j] == v_new[j]; @ loop assigns i, v[1..n-2]; @*/ for (int i = 1; i < n-1; i++) { v[i] = v_new[i]; } } void main() { $assume(n*h <= 1); $assume(step*dt < 100); $assume($forall (int i:0..n-1) v[i] == u(i*h, step*dt)); /*@ loop invariant 0<=i && i<=n; @ loop invariant $forall (int j:0..i-1) v[j] == u1[j]; @ loop assigns i, v[0..n-1]; @*/ for (int i = 0; i < n; i++) { v[i] = u1[i]; } upwind(); $assert($uniform (int i:1..n-2) (u(i*h, (step+1)*dt)-v[i])/dt - $D[u,{t,1}](i*h, step*dt) - a*$D[u,{x,1}](i*h, step*dt) == $O(dt) + $O(h)); }