Ejemplo n.º 1
0
void DiagonalROME<Scalar>::setDiagonalBarVector(
    const RCP<const Thyra::VectorBase<Scalar> > &diag_bar)
{

    typedef Teuchos::ScalarTraits<Scalar> ST;
    using Teuchos::rcp_dynamic_cast;
    using Thyra::createMember;
    using Thyra::ele_wise_divide;
    using Thyra::V_S;

    diag_bar_ = diag_bar.assert_not_null();

    // Reset the scalar product for p_space!

    RCP<Thyra::VectorBase<Scalar> > s_bar = createMember<Scalar>(p_space_);

    // s_bar[i] = diag[i] / diag_bar[i]
    V_S( s_bar.ptr(), ST::zero() );
    ele_wise_divide( ST::one(), *diag_, *diag_bar_, s_bar.ptr() );
    s_bar_ = s_bar;

    const RCP<Thyra::ScalarProdVectorSpaceBase<Scalar> > sp_p_space =
        rcp_dynamic_cast<Thyra::ScalarProdVectorSpaceBase<Scalar> >(p_space_, true);
    //sp_p_space->setScalarProd(diagonalScalarProd<Scalar>(s_bar_));

}
Ejemplo n.º 2
0
bool sillyCgSolve(
  const Thyra::LinearOpBase<Scalar> &A,
  const Thyra::VectorBase<Scalar> &b,
  const int maxNumIters,
  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
  const Teuchos::Ptr<Thyra::VectorBase<Scalar> > &x,
  std::ostream &out
  )
{

  // Create some typedefs and some other stuff to make the code cleaner
  typedef Teuchos::ScalarTraits<Scalar> ST; typedef typename ST::magnitudeType ScalarMag;
  const Scalar one = ST::one(), zero = ST::zero();  using Teuchos::as;
  using Teuchos::RCP; using Thyra::VectorSpaceBase; using Thyra::VectorBase;
  using Thyra::NOTRANS; using Thyra::V_V; using Thyra::apply;
  

  // Validate input
  THYRA_ASSERT_LINEAR_OP_VEC_APPLY_SPACES("sillyCgSolve()", A, Thyra::NOTRANS, *x, &b);
  Teuchos::EVerbosityLevel vl = Teuchos::VERB_MEDIUM;

  out << "\nStarting CG solver ...\n" << std::scientific << "\ndescribe A:\n"<<describe(A, vl)
      << "\ndescribe b:\n"<<describe(b, vl)<<"\ndescribe x:\n"<<describe(*x, vl)<<"\n";

  // Initialization
  const RCP<const VectorSpaceBase<Scalar> > space = A.domain();
  const RCP<VectorBase<Scalar> > r = createMember(space);
  // r = -A*x + b
  V_V(r.ptr(), b); apply<Scalar>(A, NOTRANS, *x, r.ptr(), -one, one);
  const ScalarMag r0_nrm = norm(*r);
  if (r0_nrm==zero) return true;
  const RCP<VectorBase<Scalar> > p = createMember(space), q = createMember(space);
  Scalar rho_old = -one;

  // Perform the iterations
  for( int iter = 0; iter <= maxNumIters; ++iter ) {

    // Check convergence and output iteration
    const ScalarMag r_nrm = norm(*r);
    const bool isConverged = r_nrm/r0_nrm <= tolerance;
    if( iter%(maxNumIters/10+1) == 0 || iter == maxNumIters || isConverged ) {
      out << "Iter = " << iter << ", ||b-A*x||/||b-A*x0|| = " << (r_nrm/r0_nrm) << std::endl;
      if( r_nrm/r0_nrm < tolerance ) return true; // Success!
    }

    // Compute iteration
    const Scalar rho = inner(*r, *r);        // <r,r>              -> rho
    if (iter==0) V_V(p.ptr(), *r);           // r                  -> p   (iter == 0)
    else Vp_V( p.ptr(), *r, rho/rho_old );   // r+(rho/rho_old)*p  -> p   (iter  > 0)
    apply<Scalar>(A, NOTRANS, *p, q.ptr());  // A*p                -> q
    const Scalar alpha = rho/inner(*p, *q);  // rho/<p,q>          -> alpha
    Vp_StV( x, +alpha, *p );                 // +alpha*p + x       -> x
    Vp_StV( r.ptr(), -alpha, *q );           // -alpha*q + r       -> r
    rho_old = rho;                           // rho                -> rho_old (for next iter)

  }

  return false; // Failure

} // end sillyCgSolve
void ImplicitBDFStepperRampingStepControl<Scalar>::initialize(
  const StepperBase<Scalar>& stepper)
{
  // Initialize can be called from the stepper when setInitialCondition
  // is called.
  using Teuchos::as;
  typedef Teuchos::ScalarTraits<Scalar> ST;
  using Thyra::createMember;

  // Set initial time:
  TimeRange<Scalar> stepperRange = stepper.getTimeRange();
  TEUCHOS_TEST_FOR_EXCEPTION(
      !stepperRange.isValid(),
      std::logic_error,
      "Error, Stepper does not have valid time range for initialization "
      "of ImplicitBDFStepperRampingStepControl!\n");

  if (is_null(parameterList_)) {
    RCP<Teuchos::ParameterList> emptyParameterList =
      Teuchos::rcp(new Teuchos::ParameterList);
    this->setParameterList(emptyParameterList);
  }

  if (is_null(errWtVecCalc_)) {
    RCP<ImplicitBDFStepperErrWtVecCalc<Scalar> > IBDFErrWtVecCalc =
      rcp(new ImplicitBDFStepperErrWtVecCalc<Scalar>());
    errWtVecCalc_ = IBDFErrWtVecCalc;
  }

  stepControlState_ = UNINITIALIZED;

  requestedStepSize_ = Scalar(-1.0);
  currentStepSize_ = initialStepSize_;
  currentOrder_ = 1;
  nextStepSize_ = initialStepSize_;
  nextOrder_ = 1;
  numberOfSteps_ = 0;
  totalNumberOfFailedSteps_ = 0;
  countOfConstantStepsAfterFailure_ = 0;

  if (is_null(delta_)) {
    delta_ = createMember(stepper.get_x_space());
  }
  if (is_null(errWtVec_)) {
    errWtVec_ = createMember(stepper.get_x_space());
  }
  V_S(delta_.ptr(),ST::zero());

  if ( doOutput_(Teuchos::VERB_HIGH) ) {
    RCP<Teuchos::FancyOStream> out = this->getOStream();
    Teuchos::OSTab ostab(out,1,"initialize");
    *out << "currentOrder_ = " << currentOrder_ << std::endl;
    *out << "numberOfSteps_ = " << numberOfSteps_ << std::endl;
  }

  setStepControlState_(BEFORE_FIRST_STEP);

}
Ejemplo n.º 4
0
void tLSCIntegrationTest::loadStableSystem()
{
   Epetra_CrsMatrix *F=0, *B=0, *Bt=0,*Qu=0;

   F=0; B=0; Bt=0; Qu=0;

   // read in stable discretization
   TEST_FOR_EXCEPT(EpetraExt::MatrixMarketFileToCrsMatrix("./data/lsc_F_2.mm",*velMap_,*velMap_,*velMap_,F));
   TEST_FOR_EXCEPT(EpetraExt::MatrixMarketFileToCrsMatrix("./data/lsc_B_2.mm",*prsMap_,*prsMap_,*velMap_,B));
   TEST_FOR_EXCEPT(EpetraExt::MatrixMarketFileToCrsMatrix("./data/lsc_Bt_2.mm",*velMap_,*velMap_,*prsMap_,Bt));
   TEST_FOR_EXCEPT(EpetraExt::MatrixMarketFileToCrsMatrix("./data/lsc_Qu_2.mm",*velMap_,*velMap_,*velMap_,Qu));

   // set stable matrix pointers
   sF_  = rcp(F); sB_  = rcp(B); sBt_ = rcp(Bt); sQu_ = rcp(Qu);

   Teko::LinearOp C;
   Teko::LinearOp tA_ = Teko::block2x2<double>(epetraLinearOp(sF_),epetraLinearOp(sBt_),epetraLinearOp(sB_),C,"A");
   sA_ = rcp(new Teko::Epetra::EpetraOperatorWrapper(tA_));

   // build an exporter to work around issue with MMFileToVector
   Epetra_Export exporter(*fullMap_,sA_->OperatorRangeMap());

   // read in RHS vector
   {
      Epetra_Vector *vfull=0, *temp=0;
 
      // read in rhs file 
      TEST_FOR_EXCEPT(EpetraExt::MatrixMarketFileToVector("./data/lsc_rhs.mm",*fullMap_,vfull));

      // MMFileToVector is immplemented incompletely...thats why an exporter is used
      temp = new Epetra_Vector(sA_->OperatorRangeMap());
      temp->Export(*vfull,exporter,Insert);
      rhs_ = rcp(temp);

      delete vfull;
   }

   // read in solution vector
   {
      Epetra_Vector *vfull=0, *temp=0;
 
      // read in exact solution file 
      TEST_FOR_EXCEPT(EpetraExt::MatrixMarketFileToVector("./data/lsc_exact_2.mm",*fullMap_,vfull));

      // MMFileToVector is immplemented incompletely...thats why an exporter is used
      temp = new Epetra_Vector(sA_->OperatorRangeMap());
      temp->Export(*vfull,exporter,Insert);
      sExact_ = rcp(temp);

      delete vfull;
   }
}
Ejemplo n.º 5
0
const Teuchos::RCP<TriKota::DiagonalROME<Scalar> >
createModel(
    const int globalDim,
    const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &g_offset
)
{
    using Teuchos::RCP;

    const RCP<const Teuchos::Comm<Thyra::Ordinal> > comm =
        Teuchos::DefaultComm<Thyra::Ordinal>::getComm();

    const int numProcs = comm->getSize();
    TEUCHOS_TEST_FOR_EXCEPT_MSG( numProcs > globalDim,
                                 "Error, the number of processors can not be greater than the global"
                                 " dimension of the vectors!." );
    const int localDim = globalDim / numProcs;
    const int localDimRemainder = globalDim % numProcs;
    TEUCHOS_TEST_FOR_EXCEPT_MSG( localDimRemainder != 0,
                                 "Error, the number of processors must divide into the global number"
                                 " of elements exactly for now!." );

    const RCP<TriKota::DiagonalROME<Scalar> > model =
        Teuchos::rcp(new TriKota::DiagonalROME<Scalar>(localDim));
    const RCP<const Thyra::VectorSpaceBase<Scalar> > p_space = model->get_p_space(0);
    const RCP<Thyra::VectorBase<Scalar> > ps = createMember(p_space);
    const Scalar ps_val = 2.0;
    Thyra::V_S(ps.ptr(), ps_val);
    model->setSolutionVector(ps);
    model->setScalarOffset(g_offset);

    return model;
}
void DefaultPolyLineSearchPointEvaluator<Scalar>::computePoint( const ScalarMag &alpha,
  const Ptr<Thyra::VectorBase<Scalar> > &p
  ) const
{
  typedef ScalarTraits<Scalar> ST;
  using Teuchos::as;
  using Thyra::V_V;
  using Thyra::Vp_StV;
  V_V( p, *vecs_[0] );
  if (alpha != ST::zero()) {
    ScalarMag alpha_i = alpha;
    const int n = vecs_.size();
    for (int i = 1; i < n; ++i, alpha_i *= alpha) {
      Vp_StV(p, alpha_i, *vecs_[i]); 
    }
  }
}
void ExplicitModelEvaluator<Scalar>::
buildInverseMassMatrix() const
{
  typedef Thyra::ModelEvaluatorBase MEB;
  using Teuchos::RCP;
  using Thyra::createMember;
  
  RCP<const Thyra::ModelEvaluator<Scalar> > me = this->getUnderlyingModel();

  // first allocate space for the mass matrix
  RCP<Thyra::LinearOpBase<Scalar> > mass = me->create_W_op();

  // intialize a zero to get rid of the x-dot 
  if(zero_==Teuchos::null) {
    zero_ = Thyra::createMember(*me->get_x_space());
    Thyra::assign(zero_.ptr(),0.0);
  }
  
  // request only the mass matrix from the physics
  // Model evaluator builds: alpha*u_dot + beta*F(u) = 0
  MEB::InArgs<Scalar>  inArgs  = me->createInArgs();
  inArgs.set_x(createMember(me->get_x_space()));
  inArgs.set_x_dot(zero_);
  inArgs.set_alpha(-1.0);
  inArgs.set_beta(0.0);

  // set the one time beta to ensure dirichlet conditions
  // are correctly included in the mass matrix: do it for
  // both epetra and Tpetra. If a panzer model evaluator has
  // not been passed in...oh well you get what you asked for!
  if(panzerModel_!=Teuchos::null)
    panzerModel_->setOneTimeDirichletBeta(-1.0);
  else if(panzerEpetraModel_!=Teuchos::null)
    panzerEpetraModel_->setOneTimeDirichletBeta(-1.0);

  // set only the mass matrix
  MEB::OutArgs<Scalar> outArgs = me->createOutArgs();
  outArgs.set_W_op(mass);

  // this will fill the mass matrix operator 
  me->evalModel(inArgs,outArgs);

  if(!massLumping_) {
    invMassMatrix_ = Thyra::inverse<Scalar>(*me->get_W_factory(),mass);
  }
  else {
    // build lumped mass matrix (assumes all positive mass entries, does a simple sum)
    Teuchos::RCP<Thyra::VectorBase<Scalar> > ones = Thyra::createMember(*mass->domain());
    Thyra::assign(ones.ptr(),1.0);

    RCP<Thyra::VectorBase<Scalar> > invLumpMass = Thyra::createMember(*mass->range());
    Thyra::apply(*mass,Thyra::NOTRANS,*ones,invLumpMass.ptr());
    Thyra::reciprocal(*invLumpMass,invLumpMass.ptr());

    invMassMatrix_ = Thyra::diagonal(invLumpMass);
  }
}
Ejemplo n.º 8
0
DiagonalROME<Scalar>::DiagonalROME(
    const int localDim,
    const RCP<const Teuchos::Comm<Thyra::Ordinal> > &comm
)
    :Np_(1), Ng_(1), comm_(comm), localDim_(localDim),
     nonlinearTermFactor_(0.0), g_offset_(0.0)
{

    typedef Teuchos::ScalarTraits<Scalar> ST;
    using Thyra::createMember;

    TEUCHOS_ASSERT( localDim > 0 );

    // Get the comm
    if (is_null(comm_)) {
        comm_ = Teuchos::DefaultComm<Thyra::Ordinal>::getComm();
    }

    // Locally replicated space for g
    g_space_ = Thyra::locallyReplicatedDefaultSpmdVectorSpace<Scalar>(comm_, 1);

    // Distributed space for p
    p_space_ = Thyra::defaultSpmdVectorSpace<Scalar>(comm_, localDim, -1);

    // Default solution
    const RCP<Thyra::VectorBase<Scalar> > ps = createMember<Scalar>(p_space_);
    V_S(ps.ptr(), ST::zero());
    ps_ = ps;

    // Default diagonal
    const RCP<Thyra::VectorBase<Scalar> > diag = createMember<Scalar>(p_space_);
    V_S(diag.ptr(), ST::one());
    diag_ = diag;
    diag_bar_ = diag;

    // Default inner product
    const RCP<Thyra::VectorBase<Scalar> > s_bar = createMember<Scalar>(p_space_);
    V_S(s_bar.ptr(), ST::one());
    s_bar_ = s_bar;

    // Default response offset
    g_offset_ = ST::zero();

}
bool DefaultBlockedTriangularLinearOpWithSolve<Scalar>::opSupportedImpl(
  EOpTransp M_trans
  ) const
{
  using Thyra::opSupported;
  assertBlockFillIsActive(false);
  for ( int k = 0; k < numDiagBlocks_; ++k ) {
    if ( !opSupported(*diagonalBlocks_[k].getConstObj(),M_trans) )
      return false;
  }
  return true;
  // ToDo: To be safe we really should do a collective reduction of all
  // clusters of processes.  However, for the typical use case, every block
  // will return the same info and we should be safe!
}
bool
DefaultBlockedTriangularLinearOpWithSolve<Scalar>::solveSupportsSolveMeasureTypeImpl(
  EOpTransp M_trans, const SolveMeasureType& solveMeasureType
  ) const
{
  using Thyra::solveSupportsSolveMeasureType;
  assertBlockFillIsActive(false);
  for ( int k = 0; k < numDiagBlocks_; ++k ) {
    if (
      !solveSupportsSolveMeasureType(
        *diagonalBlocks_[k].getConstObj(),
        M_trans, solveMeasureType
        )
      )
    {
      return false;
    }
  }
  return true;
}
Simple2DModelEvaluator<Scalar>::Simple2DModelEvaluator()
  : x_space_(Thyra::defaultSpmdVectorSpace<Scalar>(2)),
    f_space_(x_space_),
    W_factory_(Thyra::defaultSerialDenseLinearOpWithSolveFactory<Scalar>()),
    d_(0.0),
    p_(x_space_->dim(), Teuchos::ScalarTraits<Scalar>::zero()),
    showGetInvalidArg_(false)
{

  using Teuchos::RCP;
  using Thyra::VectorBase;
  using Thyra::createMember;
  typedef Thyra::ModelEvaluatorBase MEB;
  typedef Teuchos::ScalarTraits<Scalar> ST;
  
  MEB::InArgsSetup<Scalar> inArgs;
  inArgs.setModelEvalDescription(this->description());
  inArgs.setSupports(MEB::IN_ARG_x);
  prototypeInArgs_ = inArgs;
  
  MEB::OutArgsSetup<Scalar> outArgs;
  outArgs.setModelEvalDescription(this->description());
  outArgs.setSupports(MEB::OUT_ARG_f);
  outArgs.setSupports(MEB::OUT_ARG_W_op);
  outArgs.setSupports(MEB::OUT_ARG_W_prec);
  prototypeOutArgs_ = outArgs;

  nominalValues_ = inArgs;
  x0_ = createMember(x_space_);
  V_S(x0_.ptr(), ST::zero());
  nominalValues_.set_x(x0_);

  set_d(10.0);
  set_p(Teuchos::tuple<Scalar>(2.0, 0.0)());
  set_x0(Teuchos::tuple<Scalar>(1.0, 1.0)());

}
NonlinearCGUtils::ESolveReturn
NonlinearCG<Scalar>::doSolve(
  const Ptr<Thyra::VectorBase<Scalar> > &p_inout,
  const Ptr<ScalarMag> &g_opt_out,
  const Ptr<const ScalarMag> &g_reduct_tol_in,
  const Ptr<const ScalarMag> &g_grad_tol_in,
  const Ptr<const ScalarMag> &alpha_init_in,
  const Ptr<int> &numIters_out
  )
{

  typedef ScalarTraits<Scalar> ST;
  typedef ScalarTraits<ScalarMag> SMT;
  
  using Teuchos::null;
  using Teuchos::as;
  using Teuchos::tuple;
  using Teuchos::rcpFromPtr;
  using Teuchos::optInArg;
  using Teuchos::inOutArg;
  using GlobiPack::computeValue;
  using GlobiPack::PointEval1D;
  using Thyra::VectorSpaceBase;
  using Thyra::VectorBase;
  using Thyra::MultiVectorBase;
  using Thyra::scalarProd;
  using Thyra::createMember;
  using Thyra::createMembers;
  using Thyra::get_ele;
  using Thyra::norm;
  using Thyra::V_StV;
  using Thyra::Vt_S;
  using Thyra::eval_g_DgDp;
  typedef Thyra::Ordinal Ordinal;
  typedef Thyra::ModelEvaluatorBase MEB;
  namespace NCGU = NonlinearCGUtils;
  using std::max;

  // Validate input

  g_opt_out.assert_not_null();

  // Set streams

  const RCP<Teuchos::FancyOStream> out = this->getOStream();
  linesearch_->setOStream(out);

  // Determine what step constants will be computed

  const bool compute_beta_PR =
    (
      solverType_ == NCGU::NONLINEAR_CG_PR_PLUS
      ||
      solverType_ == NCGU::NONLINEAR_CG_FR_PR
      );

  const bool compute_beta_HS = (solverType_ == NCGU::NONLINEAR_CG_HS);

  //
  // A) Set up the storage for the algorithm
  //
  
  const RCP<DefaultPolyLineSearchPointEvaluator<Scalar> >
    pointEvaluator = defaultPolyLineSearchPointEvaluator<Scalar>();

  const RCP<UnconstrainedOptMeritFunc1D<Scalar> >
    meritFunc = unconstrainedOptMeritFunc1D<Scalar>(
      model_, paramIndex_, responseIndex_ );

  const RCP<const VectorSpaceBase<Scalar> >
    p_space = model_->get_p_space(paramIndex_),
    g_space = model_->get_g_space(responseIndex_);

  // Stoarge for current iteration
  RCP<VectorBase<Scalar> >
    p_k = rcpFromPtr(p_inout),        // Current solution for p
    p_kp1 = createMember(p_space),    // Trial point for p (in line search)
    g_vec = createMember(g_space),    // Vector (size 1) form of objective g(p) 
    g_grad_k = createMember(p_space), // Gradient of g DgDp^T
    d_k = createMember(p_space),      // Search direction
    g_grad_k_diff_km1 = null;         // g_grad_k - g_grad_km1 (if needed)

  // Storage for previous iteration
  RCP<VectorBase<Scalar> >
    g_grad_km1 = null, // Will allocate if we need it!
    d_km1 = null; // Will allocate if we need it!
  ScalarMag
    alpha_km1 = SMT::zero(),
    g_km1 = SMT::zero(),
    g_grad_km1_inner_g_grad_km1 = SMT::zero(),
    g_grad_km1_inner_d_km1 = SMT::zero();
  
  if (compute_beta_PR || compute_beta_HS) {
    g_grad_km1 = createMember(p_space);
    g_grad_k_diff_km1 = createMember(p_space);
  }
  
  if (compute_beta_HS) {
    d_km1 = createMember(p_space);
  }

  //
  // B) Do the nonlinear CG iterations
  //

  *out << "\nStarting nonlinear CG iterations ...\n";

  if (and_conv_tests_) {
    *out << "\nNOTE: Using AND of convergence tests!\n";
  }
  else {
    *out << "\nNOTE: Using OR of convergence tests!\n";
  }

  const Scalar alpha_init =
    ( !is_null(alpha_init_in) ? *alpha_init_in : alpha_init_ );
  const Scalar g_reduct_tol =
    ( !is_null(g_reduct_tol_in) ? *g_reduct_tol_in : g_reduct_tol_ );
  const Scalar g_grad_tol =
    ( !is_null(g_grad_tol_in) ? *g_grad_tol_in : g_grad_tol_ );

  const Ordinal globalDim = p_space->dim();

  bool foundSolution = false;
  bool fatalLinesearchFailure = false;
  bool restart = true;
  int numConsecutiveLineSearchFailures = 0;

  int numConsecutiveIters = 0;

  for (numIters_ = 0; numIters_ < maxIters_; ++numIters_, ++numConsecutiveIters) {

    Teuchos::OSTab tab(out);

    *out << "\nNonlinear CG Iteration k = " << numIters_ << "\n";

    Teuchos::OSTab tab2(out);

    //
    // B.1) Evaluate the point (on first iteration)
    //
    
    eval_g_DgDp(
      *model_, paramIndex_, *p_k, responseIndex_,
      numIters_ == 0 ? g_vec.ptr() : null, // Only on first iteration
      MEB::Derivative<Scalar>(g_grad_k, MEB::DERIV_MV_GRADIENT_FORM) );

    const ScalarMag g_k = get_ele(*g_vec, 0);
    // Above: If numIters_ > 0, then g_vec was updated in meritFunc->eval(...).

    //
    // B.2) Check for convergence
    //

    // B.2.a) ||g_k - g_km1|| |g_k + g_mag| <= g_reduct_tol

    bool g_reduct_converged = false;

    if (numIters_ > 0) {

      const ScalarMag g_reduct = g_k - g_km1;
      
      *out << "\ng_k - g_km1 = "<<g_reduct<<"\n";
      
      const ScalarMag g_reduct_err =
        SMT::magnitude(g_reduct / SMT::magnitude(g_k + g_mag_));
      
      g_reduct_converged = (g_reduct_err <= g_reduct_tol);
      
      *out << "\nCheck convergence: |g_k - g_km1| / |g_k + g_mag| = "<<g_reduct_err
           << (g_reduct_converged ? " <= " : " > ")
           << "g_reduct_tol = "<<g_reduct_tol<<"\n";
      
    }

    // B.2.b) ||g_grad_k|| g_mag <= g_grad_tol

    const Scalar g_grad_k_inner_g_grad_k = scalarProd<Scalar>(*g_grad_k, *g_grad_k);
    const ScalarMag norm_g_grad_k = ST::magnitude(ST::squareroot(g_grad_k_inner_g_grad_k));

    *out << "\n||g_grad_k|| = "<<norm_g_grad_k << "\n";

    const ScalarMag g_grad_err = norm_g_grad_k / g_mag_;

    const bool g_grad_converged = (g_grad_err <= g_grad_tol);

    *out << "\nCheck convergence: ||g_grad_k|| / g_mag = "<<g_grad_err
         << (g_grad_converged ? " <= " : " > ")
         << "g_grad_tol = "<<g_grad_tol<<"\n";

    // B.2.c) Convergence status
    
    bool isConverged = false;
    if (and_conv_tests_) {
      isConverged = g_reduct_converged && g_grad_converged;
    }
    else {
      isConverged = g_reduct_converged || g_grad_converged;
    }

    if (isConverged) {
      if (numIters_ < minIters_) {
        *out << "\nnumIters="<<numIters_<<" < minIters="<<minIters_
             << ", continuing on!\n";
      }
      else {
        *out << "\nFound solution, existing algorithm!\n";
        foundSolution = true;
      }
    }
    else {
      *out << "\nNot converged!\n";
    }
    
    if (foundSolution) {
      break;
    }

    //
    // B.3) Compute the search direction d_k
    //

    if (numConsecutiveIters == globalDim) {

      *out << "\nThe number of consecutive iterations exceeds the"
           << " global dimension so restarting!\n";

      restart = true;

    }

    if (restart) {

      *out << "\nResetting search direction back to steppest descent!\n";

      // d_k = -g_grad_k
      V_StV( d_k.ptr(), as<Scalar>(-1.0), *g_grad_k );

      restart = false;

    }
    else {
      
      // g_grad_k - g_grad_km1
      if (!is_null(g_grad_k_diff_km1)) {
        V_VmV( g_grad_k_diff_km1.ptr(), *g_grad_k, *g_grad_km1 );
      }

      // beta_FR = inner(g_grad_k, g_grad_k) / inner(g_grad_km1, g_grad_km1)
      const Scalar beta_FR =
        g_grad_k_inner_g_grad_k / g_grad_km1_inner_g_grad_km1;
      *out << "\nbeta_FR = " << beta_FR << "\n";
      // NOTE: Computing beta_FR is free so we might as well just do it!

      // beta_PR = inner(g_grad_k, g_grad_k - g_grad_km1) /
      //    inner(g_grad_km1, g_grad_km1)
      Scalar beta_PR = ST::zero();
      if (compute_beta_PR) {
        beta_PR =
          inner(*g_grad_k, *g_grad_k_diff_km1) / g_grad_km1_inner_g_grad_km1;
        *out << "\nbeta_PR = " << beta_PR << "\n";
      }

      // beta_HS = inner(g_grad_k, g_grad_k - g_grad_km1) /
      //    inner(g_grad_k - g_grad_km1, d_km1)
      Scalar beta_HS = ST::zero();
      if (compute_beta_HS) {
        beta_HS =
          inner(*g_grad_k, *g_grad_k_diff_km1) / inner(*g_grad_k_diff_km1, *d_km1);
        *out << "\nbeta_HS = " << beta_HS << "\n";
      }
      
      Scalar beta_k = ST::zero();
      switch(solverType_) {
        case NCGU::NONLINEAR_CG_FR: {
          beta_k = beta_FR;
          break;
        }
        case NCGU::NONLINEAR_CG_PR_PLUS: {
          beta_k = max(beta_PR, ST::zero());
          break;
        }
        case NCGU::NONLINEAR_CG_FR_PR: {
          // NOTE: This does not seem to be working :-(
          if (numConsecutiveIters < 2) {
            beta_k = beta_PR;
          }
          else if (beta_PR < -beta_FR)
            beta_k = -beta_FR;
          else if (ST::magnitude(beta_PR) <= beta_FR)
            beta_k = beta_PR;
          else // beta_PR > beta_FR
            beta_k = beta_FR;
        }
        case NCGU::NONLINEAR_CG_HS: {
          beta_k = beta_HS;
          break;
        }
        default:
          TEUCHOS_TEST_FOR_EXCEPT(true);
      }
      *out << "\nbeta_k = " << beta_k << "\n";

      // d_k = beta_k * d_last + -g_grad_k
      if (!is_null(d_km1))
        V_StV( d_k.ptr(), beta_k, *d_km1 );
      else
        Vt_S( d_k.ptr(), beta_k );
      Vp_StV( d_k.ptr(), as<Scalar>(-1.0), *g_grad_k );

    }
    
    //
    // B.4) Perform the line search
    //

    // B.4.a) Compute the initial step length

    Scalar alpha_k = as<Scalar>(-1.0);

    if (numIters_ == 0) {
      alpha_k = alpha_init;
    }
    else {
      if (alpha_reinit_) {
        alpha_k = alpha_init;
      }
      else {
        alpha_k = alpha_km1;
        // ToDo: Implement better logic from Nocedal and Wright for selecting
        // this step length after first iteration!
      }
    }

    // B.4.b) Perform the linesearch (computing updated quantities in process)

    pointEvaluator->initialize(tuple<RCP<const VectorBase<Scalar> > >(p_k, d_k)());

    ScalarMag g_grad_k_inner_d_k = ST::zero();

    // Set up the merit function to only compute the value
    meritFunc->setEvaluationQuantities(pointEvaluator, p_kp1, g_vec, null);

    PointEval1D<ScalarMag> point_k(ST::zero(), g_k);
    if (linesearch_->requiresBaseDeriv()) {
      g_grad_k_inner_d_k = scalarProd(*g_grad_k, *d_k);
      point_k.Dphi = g_grad_k_inner_d_k;
    }

    ScalarMag g_kp1 = computeValue(*meritFunc, alpha_k);
    // NOTE: The above call updates p_kp1 and g_vec as well!

    PointEval1D<ScalarMag> point_kp1(alpha_k, g_kp1);

    const bool linesearchResult = linesearch_->doLineSearch(
      *meritFunc, point_k, inOutArg(point_kp1), null );

    alpha_k = point_kp1.alpha;
    g_kp1 = point_kp1.phi;

    if (linesearchResult) {
      numConsecutiveLineSearchFailures = 0;
    }
    else {
      if (numConsecutiveLineSearchFailures==0) {
        *out << "\nLine search failure, resetting the search direction!\n";
        restart = true;
      }
      if (numConsecutiveLineSearchFailures==1) {
        *out << "\nLine search failure on last iteration also, terminating algorithm!\n";
        fatalLinesearchFailure = true;
      }
      ++numConsecutiveLineSearchFailures;
    }

    if (fatalLinesearchFailure) {
      break;
    }

    //
    // B.5) Transition to the next iteration
    //
    
    alpha_km1 = alpha_k;
    g_km1 = g_k;
    g_grad_km1_inner_g_grad_km1 = g_grad_k_inner_g_grad_k;
    g_grad_km1_inner_d_km1 = g_grad_k_inner_d_k;
    std::swap(p_k, p_kp1);
    if (!is_null(g_grad_km1))
      std::swap(g_grad_km1, g_grad_k);
    if (!is_null(d_km1))
      std::swap(d_k, d_km1);
    
#ifdef TEUCHOS_DEBUG
    // Make sure we compute these correctly before they are used!
    V_S(g_grad_k.ptr(), ST::nan());
    V_S(p_kp1.ptr(), ST::nan());
#endif

  }

  //
  // C) Final clean up
  //
  
  // Get the most current value of g(p)
  *g_opt_out = get_ele(*g_vec, 0);

  // Make sure that the final value for p has been copied in!
  V_V( p_inout, *p_k );

  if (!is_null(numIters_out)) {
    *numIters_out = numIters_;
  }

  if (numIters_ == maxIters_) {
    *out << "\nMax nonlinear CG iterations exceeded!\n";
  }
  
  if (foundSolution) {
    return NonlinearCGUtils::SOLVE_SOLUTION_FOUND;
  }
  else if(fatalLinesearchFailure) {
    return NonlinearCGUtils::SOLVE_LINSEARCH_FAILURE;
  }

  // Else, the max number of iterations was exceeded
  return NonlinearCGUtils::SOLVE_MAX_ITERS_EXCEEDED;

}
Ejemplo n.º 13
0
bool runCgSolveExample(
  const int dim,
  const Scalar diagScale,
  const bool symOp,
  const bool showAllTests,
  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType tolerance,
  const int maxNumIters
  )
{

  using Teuchos::as;
  using Teuchos::null;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using Teuchos::OSTab;
  typedef Teuchos::ScalarTraits<Scalar> ST;
  using Thyra::multiply;
  using Thyra::scale;
  typedef typename ST::magnitudeType  ScalarMag;
  bool success = true;
  bool result;
  Teuchos::RCP<Teuchos::FancyOStream> out =
    Teuchos::VerboseObjectBase::getDefaultOStream();
  *out << "\n***\n*** Running silly CG solver using scalar type = \'"
       << ST::name() << "\' ...\n***\n";
  Teuchos::Time timer("");
  timer.start(true);

  //
  // (A) Setup a simple linear system with tridiagonal operator:
  //
  //       [   a*2   -1                         ]
  //       [ -r(1)  a*2       -1                ]
  //  A =  [          .        .        .       ]
  //       [             -r(n-2)      a*2    -1 ]
  //       [                      -r(n-1)   a*2 ]
  //

  // (A.1) Create the tridiagonal matrix operator
  *out << "\nConstructing tridiagonal matrix A of dimension = " << dim
       << " and diagonal multiplier = " << diagScale << " ...\n";
  Teuchos::Array<Scalar> lower(dim-1), diag(dim), upper(dim-1);
  const Scalar
    up = -ST::one(),
    diagTerm = as<Scalar>(2.0) * diagScale * ST::one(),
    low = -(symOp ? ST::one() : ST::random());
  int k = 0;
  // First row
  diag[k] = diagTerm; upper[k] = up;
  // Middle rows
  for( k = 1; k < dim - 1; ++k ) {
    lower[k-1] = low; diag[k] = diagTerm; upper[k] = up;
  }
  // Last row
  lower[k-1] = low; diag[k] = diagTerm;
  RCP<const Thyra::LinearOpBase<Scalar> > A =
    rcp(new ExampleTridiagSerialLinearOp<Scalar>(dim, lower, diag, upper));

  // (A.2) Testing the linear operator constructed linear operator
  *out << "\nTesting the constructed linear operator A ...\n";
  Thyra::LinearOpTester<Scalar> linearOpTester;
  linearOpTester.enable_all_tests(false);
  linearOpTester.check_linear_properties(true);
  linearOpTester.set_all_error_tol(tolerance);
  linearOpTester.set_all_warning_tol(1e-2*tolerance);
  linearOpTester.show_all_tests(showAllTests);
  result = linearOpTester.check(*A, out.ptr());
  if(!result) success = false;

  // (A.3) Create RHS vector b and set to a random value
  RCP<Thyra::VectorBase<Scalar> > b = createMember(A->range());
  Thyra::seed_randomize<Scalar>(0);
  Thyra::randomize( -ST::one(), +ST::one(), b.ptr() );

  // (A.4) Create LHS vector x and set to zero
  RCP<Thyra::VectorBase<Scalar> > x = createMember(A->domain());
  Thyra::V_S( x.ptr(), ST::zero() );

  // (A.5) Create the final linear system
  if(!symOp) {
    *out << "\nSetting up normal equations for unsymmetric system A^H*(A*x-b) => new A*x = b ...\n";
    // A^H*A
    RCP<const Thyra::LinearOpBase<Scalar> > AtA = multiply(adjoint(A), A);
    // A^H*b
    RCP<Thyra::VectorBase<Scalar> > nb = createMember(AtA->range());
    Thyra::apply<Scalar>(*A, Thyra::CONJTRANS, *b, nb.ptr());
    A = AtA;
    b = nb;
  }

  // (A.6) Testing the linear operator used with the solve
  *out << "\nTesting the linear operator used with the solve ...\n";
  linearOpTester.check_for_symmetry(true);
  result = linearOpTester.check(*A, out.ptr());
  if(!result) success = false;

  //
  // (B) Solve the linear system with the silly CG solver
  //
  *out << "\nSolving the linear system with sillyCgSolve(...) ...\n";
  {
    OSTab tab2(out);
    result = sillyCgSolve(*A, *b, maxNumIters, tolerance, x.ptr(), *out);
  }
  if(!result) success = false;

  //
  // (C) Check that the linear system was solved to the specified tolerance
  //
  RCP<Thyra::VectorBase<Scalar> > r = createMember(A->range());                     
  // r = b
  Thyra::V_V(r.ptr(), *b);
   // r = -A*x + r
  Thyra::apply<Scalar>(*A, Thyra::NOTRANS, *x, r.ptr(), -ST::one(), ST::one());
  const ScalarMag r_nrm = Thyra::norm(*r), b_nrm = Thyra::norm(*b);
  const ScalarMag rel_err = r_nrm/b_nrm, relaxTol = 10.0*tolerance;
  result = rel_err <= relaxTol;
  if(!result) success = false;
  *out << "\nChecking the residual ourselves ...\n";
  {
    OSTab tab(out);
    *out
      << "\n||b-A*x||/||b|| = "<<r_nrm<<"/"<<b_nrm<<" = "<<rel_err<<(result?" <= ":" > ")
      <<"10.0*tolerance = "<<relaxTol<<": "<<(result?"passed":"failed")<<std::endl;
  }
  timer.stop();
  *out << "\nTotal time = " << timer.totalElapsedTime() << " sec\n";
  
  return success;

} // end runCgSolveExample()
int main(int argc, char *argv[])
{

    using std::endl;
    typedef double Scalar;
    typedef double ScalarMag;
    using Teuchos::describe;
    using Teuchos::RCP;
    using Teuchos::rcp;
    using Teuchos::rcp_implicit_cast;
    using Teuchos::rcp_dynamic_cast;
    using Teuchos::as;
    using Teuchos::ParameterList;
    using Teuchos::CommandLineProcessor;
    typedef Teuchos::ParameterList::PrintOptions PLPrintOptions;
    typedef Thyra::ModelEvaluatorBase MEB;
    using Thyra::createMember;
    using Thyra::createMembers;

    bool success = true;

    Teuchos::GlobalMPISession mpiSession(&argc,&argv);

    RCP<Epetra_Comm> epetra_comm;
#ifdef HAVE_MPI
    epetra_comm = rcp( new Epetra_MpiComm(MPI_COMM_WORLD) );
#else
    epetra_comm = rcp( new Epetra_SerialComm );
#endif // HAVE_MPI

    RCP<Teuchos::FancyOStream>
    out = Teuchos::VerboseObjectBase::getDefaultOStream();

    try {

        //
        // A) Read commandline options
        //

        CommandLineProcessor clp;
        clp.throwExceptions(false);
        clp.addOutputSetupOptions(true);

        std::string paramsFileName = "";
        clp.setOption( "params-file", &paramsFileName,
                       "File name for XML parameters" );

        std::string extraParamsString = "";
        clp.setOption( "extra-params", &extraParamsString,
                       "Extra XML parameter string" );

        Teuchos::EVerbosityLevel verbLevel = Teuchos::VERB_DEFAULT;
        setVerbosityLevelOption( "verb-level", &verbLevel,
                                 "Top-level verbosity level.  By default, this gets deincremented as you go deeper into numerical objects.",
                                 &clp );

        double finalTime = 1.0;
        clp.setOption( "final-time", &finalTime, "Final time (the inital time)" );

        int numTimeSteps = 2;
        clp.setOption( "num-time-steps", &numTimeSteps, "Number of time steps" );

        bool dumpFinalSolutions = false;
        clp.setOption(
            "dump-final-solutions", "no-dump-final-solutions", &dumpFinalSolutions,
            "Determine if the final solutions are dumpped or not." );

        double maxStateError = 1e-6;
        clp.setOption( "max-state-error", &maxStateError,
                       "The maximum allowed error in the integrated state in relation to the exact state solution" );

        // ToDo: Read in more parameters

        CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
        if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;

        if ( Teuchos::VERB_DEFAULT == verbLevel )
            verbLevel = Teuchos::VERB_LOW;

        const Teuchos::EVerbosityLevel
        solnVerbLevel = ( dumpFinalSolutions ? Teuchos::VERB_EXTREME : verbLevel );

        //
        // B) Get the base parameter list that all other parameter lists will be
        // read from.
        //

        RCP<ParameterList> paramList = Teuchos::parameterList();
        if (paramsFileName.length())
            updateParametersFromXmlFile( paramsFileName, &*paramList );
        if (extraParamsString.length())
            updateParametersFromXmlString( extraParamsString, &*paramList );

        paramList->validateParameters(*getValidParameters());

        //
        // C) Create the Stratimikos linear solver factories.
        //

        // Get the linear solve strategy that will be used to solve for the linear
        // system with the dae's W matrix.
        Stratimikos::DefaultLinearSolverBuilder daeLinearSolverBuilder;
        daeLinearSolverBuilder.setParameterList(sublist(paramList,DAELinearSolver_name));
        RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> >
        daeLOWSF = createLinearSolveStrategy(daeLinearSolverBuilder);

        // Get the linear solve strategy that can be used to override the overall
        // linear system solve
        Stratimikos::DefaultLinearSolverBuilder overallLinearSolverBuilder;
        overallLinearSolverBuilder.setParameterList(sublist(paramList,OverallLinearSolver_name));
        RCP<Thyra::LinearOpWithSolveFactoryBase<Scalar> >
        overallLOWSF = createLinearSolveStrategy(overallLinearSolverBuilder);

        //
        // D) Create the underlying EpetraExt::ModelEvaluator
        //

        RCP<EpetraExt::DiagonalTransientModel> epetraDaeModel =
            EpetraExt::diagonalTransientModel(
                epetra_comm,
                sublist(paramList,DiagonalTransientModel_name)
            );

        *out <<"\nepetraDaeModel valid options:\n";
        epetraDaeModel->getValidParameters()->print(
            *out, PLPrintOptions().indent(2).showTypes(true).showDoc(true)
        );

        //
        // E) Create the Thyra-wrapped ModelEvaluator
        //

        RCP<Thyra::ModelEvaluator<double> > daeModel =
            epetraModelEvaluator(epetraDaeModel,daeLOWSF);

        //
        // F) Create the TimeDiscretizedBackwardEulerModelEvaluator
        //

        MEB::InArgs<Scalar> initCond = daeModel->createInArgs();
        initCond.setArgs(daeModel->getNominalValues());

        RCP<Thyra::ModelEvaluator<Scalar> >
        discretizedModel = Rythmos::timeDiscretizedBackwardEulerModelEvaluator<Scalar>(
                               daeModel, initCond, finalTime, numTimeSteps, overallLOWSF );

        *out << "\ndiscretizedModel = " << describe(*discretizedModel,verbLevel);

        //
        // F) Setup a nonlinear solver and solve the system
        //

        // F.1) Setup a nonlinear solver

        Thyra::DampenedNewtonNonlinearSolver<Scalar> nonlinearSolver;
        nonlinearSolver.setOStream(out);
        nonlinearSolver.setVerbLevel(verbLevel);
        //nonlinearSolver.setParameterList(sublist(paramList,NonlinearSolver_name));
        //2007/11/27: rabartl: ToDo: Implement parameter list handling for
        //DampenedNonlinearSolve so that I can uncomment the above line.
        nonlinearSolver.setModel(discretizedModel);

        // F.2) Solve the system

        RCP<Thyra::VectorBase<Scalar> >
        x_bar = createMember(discretizedModel->get_x_space());
        V_S( x_bar.ptr(), 0.0 );

        Thyra::SolveStatus<Scalar> solveStatus =
            Thyra::solve( nonlinearSolver, &*x_bar );

        *out << "\nsolveStatus:\n" << solveStatus;

        *out << "\nx_bar = " << describe(*x_bar,solnVerbLevel);

        //
        // G) Verify that the solution is correct???
        //

        // Check against the end time exact solution.

        RCP<const Thyra::VectorBase<Scalar> >
        exact_x_final = Thyra::create_Vector(
                            epetraDaeModel->getExactSolution(finalTime),
                            daeModel->get_x_space()
                        );

        RCP<const Thyra::VectorBase<Scalar> > solved_x_final
            = rcp_dynamic_cast<Thyra::ProductVectorBase<Scalar> >(x_bar,true)->getVectorBlock(numTimeSteps-1);

        const bool result = Thyra::testRelNormDiffErr(
                                "exact_x_final", *exact_x_final, "solved_x_final", *solved_x_final,
                                "maxStateError", maxStateError, "warningTol", 1.0, // Don't warn
                                &*out, solnVerbLevel
                            );
        if (!result) success = false;

    }
    TEUCHOS_STANDARD_CATCH_STATEMENTS(true,*out,success);

    if(success)
        *out << "\nEnd Result: TEST PASSED" << endl;
    else
        *out << "\nEnd Result: TEST FAILED" << endl;

    return ( success ? 0 : 1 );

} // end main() [Doxygen looks for this!]
Ejemplo n.º 15
0
bool run_composite_linear_ops_tests(
  const Teuchos::RCP<const Teuchos::Comm<Thyra::Ordinal> > comm,
  const int n,
  const bool useSpmd,
  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &tol,
  const bool dumpAll,
  Teuchos::FancyOStream *out_arg
  )
{

  using Teuchos::as;
  typedef Teuchos::ScalarTraits<Scalar> ST;
  typedef typename ST::magnitudeType    ScalarMag;
  typedef Teuchos::ScalarTraits<ScalarMag> STM;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using Teuchos::null;
  using Teuchos::rcp_const_cast;
  using Teuchos::rcp_dynamic_cast;
  using Teuchos::dyn_cast;
  using Teuchos::OSTab;
  using Thyra::relErr;
  using Thyra::passfail;

  RCP<Teuchos::FancyOStream>
    out = rcp(new Teuchos::FancyOStream(rcp(out_arg,false)));

  const Teuchos::EVerbosityLevel
    verbLevel = dumpAll?Teuchos::VERB_EXTREME:Teuchos::VERB_HIGH;

  if (nonnull(out)) *out
    << "\n*** Entering run_composite_linear_ops_tests<"<<ST::name()<<">(...) ...\n";

  bool success = true, result;

  const ScalarMag warning_tol = ScalarMag(1e-2)*tol, error_tol = tol;
  Thyra::LinearOpTester<Scalar> linearOpTester;
  linearOpTester.linear_properties_warning_tol(warning_tol);
  linearOpTester.linear_properties_error_tol(error_tol);
  linearOpTester.adjoint_warning_tol(warning_tol);
  linearOpTester.adjoint_error_tol(error_tol);
  linearOpTester.dump_all(dumpAll);
  Thyra::LinearOpTester<Scalar> symLinearOpTester(linearOpTester);
  symLinearOpTester.check_for_symmetry(true);
  symLinearOpTester.symmetry_warning_tol(STM::squareroot(warning_tol));
  symLinearOpTester.symmetry_error_tol(STM::squareroot(error_tol));

  RCP<const Thyra::VectorSpaceBase<Scalar> > space;
  if(useSpmd) space = Thyra::defaultSpmdVectorSpace<Scalar>(comm,n,-1);
  else space = Thyra::defaultSpmdVectorSpace<Scalar>(n);
  if (nonnull(out)) *out
    << "\nUsing a basic vector space described as " << describe(*space,verbLevel) << " ...\n";

  if (nonnull(out)) *out << "\nCreating random n x (n/2) multi-vector origA ...\n";
  RCP<Thyra::MultiVectorBase<Scalar> >
    mvOrigA = createMembers(space,n/2,"origA");
  Thyra::seed_randomize<Scalar>(0);
  //RTOpPack::show_spmd_apply_op_dump = true;
  Thyra::randomize( as<Scalar>(as<Scalar>(-1)*ST::one()), as<Scalar>(as<Scalar>(+1)*ST::one()),
    mvOrigA.ptr() );
  RCP<const Thyra::LinearOpBase<Scalar> >
    origA = mvOrigA;
  if (nonnull(out)) *out << "\norigA =\n" << describe(*origA,verbLevel);
  //RTOpPack::show_spmd_apply_op_dump = false;

  if (nonnull(out)) *out << "\nTesting origA ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*origA, out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out
    << "\nCreating implicit scaled linear operator A1 = scale(0.5,origA) ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A1 = scale(as<Scalar>(0.5),origA);
  if (nonnull(out)) *out << "\nA1 =\n" << describe(*A1,verbLevel);

  if (nonnull(out)) *out << "\nTesting A1 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A1,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nTesting that A1.getOp() == origA ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.compare(
    *dyn_cast<const Thyra::DefaultScaledAdjointLinearOp<Scalar> >(*A1).getOp(),
    *origA,out.ptr());
  if(!result) success = false;

  {

    if (nonnull(out)) *out
      << "\nUnwrapping origA to get non-persisting pointer to origA_1, scalar and transp ...\n";
    Scalar  scalar;
    Thyra::EOpTransp transp;
    const Thyra::LinearOpBase<Scalar> *origA_1 = NULL;
    unwrap( *origA, &scalar, &transp, &origA_1 );
    TEUCHOS_TEST_FOR_EXCEPT( origA_1 == NULL );

    if (nonnull(out)) *out << "\nscalar = " << scalar << " == 1 ? ";
    result = (scalar == ST::one());
    if(!result) success = false;
    if (nonnull(out))	*out << passfail(result) << std::endl;

    if (nonnull(out)) *out << "\ntransp = " << toString(transp) << " == NOTRANS ? ";
    result = (transp == Thyra::NOTRANS);
    if(!result) success = false;
    if (nonnull(out))	*out << passfail(result) << std::endl;

    if (nonnull(out)) *out << "\nTesting that origA_1 == origA ...\n";
    Thyra::seed_randomize<Scalar>(0);
    result = linearOpTester.compare(*origA_1,*origA,out.ptr());
    if(!result) success = false;

  }

  {

    if (nonnull(out)) *out << "\nUnwrapping A1 to get non-persisting pointer to origA_2 ...\n";
    Scalar  scalar;
    Thyra::EOpTransp transp;
    const Thyra::LinearOpBase<Scalar> *origA_2 = NULL;
    unwrap( *A1, &scalar, &transp, &origA_2 );
    TEUCHOS_TEST_FOR_EXCEPT( origA_2 == NULL );

    if (nonnull(out)) *out << "\nscalar = " << scalar << " == 0.5 ? ";
    result = (scalar == as<Scalar>(0.5));
    if(!result) success = false;
    if (nonnull(out))	*out << passfail(result) << std::endl;

    if (nonnull(out)) *out << "\ntransp = " << toString(transp) << " == NOTRANS ? ";
    result = (transp == Thyra::NOTRANS);
    if(!result) success = false;
    if (nonnull(out))	*out << passfail(result) << std::endl;

    if (nonnull(out)) *out << "\nTesting that origA_2 == origA ...\n";
    Thyra::seed_randomize<Scalar>(0);
    result = linearOpTester.compare(*origA_2,*origA,out.ptr());
    if(!result) success = false;

  }

  if (nonnull(out)) *out << "\nCreating implicit scaled linear operator A2 = adjoint(A1) ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A2 = adjoint(A1);
  if (nonnull(out)) *out << "\nA2 =\n" << describe(*A2,verbLevel);

  if (nonnull(out)) *out << "\nTesting A2 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A2,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nTesting that A2.getOp() == A1 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.compare(*dyn_cast<const Thyra::DefaultScaledAdjointLinearOp<Scalar> >(*A2).getOp(),*A1,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating implicit scaled, adjoined linear operator A3 = adjoint(scale(2.0,(A2)) ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A3 = adjoint(scale(as<Scalar>(2.0),A2));
  if (nonnull(out)) *out << "\nA3 =\n" << describe(*A3,verbLevel);

  if (nonnull(out)) *out << "\nTesting A3 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A3,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nTesting that A3 == origA ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.compare(*A3,*origA,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCalling all of the rest of the functions for non-const just to test them ...\n";
  RCP<Thyra::LinearOpBase<Scalar> >
    A4 = nonconstScale(
      as<Scalar>(0.25)
      ,nonconstAdjoint(
        nonconstTranspose(
          nonconstAdjoint(
            nonconstScaleAndAdjoint(
              as<Scalar>(4.0)
              ,Thyra::TRANS
              ,Teuchos::rcp_const_cast<Thyra::LinearOpBase<Scalar> >(origA)
              )
            )
          )
        )
      );
  if(!ST::isComplex) A4 = nonconstTranspose(nonconstAdjoint(A4)); // Should result in CONJ
  if (nonnull(out)) *out << "\nA4 =\n" << describe(*A4,verbLevel);

  if (nonnull(out)) *out << "\nTesting A4 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A4,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCalling all of the rest of the functions for const just to test them ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A5 = scale(
      as<Scalar>(0.25)
      ,adjoint(
        transpose(
          adjoint(
            scaleAndAdjoint(
              as<Scalar>(4.0)
              ,Thyra::TRANS
              ,origA
              )
            )
          )
        )
      );
  if(!ST::isComplex) A5 = transpose(adjoint(A5)); // Should result in CONJ
  if (nonnull(out)) *out << "\nA5 =\n" << describe(*A5,verbLevel);

  if (nonnull(out)) *out << "\nTesting A5 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A5,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a multiplied operator A6 = origA^H*A1 ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A6 = multiply(adjoint(origA),A1);
  if (nonnull(out)) *out << "\nA6 =\n" << describe(*A6,verbLevel);

  if (nonnull(out)) *out << "\nTesting A6 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A6,out.ptr());
  if(!result) success = false;
  // Note that testing the symmetry above helps to check the transpose mode
  // against the non-transpose mode!

