https://github.com/JeffersonLab/chroma
Raw File
Tip revision: 2b26cd98bcac830268245a01ea86bf6b2e46df9c authored by Balint Joo on 04 May 2018, 17:44:13 UTC
Updated License to 2018 Jefferson Lab License
Tip revision: 2b26cd9
teoprec_linop.h
// -*- C++ -*-
// $Id: teoprec_linop.h,v 3.2 2007-02-22 21:11:45 bjoo Exp $
/*! @file
 * @brief Even-odd Time-preconditioned Linear Operators
 */

#ifndef __teoprec_linop_h__
#define __teoprec_linop_h__

#include "linearop.h"

namespace Chroma
{

  //-----------------------------------------------------------------------------------
  //! Even-odd and time preconditioned linear operator
  /*! @ingroup linop
   *
   * Given a matrix M written in separate time and space operators
   *
   *  M = D_t  +  D_s
   *
   * The time preconditioning consists of multiplying by the inverse
   * of the time operator to give
   *
   *     M'  =  1 +  D_t^(-1)*D_s
   *
   * For spatial even-odd precond., this interface requires the D_t to
   * be diagonal in spatial components - have no space-space or space-time
   * components. Hence, this means no even-odd component. 
   * Also, the D_s must no time coupling, and no even-even or odd-odd
   * component - e.g. all diagonal terms have been pushed into D_t.
   *
   * Rewrite M' into block form:
   *
   *       [      A             D        ]
   *       [       E,E           E,O     ]
   *  M' = [                             ]
   *       [      D             A        ]
   *       [       O,E           O,O     ]
   *
   * where the E,O refer to only the spatial dimensions and
   *
   *  A(e,e) =  1 + D_t^(-1)(e,e) * D_s(e,e) -> 1   # D_s(e,e)=0
   *  D(e,o) =  D_t^(-1)(e,e) * D_s(e,o)            # is a matrix in time-time
   *  D(o,e) =  D_t^(-1)(o,o) * D_s(o,e)            # is a matrix in time-time
   *  A(o,o) =  1 + D_t^(-1)(o,o) * D_s(o,o) -> 1   # D_s(o,o)=0
   *
   *  A(e,e)^(-1) = <diagonal in space, matrix in time-time components>
   *
   * Spatial even-odd preconditioning consists of using the triangular matrices
   *
   *      [      1              0        ]
   *      [       E,E            E,O     ]
   *  L = [                              ]
   *      [     D     A^(-1)    1        ]
   *      [      O,E   E,E        O,O    ]
   *
   * and
   *
   *      [      A              D       ]
   *      [       E,E            E,O    ]
   *  U = [                             ]
   *      [      0              1       ]
   *      [       O,E            O,O    ]
   *
   * The preconditioned matrix is formed from
   *
   *  ~
   *  M   =  L^-1 * M' * U^-1
   *
   * where
   *
   *           [      1              0        ]
   *           [       E,E            E,O     ]
   *  L^(-1) = [                              ]
   *           [   - D     A^(-1)    1        ]
   *           [      O,E   E,E        O,O    ]
   *
   * and
   *
   *           [      A^(-1)       - A^(-1) D       ]
   *           [       E,E            E,E    E,O    ]
   *  U^(-1) = [                                    ]
   *           [      0                1            ]
   *           [       O,E              O,O         ]
   *
   * Resulting in a new  M
   *
   *      [      1                    0                      ]
   *  ~   [       E,E                  E,O                   ]
   *  M = [                                                  ]
   *      [      0                A     -  D    A^(-1)  D    ]
   *      [       O,E              O,O      O,E   E,E    E,O ]
   *
   *
   * This class is used to implement the resulting linear operator
   *
   *  ~
   *  M  =  A(o,o) - D(o,e) * A^-1(e,e) * D(e,o)
   *     =  1   -  D_t^(-1)(o,o) * D_s(o,e) * D_t^(-1)(e,e) * D_s(e,o)
   *
   *  ~
   *  M^dag  = 1  -  D_s(o,e)^dag * D_t^(-1)(e,e)^dag * D_s(e,o)^dag * D_t^(-1)(o,o)^dag
   *
   * By construction, the linear operator is ONLY defined on the odd subset
   *
   * The non-symmetrical nature of the daggered version means the two
   * cases (no-dagger and dagger) must be handled separately. This is
   * in contrast to the standard (4D) even-odd precond. case where the
   * the daggered version has the same structure, except the dagger
   * is pushed down into the individual pieces.
   */

  template<typename T, typename P, typename Q>
  class EvenOddTimePrecLinearOperator : public DiffLinearOperator<T,P,Q>
  {
  public:
    //! Virtual destructor to help with cleanup;
    virtual ~EvenOddTimePrecLinearOperator() {}

    //! Only defined on the odd lattice
    const Subset& subset() const {return rb[1];}   // not correct, need space-rb

    //! Apply the even-even block onto a source vector
    /*! This does not need to be optimized */
    virtual void evenEvenTimeLinOp(T& chi, const T& psi, 
				   enum PlusMinus isign) const = 0;
  
    //! Apply the inverse of the even-even block onto a source vector
    virtual void evenEvenTimeInvLinOp(T& chi, const T& psi, 
				      enum PlusMinus isign) const = 0;
  
