/***********************************************************************/
/* finite_difference.hh: classes used for finite difference simulation */
/*                                                                     */
/* B. Haasdonk, 22.10.2008                                             */
/***********************************************************************/

#ifndef FINITE_DIFFERENCE_HH
#define FINITE_DIFFERENCE_HH

#include <iostream>
#include <fstream>
#include <math.h>

using std::string;
using std::ofstream;
using std::cerr;

//----------------------------------------------------------------------
// model class representing the data functions
//----------------------------------------------------------------------
class Model
{
public:  
  // constructor without any arguments (not necessary)
  Model()
        {};  
  
  // flux function evaluation
  double f(const double u) const
        {
          ...
        }
  
  // flux function derivative evaluation
  double Df(const double u) const
        {
          ...
        }

  // initial data evaluation
  double u0(const double x) const 
        {
          ...
        }

  // Dirichlet data evaluation
  double udir(const double x, const double t) const 
         {
           ...
         }

  // initial data evaluation
  double uexact(const double x, const double t) const 
        {
          ...
        }

  // destructor doing nothing (not necessary)
  ~Model()
        {}
  
private:
  // no private variables required
};


//----------------------------------------------------------------------
// numericalflux class, for simplicity assuming 
// f'(s) not changing sign in [u,v] 
//----------------------------------------------------------------------
class NumericalFlux
{
public:
  // constructor storing the model
  NumericalFlux(const Model& model): 
          model_(model)
        {}
  
  // evaluate numflux g(u,v) in u and v
  double g(const double u,const double v) const
        {
          ...
        }
  
  // destructor doing nothing
  ~NumericalFlux()
        {}
  
private:
  ...
};


//----------------------------------------------------------------------
// grid class representing the grid, for simplicity: equidistant
//----------------------------------------------------------------------
class Grid
{
public:
  // constructor generating a grid on [a,b] with N equidistant points
  Grid(const double a, const double b, const int npoints)
          ...
        {
          ...
        } 

  // return number of points
  int npoints() const
        {
          ...
        }
  
  // return left boundary a
  double a() const 
        {
          ...
        }
  
  // return right boundary b
  double b() const 
        {
          ...
        }
  
  // get point number i (ranging from 0 to N-1), i.e. n=i+1 
  double point(const int i) const 
        {
          ...
        }
  
  // return normal in left boundary point a
  double normal_a() const 
        {
          ...
        }

  // return normal in right boundary point b
  double normal_b() const 
        {
          ...
        }
  
  // return size of surrounding of point i (from 0 to N-1), i.e. n=i+1
  double dx(const int i) const 
        {
          ...
        }
  
  // destructor doing nothing
  ~Grid()
        {}
  
private:
  ...
};

//----------------------------------------------------------------------
// discretefunction class representing the numerical solution
//----------------------------------------------------------------------
class DiscreteFunction
{
public:  
  // constructor with grid
  DiscreteFunction(const Grid& grid)
      ...
        {
          ...
        }
  
  // scale the discrete function
  void operator*=(const double factor)
        {
          ...
        }
  
  
  // add discFunc to the discrete function
  void operator+=(const DiscreteFunction& discFunc)
        {
          ...
        }
  
  // get number of DOFs
  int ndofs() const
        {
          ...
        }
  
  // set and get a reference to the i-th DOF i=0...ndofs-1, non-const version
  double& operator[](const int i)
        {
          ...
        }

  // set and get a reference to the i-th DOF i=0...ndofs-1, const version
  double& operator[](const int i) const
        {
          ...
        }

  // return the underlying grid
  const Grid& grid() const 
        {
          ...
        }
  
  // save in ascii to file to be read in gnuplot  
  void writeAsciiFile(const string& filename) const
  {
    ...
  }

  // destructor freeing DOF memory
  ~DiscreteFunction()
        {
          ...
        }
  
private:
  ...
};

//----------------------------------------------------------------------
// projection class projecting the initial data
//----------------------------------------------------------------------
class Projection
{
public:
  // constructor doing nothing
  Projection()
        {}
  
  // perform projection 
  void apply(const Model& model, const DiscreteFunction& discFunc) const 
        {
          ...
        }
 
  // destructor doing nothing
  ~Projection()
        {}
  
private:
  // no private variables required 
};

//----------------------------------------------------------------------
// discretespaceoperator class for the space finite difference discretization
//----------------------------------------------------------------------
class DiscreteSpaceOperator
{
public:  
  // constructor with numerical flux model and reference on time variable
  DiscreteSpaceOperator(const NumericalFlux& numFlux, 
                        const Model& model, double& t)
      ...
        {
          ...
        }

  // apply the operator on argument and store result in destination
  void apply(const DiscreteFunction& argument, 
             DiscreteFunction& destination) const
        {
          ...
        }
  
 
  // destructor doing nothing
  ~DiscreteSpaceOperator()
        {}
  
private:
  ...
};

#endif