#ifdef TEUCHOS_DEBUG
  if (nonnull(out)) *out << "\nCreating an invalid multiplied operator A6b = origA*origA (should throw an exception) ...\n\n";
  try {
    RCP<const Thyra::LinearOpBase<Scalar> >
      A6b = multiply(origA,origA);
    result = true;
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,out.get()?*out:std::cerr,result)
  if (nonnull(out))
    *out << "\nCaught expected exception : " << (result?"failed\n":"passed\n");
  if(result) success = false;
#endif // TEUCHOS_DEBUG

  if (nonnull(out)) *out << "\nCreating a non-const multiplied operator A7 = origA^H*A1 ...\n";
  RCP<Thyra::LinearOpBase<Scalar> >
    A7 = nonconstMultiply(
      rcp_const_cast<Thyra::LinearOpBase<Scalar> >(adjoint(origA))
      ,rcp_const_cast<Thyra::LinearOpBase<Scalar> >(A1)
      );
  if (nonnull(out)) *out << "\nA7 =\n" << describe(*A7,verbLevel);

  if (nonnull(out)) *out << "\nTesting A7 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A7,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating an added operator A8 = origA + A1 ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A8 = add(origA,A1);
  if (nonnull(out)) *out << "\nA8 =\n" << describe(*A8,verbLevel);

  if (nonnull(out)) *out << "\nTesting A8 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A8,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a symmetric subtracted operator A8b = A6 + adjoint(origA)*origA ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A8b = subtract(A6,multiply(adjoint(origA),origA));
  if (nonnull(out)) *out << "\nA8b =\n" << describe(*A8b,verbLevel);

  if (nonnull(out)) *out << "\nTesting A8b ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A8b,out.ptr());
  if(!result) success = false;

