/* diffusion1d_seq.mmp: 1d diffusion based on: 
 * diffusion1d_seq.c: sequential version of 1d diffusion.
 * The length of the rod is 1. The endpoints are frozen at 0 degrees.
 *
 * Author: Stephen F. Siegel <siegel@cis.udel.edu>, February, 2009.
 */

#include<stdlib.h>
#include<assert.h>

/* Global variables */
#pragma TASS input  {nx == 2}
int nx;          /* number of discrete points including endpoints */
#pragma TASS input {m>=0 && m <= 5} 
double m;           /* initial temperature of rod */
#pragma TASS input {k>0 && k<.5} 
double k;	   /* D*dt/(dx*dx) {k>0 && k<.5}*/
#pragma TASS input {nsteps>=1 && nsteps <= 5} 
int nsteps;  /* number of time steps */
#pragma TASS input {dt>0}
double dt;	       /* size of a time step */
#pragma TASS input 
double M1;                 /* constant bounds on 2nd derivative */
#pragma TASS input 
double M2;
double dx;			   	       /* distance between two grid points: 1/(nx-1) */
double v[nx];					   /* temperature function */
double v_new[nx];
double kappa;
int iter;				       /* the current iteration */

//abstract continuous(4) double u(double x, double t);  /* The double function we are approximating */

#pragma TASS output 
double data[nsteps][nx];

/* init: initializes global variables. */
void init() {
	int i;
	
	dx = 1.0/(nx-1);
	kappa = (k/dt)*dx*dx;
	i = 0;
	while (i < nx) {
		v[i] = m;
		i = i + 1;
	}
	v[0] = 0.0;
	v[nx-1] = 0.0;
}

/* write_plain: copy current data to output array */
void write(int time) {
	int i;
	
	i = 0;
	while (i < nx) {
		data[time][i] = v[i];
		i = i + 1;
	}
}



/* updates u for next time step. */
void update() {
	int i;
	
	/* This is our assumption about L[u] */  
	/*#pragma TASS assume forall {double t | t >= 0} forall {double x } */
	/*\D[u,{t,1}](t,x) - kappa*\D[u,{x,2}](t,x) == 0;*/  
	
	/*assume forall {double t} forall {double x} */
	/*  abs(\D[u,{t,2}](t,x)) <= M1 && abs(\D[u,{x,4}](t,x)) <= M2;*/
	
	//assume forall {double t} u(0,t) == 0;
	//assume forall {double t} u(dx*nx) == 0;
	/* With an insulated side:
	 #pragma TASS assume forall {double t} \D[u,{x,1}](0,t) == 0;
	 #pragma TASS assume forall {double t} u(dx*nx) == 0;
	 */
	
	/* Our assumption about v and u */
	//#pragma TASS assume forall {int i | 0 <= i && i <= nx-1} v[i] == u(i*dx, iter*dt);
	
	i = 1;
	while (i < nx-1) {
		v_new[i] =  v[i] + k*(v[i+1] + v[i-1] -2*v[i]);
		i = i + 1;
	}
	v_new[0] = 0.0;
	v_new[nx-1] = 0.0;
	
	/* We assume the boundary conditions at time iter are correct to get the b.c. at iter+1 */
	assert v_new[0] == 0;
	assert v_new[nx-1] == 0;
	
	/* Insulated case: (note: should fail for this case)
	 #pragma TASS  assert v_new[0] == v_new[1];
	 #pragma TASS  assert v_new[nx-1] == 0;
	 */
	
	/* Need to check B_hat[u] */
	
	/* Our assertion about L_hat[v] */
	//#pragma TASS assert forall {int i | 1 <= i && i <= nx-2} (v_new[i]-v[i])/dt - 
	//kappa*(v[i+1]-2*v[i]+v[i-1])/(dx*dx) == 0;
	
	/*
	 #pragma TASS assert forall {int i | 1 <= i && i <= nx-2} v_new[i] - 
	 ( (u(i*dx,(iter+1)*dt) - u(i*dx,iter*dt))/dt - 
	 k*( (u((i+1)*dx,iter*dt) - 2*u(i*dx,iter*dt) + 
	 u((i-1)*dx,iter*dt))/dt)) <= (M1/2)*dt + (kappa*M2/12)*dx*dx;
	 */
	
	/* need to ensure we satisfy B_hat */
	
	/* Copy v_new to v */
	i = 1;
	while (i < nx-1) {
		v[i] = v_new[i];
		i = i + 1;
	}
}

/* main: executes simulation, saves output information for each time
 * step */
void main() {
	iter = 0;
	init();
	write(iter);
	while (iter < nsteps) {
		update();
		write(iter);
		iter++;
	}
}