#include "Sundance.h"

int main(int argc, void** argv)
{
  try
    {
      char* a = "";
		
      Sundance::init(0, (void**)(&a));

		
      string inputfile("block.exoII");

      string fileTimestepOut = inputfile + ".tsout";

      string fileMultiVarsOut = inputfile + ".mvout";

		
      // copy the exodus mesh into two separate files so that 
      // we can write results to both without altering the original
      ExodusWriter::duplicateMesh(inputfile, fileTimestepOut);
      ExodusWriter::duplicateMesh(inputfile, fileMultiVarsOut);
		

      // load in the mesh
		
      MeshReader reader = new ExodusMeshReader(inputfile);
      Mesh mesh = reader.getMesh();

      // create the variables
		
      Expr x = new CoordExpr(0);
      Expr y = new CoordExpr(1);
      Expr z = new CoordExpr(1);
		

      CellSet boundary = new BoundaryCellSet();

      CellSet left = boundary.subset(x == 0.0);
      CellSet right = boundary.subset(x == 1.0);
      CellSet bottom = boundary.subset(y == 0.0);
      CellSet top = boundary.subset(y == 1.0);
      CellSet front = boundary.subset(z == 1.0);
      CellSet back = boundary.subset(z == 0.0);




      Expr dx = new Derivative(0);
      Expr dy = new Derivative(1);
      Expr dz = new Derivative(1);

      Expr grad = List(dx,dy,dz);

      Expr u = new UnknownFunction(new Lagrange(1));
		
      Expr deltau = new TestFunction(new Lagrange(1));

      Expr e = (grad*u) * (grad*deltau);
      Expr equ = Integral(e, new GaussianQuadrature(2));

      int numiterations = 10;

      // Multi variable init
      // create a list of names for multiple variables
      char buffer[256];
      string names[numiterations];
      for(int i = 0; i < numiterations; i++)
        {
          sprintf(buffer, "%d", i);	
          names[i] = string("var") + buffer;
        }
      // Create a writer for multiple variables
      ExodusWriter writerVars(fileMultiVarsOut);
      // initialize the variable names for that writer
      writerVars.initializeVariables(names, numiterations);


      // Time step init
      // Create a writer for time speping a single variable
      ExodusWriter writerTime(fileTimestepOut);



      // This will generate steady state solutions to 30 different bc's for the heat equation
      // these solutions will then be output as different variables and also as time steps in a single variable
      for(int i = 0; i < numiterations; i++)
        {

          // formulate BC's
          EssentialBC bcLeft = EssentialBC(left, deltau*(u));
          EssentialBC bcRight = EssentialBC(right, deltau*(u - y*y*i/10));


          // create problem 
          StaticLinearProblem prob(mesh, equ, bcLeft && bcRight, deltau, u);
		

          // setup the solver
          TSFPreconditionerFactory prec = new ILUKPreconditionerFactory(2);
		
          double tolerance = 1.0e-10;

          TSFLinearSolver solver = new BICGSTABSolver(prec, tolerance, 1000);

          // solve the system
          Expr soln = prob.solve(solver);

          cerr << "Done Solving for problem " << i << endl;


          // for the multivariable file, generate the appropriate name for this variable
          sprintf(buffer, "%d", i);	
		
          string varname = string("var") + string(buffer);

			
          writerVars.writeField(varname, soln);

			
			
          // for the timestep file, use the solution as the next time step
          // NOTE: -1 is given as the time step so that the next time step will
          // be used automatically.  If a specific timestep is desired, use that 
          // value instead 
          // i.e. writer.writeField("heat", soln, (float)i/12, i+1);

          writerTime.writeField("heat", soln, (float)i/12, -1);
        }
	
    }
  catch(exception& e)
    {
      Sundance::handleError(e, __FILE__);
    }

  Sundance::finalize();
}