#ifdef TEUCHOS_DEBUG
  if (nonnull(out)) *out << "\nCreating an invalid added operator A8c = origA + adjoint(origA) (should throw an exception) ...\n\n";
  try {
    RCP<const Thyra::LinearOpBase<Scalar> >
      A8c = add(origA,adjoint(origA));
    result = true;
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,out.get()?*out:std::cerr,result)
  if (nonnull(out))
    *out << "\nCaught expected exception : " << (result?"failed\n":"passed\n");
  if(result) success = false;
#endif // TEUCHOS_DEBUG

  RCP<const Thyra::LinearOpBase<Scalar> >
    nullOp = null;

  if (nonnull(out)) *out << "\nCreating a blocked 2x2 linear operator A9 = [ A6, A1^H; A1, null ] ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A9 = Thyra::block2x2<Scalar>(
      A6,  adjoint(A1)
      ,A1, nullOp
      );
  if (nonnull(out)) *out << "\nA9 =\n" << describe(*A9,verbLevel);

  if (nonnull(out)) *out << "\nTesting A9 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A9,out.ptr());
  if(!result) success = false;
  // Note that testing the symmetry above helps to check the transpose mode
  // against the non-transpose mode!

  if (nonnull(out)) *out << "\nCreating a blocked 2x2 linear operator A9_a = [ A6, A1^H; A1, null ] using pre-formed range and domain product spaces ...\n";
  RCP<Thyra::PhysicallyBlockedLinearOpBase<Scalar> >
    A9_a = rcp(new Thyra::DefaultBlockedLinearOp<Scalar>());
  A9_a->beginBlockFill(
    rcp_dynamic_cast<const Thyra::BlockedLinearOpBase<Scalar> >(A9,true)->productRange()
    ,rcp_dynamic_cast<const Thyra::BlockedLinearOpBase<Scalar> >(A9,true)->productDomain()
    );
  A9_a->setBlock(0,0,A6);
  A9_a->setBlock(0,1,adjoint(A1));
  A9_a->setBlock(1,0,A1);
  A9_a->endBlockFill();
  if (nonnull(out)) *out << "\nA9_a =\n" << describe(*A9_a,verbLevel);

  if (nonnull(out)) *out << "\nTesting A9_a ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A9_a,out.ptr());
  if(!result) success = false;
  // Note that testing the symmetry above helps to check the transpose mode
  // against the non-transpose mode!

  if (nonnull(out)) *out << "\nComparing A9 == A9_a ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.compare(*A9,*A9_a,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a blocked 2x2 linear operator A9_b = [ A6, A1^H; A1, null ] using flexible fill ...\n";
  RCP<Thyra::PhysicallyBlockedLinearOpBase<Scalar> >
    A9_b = rcp(new Thyra::DefaultBlockedLinearOp<Scalar>());
  A9_b->beginBlockFill();
  A9_b->setBlock(0,0,A6);
  A9_b->setBlock(0,1,adjoint(A1));
  A9_b->setBlock(1,0,A1);
  A9_b->endBlockFill();
  if (nonnull(out)) *out << "\nA9_b =\n" << describe(*A9_b,verbLevel);

  if (nonnull(out)) *out << "\nTesting A9_b ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A9_b,out.ptr());
  if(!result) success = false;
  // Note that testing the symmetry above helps to check the transpose mode
  // against the non-transpose mode!

  if (nonnull(out)) *out << "\nComparing A9 == A9_b ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.compare(*A9,*A9_b,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a blocked 2x2 linear operator A9a = [ null, A1^H; A1, null ] ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A9a = Thyra::block2x2<Scalar>(
      nullOp,  adjoint(A1),
      A1,      nullOp
      );
  if (nonnull(out)) *out << "\nA9a =\n" << describe(*A9a,verbLevel);

  if (nonnull(out)) *out << "\nTesting A9a ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A9a,out.ptr());
  if(!result) success = false;
  // Note that testing the symmetry above helps to check the transpose mode
  // against the non-transpose mode!

