TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( SimpleDenseLinearOp, basic, Scalar ) { using Teuchos::rcp_dynamic_cast; typedef ScalarTraits<Scalar> ST; const RCP<MultiVectorBase<Scalar> > mv = createSerialMultiVector<Scalar>(g_dim, g_dim/2, ST::one()); const RCP<LinearOpBase<Scalar> > op = createNonconstSimpleDenseLinearOp<Scalar>(mv); TEST_EQUALITY( mv, rcp_dynamic_cast<SimpleDenseLinearOp<Scalar> >(op)->getNonconstMultiVector() ); Thyra::LinearOpTester<Scalar> linearOpTester; linearOpTester.dump_all(g_dumpAll); TEST_ASSERT(linearOpTester.check(*op, ptrFromRef(out))); }
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 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; }
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!]
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", ¶mListFile, "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 ); }