/* $Id: precondmg.h,v 1.4 1996/11/20 09:57:28 roitzsch Exp $ */

#ifndef PRECONDMG_H
#define PRECONDMG_H

#include "precond.h"
#include "stack.h"

class FamilyTree;

//-------------------------------------------------------------------------
//-------------------------------------------------------------------------


// --	         Multi-Grid and Multi-Level Preconditioners:


class MGPreconditioner : public Preconditioner
{
  public:

    MGPreconditioner ();
    virtual ~MGPreconditioner();

    virtual void update(SystemMatrix* A, FamilyTree* familyTree,
			DirichletBCs* dirichletBCs);
    virtual void invert(Vector<Num>& lhs, SystemMatrix* A, Vector<Num>& rhs);

    virtual int memSpace(int print=0);

  protected:

    FamilyTree*	  	  familyTree;
    Stack<SystemMatrix*>  Al;
    Stack<Vector<Num>*>	  rl;
    Stack<Vector<Num>*>	  el;
    Stack<Real> 	  omega;

    int	 		  nPreSmooth, nPostSmooth, nCycle;
    int  		  maxLevel, dimM1;
    int  		  baseLevel; 

    Real  nodeProgFactor;			// for level-skip operations
    Bool  skipLevelM1;
    int   lastDim ;

    virtual void updateMG(SystemMatrix* A, FamilyTree* familyTree,
			  DirichletBCs* dirichletBCs);
    virtual void updateML(SystemMatrix* A, FamilyTree* familyTree,
			  DirichletBCs* dirichletBCs);
    virtual void skipLevel(SystemMatrix* A);

    virtual void GalerkinRestriction();

    virtual void MGCycle(Vector<Num>& e, SystemMatrix& A, Vector<Num>& r, 
			 int level) = 0;

    virtual void restr(Vector<Num>& rh, Vector<Num>& rl, int level);
    virtual void prolong (Vector<Num>& el, Vector<Num>& eh, int level);

    void cleanStacks(int level);
};
//-------------------------------------------------------------------------


// --	Multiplicative Multi-Grid (MG) and Multi-Level (ML) Preconditioners:


class MMGPreconditioner : public MGPreconditioner
{

  public:

    MMGPreconditioner();
    virtual precondMode mode() { return multiGrid; }
    virtual void close (SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);

  protected:

    Vector<Num>	aux;				// auxiliary vector

    virtual void MGCycle(Vector<Num>& e, SystemMatrix& A, Vector<Num>& r, 
			 int level);
    virtual void preSmooth (int level, Vector<Num>& e, SystemMatrix& A, 
			    Vector<Num>& r) = 0;
    virtual void postSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			    Vector<Num>& r) = 0;
};
//-------------------------------------------------------------------------


// --	Additive Multi-Grid (AMG) and Multi-Level (AML) Preconditioners:


class AMGPreconditioner : public MGPreconditioner
{
  public:

    AMGPreconditioner() : MGPreconditioner() { }
    virtual precondMode mode() { return multiGrid; }

  protected:

    virtual void MGCycle(Vector<Num>& e, SystemMatrix& A, Vector<Num>& r, 
			 int level);
    virtual void smooth(int level, Vector<Num>& e, SystemMatrix& A, 
			Vector<Num>& r) = 0;
};
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------


class MGJacobi : public MMGPreconditioner 
{
  public: 
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);

  protected:
    virtual void initParameters();
    virtual void preSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			   Vector<Num>& r);
    virtual void postSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			    Vector<Num>& r);
};

class MGSGS : public MMGPreconditioner 
{
  public: 
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);

  protected:
    virtual void preSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			   Vector<Num>& r);
    virtual void postSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			    Vector<Num>& r);
};

class MGSSOR : public MMGPreconditioner 
{
  public: 
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);

  protected:
    virtual void initParameters();
    virtual void preSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			   Vector<Num>& r);
    virtual void postSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			    Vector<Num>& r);
};
//-------------------------------------------------------------------------


class MGCG : public MMGPreconditioner 
{
  public: 
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void close(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);

  protected:
    virtual void preSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			   Vector<Num>& r);
    virtual void postSmooth(int level, Vector<Num>& e, SystemMatrix& A, 
			    Vector<Num>& r);

    void CGIterate(Vector<Num>& x, SystemMatrix& A, int nSmooth);
    Vector<Num>	p;
    Vector<Num> r;
};
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------


class AMGJacobi : public AMGPreconditioner 
{
  public: 
    virtual Bool diagonalOnly() { return True; }

  protected:
    virtual void initParameters();
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void smooth(int level, Vector<Num>& e, SystemMatrix& A, 
			Vector<Num>& r);
};

class AMGSGS : public AMGPreconditioner 
{
  public: 
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
  protected:
    virtual void smooth(int level, Vector<Num>& e, SystemMatrix& A, 
			Vector<Num>& r);
};
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------


// --	   	Multiplicative Multi-Level Preconditioners:


class MLJacobi : public MGJacobi
{
  public:
    virtual precondMode mode() { return multiLevel; }
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void update(SystemMatrix* A, FamilyTree* familyTree0,
			DirichletBCs* dirichletBCs0)
				     { updateML(A, familyTree0, dirichletBCs0); }
};
//-------------------------------------------------------------------------


class MLSGS : public MGSGS
{
  public:
    virtual precondMode mode() { return multiLevel; }
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void update(SystemMatrix* A, FamilyTree* familyTree0,
			DirichletBCs* dirichletBCs0)
				    { updateML(A, familyTree0, dirichletBCs0); }
};
//-------------------------------------------------------------------------


class MLSSOR : public MGSSOR
{
  public:
    virtual precondMode mode() { return multiLevel; }
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void update(SystemMatrix* A, FamilyTree* familyTree0,
			DirichletBCs* dirichletBCs0)
				     { updateML(A, familyTree0, dirichletBCs0); }
  protected:
    virtual void initParameters();
};
//-------------------------------------------------------------------------


class MLCG : public MGCG
{
  public:
    virtual precondMode mode() { return multiLevel; }
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void update(SystemMatrix* A, FamilyTree* familyTree0,
			DirichletBCs* dirichletBCs0)
				    { updateML(A, familyTree0, dirichletBCs0); }
};
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------


// --		Additive Multi-Level Preconditioners:


class AMLJacobi : public AMGJacobi
{
  public:
    virtual Bool diagonalOnly() { return True; }

    virtual precondMode mode() { return multiLevel; }
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void update(SystemMatrix* A, FamilyTree* familyTree0,
			DirichletBCs* dirichletBCs0)
				     { updateML(A, familyTree0, dirichletBCs0); }
  protected:
    virtual void initParameters();
};
//-------------------------------------------------------------------------

class AMLSGS : public AMGSGS
{
  public:
    virtual precondMode mode() { return multiLevel; }
    virtual void initialize(SystemMatrix* A, Vector<Num>& x, Vector<Num>& b);
    virtual void update(SystemMatrix* A, FamilyTree* familyTree0,
			DirichletBCs* dirichletBCs0)
				     { updateML(A, familyTree0, dirichletBCs0); }
};
//-------------------------------------------------------------------------

#endif