#ifdef TEUCHOS_DEBUG
  if (nonnull(out)) *out << "\nCreating an invalid blocked 2x2 operator A9b = [ A6, A1^H; A1, A1 ] (should throw an exception) ...\n\n";
  try {
    RCP<const Thyra::LinearOpBase<Scalar> >
      A9b = Thyra::block2x2<Scalar>(
        A6,  adjoint(A1),
        A1,  A1
        );
    result = true;
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,out.get()?*out:std::cerr,result)
  if (nonnull(out))
    *out << "\nCaught expected exception : " << (result?"failed\n":"passed\n");
  if(result) success = false;
#endif // TEUCHOS_DEBUG

#ifdef TEUCHOS_DEBUG
  if (nonnull(out)) *out << "\nCreating an invalid blocked 2x2 operator A9c = [ A1, A1 ; null, null ] (should throw an exception) ...\n\n";
  try {
    RCP<const Thyra::LinearOpBase<Scalar> >
      A9c = Thyra::block2x2<Scalar>(
        A1,       A1,
        nullOp,   nullOp
        );
    result = true;
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,out.get()?*out:std::cerr,result)
  if (nonnull(out))
    *out << "\nCaught expected exception : " << (result?"failed\n":"passed\n");
  if(result) success = false;
#endif // TEUCHOS_DEBUG

