// Copyright (C) 2007 Johan Jansson.
// Licensed under the GNU GPL Version 2.

#include <dolfin.h>
#include <unicorn/TimeDependentPDE.h>
#include "Projection.h"
#include "Convection.h"
#include "ConvectionJac.h"
#include "Coefficients.h"
  
using namespace dolfin;
using namespace dolfin::unicorn;


class ConvectionPDE : public TimeDependentPDE
{
public:
  ConvectionPDE(Form* a, Form* L,
		Mesh& mesh,
		BoundaryCondition& bc, real T,
		Form* aJac, Form* aP, Form* LP) :
    TimeDependentPDE(*a, *L,
		     mesh, bc, T,
		     aJac, aP, LP)
  {
  }

};


int main()
{
  // Set up problem
  UnitSquare mesh(40, 40);
  //Mesh mesh("cell.xml");

  Beta beta(mesh);
  MyBC bcf(mesh);
  InitialValue u0(mesh);
  ConvectionExact uexact(mesh);
  DirichletBoundary dboundary;

  DirichletBC bc(bcf, mesh, dboundary);
  
  transform(mesh);

  real T = 4.0;
  real k = 1.0e-2;

  set("ODE method", "cg");
  set("ODE order", 1);
  set("ODE implicit", true);
  //set("ODE implicit", false);
  //set("ODE nonlinear solver", "fixed-point");
  set("ODE nonlinear solver", "newton");
  //set("ODE linear solver", "direct");
  set("ODE linear solver", "iterative");
  set("ODE matrix-free jacobian", false);
  set("ODE tolerance", 1.0e-9);
  set("ODE discrete tolerance", 1.0e-9);
  
  set("ODE monitor convergence", true);
  
  set("ODE fixed time step", true);
  set("ODE initial time step", k);
  set("ODE maximum time step", k);

  set("ODE save solution", false);
  
  Function U;

  Form* a = new ConvectionBilinearForm();
  Form* L = new ConvectionLinearForm(U, beta);
  Form* aJac = new ConvectionJacBilinearForm(beta);
  Form* aP = new ProjectionBilinearForm();
  Form* LP = new ProjectionLinearForm(u0);
  
  ConvectionPDE pde(a, L, mesh, bc, T, aJac, aP, LP);

  // Compute solution
  pde.solve(U);

  return 0;
}
