/** \brief Pass in an already constructed inverse operator. Update
  *        the inverse operator based on the new source operator.
  *
  * Pass in an already constructed inverse operator. Update
  * the inverse operator based on the new source operator.
  *
  * \params[in]     source Source operator to be inverted.
  * \params[in,out] dest   Pre constructed inverse operator to be
  *                        rebuilt using the <code>source</code>
  *                        object.
  */
void PreconditionerInverseFactory::rebuildInverse(const LinearOp & source,InverseLinearOp & dest) const
{
   Teko_DEBUG_MSG("BEGIN PreconditionerInverseFactory::rebuildInverse",10);

   RCP<Thyra::PreconditionerBase<double> > prec 
         = Teuchos::rcp_dynamic_cast<Teko::PreconditionerLinearOp<double> >(dest)->getNonconstPreconditioner();

   precFactory_->initializePrec(Thyra::defaultLinearOpSource(source),&*prec);

   Teko_DEBUG_MSG("END PreconditionerInverseFactory::rebuildInverse",10);
}
/** returns an (approximate) inverse of the diagonal blocks of A
  * where A is closely related to the original source for invD0 and invD1
  */
void InvFactoryDiagStrategy::getInvD(const BlockedLinearOp & A,BlockPreconditionerState & state,std::vector<LinearOp> & invDiag) const
{ 
   Teko_DEBUG_SCOPE("InvFactoryDiagStrategy::getInvD",10);

   // loop over diagonals, build an inverse operator for each
   int diagCnt = A->productRange()->numBlocks();
   int invCnt = invDiagFact_.size();

   Teko_DEBUG_MSG("# diags = " << diagCnt << ", # inverses = " << invCnt,6);

   const std::string opPrefix = "JacobiDiagOp";
   if(diagCnt<=invCnt) {
      for(int i=0;i<diagCnt;i++) 
         invDiag.push_back(buildInverse(*invDiagFact_[i],getBlock(i,i,A),state,opPrefix,i));
   }
   else {
      for(int i=0;i<invCnt;i++) 
         invDiag.push_back(buildInverse(*invDiagFact_[i],getBlock(i,i,A),state,opPrefix,i));

      for(int i=invCnt;i<diagCnt;i++) 
         invDiag.push_back(buildInverse(*defaultInvFact_,getBlock(i,i,A),state,opPrefix,i));
   }
}
LinearOp ModALPreconditionerFactory::buildPreconditionerOperator(BlockedLinearOp & alOp,
      BlockPreconditionerState & state) const
{
   Teko_DEBUG_SCOPE("ModALPreconditionerFactory::buildPreconditionerOperator()", 10);
   Teko_DEBUG_EXPR(Teuchos::Time timer(""));
   Teko_DEBUG_EXPR(Teuchos::Time totalTimer(""));
   Teko_DEBUG_EXPR(totalTimer.start());

   // Only for 2D or 3D problems.
   int dim = blockRowCount(alOp) - 1;
   TEUCHOS_ASSERT(dim == 2 || dim == 3);

   // Build what is necessary for the state object.
   Teko_DEBUG_EXPR(timer.start(true));
   invOpsStrategy_->buildState(alOp, state);
   Teko_DEBUG_EXPR(timer.stop());
   Teko_DEBUG_MSG("ModALPreconditionerFactory::buildPreconditionerOperator():BuildStateTime = "
         << timer.totalElapsedTime(), 2);

   // Extract inverse operators from strategy
   Teko_DEBUG_EXPR(timer.start(true));
   LinearOp invA11p = invOpsStrategy_->getInvA11p(state);
   LinearOp invA22p = invOpsStrategy_->getInvA22p(state);
   LinearOp invA33p;
   if(dim == 3)
   {
      invA33p = invOpsStrategy_->getInvA33p(state);
   }

   // The inverse of S can be built from strategy,
   // or just a diagonal matrix.
   ModALPrecondState * modALState = dynamic_cast<ModALPrecondState*>(&state);
   TEUCHOS_ASSERT(modALState != NULL);
   LinearOp invS;
   if(modALState->isStabilized_)
   {
      invS = invOpsStrategy_->getInvS(state);
   }
   else
   {
      invS = scale(modALState->gamma_, modALState->invPressureMassMatrix_);
   }

   Teko_DEBUG_EXPR(timer.stop());
   Teko_DEBUG_MSG("ModALPrecFact::buildPreconditionerOperator(): GetInvTime = "
         << timer.totalElapsedTime(), 2);

   // Build diagonal operations.
   std::vector<LinearOp> invDiag;
   invDiag.resize(dim + 1);
   invDiag[0] = invA11p;
   invDiag[1] = invA22p;
   if(dim == 2)
   {
      invDiag[2] = scale(-1.0, invS);
   }
   else if(dim == 3)
   {
      invDiag[2] = invA33p;
      invDiag[3] = scale(-1.0, invS);
   }

   // Get the upper triangular matrix.
   BlockedLinearOp U = getUpperTriBlocks(alOp);

   Teko_DEBUG_EXPR(totalTimer.stop());
   Teko_DEBUG_MSG("ModALPrecFact::buildPreconditionerOperator TotalTime = "
         << totalTimer.totalElapsedTime(), 2);

   // Create the preconditioner
   return createBlockUpperTriInverseOp(U, invDiag, "Modified AL preconditioner-Upper");
}