    //! Apply the the even-odd block onto a source vector
    virtual void evenOddSpaceLinOp(T& chi, const T& psi, 
				   enum PlusMinus isign) const = 0;

    //! Apply the the odd-even block onto a source vector
    virtual void oddEvenSpaceLinOp(T& chi, const T& psi, 
				   enum PlusMinus isign) const = 0;

    //! Apply the the odd-odd block onto a source vector
    virtual void oddOddTimeLinOp(T& chi, const T& psi, 
				 enum PlusMinus isign) const = 0;

    //! Apply the operator onto a source vector
    virtual void operator() (T& chi, const T& psi, 
			     enum PlusMinus isign) const
    {
      T   tmp1, tmp2; moveToFastMemoryHint(tmp1); moveToFastMemoryHint(tmp2);

      switch (isign)
      {
      case PLUS:
	//  chi   =  psi  -  D_t^(-1)(o,o)*D_s(o,e)*D_t^(-1)(e,e)*D_s(e,o)*psi
	evenOddSpaceLinOp(tmp1, psi, isign);
	evenEvenTimeInvLinOp(tmp2, tmp1, isign);
	OddEvenSpaceLinOp(tmp1, tmp2, isign);
	oddOddTimeInvLinOp(tmp2, tmp1, isign);
	chi[rb[1]] = psi - tmp2;
	break;

      case MINUS:
	//  chi   =  psi  -  D_s(o,e)^dag * D_t^(-1)(e,e)^dag * D_s(e,o)^dag * D_t^(-1)(o,o)^dag*psi
	oddOddTimeInvLinOp(tmp1, psi, isign);
	evenOddSpaceLinOp(tmp2, tmp1, isign);
	evenEvenTimeInvLinOp(tmp1, tmp2, isign);
	OddEvenSpaceLinOp(tmp2, tmp1, isign);
	chi[rb[1]] = psi - tmp2;
	break;

      default:
	QDPIO::cerr << "unknown sign" << endl;
	QDP_abort(1);
      }
    }

    //! Apply the UNPRECONDITIONED operator onto a source vector
    /*! Mainly intended for debugging */
    virtual void unprecLinOp(T& chi, const T& psi, 
			     enum PlusMinus isign) const
    {
      T   tmp1, tmp2; moveToFastMemoryHint(tmp1); moveToFastMemoryHint(tmp2);

      //  chi   =  D_t*psi  +  D_s*psi
      evenEvenTimeLinOp(tmp1, psi, isign);
      evenOddSpaceLinOp(tmp2, psi, isign);
      chi[rb[0]] = tmp1 + tmp2;

      oddOddTimeLinOp(tmp1, psi, isign);
      oddEvenSpaceLinOp(tmp2, psi, isign);
      chi[rb[1]] = tmp1 + tmp2;
    }

    //! Apply the even-even block onto a source vector
    virtual void derivEvenEvenTimeLinOp(P& ds_u, const T& chi, const T& psi, 
					enum PlusMinus isign) const = 0;
  
    //! Apply the the even-odd block onto a source vector
    virtual void derivEvenOddSpaceLinOp(P& ds_u, const T& chi, const T& psi, 
					enum PlusMinus isign) const = 0;
 
    //! Apply the the odd-even block onto a source vector
    virtual void derivOddEvenSpaceLinOp(P& ds_u, const T& chi, const T& psi, 
					enum PlusMinus isign) const = 0;

    //! Apply the the odd-odd block onto a source vector
    virtual void derivOddOddTimeLinOp(P& ds_u, const T& chi, const T& psi, 
				      enum PlusMinus isign) const = 0;

    //! Apply the derivative of the operator onto a source vector
    /*! User should make sure deriv routines do a resize  */
    virtual void deriv(P& ds_u, const T& chi, const T& psi, 
		       enum PlusMinus isign) const = 0;

    //! Apply the derivative of the UNPRECONDITIONED operator onto a source vector
    /*! Mainly intended for debugging */
    virtual void derivUnprecLinOp(P& ds_u, const T& chi, const T& psi, 
				  enum PlusMinus isign) const
    {
      T   tmp1, tmp2; moveToFastMemoryHint(tmp1); moveToFastMemoryHint(tmp2);
      P   ds_tmp; moveToFastMemoryHint(ds_tmp);

      //  chi   =  D_t*psi  +  D_s*psi

      //  ds_u  =  chi^dag * (D_t)'_ee * psi
      derivEvenEvenTimeLinOp(ds_u, chi, psi, isign);

      //  ds_u +=  chi^dag * (D_s)'_eo * psi
      derivEvenOddSpaceLinOp(ds_tmp, chi, psi, isign);
      ds_u += ds_tmp;

      //  ds_u +=  chi^dag * (D_t)'_oo * psi
      derivOddOddTimeLinOp(ds_tmp, chi, psi, isign);
      ds_u += ds_tmp;

      //  ds_u +=  chi^dag * (D_s)'_oe * psi
      derivOddEvenSpaceLinOp(ds_tmp, chi, psi, isign);
      ds_u += ds_tmp;
    }

  };


}



#endif
back to top