TEUCHOS_UNIT_TEST( EpetraLinearOp, rectangular ) { using Teuchos::null; using Teuchos::inOutArg; using Teuchos::updateSuccess; const RCP<const Epetra_Comm> comm = getEpetraComm(); const int numProcs = comm->NumProc(); const int numLocalRows = g_localDim; const int numRows = numLocalRows * comm->NumProc(); const int numCols = numLocalRows / 2; const RCP<Epetra_CrsMatrix> epetraCrsM = getEpetraMatrix(numRows, numCols); const RCP<const LinearOpBase<double> > epetraOp = epetraLinearOp(epetraCrsM); LinearOpTester<double> linearOpTester; linearOpTester.check_adjoint(numProcs == 1); linearOpTester.show_all_tests(g_show_all_tests); linearOpTester.dump_all(g_dumpAll); updateSuccess(linearOpTester.check(*epetraOp, inOutArg(out)), success); // NOTE: Above, it would seem the Epetra_CrsMatrix::Apply(...) does not work // when doing and adjoint where the RowMap has empty processes. }
SolveStatus<Scalar> DefaultMultiVectorLinearOpWithSolve<Scalar>::solveImpl( const EOpTransp transp, const MultiVectorBase<Scalar> &BB, const Ptr<MultiVectorBase<Scalar> > &XX, const Ptr<const SolveCriteria<Scalar> > solveCriteria ) const { using Teuchos::dyn_cast; using Teuchos::outArg; using Teuchos::inOutArg; typedef DefaultMultiVectorProductVector<Scalar> MVPV; const Ordinal numCols = BB.domain()->dim(); SolveStatus<Scalar> overallSolveStatus; accumulateSolveStatusInit(outArg(overallSolveStatus)); for (Ordinal col_j = 0; col_j < numCols; ++col_j) { const RCP<const VectorBase<Scalar> > b = BB.col(col_j); const RCP<VectorBase<Scalar> > x = XX->col(col_j); RCP<const MultiVectorBase<Scalar> > B = dyn_cast<const MVPV>(*b).getMultiVector().assert_not_null(); RCP<MultiVectorBase<Scalar> > X = dyn_cast<MVPV>(*x).getNonconstMultiVector().assert_not_null(); const SolveStatus<Scalar> solveStatus = Thyra::solve(*lows_.getConstObj(), transp, *B, X.ptr(), solveCriteria); accumulateSolveStatus( SolveCriteria<Scalar>(), // Never used solveStatus, inOutArg(overallSolveStatus) ); } return overallSolveStatus; }
int main (int argc, char *argv[]) { using Teuchos::inOutArg; using Teuchos::ParameterList; using Teuchos::parameterList; using Teuchos::RCP; using Teuchos::rcp; using Teuchos::rcpFromRef; using std::endl; typedef double ST; typedef Epetra_Operator OP; typedef Epetra_MultiVector MV; typedef Belos::OperatorTraits<ST,MV,OP> OPT; typedef Belos::MultiVecTraits<ST,MV> MVT; // This calls MPI_Init and MPI_Finalize as necessary. Belos::Test::MPISession session (inOutArg (argc), inOutArg (argv)); RCP<const Epetra_Comm> comm = session.getComm (); bool success = false; bool verbose = false; try { int MyPID = comm->MyPID (); // // Parameters to read from command-line processor // int frequency = -1; // how often residuals are printed by solver int numRHS = 1; // total number of right-hand sides to solve for int maxIters = 13000; // maximum number of iterations for solver to use std::string filename ("bcsstk14.hb"); double tol = 1.0e-5; // relative residual tolerance // // Read in command-line arguments // Teuchos::CommandLineProcessor cmdp (false, true); cmdp.setOption ("verbose", "quiet", &verbose, "Print messages and results."); cmdp.setOption ("frequency", &frequency, "Solvers frequency for printing " "residuals (#iters)."); cmdp.setOption ("tol", &tol, "Relative residual tolerance used by MINRES " "solver."); cmdp.setOption ("filename", &filename, "Filename for Harwell-Boeing test " "matrix."); cmdp.setOption ("num-rhs", &numRHS, "Number of right-hand sides to solve."); cmdp.setOption ("max-iters", &maxIters, "Maximum number of iterations per " "linear system (-1 means \"adapt to problem/block size\")."); if (cmdp.parse (argc,argv) != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL) { return EXIT_FAILURE; } Teuchos::oblackholestream blackHole; std::ostream& verbOut = (verbose && MyPID == 0) ? std::cout : blackHole; // // Generate the linear system(s) to solve. // verbOut << "Generating the linear system(s) to solve" << endl << endl; RCP<Epetra_CrsMatrix> A; RCP<Epetra_MultiVector> B, X; RCP<Epetra_Map> rowMap; try { // This might change the number of right-hand sides, if we read in // a right-hand side from the Harwell-Boeing file. Belos::Util::createEpetraProblem (filename, &rowMap, &A, &B, &X, &MyPID, numRHS); } catch (std::exception& e) { TEUCHOS_TEST_FOR_EXCEPTION (true, std::runtime_error, "Failed to create Epetra problem for matrix " "filename \"" << filename << "\". " "createEpetraProblem() reports the following " "error: " << e.what()); } // // Compute the initial residual norm of the problem, so we can see // by how much it improved after the solve. // std::vector<double> initialResidualNorms (numRHS); std::vector<double> initialResidualInfNorms (numRHS); Epetra_MultiVector R (*rowMap, numRHS); OPT::Apply (*A, *X, R); MVT::MvAddMv (-1.0, R, 1.0, *B, R); // R := -(A*X) + B. MVT::MvNorm (R, initialResidualNorms); MVT::MvNorm (R, initialResidualInfNorms, Belos::InfNorm); if (verbose) { verbOut << "Initial residual 2-norms: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << initialResidualNorms[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl << "Initial residual Inf-norms: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << initialResidualInfNorms[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl; } std::vector<double> rhs2Norms (numRHS); std::vector<double> rhsInfNorms (numRHS); MVT::MvNorm (*B, rhs2Norms); MVT::MvNorm (*B, rhsInfNorms, Belos::InfNorm); if (verbose) { verbOut << "Right-hand side 2-norms: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << rhs2Norms[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl << "Right-hand side Inf-norms: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << rhsInfNorms[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl; } std::vector<double> initialGuess2Norms (numRHS); std::vector<double> initialGuessInfNorms (numRHS); MVT::MvNorm (*X, initialGuess2Norms); MVT::MvNorm (*X, initialGuessInfNorms, Belos::InfNorm); if (verbose) { verbOut << "Initial guess 2-norms: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << initialGuess2Norms[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl << "Initial guess Inf-norms: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << initialGuessInfNorms[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl; } // // Compute the infinity-norm of A. // const double normOfA = A->NormInf (); verbOut << "||A||_inf: \t" << normOfA << endl; // // Compute ||A|| ||X_i|| + ||B_i|| for each right-hand side B_i. // std::vector<double> scaleFactors (numRHS); for (int i = 0; i < numRHS; ++i) { scaleFactors[i] = normOfA * initialGuessInfNorms[i] + rhsInfNorms[i]; } if (verbose) { verbOut << "||A||_inf ||X_i||_inf + ||B_i||_inf: \t"; for (int i = 0; i < numRHS; ++i) { verbOut << scaleFactors[i]; if (i < numRHS-1) { verbOut << ", "; } } verbOut << endl; } // // Solve using Belos // verbOut << endl << "Setting up Belos" << endl; const int NumGlobalElements = B->GlobalLength(); // Set up Belos solver parameters. RCP<ParameterList> belosList = parameterList ("MINRES"); belosList->set ("Maximum Iterations", maxIters); belosList->set ("Convergence Tolerance", tol); if (verbose) { belosList->set ("Verbosity", Belos::Errors + Belos::Warnings + Belos::IterationDetails + Belos::OrthoDetails + Belos::FinalSummary + Belos::TimingDetails + Belos::Debug); belosList->set ("Output Frequency", frequency); } else { belosList->set ("Verbosity", Belos::Errors + Belos::Warnings); } belosList->set ("Output Stream", rcpFromRef (verbOut)); // Construct an unpreconditioned linear problem instance. typedef Belos::LinearProblem<double,MV,OP> prob_type; RCP<prob_type> problem = rcp (new prob_type (A, X, B)); if (! problem->setProblem()) { verbOut << endl << "ERROR: Failed to set up Belos::LinearProblem!" << endl; return EXIT_FAILURE; } // Create an iterative solver manager. Belos::SolverFactory<double, MV, OP> factory; RCP<Belos::SolverManager<double,MV,OP> > newSolver = factory.create ("MINRES", belosList); newSolver->setProblem (problem); // Print out information about problem. Make sure to use the // information as stored in the Belos ParameterList, so that we know // what the solver will do. verbOut << endl << "Dimension of matrix: " << NumGlobalElements << endl << "Number of right-hand sides: " << numRHS << endl << "Max number of MINRES iterations: " << belosList->get<int> ("Maximum Iterations") << endl << "Relative residual tolerance: " << belosList->get<double> ("Convergence Tolerance") << endl << "Output frequency: " << belosList->get<int> ("Output Frequency") << endl << endl; // Solve the linear system. verbOut << "Solving the linear system" << endl << endl; Belos::ReturnType ret = newSolver->solve(); verbOut << "Belos results:" << endl << "- Number of iterations: " << newSolver->getNumIters () << endl << "- " << (ret == Belos::Converged ? "Converged" : "Not converged") << endl; // // After the solve, compute residual(s) explicitly. This tests // whether the Belos solver did so correctly. // std::vector<double> absoluteResidualNorms (numRHS); OPT::Apply (*A, *X, R); MVT::MvAddMv (-1.0, R, 1.0, *B, R); MVT::MvNorm (R, absoluteResidualNorms); std::vector<double> relativeResidualNorms (numRHS); for (int i = 0; i < numRHS; ++i) { relativeResidualNorms[i] = (initialResidualNorms[i] == 0.0) ? absoluteResidualNorms[i] : absoluteResidualNorms[i] / initialResidualNorms[i]; } verbOut << "---------- Computed relative residual norms ----------" << endl << endl; bool badRes = false; if (verbose) { for (int i = 0; i < numRHS; ++i) { const double actRes = relativeResidualNorms[i]; verbOut << "Problem " << i << " : \t" << actRes << endl; if (actRes > tol) { badRes = true; } } } # ifdef BELOS_TEUCHOS_TIME_MONITOR Teuchos::TimeMonitor::summarize (verbOut); # endif // BELOS_TEUCHOS_TIME_MONITOR success = (ret == Belos::Converged && !badRes); if (success) { verbOut << endl << "End Result: TEST PASSED" << endl; } else { verbOut << endl << "End Result: TEST FAILED" << endl; } } // try TEUCHOS_STANDARD_CATCH_STATEMENTS(verbose, std::cerr, success); return success ? EXIT_SUCCESS : EXIT_FAILURE; } // end test_minres_hb.cpp
bool BrentsLineSearch<Scalar>::doLineSearch( const MeritFunc1DBase<Scalar> &phi, const PointEval1D<Scalar> &point_k, const Ptr<PointEval1D<Scalar> > &point_kp1, const Ptr<int> &numIters ) const { using Teuchos::as; using Teuchos::OSTab; using Teuchos::outArg; using Teuchos::inOutArg; typedef ScalarTraits<Scalar> ST; typedef PointEval1D<Scalar> PE1D; #ifdef TEUCHOS_DEBUG TEUCHOS_ASSERT_EQUALITY(point_k.alpha, ST::zero()); TEUCHOS_ASSERT_INEQUALITY(point_k.phi, !=, PE1D::valNotGiven()); TEUCHOS_ASSERT_EQUALITY(point_k.Dphi, PE1D::valNotGiven()); TEUCHOS_ASSERT(!is_null(point_kp1)); TEUCHOS_ASSERT_INEQUALITY(point_kp1->alpha, >, ST::zero()); TEUCHOS_ASSERT_INEQUALITY(point_kp1->phi, !=, PE1D::valNotGiven()); TEUCHOS_ASSERT_EQUALITY(point_kp1->Dphi, PE1D::valNotGiven()); #endif const RCP<Teuchos::FancyOStream> out = this->getOStream(); bracket_.setOStream(out); brentsMin_.setOStream(out); *out << "\nStarting bracketing and brents 1D minimization linesearch ...\n"; OSTab tab(out); int totalNumIters = 0; PointEval1D<Scalar> p_l = point_k; PointEval1D<Scalar> &p_m = *point_kp1; // Update in place! PointEval1D<Scalar> p_u; bool success = true; // A) Bracket the minimum int numBracketIters = -1; const bool bracketSuccess = bracket_.bracketMinimum( phi, inOutArg(p_l), inOutArg(p_m), outArg(p_u), outArg(numBracketIters) ); if (!bracketSuccess) success = false; totalNumIters += numBracketIters; // B) Do approximate mimimization in the bracket if (bracketSuccess) { int numBrentsIters = -1; const bool brentsSuccess = brentsMin_.approxMinimize( phi, p_l, inOutArg(p_m), p_u, outArg(numBrentsIters) ); if (!brentsSuccess) success = false; totalNumIters += numBrentsIters; } // C) Overall success? if (!is_null(numIters)) *numIters = totalNumIters; return success; }
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; }
void VanderPolModel::evalModelImpl( const ModelEvaluatorBase::InArgs<double> &inArgs, const ModelEvaluatorBase::OutArgs<double> &outArgs ) const { using Teuchos::as; using Teuchos::outArg; using Teuchos::optInArg; using Teuchos::inOutArg; using Sacado::Fad::DFad; TEST_FOR_EXCEPTION( !isInitialized_, std::logic_error, "Error, setParameterList must be called first!\n" ); const RCP<const VectorBase<double> > x_in = inArgs.get_x().assert_not_null(); Thyra::ConstDetachedVectorView<double> x_in_view( *x_in ); double t = inArgs.get_t(); double eps = epsilon_; if (acceptModelParams_) { const RCP<const VectorBase<double> > p_in = inArgs.get_p(0).assert_not_null(); Thyra::ConstDetachedVectorView<double> p_in_view( *p_in ); eps = p_in_view[0]; } RCP<const VectorBase<double> > x_dot_in; double alpha = -1.0; double beta = -1.0; if (isImplicit_) { x_dot_in = inArgs.get_x_dot().assert_not_null(); alpha = inArgs.get_alpha(); beta = inArgs.get_beta(); } const RCP<VectorBase<double> > f_out = outArgs.get_f(); const RCP<Thyra::LinearOpBase<double> > W_out = outArgs.get_W_op(); RCP<Thyra::MultiVectorBase<double> > DfDp_out; if (acceptModelParams_) { Derivative<double> DfDp = outArgs.get_DfDp(0); DfDp_out = DfDp.getMultiVector(); } // Determine how many derivatives we will compute int num_derivs = 0; if (nonnull(W_out)) { num_derivs += 2; if (isImplicit_) { num_derivs += 2; } } if (nonnull(DfDp_out)) num_derivs += 1; // Set up the FAD derivative objects int deriv_i = 0; Array<DFad<double> > x_dot_fad; int x_dot_idx_offset = 0; if (isImplicit_) { Thyra::ConstDetachedVectorView<double> x_dot_in_view( *x_dot_in ); if (nonnull(W_out)) { x_dot_idx_offset = deriv_i; x_dot_fad = convertToIndepVarFadArray<double>(x_dot_in_view.sv().values()(), num_derivs, inOutArg(deriv_i)); } else { x_dot_fad = convertToPassiveFadArray<double>(x_dot_in_view.sv().values()()); } } Array<DFad<double> > x_fad; int x_idx_offset = 0; if (nonnull(W_out)) { x_idx_offset = deriv_i; x_fad = convertToIndepVarFadArray<double>(x_in_view.sv().values()(), num_derivs, inOutArg(deriv_i)); } else { x_fad = convertToPassiveFadArray<double>(x_in_view.sv().values()()); } DFad<double> eps_fad(eps); // Default passive int eps_idx_offset = 0; if (nonnull(DfDp_out)) { eps_idx_offset = deriv_i; eps_fad = DFad<double>(num_derivs, deriv_i++, eps); } // Compute the function Array<DFad<double> > f_fad(2); this->eval_f<DFad<double> >( x_dot_fad, x_fad, eps_fad, t, f_fad ); // Extract the output if (nonnull(f_out)) { Thyra::DetachedVectorView<double> f_out_view( *f_out ); for ( int i = 0; i < as<int>(f_fad.size()); ++i ) f_out_view[i] = f_fad[i].val(); } if (nonnull(W_out)) { const RCP<Thyra::MultiVectorBase<double> > matrix = Teuchos::rcp_dynamic_cast<Thyra::MultiVectorBase<double> >(W_out, true); Thyra::DetachedMultiVectorView<double> matrix_view( *matrix ); if (isImplicit_) { for ( int i = 0; i < matrix_view.subDim(); ++i) { for ( int j = 0; j < matrix_view.numSubCols(); ++j) { matrix_view(i, j) = alpha * f_fad[i].dx(x_dot_idx_offset+j) + beta * f_fad[i].dx(x_idx_offset + j); } } } else { for ( int i = 0; i < matrix_view.subDim(); ++i) { for ( int j = 0; j < matrix_view.numSubCols(); ++j) { matrix_view(i, j) = f_fad[i].dx(x_idx_offset + j); } } } } if (nonnull(DfDp_out)) { Thyra::DetachedMultiVectorView<double> DfDp_out_view( *DfDp_out ); for ( int i = 0; i < DfDp_out_view.subDim(); ++i ) DfDp_out_view(i,0) = f_fad[i].dx(eps_idx_offset); } }
TEUCHOS_UNIT_TEST( EpetraOperatorWrapper, basic ) { #ifdef HAVE_MPI Epetra_MpiComm comm(MPI_COMM_WORLD); #else Epetra_SerialComm comm; #endif out << "\nRunning on " << comm.NumProc() << " processors\n"; int nx = 39; // essentially random values int ny = 53; out << "Using Trilinos_Util to create test matrices\n"; // create some big blocks to play with Trilinos_Util::CrsMatrixGallery FGallery("recirc_2d",comm,false); // CJ TODO FIXME: change for Epetra64 FGallery.Set("nx",nx); FGallery.Set("ny",ny); RCP<Epetra_CrsMatrix> F = rcp(FGallery.GetMatrix(),false); Trilinos_Util::CrsMatrixGallery CGallery("laplace_2d",comm,false); // CJ TODO FIXME: change for Epetra64 CGallery.Set("nx",nx); CGallery.Set("ny",ny); RCP<Epetra_CrsMatrix> C = rcp(CGallery.GetMatrix(),false); Trilinos_Util::CrsMatrixGallery BGallery("diag",comm,false); // CJ TODO FIXME: change for Epetra64 BGallery.Set("nx",nx*ny); BGallery.Set("a",5.0); RCP<Epetra_CrsMatrix> B = rcp(BGallery.GetMatrix(),false); Trilinos_Util::CrsMatrixGallery BtGallery("diag",comm,false); // CJ TODO FIXME: change for Epetra64 BtGallery.Set("nx",nx*ny); BtGallery.Set("a",3.0); RCP<Epetra_CrsMatrix> Bt = rcp(BtGallery.GetMatrix(),false); // load'em up in a thyra operator out << "Building block2x2 Thyra matrix ... wrapping in EpetraOperatorWrapper\n"; const RCP<const LinearOpBase<double> > A = Thyra::block2x2<double>( Thyra::epetraLinearOp(F), Thyra::epetraLinearOp(Bt), Thyra::epetraLinearOp(B), Thyra::epetraLinearOp(C), "A" ); const RCP<Thyra::EpetraOperatorWrapper> epetra_A = rcp(new Thyra::EpetraOperatorWrapper(A)); // begin the tests! const Epetra_Map & rangeMap = epetra_A->OperatorRangeMap(); const Epetra_Map & domainMap = epetra_A->OperatorDomainMap(); // check to see that the number of global elements is correct TEST_EQUALITY(rangeMap.NumGlobalElements(), 2*nx*ny); TEST_EQUALITY(domainMap.NumGlobalElements(), 2*nx*ny); // largest global ID should be one less then the # of elements TEST_EQUALITY(rangeMap.NumGlobalElements()-1, rangeMap.MaxAllGID()); TEST_EQUALITY(domainMap.NumGlobalElements()-1, domainMap.MaxAllGID()); // create a vector to test: copyThyraIntoEpetra { const RCP<VectorBase<double> > tv = Thyra::createMember(A->domain()); Thyra::randomize(-100.0, 100.0, tv.ptr()); const RCP<const VectorBase<double> > tv_0 = Thyra::productVectorBase<double>(tv)->getVectorBlock(0); const RCP<const VectorBase<double> > tv_1 = Thyra::productVectorBase<double>(tv)->getVectorBlock(1); const Thyra::ConstDetachedSpmdVectorView<double> vv_0(tv_0); const Thyra::ConstDetachedSpmdVectorView<double> vv_1(tv_1); int off_0 = vv_0.globalOffset(); int off_1 = vv_1.globalOffset(); // create its Epetra counter part Epetra_Vector ev(epetra_A->OperatorDomainMap()); epetra_A->copyThyraIntoEpetra(*tv, ev); // compare handle_tv to ev! TEST_EQUALITY(tv->space()->dim(), as<Ordinal>(ev.GlobalLength())); const int numMyElements = domainMap.NumMyElements(); double tval = 0.0; for(int i=0; i < numMyElements; i++) { int gid = domainMap.GID(i); if(gid<nx*ny) tval = vv_0[gid-off_0]; else tval = vv_1[gid-off_1-nx*ny]; TEST_EQUALITY(ev[i], tval); } } // create a vector to test: copyEpetraIntoThyra { // create an Epetra vector Epetra_Vector ev(epetra_A->OperatorDomainMap()); ev.Random(); // create its thyra counterpart const RCP<VectorBase<double> > tv = Thyra::createMember(A->domain()); const RCP<const VectorBase<double> > tv_0 = Thyra::productVectorBase<double>(tv)->getVectorBlock(0); const RCP<const VectorBase<double> > tv_1 = Thyra::productVectorBase<double>(tv)->getVectorBlock(1); const Thyra::ConstDetachedSpmdVectorView<double> vv_0(tv_0); const Thyra::ConstDetachedSpmdVectorView<double> vv_1(tv_1); int off_0 = rcp_dynamic_cast<const Thyra::SpmdVectorSpaceBase<double> >( tv_0->space())->localOffset(); int off_1 = rcp_dynamic_cast<const Thyra::SpmdVectorSpaceBase<double> >( tv_1->space())->localOffset(); epetra_A->copyEpetraIntoThyra(ev, tv.ptr()); // compare tv to ev! TEST_EQUALITY(tv->space()->dim(), as<Ordinal>(ev.GlobalLength())); int numMyElements = domainMap.NumMyElements(); double tval = 0.0; for(int i=0;i<numMyElements;i++) { int gid = domainMap.GID(i); if(gid<nx*ny) tval = vv_0[gid-off_0]; else tval = vv_1[gid-off_1-nx*ny]; TEST_EQUALITY(ev[i], tval); } } // Test using Thyra::LinearOpTester const RCP<const LinearOpBase<double> > thyraEpetraOp = epetraLinearOp(epetra_A); LinearOpTester<double> linearOpTester; linearOpTester.show_all_tests(true); const bool checkResult = linearOpTester.check(*thyraEpetraOp, inOutArg(out)); TEST_ASSERT(checkResult); }