| 1 | /* 1-dimension diffusion equation solver with constant boundaries.
|
|---|
| 2 | * Accuracy is first-order in time and second order in space.
|
|---|
| 3 | * To verify with CIVL, type:
|
|---|
| 4 | * civl verify diffusion.cvl
|
|---|
| 5 | */
|
|---|
| 6 |
|
|---|
| 7 | $input int n; // number of discrete spatial points
|
|---|
| 8 | $assume(n >= 1);
|
|---|
| 9 | $input double dx; // distance between two consecutive points
|
|---|
| 10 | $assume(0<dx && dx<1);
|
|---|
| 11 | $input double dt; // duration of one time step
|
|---|
| 12 | $assume(0<dt && dt<1);
|
|---|
| 13 | $input double k; // diffusivity constant
|
|---|
| 14 | $assume(k > 0);
|
|---|
| 15 | $input double u_init[n]; // initial temperatures
|
|---|
| 16 | // assume u:R^2->R has 4 continuous derivatives in [-1,1]x[0,100]:
|
|---|
| 17 | $abstract $differentiable(4, [-1,1][0,100]) $real u($real x, $real t);
|
|---|
| 18 | $input int step; // some arbitrary time step
|
|---|
| 19 | $assume(step >= 0);
|
|---|
| 20 | double v[n]; // values at this time step
|
|---|
| 21 | double v_new[n]; // values at next time step
|
|---|
| 22 |
|
|---|
| 23 | /* Updates the array v. The new values of v are computed from the old
|
|---|
| 24 | * values of v, and the constants dt, dx, and k.
|
|---|
| 25 | */
|
|---|
| 26 | void update() {
|
|---|
| 27 | // compute the new values in v_new:
|
|---|
| 28 | /*@ loop invariant 1<=i && i<=n-1;
|
|---|
| 29 | @ loop invariant $forall (int j:1..i-1)
|
|---|
| 30 | @ v_new[j] == v[j] + dt*k*(v[j+1] - 2*v[j] + v[j-1])/(dx*dx);
|
|---|
| 31 | @ loop assigns i, v_new[1..n-2];
|
|---|
| 32 | @*/
|
|---|
| 33 | for (int i=1; i<n-1; i++) {
|
|---|
| 34 | v_new[i] = v[i] + dt*k*(v[i+1] - 2*v[i] + v[i-1])/(dx*dx);
|
|---|
| 35 | }
|
|---|
| 36 | // copy v_new back to v:
|
|---|
| 37 | /*@ loop invariant 1<=i && i<=n-1;
|
|---|
| 38 | @ loop invariant $forall (int j:1..i-1) v[j] == v_new[j];
|
|---|
| 39 | @ loop assigns i, v[1..n-2];
|
|---|
| 40 | @*/
|
|---|
| 41 | for (int i=1; i<n-1; i++) {
|
|---|
| 42 | v[i] = v_new[i];
|
|---|
| 43 | }
|
|---|
| 44 | }
|
|---|
| 45 |
|
|---|
| 46 | /* This main function is the driver.
|
|---|
| 47 | * The annotations assume v[i] is exactly u(i*dx,step*dt) just before
|
|---|
| 48 | * updating, and claim that the new v[i] is a very good approximation to
|
|---|
| 49 | * u(i*dx,(step+1)*dt). Specifically, the approximation is
|
|---|
| 50 | * O(dt)+O(dx^2) accurate in the interior spatial region. (The endpoints
|
|---|
| 51 | * are held constant.)
|
|---|
| 52 | */
|
|---|
| 53 | void main() {
|
|---|
| 54 | /*@ loop invariant 0<=i && i<=n;
|
|---|
| 55 | @ loop invariant $forall (int j:0..i-1) v[j] == u_init[j];
|
|---|
| 56 | @ loop assigns i, v[0..n-1];
|
|---|
| 57 | @*/
|
|---|
| 58 | for (int i = 0; i < n; i++) {
|
|---|
| 59 | v[i] = u_init[i];
|
|---|
| 60 | }
|
|---|
| 61 | $assume(n*dx < 1);
|
|---|
| 62 | $assume(step*dt < 100);
|
|---|
| 63 | $assume($forall (int i=0..n-1) v[i] == u(i*dx, step*dt));
|
|---|
| 64 | update();
|
|---|
| 65 | $assert($uniform (int i=1..n-2)
|
|---|
| 66 | (u(i*dx, (step+1)*dt) - v[i])/dt - $D[u,{t,1}](i*dx, step*dt) + k*$D[u,{x,2}](i*dx, step*dt)
|
|---|
| 67 | == $O(dt) + $O(dx*dx));
|
|---|
| 68 | }
|
|---|