#ifdef TEUCHOS_DEBUG
  if (nonnull(out)) *out << "\nCreating an invalid blocked 2x2 operator A9d = [ A1, null; A1, null ] (should throw an exception) ...\n\n";
  try {
    RCP<const Thyra::LinearOpBase<Scalar> >
      A9d = Thyra::block2x2<Scalar>(
        A1,  nullOp,
        A1,  nullOp
        );
    result = true;
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,out.get()?*out:std::cerr,result)
  if (nonnull(out))
    *out << "\nCaught expected exception : " << (result?"failed\n":"passed\n");
  if(result) success = false;
#endif // TEUCHOS_DEBUG

  if (nonnull(out)) *out << "\nCreating a blocked 2x1 linear operator A10 = [ A6; A1 ] ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A10 = Thyra::block2x1<Scalar>(
      A6,
      A1
      );
  if (nonnull(out)) *out << "\nA10 =\n" << describe(*A10,verbLevel);

  if (nonnull(out)) *out << "\nTesting A10 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A10,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a blocked 1x2 linear operator A11 = [ A9, A10 ] ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A11 = Thyra::block1x2<Scalar>( A9, A10 );
  if (nonnull(out)) *out << "\nA11 =\n" << describe(*A11,verbLevel);

  if (nonnull(out)) *out << "\nTesting A11 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A11,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a zero linear operator A12 = 0 (range and domain spaces of origA) ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A12 = Thyra::zero(origA->range(),origA->domain());
  if (nonnull(out)) *out << "\nA12 =\n" << describe(*A12,verbLevel);

  if (nonnull(out)) *out << "\nTesting A12 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.check(*A12,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a blocked 2x2 linear operator A13 = [ zero, A1^H; A1, zero ] ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A13 = Thyra::block2x2<Scalar>(
      Thyra::zero(A1->domain(),A1->domain()),   adjoint(A1),
      A1,                                       Thyra::zero(A1->range(),A1->range())
      );
  if (nonnull(out)) *out << "\nA13 =\n" << describe(*A13,verbLevel);

  if (nonnull(out)) *out << "\nComparing A9a == A13 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = linearOpTester.compare(*A9a,*A13,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\nCreating a zero linear operator A14 = I (range space of origA) ...\n";
  RCP<const Thyra::LinearOpBase<Scalar> >
    A14 = Thyra::identity(origA->range());
  if (nonnull(out)) *out << "\nA14 =\n" << describe(*A14,verbLevel);

  if (nonnull(out)) *out << "\nTesting A14 ...\n";
  Thyra::seed_randomize<Scalar>(0);
  result = symLinearOpTester.check(*A14,out.ptr());
  if(!result) success = false;

  if (nonnull(out)) *out << "\n*** Leaving run_composite_linear_ops_tests<"<<ST::name()<<">(...) ...\n";

  return success;

} // end run_composite_linear_ops_tests() [Doxygen looks for this!]
void CubicSplineInterpolator<Scalar>::interpolate(
  const Array<Scalar> &t_values,
  typename DataStore<Scalar>::DataStoreVector_t *data_out
  ) const
{
  using Teuchos::as;
  using Teuchos::outArg;
  typedef Teuchos::ScalarTraits<Scalar> ST;

  TEUCHOS_TEST_FOR_EXCEPTION( nodesSet_ == false, std::logic_error,
      "Error!, setNodes must be called before interpolate"
      );
#ifdef HAVE_RYTHMOS_DEBUG
  // Check that our nodes_ have not changed between the call to setNodes and interpolate
  assertNodesUnChanged<Scalar>(*nodes_,*nodes_copy_);
  // Assert that the base interpolator preconditions are satisfied
  assertBaseInterpolatePreconditions(*nodes_,t_values,data_out);
#endif // HAVE_RYTHMOS_DEBUG
  
  // Output info
  const RCP<FancyOStream> out = this->getOStream();
  const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel(); 
  Teuchos::OSTab ostab(out,1,"CSI::interpolator");
  if ( as<int>(verbLevel) >= as<int>(Teuchos::VERB_HIGH) ) {
    *out << "nodes_:" << std::endl;
    for (Teuchos::Ordinal i=0 ; i<(*nodes_).size() ; ++i) {
      *out << "nodes_[" << i << "] = " << std::endl;
      (*nodes_)[i].describe(*out,Teuchos::VERB_EXTREME);
    }
    *out << "t_values = " << std::endl;
    for (Teuchos::Ordinal i=0 ; i<t_values.size() ; ++i) {
      *out << "t_values[" << i << "] = " << t_values[i] << std::endl;
    }
  }

  data_out->clear();

  // Return immediately if no time points are requested ...
  if (t_values.size() == 0) {
    return;
  }

  if ((*nodes_).size() == 1) {
    // trivial case of one node.  Preconditions assert that t_values[0] ==
    // (*nodes_)[0].time so we can just pass it out
    DataStore<Scalar> DS((*nodes_)[0]);
    data_out->push_back(DS);
  }
  else { // (*nodes_).size() >= 2
    int n = 0; // index into t_values
    // Loop through all of the time interpolation points in the buffer and
    // satisfiy all of the requested time points that you find.  NOTE: The
    // loop will be existed once all of the time points are satisified (see
    // return below).
    for (Teuchos::Ordinal i=0 ; i < (*nodes_).size()-1; ++i) {
      const Scalar& ti = (*nodes_)[i].time;
      const Scalar& tip1 = (*nodes_)[i+1].time;
      const TimeRange<Scalar> range_i(ti,tip1);
      // For the interpolation range of [ti,tip1], satisify all of the
      // requested points in this range.
      while ( range_i.isInRange(t_values[n]) ) {
        // First we check for exact node matches:
        if (compareTimeValues(t_values[n],ti)==0) {
          DataStore<Scalar> DS((*nodes_)[i]);
          data_out->push_back(DS);
        }
        else if (compareTimeValues(t_values[n],tip1)==0) {
          DataStore<Scalar> DS((*nodes_)[i+1]);
          data_out->push_back(DS);
        } else {
          if (!splineCoeffComputed_) {
            computeCubicSplineCoeff<Scalar>(*nodes_,outArg(splineCoeff_));
            splineCoeffComputed_ = true;
          }
          DataStore<Scalar> DS;
          RCP<Thyra::VectorBase<Scalar> > x = createMember((*nodes_)[i].x->space());
          evaluateCubicSpline<Scalar>( splineCoeff_, i, t_values[n], outArg(*x) );
          DS.time = t_values[n];
          DS.x = x;
          DS.accuracy = ST::zero();
          data_out->push_back(DS);
        }
        // Move to the next user time point to consider!
        n++;
        if (n == as<int>(t_values.size())) {
          // WE ARE ALL DONE!  MOVE OUT!
          return;
        }
      }
      // Move on the the next interpolation time range
    }
  } // (*nodes_).size() == 1
}
Ejemplo n.º 17
0
bool tLSCIntegrationTest::test_withmassStable(int verbosity,std::ostream & os)
{
   Teuchos::ParameterList paramList;
   solveList(paramList,8);

   RCP<Teko::InverseFactory> invFact = Teko::invFactoryFromParamList(paramList,"ML");
   TEUCHOS_ASSERT(invFact!=Teuchos::null);

   bool status = false;
   bool allPassed = true;

   // load everything
   loadStableSystem();

   // if you get here you automatically pass the first test
   if(verbosity>=10 ) {
      os << std::endl << "   tLSCIntegrationTest::test_withmassStable: loading system ... " 
         << toString(true) << std::endl;
   }

   LinearOp Qu = epetraLinearOp(sQu_);
   const RCP<Teko::NS::LSCStrategy> strategy = rcp(new Teko::NS::InvLSCStrategy(invFact,Qu));
   const RCP<Teko::BlockPreconditionerFactory> precFact = rcp(new Teko::NS::LSCPreconditionerFactory(strategy));
   const RCP<Teko::Epetra::EpetraBlockPreconditioner> prec = rcp(new Teko::Epetra::EpetraBlockPreconditioner(precFact));
   prec->buildPreconditioner(sA_);

   // B. Build solver and solve system
   Epetra_Vector x(sA_->OperatorDomainMap());
   x.Scale(0.0);

   // build Epetra problem
   Epetra_LinearProblem problem(&*sA_,&x,&*rhs_); // this doesn't take const arguments!

   AztecOO solver(problem);
   solver.SetAztecOption(AZ_solver,AZ_gmres);
   solver.SetAztecOption(AZ_precond,AZ_none);
   solver.SetAztecOption(AZ_kspace,50);
   solver.SetAztecOption(AZ_output,AZ_none);
   solver.SetPrecOperator(&*prec);

   solver.Iterate(1000,1e-8);

   // check iteration count
   status = (solver.NumIters()<=16);
   if(not status || verbosity>=10 ) { 
      os << std::endl << "   tLSCIntegrationTest::test_withmassStable " << toString(status) 
                      << ": # of iterations = " << solver.NumIters() << " (should be 16)" << std::endl;
   }
   allPassed &= status;
 
   // check exact answer (versus IFISS solution)
   x.Update(-1.0,*sExact_,1.0); // x = x - x*
   double errnorm,exactnorm,relerr;
   x.Norm2(&errnorm);
   sExact_->Norm2(&exactnorm);
   status = ((relerr = errnorm/exactnorm) <= tolerance_);
   if(not status || verbosity>=10 ) { 
      os << std::endl << "   tLSCIntegrationTest::test_withmassStable " << toString(status) 
                      << ": error in solution = " << std::scientific << relerr << " <= " << tolerance_ << std::endl;
   }
   allPassed &= status;

   return allPassed;
}
bool tBlockJacobiPreconditionerFactory::test_initializePrec(int verbosity,std::ostream & os)
{
   using Thyra::zero;

   bool status = false;
   bool allPassed = true;

   std::string constrType[3] = {
       std::string("Static"),
       std::string("2x2 Static Strategy"),
       std::string("3x3 Static Strategy") };

   // three by three bloock diagonal 
   std::vector<RCP<const Thyra::LinearOpBase<double> > > invD;
   invD.push_back(invF_); invD.push_back(invC_); invD.push_back(invF_);

   // allocate new linear operator
   const RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blkOp
        = Thyra::defaultBlockedLinearOp<double>();
   blkOp->beginBlockFill(3,3);
   blkOp->setBlock(0,0,F_);  blkOp->setBlock(0,1,Bt_);
   blkOp->setBlock(1,0,B_);  blkOp->setBlock(1,1,C_);  blkOp->setBlock(1,2,B_);
   blkOp->setBlock(2,1,Bt_); blkOp->setBlock(2,2,F_);
   blkOp->endBlockFill();

   const RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > invBlkOp
        = Thyra::defaultBlockedLinearOp<double>();
   invBlkOp->beginBlockFill(3,3);
   invBlkOp->setBlock(0,0,invF_);  
   invBlkOp->setBlock(1,1,invC_);
   invBlkOp->setBlock(2,2,invF_);
   invBlkOp->endBlockFill();

   // build factory array
   RCP<JacobiPreconditionerFactory> fact_array[3] 
         = { rcp(new JacobiPreconditionerFactory(invF_,invC_)),
             rcp(new JacobiPreconditionerFactory(rcp(new StaticInvDiagStrategy(invF_,invC_)))),
             rcp(new JacobiPreconditionerFactory(rcp(new StaticInvDiagStrategy(invD)))) };

   RCP<const Thyra::LinearOpBase<double> > A[3] = { 
       block2x2(F_,Bt_,B_,C_),
       block2x2(F_,Bt_,B_,C_), 
       blkOp };

   // this is what the factory should build
   RCP<const Thyra::LinearOpBase<double> > invA[3] = { 
       block2x2(invF_,zero(Bt_->range(),Bt_->domain()),zero(B_->range(),B_->domain()),invC_),
       block2x2(invF_,zero(Bt_->range(),Bt_->domain()),zero(B_->range(),B_->domain()),invC_),
       invBlkOp };

   // test both constructors
   for(int i=0;i<3;i++) {
      RCP<const Thyra::LinearOpBase<double> > op;

      RCP<Thyra::PreconditionerFactoryBase<double> > fact = fact_array[i];
      RCP<Thyra::PreconditionerBase<double> > prec = fact->createPrec();

      // initialize the preconditioner
      fact->initializePrec(Thyra::defaultLinearOpSource(A[i]), &*prec);

      op = prec->getRightPrecOp();
      TEST_EQUALITY(op,Teuchos::null,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << "using \"" << constrType[i] << "\" constructor " << toString(status) 
            << ": Preconditioner \"getRightPrecOp\" is not null (it should be!)");

      op = prec->getLeftPrecOp();
      TEST_EQUALITY(op,Teuchos::null,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << "using \"" << constrType[i] << "\" constructor " << toString(status) 
            << ": Preconditioner \"getLeftPrecOp\" is not null (it should be!)");

      op = prec->getUnspecifiedPrecOp();
      TEST_NOT_EQUAL(op,Teuchos::null,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << "using \"" << constrType[i] << "\" constructor " << toString(status) 
            << ": Preconditioner \"getUnspecifiedPrecOp\" is null (it should not be!)");

     LinearOpTester<double> tester;
     tester.show_all_tests(true);
     std::stringstream ss;
     Teuchos::FancyOStream fos(rcpFromRef(ss),"      |||");
     const bool result = tester.compare( *invA[i], *op, &fos );
     TEST_ASSERT(result,
            std::endl << "   tBlockJacobiPreconditionerFactory::test_initializePrec "
            << ": Comparing factory generated operator to correct operator");
     if(not result || verbosity>=10) 
        os << ss.str(); 
   }

   return allPassed;
}
int exampleImplicitlyComposedLinearOperators(
  const int n0,
  const int n1,
  const int n2,
  Teuchos::FancyOStream &out,
  const Teuchos::EVerbosityLevel verbLevel,
  typename Teuchos::ScalarTraits<Scalar>::magnitudeType errorTol,
  const bool testAdjoint
  )
{

  // Using and other declarations
  typedef Teuchos::ScalarTraits<Scalar> ST;
  using Teuchos::as;
  using Teuchos::RCP;
  using Teuchos::OSTab;
  using Thyra::VectorSpaceBase;
  using Thyra::VectorBase;
  using Thyra::MultiVectorBase;
  using Thyra::LinearOpBase;
  using Thyra::defaultSpmdVectorSpace;
  using Thyra::randomize;
  using Thyra::identity;
  using Thyra::diagonal;
  using Thyra::multiply;
  using Thyra::add;
  using Thyra::subtract;
  using Thyra::scale;
  using Thyra::adjoint;
  using Thyra::block1x2;
  using Thyra::block2x2;
  using Thyra::block2x2;

  out << "\n***"
      << "\n*** Demonstrating building linear operators for scalar type "
      << ST::name()
      << "\n***\n";

  OSTab tab(out);

  //
  // A) Set up the basic objects and other inputs to build the implicitly
  // composed linear operators.
  //
  
  // Create serial vector spaces in this case
  const RCP<const VectorSpaceBase<Scalar> >
    space0 = defaultSpmdVectorSpace<Scalar>(n0),
    space1 = defaultSpmdVectorSpace<Scalar>(n1),
    space2 = defaultSpmdVectorSpace<Scalar>(n2);

  // Create the component linear operators first as multi-vectors
  const RCP<MultiVectorBase<Scalar> >
    mvA = createMembers(space2, n0, "A"),
    mvB = createMembers(space0, n2, "B"),
    mvC = createMembers(space0, n0, "C"),
    mvE = createMembers(space0, n1, "E"),
    mvF = createMembers(space0, n1, "F"),
    mvJ = createMembers(space2, n1, "J"),
    mvK = createMembers(space1, n2, "K"),
    mvL = createMembers(space2, n1, "L"),
    mvN = createMembers(space0, n1, "N"),
    mvP = createMembers(space2, n1, "P"),
    mvQ = createMembers(space0, n2, "Q");

  // Create the vector diagonal for D
  const RCP<VectorBase<Scalar> > d = createMember(space2);

  // Get the constants
  const Scalar
    one = 1.0,
    beta = 2.0,
    gamma = 3.0,
    eta = 4.0;

  // Randomize the values in the Multi-Vector
  randomize( -one, +one, mvA.ptr() );
  randomize( -one, +one, mvB.ptr() );
  randomize( -one, +one, mvC.ptr() );
  randomize( -one, +one, d.ptr() );
  randomize( -one, +one, mvE.ptr() );
  randomize( -one, +one, mvF.ptr() );
  randomize( -one, +one, mvJ.ptr() );
  randomize( -one, +one, mvK.ptr() );
  randomize( -one, +one, mvL.ptr() );
  randomize( -one, +one, mvN.ptr() );
  randomize( -one, +one, mvP.ptr() );
  randomize( -one, +one, mvQ.ptr() );

  // Get the linear operator forms of the basic component linear operators
  const RCP<const LinearOpBase<Scalar> >
    A = mvA,
    B = mvB,
    C = mvC,
    E = mvE,
    F = mvF,
    J = mvJ,
    K = mvK,
    L = mvL,
    N = mvN,
    P = mvP,
    Q = mvQ;

  out << describe(*A, verbLevel);
  out << describe(*B, verbLevel);
  out << describe(*C, verbLevel);
  out << describe(*E, verbLevel);
  out << describe(*F, verbLevel);
  out << describe(*J, verbLevel);
  out << describe(*K, verbLevel);
  out << describe(*L, verbLevel);
  out << describe(*N, verbLevel);
  out << describe(*P, verbLevel);
  out << describe(*Q, verbLevel);

  //
  // B) Create the composed linear operators
  //

  // I
  const RCP<const LinearOpBase<Scalar> > I = identity(space1, "I");

  // D = diag(d)
  const RCP<const LinearOpBase<Scalar> > D = diagonal(d, "D");

  // M00 = [ gama*B*A + C,  E + F ] ^H
  //       [ J^H * A,       I     ]
  const RCP<const LinearOpBase<Scalar> > M00 =
    adjoint(
      block2x2(
        add( scale(gamma,multiply(B,A)), C ),  add( E, F ),
        multiply(adjoint(J),A),                I
        ),
      "M00"
      );

  out << "\nM00 = " << describe(*M00, verbLevel);

  // M01 = beta * [ Q ]
  //              [ K ]
  const RCP<const LinearOpBase<Scalar> > M01 =
    scale(
      beta,
      block2x1( Q, K ),
      "M01"
      );

  out << "\nM01 = "  << describe(*M01, verbLevel);
            
  // M10 = [ L * N^H,  eta*P ]
  const RCP<const LinearOpBase<Scalar> > M10 =
    block1x2(
      multiply(L,adjoint(N)),  scale(eta,P),
      "M10"
      );

  out << "\nM10 = " << describe(*M10, verbLevel);

  // M11 = D - Q^H*Q
  const RCP<const LinearOpBase<Scalar> > M11 =
    subtract( D, multiply(adjoint(Q),Q), "M11" );

  out << "\nM11 = "  << describe(*M11, verbLevel);
  

  // M = [ M00, M01 ]
  //     [ M10, M11 ]
  const RCP<const LinearOpBase<Scalar> > M =
    block2x2(
      M00, M01,
      M10, M11,
      "M"
      );

  out << "\nM = " << describe(*M, verbLevel);

  
  //
  // C) Test the final composed operator
  //

  Thyra::LinearOpTester<Scalar> linearOpTester;
  linearOpTester.set_all_error_tol(errorTol);
  linearOpTester.check_adjoint(testAdjoint);
  if (as<int>(verbLevel) >= as<int>(Teuchos::VERB_HIGH))
    linearOpTester.show_all_tests(true);
  if (as<int>(verbLevel) >= as<int>(Teuchos::VERB_EXTREME))
    linearOpTester.dump_all(true);

  const bool result = linearOpTester.check(*M,&out);

  return result;

}
void computeCubicSplineCoeff(
    const typename DataStore<Scalar>::DataStoreVector_t & data,
    const Ptr<CubicSplineCoeff<Scalar> > & coeffPtr
    )
{
  using Teuchos::outArg;
  typedef Teuchos::ScalarTraits<Scalar> ST;
  using Thyra::createMember;
  TEUCHOS_TEST_FOR_EXCEPTION( 
      (data.size() < 2), std::logic_error,
      "Error!  A minimum of two data points is required for this cubic spline."
      );
  // time data in the DataStoreVector should be unique and sorted 
  Array<Scalar> t;
  Array<Teuchos::RCP<const Thyra::VectorBase<Scalar> > > x_vec, xdot_vec;
  dataStoreVectorToVector<Scalar>( data, &t, &x_vec, &xdot_vec, NULL );
#ifdef HAVE_RYTHMOS_DEBUG
  assertTimePointsAreSorted<Scalar>( t );
#endif // HAVE_RYTHMOS_DEBUG
  // 11/18/08 tscoffe:  Question:  Should I erase everything in coeffPtr or
  // re-use what I can?  For now, I'll erase and create new each time.
  CubicSplineCoeff<Scalar>& coeff = *coeffPtr;
  // If there are only two points, then we do something special and just create
  // a linear polynomial between the points and return.
  if (t.size() == 2) {
    coeff.t.clear(); 
    coeff.a.clear(); coeff.b.clear(); coeff.c.clear(); coeff.d.clear();
    coeff.t.reserve(2); 
    coeff.a.reserve(1); coeff.b.reserve(1); coeff.c.reserve(1); coeff.d.reserve(1);
    coeff.t.push_back(t[0]);
    coeff.t.push_back(t[1]);
    coeff.a.push_back(x_vec[0]->clone_v());
    coeff.b.push_back(createMember(x_vec[0]->space()));
    coeff.c.push_back(createMember(x_vec[0]->space()));
    coeff.d.push_back(createMember(x_vec[0]->space()));
    Scalar h = coeff.t[1] - coeff.t[0];
    V_StVpStV(outArg(*coeff.b[0]),ST::one()/h,*x_vec[1],-ST::one()/h,*x_vec[0]);
    V_S(outArg(*coeff.c[0]),ST::zero());
    V_S(outArg(*coeff.d[0]),ST::zero());
    return;
  }
  // Data objects we'll need:
  int n = t.length()-1; // Number of intervals
  coeff.t.clear(); coeff.t.reserve(n+1);
  coeff.a.clear(); coeff.a.reserve(n+1);
  coeff.b.clear(); coeff.b.reserve(n);
  coeff.c.clear(); coeff.c.reserve(n+1);
  coeff.d.clear(); coeff.d.reserve(n);

  Array<Scalar> h(n);
  Array<RCP<Thyra::VectorBase<Scalar> > > alpha(n), z(n+1);
  Array<Scalar> l(n+1), mu(n);
  for (int i=0 ; i<n ; ++i) {
    coeff.t.push_back(t[i]);
    coeff.a.push_back(x_vec[i]->clone_v());
    coeff.b.push_back(Thyra::createMember(x_vec[0]->space()));
    coeff.c.push_back(Thyra::createMember(x_vec[0]->space()));
    coeff.d.push_back(Thyra::createMember(x_vec[0]->space()));
    alpha[i] = Thyra::createMember(x_vec[0]->space());
    z[i] = Thyra::createMember(x_vec[0]->space());
  }
  coeff.a.push_back(x_vec[n]->clone_v());
  coeff.t.push_back(t[n]);
  coeff.c.push_back(Thyra::createMember(x_vec[0]->space()));
  z[n] = Thyra::createMember(x_vec[0]->space());
  Scalar zero = ST::zero();
  Scalar one = ST::one();
  Scalar two = Scalar(2*ST::one());
  Scalar three = Scalar(3*ST::one());

  // Algorithm starts here:
  for (int i=0 ; i<n ; ++i) {
    h[i] = coeff.t[i+1]-coeff.t[i];
  }
  for (int i=1 ; i<n ; ++i) {
    V_StVpStV(outArg(*(alpha[i])),three/h[i],*coeff.a[i+1],-3/h[i],*coeff.a[i]);
    Vp_StV(outArg(*(alpha[i])),-three/h[i-1],*coeff.a[i]);
    Vp_StV(outArg(*(alpha[i])),+three/h[i-1],*coeff.a[i-1]);
  }
  l[0] = one;
  mu[0] = zero;
  V_S(outArg(*(z[0])),zero);
  for (int i=1 ; i<n ; ++i) {
    l[i] = 2*(coeff.t[i+1]-coeff.t[i-1])-h[i-1]*mu[i-1];
    mu[i] = h[i]/l[i];
    V_StVpStV(outArg(*(z[i])),one/l[i],*alpha[i],-h[i-1]/l[i],*z[i-1]);
  }
  l[n] = one;
  V_S(outArg(*(z[n])),zero);
  V_S(outArg(*(coeff.c[n])),zero);
  for (int j=n-1 ; j >= 0 ; --j) {
    V_StVpStV(outArg(*(coeff.c[j])),one,*z[j],-mu[j],*coeff.c[j+1]);
    V_StVpStV(outArg(*(coeff.b[j])),one/h[j],*coeff.a[j+1],-one/h[j],*coeff.a[j]);
    Vp_StV(outArg(*(coeff.b[j])),-h[j]/three,*coeff.c[j+1]);
    Vp_StV(outArg(*(coeff.b[j])),-h[j]*two/three,*coeff.c[j]);
    V_StVpStV(outArg(*(coeff.d[j])),one/(three*h[j]),*coeff.c[j+1],-one/(three*h[j]),*coeff.c[j]);
  }
  // Pop the last entry off of a and c to make them the right size.
  coeff.a.erase(coeff.a.end()-1);
  coeff.c.erase(coeff.c.end()-1);
}
Ejemplo n.º 21
0
//! Scale a multivector by a constant
inline void scale(const double alpha,BlockedMultiVector & x) 
{  MultiVector x_mv = toMultiVector(x); scale(alpha,x_mv); }
int main(int argc, char* argv[])
{

    using Teuchos::describe;
    using Teuchos::rcp;
    using Teuchos::rcp_dynamic_cast;
    using Teuchos::rcp_const_cast;
    using Teuchos::RCP;
    using Teuchos::CommandLineProcessor;
    using Teuchos::ParameterList;
    using Teuchos::sublist;
    using Teuchos::getParametersFromXmlFile;
    typedef ParameterList::PrintOptions PLPrintOptions;
    using Thyra::inverse;
    using Thyra::initializePreconditionedOp;
    using Thyra::initializeOp;
    using Thyra::unspecifiedPrec;
    using Thyra::solve;
    typedef RCP<const Thyra::LinearOpBase<double> > LinearOpPtr;
    typedef RCP<Thyra::VectorBase<double> > VectorPtr;

    bool success = true;
    bool verbose = true;

    Teuchos::GlobalMPISession mpiSession(&argc,&argv);

    Teuchos::RCP<Teuchos::FancyOStream>
    out = Teuchos::VerboseObjectBase::getDefaultOStream();

    try {

        //
        // Read in options from the command line
        //

        CommandLineProcessor clp(false); // Don't throw exceptions

        const int numVerbLevels = 6;
        Teuchos::EVerbosityLevel
        verbLevelValues[] =
        {
            Teuchos::VERB_DEFAULT, Teuchos::VERB_NONE,
            Teuchos::VERB_LOW, Teuchos::VERB_MEDIUM,
            Teuchos::VERB_HIGH, Teuchos::VERB_EXTREME
        };
        const char*
        verbLevelNames[] =
        { "default", "none", "low", "medium", "high", "extreme" };

        Teuchos::EVerbosityLevel verbLevel = Teuchos::VERB_MEDIUM;
        clp.setOption( "verb-level", &verbLevel,
                       numVerbLevels, verbLevelValues, verbLevelNames,
                       "Verbosity level used for all objects."
                     );

        std::string matrixFile = ".";
        clp.setOption( "matrix-file", &matrixFile,
                       "Matrix file."
                     );

        std::string paramListFile = "";
        clp.setOption( "param-list-file", &paramListFile,
                       "Parameter list for preconditioner and solver blocks."
                     );

        bool showParams = false;
        clp.setOption( "show-params", "no-show-params", &showParams,
                       "Show the parameter list or not."
                     );

        bool testPrecIsLinearOp = true;
        clp.setOption( "test-prec-is-linear-op", "test-prec-is-linear-op", &testPrecIsLinearOp,
                       "Test if the preconditioner is a linear operator or not."
                     );

        double solveTol = 1e-8;
        clp.setOption( "solve-tol", &solveTol,
                       "Tolerance for the solution to determine success or failure!"
                     );

        clp.setDocString(
            "This example program shows how to use one linear solver (e.g. AztecOO)\n"
            "as a preconditioner for another iterative solver (e.g. Belos).\n"
        );

        // Note: Use --help on the command line to see the above documentation

        CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
        if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) return parse_return;


        //
        *out << "\nA) Reading in the matrix ...\n";
        //

#ifdef HAVE_MPI
        Epetra_MpiComm comm(MPI_COMM_WORLD);
#else
        Epetra_SerialComm comm;
#endif

        const LinearOpPtr A = readEpetraCrsMatrixFromMatrixMarketAsLinearOp(
                                  matrixFile, comm, "A");
        *out << "\nA = " << describe(*A,verbLevel) << "\n";

        const RCP<ParameterList> paramList = getParametersFromXmlFile(paramListFile);
        if (showParams) {
            *out << "\nRead in parameter list:\n\n";
            paramList->print(*out, PLPrintOptions().indent(2).showTypes(true));
        }

        //
        *out << "\nB) Get the preconditioner as a forward solver\n";
        //

        const RCP<ParameterList> precParamList = sublist(paramList, "Preconditioner Solver");
        Stratimikos::DefaultLinearSolverBuilder precSolverBuilder;
        precSolverBuilder.setParameterList(precParamList);
        const RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > precSolverStrategy
            = createLinearSolveStrategy(precSolverBuilder);
        //precSolverStrategy->setVerbLevel(verbLevel);

        const LinearOpPtr A_inv_prec = inverse<double>(*precSolverStrategy, A,
                                       Thyra::SUPPORT_SOLVE_FORWARD_ONLY,
                                       Teuchos::null, // Use internal solve criteria
                                       Thyra::IGNORE_SOLVE_FAILURE // Ignore solve failures since this is just a prec
                                                      );
        *out << "\nA_inv_prec = " << describe(*A_inv_prec, verbLevel) << "\n";

        if (testPrecIsLinearOp) {
            *out << "\nTest that the preconditioner A_inv_prec is indeed a linear operator.\n";
            Thyra::LinearOpTester<double> linearOpTester;
            linearOpTester.check_adjoint(false);
            const bool linearOpCheck = linearOpTester.check(*A_inv_prec, out.ptr());
            if (!linearOpCheck) {
                success = false;
            }
        }

        //
        *out << "\nC) Create the forward solver using the created preconditioner ...\n";
        //

        const RCP<ParameterList> fwdSolverParamList = sublist(paramList, "Forward Solver");
        Stratimikos::DefaultLinearSolverBuilder fwdSolverSolverBuilder;
        fwdSolverSolverBuilder.setParameterList(fwdSolverParamList);
        const RCP<const Thyra::LinearOpWithSolveFactoryBase<double> > fwdSolverSolverStrategy
            = createLinearSolveStrategy(fwdSolverSolverBuilder);

        const RCP<Thyra::LinearOpWithSolveBase<double> >
        A_lows = fwdSolverSolverStrategy->createOp();

        initializePreconditionedOp<double>( *fwdSolverSolverStrategy, A,
                                            unspecifiedPrec(A_inv_prec), A_lows.ptr());
        //A_lows->setVerbLevel(verbLevel);
        *out << "\nA_lows = " << describe(*A_lows, verbLevel) << "\n";

        //
        *out << "\nD) Solve the linear system for a random RHS ...\n";
        //

        VectorPtr x = createMember(A->domain());
        VectorPtr b = createMember(A->range());
        Thyra::randomize(-1.0, +1.0, b.ptr());
        Thyra::assign(x.ptr(), 0.0); // Must give an initial guess!

        Thyra::SolveStatus<double>
        solveStatus = solve<double>( *A_lows, Thyra::NOTRANS, *b, x.ptr() );

        *out << "\nSolve status:\n" << solveStatus;

        *out << "\nSolution ||x|| = " << Thyra::norm(*x) << "\n";

        if(showParams) {
            *out << "\nParameter list after use:\n\n";
            paramList->print(*out, PLPrintOptions().indent(2).showTypes(true));
        }

        //
        *out << "\nF) Checking the error in the solution of r=b-A*x ...\n";
        //

        VectorPtr Ax = Thyra::createMember(b->space());
        Thyra::apply( *A, Thyra::NOTRANS, *x, Ax.ptr() );
        VectorPtr r = Thyra::createMember(b->space());
        Thyra::V_VmV<double>(r.ptr(), *b, *Ax);

        double
        Ax_nrm = Thyra::norm(*Ax),
        r_nrm = Thyra::norm(*r),
        b_nrm = Thyra::norm(*b),
        r_nrm_over_b_nrm = r_nrm / b_nrm;

        bool resid_tol_check = ( r_nrm_over_b_nrm <= solveTol );
        if(!resid_tol_check) success = false;

        *out
                << "\n||A*x|| = " << Ax_nrm << "\n";

        *out
                << "\n||A*x-b||/||b|| = " << r_nrm << "/" << b_nrm
                << " = " << r_nrm_over_b_nrm << " <= " << solveTol
                << " : " << Thyra::passfail(resid_tol_check) << "\n";

        Teuchos::TimeMonitor::summarize(*out<<"\n");
    }
    TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success)

    if (verbose) {
        if(success)  *out << "\nCongratulations! All of the tests checked out!\n";
        else         *out << "\nOh no! At least one of the tests failed!\n";
    }

    return ( success ? EXIT_SUCCESS : EXIT_FAILURE );
}