$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 #include "libmesh/libmesh_common.h" 00021 00022 #ifdef LIBMESH_HAVE_NOX 00023 00024 00025 // C++ includes 00026 00027 // Local Includes 00028 #include "libmesh/libmesh_logging.h" 00029 #include "libmesh/dof_map.h" 00030 #include "libmesh/nonlinear_implicit_system.h" 00031 #include "libmesh/trilinos_nox_nonlinear_solver.h" 00032 #include "libmesh/system.h" 00033 #include "libmesh/trilinos_epetra_vector.h" 00034 #include "libmesh/trilinos_epetra_matrix.h" 00035 #include "libmesh/trilinos_preconditioner.h" 00036 00037 // ---------- Standard Includes ---------- 00038 #include <iostream> 00039 #include "Epetra_Vector.h" 00040 #include "Epetra_Operator.h" 00041 #include "Epetra_RowMatrix.h" 00042 #include "NOX_Epetra_Interface_Required.H" // base class 00043 #include "NOX_Epetra_Interface_Jacobian.H" // base class 00044 #include "NOX_Epetra_Interface_Preconditioner.H" // base class 00045 #include "NOX_Epetra_MatrixFree.H" 00046 #include "NOX_Epetra_LinearSystem_AztecOO.H" 00047 #include "NOX_Epetra_Group.H"// class definition 00048 #include "NOX_Epetra_Vector.H" 00049 00050 namespace libMesh 00051 { 00052 00053 class Problem_Interface : public NOX::Epetra::Interface::Required, 00054 public NOX::Epetra::Interface::Jacobian, 00055 public NOX::Epetra::Interface::Preconditioner 00056 { 00057 public: 00058 explicit 00059 Problem_Interface(NoxNonlinearSolver<Number> * solver); 00060 00061 ~Problem_Interface(); 00062 00064 bool computeF(const Epetra_Vector& x, Epetra_Vector& FVec, 00065 NOX::Epetra::Interface::Required::FillType fillType); 00066 00068 bool computeJacobian(const Epetra_Vector& x, Epetra_Operator& Jac); 00069 00071 bool computePrecMatrix(const Epetra_Vector& x, Epetra_RowMatrix& M); 00072 00074 bool computePreconditioner(const Epetra_Vector& x, Epetra_Operator& Prec, 00075 Teuchos::ParameterList* p); 00076 00077 NoxNonlinearSolver<Number> * _solver; 00078 }; 00079 00080 //----------------------------------------------------------------------------- 00081 Problem_Interface::Problem_Interface(NoxNonlinearSolver<Number> * solver) : 00082 _solver(solver) 00083 { } 00084 00085 Problem_Interface::~Problem_Interface() 00086 { } 00087 00088 bool Problem_Interface::computeF(const Epetra_Vector& x, Epetra_Vector& r, 00089 NOX::Epetra::Interface::Required::FillType /*fillType*/) 00090 { 00091 START_LOG("residual()", "TrilinosNoxNonlinearSolver"); 00092 00093 NonlinearImplicitSystem &sys = _solver->system(); 00094 00095 EpetraVector<Number> X_global(*const_cast<Epetra_Vector *>(&x), sys.comm()), R(r, sys.comm()); 00096 EpetraVector<Number>& X_sys = *cast_ptr<EpetraVector<Number>*>(sys.solution.get()); 00097 EpetraVector<Number>& R_sys = *cast_ptr<EpetraVector<Number>*>(sys.rhs); 00098 00099 // Use the systems update() to get a good local version of the parallel solution 00100 X_global.swap(X_sys); 00101 R.swap(R_sys); 00102 00103 sys.get_dof_map().enforce_constraints_exactly(sys); 00104 sys.update(); 00105 00106 // Swap back 00107 X_global.swap(X_sys); 00108 R.swap(R_sys); 00109 00110 R.zero(); 00111 00112 //----------------------------------------------------------------------------- 00113 // if the user has provided both function pointers and objects only the pointer 00114 // will be used, so catch that as an error 00115 00116 if (_solver->residual && _solver->residual_object) 00117 libmesh_error_msg("ERROR: cannot specifiy both a function and object to compute the Residual!"); 00118 00119 if (_solver->matvec && _solver->residual_and_jacobian_object) 00120 libmesh_error_msg("ERROR: cannot specifiy both a function and object to compute the combined Residual & Jacobian!"); 00121 00122 if (_solver->residual != NULL) _solver->residual (*sys.current_local_solution.get(), R, sys); 00123 else if (_solver->residual_object != NULL) _solver->residual_object->residual (*sys.current_local_solution.get(), R, sys); 00124 else if (_solver->matvec != NULL) _solver->matvec (*sys.current_local_solution.get(), &R, NULL, sys); 00125 else if (_solver->residual_and_jacobian_object != NULL) _solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), &R, NULL, sys); 00126 else return false; 00127 00128 R.close(); 00129 X_global.close(); 00130 00131 STOP_LOG("residual()", "TrilinosNoxNonlinearSolver"); 00132 00133 return true; 00134 } 00135 00136 bool Problem_Interface::computeJacobian(const Epetra_Vector & x, 00137 Epetra_Operator & jac) 00138 { 00139 START_LOG("jacobian()", "TrilinosNoxNonlinearSolver"); 00140 00141 NonlinearImplicitSystem &sys = _solver->system(); 00142 00143 EpetraMatrix<Number> Jac(&dynamic_cast<Epetra_FECrsMatrix &>(jac), sys.comm()); 00144 EpetraVector<Number>& X_sys = *cast_ptr<EpetraVector<Number>*>(sys.solution.get()); 00145 EpetraVector<Number> X_global(*const_cast<Epetra_Vector *>(&x), sys.comm()); 00146 00147 // Set the dof maps 00148 Jac.attach_dof_map(sys.get_dof_map()); 00149 00150 // Use the systems update() to get a good local version of the parallel solution 00151 X_global.swap(X_sys); 00152 00153 sys.get_dof_map().enforce_constraints_exactly(sys); 00154 sys.update(); 00155 00156 X_global.swap(X_sys); 00157 00158 //----------------------------------------------------------------------------- 00159 // if the user has provided both function pointers and objects only the pointer 00160 // will be used, so catch that as an error 00161 if (_solver->jacobian && _solver->jacobian_object) 00162 libmesh_error_msg("ERROR: cannot specify both a function and object to compute the Jacobian!"); 00163 00164 if (_solver->matvec && _solver->residual_and_jacobian_object) 00165 libmesh_error_msg("ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!"); 00166 00167 if (_solver->jacobian != NULL) _solver->jacobian (*sys.current_local_solution.get(), Jac, sys); 00168 else if (_solver->jacobian_object != NULL) _solver->jacobian_object->jacobian (*sys.current_local_solution.get(), Jac, sys); 00169 else if (_solver->matvec != NULL) _solver->matvec (*sys.current_local_solution.get(), NULL, &Jac, sys); 00170 else if (_solver->residual_and_jacobian_object != NULL) _solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), NULL, &Jac, sys); 00171 else 00172 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!"); 00173 00174 Jac.close(); 00175 X_global.close(); 00176 00177 STOP_LOG("jacobian()", "TrilinosNoxNonlinearSolver"); 00178 00179 return true; 00180 } 00181 00182 bool Problem_Interface::computePrecMatrix(const Epetra_Vector & /*x*/, Epetra_RowMatrix & /*M*/) 00183 { 00184 // libMesh::out << "ERROR: Problem_Interface::preconditionVector() - Use Explicit Jacobian only for this test problem!" << endl; 00185 throw 1; 00186 } 00187 00188 bool Problem_Interface::computePreconditioner(const Epetra_Vector & x, 00189 Epetra_Operator & prec, 00190 Teuchos::ParameterList * /*p*/) 00191 { 00192 START_LOG("preconditioner()", "TrilinosNoxNonlinearSolver"); 00193 00194 NonlinearImplicitSystem &sys = _solver->system(); 00195 TrilinosPreconditioner<Number> & tpc = dynamic_cast<TrilinosPreconditioner<Number> &>(prec); 00196 00197 EpetraMatrix<Number> Jac(dynamic_cast<Epetra_FECrsMatrix *>(tpc.mat()),sys.comm()); 00198 EpetraVector<Number>& X_sys = *cast_ptr<EpetraVector<Number>*>(sys.solution.get()); 00199 EpetraVector<Number> X_global(*const_cast<Epetra_Vector *>(&x), sys.comm()); 00200 00201 // Set the dof maps 00202 Jac.attach_dof_map(sys.get_dof_map()); 00203 00204 // Use the systems update() to get a good local version of the parallel solution 00205 X_global.swap(X_sys); 00206 00207 sys.get_dof_map().enforce_constraints_exactly(sys); 00208 sys.update(); 00209 00210 X_global.swap(X_sys); 00211 00212 //----------------------------------------------------------------------------- 00213 // if the user has provided both function pointers and objects only the pointer 00214 // will be used, so catch that as an error 00215 if (_solver->jacobian && _solver->jacobian_object) 00216 libmesh_error_msg("ERROR: cannot specify both a function and object to compute the Jacobian!"); 00217 00218 if (_solver->matvec && _solver->residual_and_jacobian_object) 00219 libmesh_error_msg("ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!"); 00220 00221 if (_solver->jacobian != NULL) _solver->jacobian (*sys.current_local_solution.get(), Jac, sys); 00222 else if (_solver->jacobian_object != NULL) _solver->jacobian_object->jacobian (*sys.current_local_solution.get(), Jac, sys); 00223 else if (_solver->matvec != NULL) _solver->matvec (*sys.current_local_solution.get(), NULL, &Jac, sys); 00224 else if (_solver->residual_and_jacobian_object != NULL) _solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), NULL, &Jac, sys); 00225 else 00226 libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!"); 00227 00228 Jac.close(); 00229 X_global.close(); 00230 00231 tpc.compute(); 00232 00233 STOP_LOG("preconditioner()", "TrilinosNoxNonlinearSolver"); 00234 00235 return true; 00236 } 00237 00238 00239 //--------------------------------------------------------------------- 00240 // NoxNonlinearSolver<> methods 00241 template <typename T> 00242 void NoxNonlinearSolver<T>::clear () 00243 { 00244 } 00245 00246 template <typename T> 00247 void NoxNonlinearSolver<T>::init (const char * /*name*/) 00248 { 00249 if (!this->initialized()) 00250 _interface = new Problem_Interface(this); 00251 } 00252 00253 template <typename T> 00254 std::pair<unsigned int, Real> 00255 NoxNonlinearSolver<T>::solve (SparseMatrix<T>& /* jac_in */, // System Jacobian Matrix 00256 NumericVector<T>& x_in, // Solution vector 00257 NumericVector<T>& /* r_in */, // Residual vector 00258 const double, // Stopping tolerance 00259 const unsigned int) 00260 { 00261 this->init (); 00262 00263 if (this->user_presolve) 00264 this->user_presolve(this->system()); 00265 00266 EpetraVector<T> * x_epetra = cast_ptr<EpetraVector<T>*>(&x_in); 00267 // Creating a Teuchos::RCP as they do in NOX examples does not work here - we get some invalid memory references 00268 // thus we make a local copy 00269 NOX::Epetra::Vector x(*x_epetra->vec()); 00270 00271 Teuchos::RCP<Teuchos::ParameterList> nlParamsPtr = Teuchos::rcp(new Teuchos::ParameterList); 00272 Teuchos::ParameterList& nlParams = *(nlParamsPtr.get()); 00273 nlParams.set("Nonlinear Solver", "Line Search Based"); 00274 00275 //print params 00276 Teuchos::ParameterList& printParams = nlParams.sublist("Printing"); 00277 printParams.set("Output Precision", 3); 00278 printParams.set("Output Processor", 0); 00279 printParams.set("Output Information", 00280 NOX::Utils::OuterIteration + 00281 NOX::Utils::OuterIterationStatusTest + 00282 NOX::Utils::InnerIteration + 00283 NOX::Utils::LinearSolverDetails + 00284 NOX::Utils::Parameters + 00285 NOX::Utils::Details + 00286 NOX::Utils::Warning); 00287 00288 Teuchos::ParameterList& dirParams = nlParams.sublist("Direction"); 00289 dirParams.set("Method", "Newton"); 00290 Teuchos::ParameterList& newtonParams = dirParams.sublist("Newton"); 00291 newtonParams.set("Forcing Term Method", "Constant"); 00292 00293 Teuchos::ParameterList& lsParams = newtonParams.sublist("Linear Solver"); 00294 lsParams.set("Aztec Solver", "GMRES"); 00295 lsParams.set("Max Iterations", static_cast<int>(this->max_linear_iterations)); 00296 lsParams.set("Tolerance", this->initial_linear_tolerance); 00297 lsParams.set("Output Frequency", 1); 00298 lsParams.set("Size of Krylov Subspace", 1000); 00299 00300 //create linear system 00301 Teuchos::RCP<NOX::Epetra::Interface::Required> iReq(_interface); 00302 Teuchos::RCP<NOX::Epetra::LinearSystemAztecOO> linSys; 00303 Teuchos::RCP<Epetra_Operator> pc; 00304 00305 if (this->jacobian || this->jacobian_object || this->residual_and_jacobian_object) 00306 { 00307 if(this->_preconditioner) 00308 { 00309 // PJNFK 00310 lsParams.set("Preconditioner", "User Defined"); 00311 00312 TrilinosPreconditioner<Number> * trilinos_pc = 00313 cast_ptr<TrilinosPreconditioner<Number> *>(this->_preconditioner); 00314 pc = Teuchos::rcp(trilinos_pc); 00315 00316 Teuchos::RCP<NOX::Epetra::Interface::Preconditioner> iPrec(_interface); 00317 linSys = Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(printParams, lsParams, iReq, iPrec, pc, x)); 00318 } 00319 else 00320 { 00321 lsParams.set("Preconditioner", "None"); 00322 // lsParams.set("Preconditioner", "Ifpack"); 00323 // lsParams.set("Preconditioner", "AztecOO"); 00324 00325 // full jacobian 00326 NonlinearImplicitSystem & sys = _interface->_solver->system(); 00327 EpetraMatrix<Number> & jacSys = *cast_ptr<EpetraMatrix<Number>*>(sys.matrix); 00328 Teuchos::RCP<Epetra_RowMatrix> jacMat = Teuchos::rcp(jacSys.mat()); 00329 00330 Teuchos::RCP<NOX::Epetra::Interface::Jacobian> iJac(_interface); 00331 linSys = Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(printParams, lsParams, iReq, iJac, jacMat, x)); 00332 } 00333 } 00334 else 00335 { 00336 // matrix free 00337 Teuchos::RCP<NOX::Epetra::MatrixFree> MF = Teuchos::rcp(new NOX::Epetra::MatrixFree(printParams, iReq, x)); 00338 00339 Teuchos::RCP<NOX::Epetra::Interface::Jacobian> iJac(MF); 00340 linSys = Teuchos::rcp(new NOX::Epetra::LinearSystemAztecOO(printParams, lsParams, iReq, iJac, MF, x)); 00341 } 00342 00343 //create group 00344 Teuchos::RCP<NOX::Epetra::Group> grpPtr = Teuchos::rcp(new NOX::Epetra::Group(printParams, iReq, x, linSys)); 00345 NOX::Epetra::Group& grp = *(grpPtr.get()); 00346 00347 Teuchos::RCP<NOX::StatusTest::NormF> absresid = 00348 Teuchos::rcp(new NOX::StatusTest::NormF(this->absolute_residual_tolerance, NOX::StatusTest::NormF::Unscaled)); 00349 Teuchos::RCP<NOX::StatusTest::NormF> relresid = 00350 Teuchos::rcp(new NOX::StatusTest::NormF(grp, this->relative_residual_tolerance)); 00351 Teuchos::RCP<NOX::StatusTest::MaxIters> maxiters = 00352 Teuchos::rcp(new NOX::StatusTest::MaxIters(this->max_nonlinear_iterations)); 00353 Teuchos::RCP<NOX::StatusTest::FiniteValue> finiteval = 00354 Teuchos::rcp(new NOX::StatusTest::FiniteValue()); 00355 Teuchos::RCP<NOX::StatusTest::NormUpdate> normupdate = 00356 Teuchos::rcp(new NOX::StatusTest::NormUpdate(this->absolute_step_tolerance)); 00357 Teuchos::RCP<NOX::StatusTest::Combo> combo = 00358 Teuchos::rcp(new NOX::StatusTest::Combo(NOX::StatusTest::Combo::OR)); 00359 combo->addStatusTest(absresid); 00360 combo->addStatusTest(relresid); 00361 combo->addStatusTest(maxiters); 00362 combo->addStatusTest(finiteval); 00363 combo->addStatusTest(normupdate); 00364 00365 Teuchos::RCP<Teuchos::ParameterList> finalPars = nlParamsPtr; 00366 00367 Teuchos::RCP<NOX::Solver::Generic> solver = NOX::Solver::buildSolver(grpPtr, combo, nlParamsPtr); 00368 NOX::StatusTest::StatusType status = solver->solve(); 00369 this->converged = (status == NOX::StatusTest::Converged); 00370 00371 const NOX::Epetra::Group& finalGroup = dynamic_cast<const NOX::Epetra::Group&>(solver->getSolutionGroup()); 00372 const NOX::Epetra::Vector& noxFinalSln = dynamic_cast<const NOX::Epetra::Vector&>(finalGroup.getX()); 00373 00374 *x_epetra->vec() = noxFinalSln.getEpetraVector(); 00375 x_in.close(); 00376 00377 Real residual_norm = finalGroup.getNormF(); 00378 unsigned int total_iters = solver->getNumIterations(); 00379 _n_linear_iterations = finalPars->sublist("Direction").sublist("Newton").sublist("Linear Solver").sublist("Output").get("Total Number of Linear Iterations", -1); 00380 00381 // do not let Trilinos to deallocate what we allocated 00382 pc.release(); 00383 iReq.release(); 00384 00385 return std::make_pair(total_iters, residual_norm); 00386 } 00387 00388 template <typename T> 00389 int 00390 NoxNonlinearSolver<T>::get_total_linear_iterations() 00391 { 00392 return _n_linear_iterations; 00393 } 00394 00395 00396 00397 //------------------------------------------------------------------ 00398 // Explicit instantiations 00399 template class NoxNonlinearSolver<Number>; 00400 00401 } // namespace libMesh 00402 00403 00404 00405 #endif // #ifdef LIBMESH_HAVE_NOX