/** \brief Build this inverse operator from an Tpetra::Operator<ST,LO,GO,NT>
  * passed in to this object.
  *
  * Build this inverse opeerator from an Tpetra::Operator<ST,LO,GO,NT>
  * passed in to this object. If this Tpetra::Operator<ST,LO,GO,NT>
  * is an EpetraOperatorWrapper object then the block Thyra components
  * are extracted.
  *
  * \param[in] A The Epetra source operator.
  * \param[in] clear If true, than any previous state saved by the operator
  *                  is discarded.
  */
void InverseFactoryOperator::buildInverseOperator(const Teuchos::RCP<const Tpetra::Operator<ST,LO,GO,NT> > & A,bool clear)
{
    Teko_DEBUG_SCOPE("InverseFactoryOperator::buildInverseOperator",10);

    // extract EpetraOperatorWrapper (throw on failure) and corresponding thyra operator
    RCP<const Thyra::LinearOpBase<ST> > thyraA = extractLinearOp(A);

    // set the mapping strategy
    SetMapStrategy(rcp(new InverseMappingStrategy(extractMappingStrategy(A))));

    initInverse(clear);

    // actually build the inverse operator
    invOperator_ = Teko::buildInverse(*inverseFactory_,thyraA);

    SetOperator(invOperator_,false);

    firstBuildComplete_ = true;

    if(setConstFwdOp_)
        fwdOp_ = A;

    setConstFwdOp_ = true;

    TEUCHOS_ASSERT(invOperator_!=Teuchos::null);
    TEUCHOS_ASSERT(getForwardOp()!=Teuchos::null);
    TEUCHOS_ASSERT(getThyraOp()!=Teuchos::null);
    TEUCHOS_ASSERT(getMapStrategy()!=Teuchos::null);
    TEUCHOS_ASSERT(firstBuildComplete_==true);
}
/** \brief Rebuild this inverse from an Tpetra::Operator<ST,LO,GO,NT>  passed
  * in this to object.
  *
  * Rebuild this inverse from an Tpetra::Operator<ST,LO,GO,NT>  passed
  * in this to object.  If <code>buildInverseOperator</code> has not been called
  * the inverse operator will be built instead. Otherwise efforts are taken
  * to only rebuild what is neccessary. Also, that this Tpetra::Operator<ST,LO,GO,NT>
  * may be an EpetraOperatorWrapper object, so the block Thyra components
  * can be extracted.
  *
  * \param[in] A The Epetra source operator. (Should be a EpetraOperatorWrapper!)
  */
void InverseFactoryOperator::rebuildInverseOperator(const Teuchos::RCP<const Tpetra::Operator<ST,LO,GO,NT> > & A)
{
    Teko_DEBUG_SCOPE("InverseFactoryOperator::rebuildPreconditioner",10);

    // if the inverse hasn't been built yet, rebuild from scratch
    if(not firstBuildComplete_) {
        buildInverseOperator(A,false);
        return;
    }

    RCP<const Thyra::LinearOpBase<ST> > thyraA = extractLinearOp(A);
    Teko::rebuildInverse(*inverseFactory_,thyraA,invOperator_);

    if(setConstFwdOp_)
        fwdOp_.initialize(A);

    SetOperator(invOperator_,false);

    setConstFwdOp_ = true;

    TEUCHOS_ASSERT(getForwardOp()!=Teuchos::null);
    TEUCHOS_ASSERT(invOperator_!=Teuchos::null);
    TEUCHOS_ASSERT(getThyraOp()!=Teuchos::null);
    TEUCHOS_ASSERT(firstBuildComplete_==true);
}
/** \brief Builder function for creating preconditioner factories (yes
  *        this is a factory factory.
  *
  * Builder function for creating preconditioner factories (yes
  * this is a factory factory.
  * 
  * \param[in] name     String name of factory to build
  * \param[in] settings Parameter list describing the parameters for the
  *                     factory to build
  * \param[in] invLib   Inverse library for the factory to use.
  *
  * \returns If the name is associated with a preconditioner
  *          a pointer is returned, otherwise Teuchos::null is returned.
  */
