// Copyright (C) 2005 Johan Hoffman.
// Licensed under the GNU GPL Version 2.
//
// Modified by Anders Logg 2006.
//
// First added:  2005
// Last changed: 2006-05-07

#ifndef __NSE_SOLVER_H
#define __NSE_SOLVER_H

//#include "Solver.h"

namespace dolfin {
  namespace unicorn {
  // This is a solver for the time dependent incompressible 
  // Navier-Stokes equations. 

    class dolfin::BoundaryCondition;
    
    class NSESolver 
    {
    public:
      
      // Create the Navier-Stokes solver
      NSESolver(Mesh& mesh, Function& f, Array<BoundaryCondition*>& bc_mom,
		BoundaryCondition& bc_con);
      
      // Solve Navier-Stokes equations
      void solve();
      
      // Solve Navier-Stokes equations (static version)
      static void solve(Mesh& mesh, Function& f,
			Array<BoundaryCondition*>& bc_mom,
			BoundaryCondition& bc_con);
      
      // Compute cell diameter
      static void ComputeCellSize(Mesh& mesh, Vector& hvector);
      
      // Get minimum cell diameter
      static void GetMinimumCellSize(Mesh& mesh, real& hmin);
      
      // Compute stabilization 
      static void ComputeStabilization(Mesh& mesh, Function& w, real nu,
				       real k, 
				       Vector& d1vector, Vector& d2vector);
      
      // Compute cell mean
      static void ComputeMean(Mesh& mesh, Function& vmean, Function& v);
      
      // Set initial velocity 
      void SetInitialVelocity(Vector& xvel);
      
      // Compute the volume inverse
      void ComputeVolInv(Mesh& mesh, Vector& vol_inv);
      
      // Compute error indicator
      void ComputeErrorIndicator(Vector& e_indx, Vector& res_mx,
				 Vector& res_cx, real k, real T);
      
      // Compute largest indicators
      void ComputeLargestIndicators(Vector& e_indx, std::vector<int>& cells,
				    real percentage);
      
      // Refine based on indicators
      void AdaptiveRefinement(std::vector<int>& cells, FiniteElement& element);
      
      // Comparison operator for index/value pairs
      struct less_pair : public std::binary_function<std::pair<int, real>,
	std::pair<int, real>, bool>
      {
	bool operator()(std::pair<int, real> x, std::pair<int, real> y)
	{
	  return x.second < y.second;
	}
      };
      
    private:
      
      Mesh& mesh;
      Function& f;
      Array<BoundaryCondition*>& bc_mom;
      BoundaryCondition& bc_con;
      
    };
    
  }}

#endif