RCP<PreconditionerFactory> 
PreconditionerFactory::buildPreconditionerFactory(const std::string & name,
                                                       const Teuchos::ParameterList & settings,
                                                       const RCP<const InverseLibrary> & invLib)
{
   Teko_DEBUG_SCOPE("PreconditionerFactory::buildPreconditionerFactory",10);

   // initialize the defaults if necessary
   if(precFactoryBuilder_.cloneCount()==0) initializePrecFactoryBuilder();

   // request the preconditioner factory from the CloneFactory
   RCP<PreconditionerFactory> precFact = precFactoryBuilder_.build(name);

   Teko_DEBUG_MSG_BEGIN(5);
      DEBUG_STREAM << "Looked up \"" << name << "\"" << std::endl;
      DEBUG_STREAM << "Built " << precFact << std::endl;
   Teko_DEBUG_MSG_END();

   if(precFact==Teuchos::null)  
      return Teuchos::null;

   // add in the inverse library
   if(invLib!=Teuchos::null) {
      precFact->setInverseLibrary(invLib);
      precFact->setRequestHandler(invLib->getRequestHandler());
   }

   // now that inverse library has been set,
   // pass in the parameter list
   precFact->initializeFromParameterList(settings);

   return precFact;
}
/** \brief Build an inverse operator
  *
  * Build the inverse operator using this factory.
  *
  * \param[in] linearOp Linear operator needing to be inverted.
  *
  * \returns New linear operator that functions as the inverse
  *          of <code>linearOp</code>.
  */
InverseLinearOp SolveInverseFactory::buildInverse(const LinearOp & linearOp) const
{
    Teko_DEBUG_SCOPE("SolveInverseFactory::buildInverse(linearOp)",10);

    // build and initialize inverse linear op with solve
    Teuchos::RCP<Thyra::LinearOpWithSolveBase<double> > invLOWS = lowsFactory_->createOp();
    lowsFactory_->initializeOp(Thyra::defaultLinearOpSource(linearOp),&*invLOWS,Thyra::SUPPORT_SOLVE_FORWARD_ONLY);

    return Thyra::nonconstInverse<double>(invLOWS);
}
/** \brief Build an inverse operator and make sure it aware of some parents state
  *        This functionality is only useful for Teko::PreconditionerFactory inverses.
  *
  * Build an inverse operator and make sure it aware of some parents state
  * This functionality is only useful for Teko::PreconditionerFactory inverses.
  *
  * \param[in] linearOp Linear operator needing to be inverted.
  * \param[in] parentState Current state object to be used. Only useful for preconditioners.
  *
  * \returns New linear operator that functions as the inverse
  *          of <code>linearOp</code>.
  */
InverseLinearOp PreconditionerInverseFactory::buildInverse(const LinearOp & linearOp, const PreconditionerState & parentState) const
{ 
   Teko_DEBUG_SCOPE("PreconditionerInverseFactory::buildInverse(A,parentState)",10);
   RCP<Thyra::PreconditionerBase<double> > prec = precFactory_->createPrec();

   {
      Teko_DEBUG_SCOPE("Casting to Teko::Preconditioner",10);
      // pass state downward if a Teko::Preconditioner object is begin used
      RCP<Teko::Preconditioner> tekoPrec = Teuchos::rcp_dynamic_cast<Teko::Preconditioner>(prec);
      if(tekoPrec!=Teuchos::null) {
         Teko_DEBUG_SCOPE("Merging states",10);
         tekoPrec->mergeStateObject(parentState);
      }
   }

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

   RCP<Teko::PreconditionerLinearOp<double> > precOp 
         = rcp(new Teko::PreconditionerLinearOp<double>(prec));

   return precOp;
}
/** 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");
}