1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 // vi: set et ts=4 sw=2 sts=2: 3 #ifndef DUNE_PDELAB_SOLVER_NEWTON_HH 4 #define DUNE_PDELAB_SOLVER_NEWTON_HH 5 6 #include <dune/common/exceptions.hh> 7 #include <dune/common/ios_state.hh> 8 9 #include <dune/pdelab/constraints/common/constraints.hh> 10 #include <dune/pdelab/solver/newtonerrors.hh> 11 #include <dune/pdelab/solver/linesearch.hh> 12 #include <dune/pdelab/solver/terminate.hh> 13 #include <dune/pdelab/solver/utility.hh> 14 15 namespace Dune::PDELab 16 { 17 namespace Impl 18 { 19 // Some SFinae magic to execute setReuse(bool) on a backend 20 template<typename T1, typename = void> 21 struct HasSetReuse 22 : std::false_type 23 {}; 24 25 template<typename T> 26 struct HasSetReuse<T, decltype(std::declval<T>().setReuse(true), void())> 27 : std::true_type 28 {}; 29 30 template<typename T> setLinearSystemReuse(T & solver_backend,bool reuse,std::true_type)31 inline void setLinearSystemReuse(T& solver_backend, bool reuse, std::true_type) 32 { 33 if (!solver_backend.getReuse() && reuse) 34 dwarn << "WARNING: Newton needed to override your choice to reuse the linear system in order to work!" << std::endl; 35 solver_backend.setReuse(reuse); 36 } 37 38 template<typename T> setLinearSystemReuse(T &,bool,std::false_type)39 inline void setLinearSystemReuse(T&, bool, std::false_type) 40 {} 41 42 template<typename T> setLinearSystemReuse(T & solver_backend,bool reuse)43 inline void setLinearSystemReuse(T& solver_backend, bool reuse) 44 { 45 setLinearSystemReuse(solver_backend, reuse, HasSetReuse<T>()); 46 } 47 } 48 49 50 /** \brief Newton solver for solving non-linear problems 51 * 52 * - The line search and the termination criterion can be changed at runtime 53 * by the setTerminate() and the setLineSearch() methods. 54 * 55 * - If Newton is created using the default parameters it is an inexact 56 * Newton since the default reduction for the linear systems is quite 57 * low. You can change this through setMinLinearReduction() 58 * 59 * \tparam GridOperator_ Grid operator for evaluation of residual and Jacobian 60 * \tparam LinearSolver_ Solver backend for solving linear system of equations 61 */ 62 template <typename GridOperator_, typename LinearSolver_> 63 class NewtonMethod 64 { 65 public: 66 //! Type of the grid operator 67 using GridOperator = GridOperator_; 68 69 //! Type of the linear solver 70 using LinearSolver = LinearSolver_; 71 72 //! Type of the domain (solution) 73 using Domain = typename GridOperator::Traits::Domain; 74 75 //! Type of the range (residual) 76 using Range = typename GridOperator::Traits::Range; 77 78 //! Type of the Jacobian matrix 79 using Jacobian = typename GridOperator::Traits::Jacobian; 80 81 //! Number type 82 using Real = typename Dune::FieldTraits<typename Domain::ElementType>::real_type; 83 84 //! Type of results 85 using Result = PDESolverResult<Real>; 86 87 //! Type of line search interface 88 using LineSearch = LineSearchInterface<Domain>; 89 90 //! Return results result() const91 const Result& result() const 92 { 93 if (not _resultValid) 94 DUNE_THROW(NewtonError, "NewtonMethod::result() called before NewtonMethod::solve()"); 95 return _result; 96 } 97 prepareStep(Domain & solution)98 virtual void prepareStep(Domain& solution) 99 { 100 _reassembled = false; 101 if (_result.defect/_previousDefect > _reassembleThreshold){ 102 if (_hangingNodeModifications){ 103 auto dirichletValues = solution; 104 // Set all non dirichlet values to zero 105 Dune::PDELab::set_shifted_dofs(_gridOperator.localAssembler().trialConstraints(), 0.0, dirichletValues); 106 // Set all constrained DOFs to zero in solution 107 Dune::PDELab::set_constrained_dofs(_gridOperator.localAssembler().trialConstraints(), 0.0, solution); 108 // Copy correct Dirichlet values back into solution vector 109 Dune::PDELab::copy_constrained_dofs(_gridOperator.localAssembler().trialConstraints(), dirichletValues, solution); 110 // Interpolate periodic constraints / hanging nodes 111 _gridOperator.localAssembler().backtransform(solution); 112 } 113 if constexpr (!linearSolverIsMatrixFree<LinearSolver>()){ 114 if (_verbosity>=3) 115 std::cout << " Reassembling matrix..." << std::endl; 116 *_jacobian = Real(0.0); 117 _gridOperator.jacobian(solution, *_jacobian); 118 _reassembled = true; 119 } 120 } 121 122 _linearReduction = _minLinearReduction; 123 // corner case: ForceIteration==true. Use _minLinearReduction when initial defect is less than AbsoluteLimit. 124 if (not _fixedLinearReduction && !(_result.iterations==0 && _result.first_defect<_absoluteLimit)){ 125 // Determine maximum defect, where Newton is converged. 126 using std::min; 127 using std::max; 128 auto stop_defect = max(_result.first_defect*_reduction, _absoluteLimit); 129 130 // To achieve second order convergence of newton we need a linear 131 // reduction of at least current_defect^2/prev_defect^2. For the 132 // last newton step a linear reduction of 133 // 1/10*end_defect/current_defect is sufficient for convergence. 134 _linearReduction = 135 max( stop_defect/(10*_result.defect), 136 min(_minLinearReduction, _result.defect*_result.defect/(_previousDefect*_previousDefect)) ); 137 } 138 139 if (_verbosity >= 3) 140 std::cout << " requested linear reduction: " 141 << std::setw(12) << std::setprecision(4) << std::scientific 142 << _linearReduction << std::endl; 143 } 144 linearSolve()145 virtual void linearSolve() 146 { 147 if (_verbosity >= 4) 148 std::cout << " Solving linear system..." << std::endl; 149 150 if constexpr (!linearSolverIsMatrixFree<LinearSolver>()){ 151 // If the jacobian was not reassembled we might save some work in the solver backend 152 Impl::setLinearSystemReuse(_linearSolver, not _reassembled); 153 } 154 155 // Solve the linear system 156 _correction = 0.0; 157 if constexpr (linearSolverIsMatrixFree<LinearSolver>()){ 158 _linearSolver.apply(_correction, _residual, _linearReduction); 159 } 160 else{ 161 _linearSolver.apply(*_jacobian, _correction, _residual, _linearReduction); 162 } 163 164 if (not _linearSolver.result().converged) 165 DUNE_THROW(NewtonLinearSolverError, 166 "NewtonMethod::linearSolve(): Linear solver did not converge " 167 "in " << _linearSolver.result().iterations << " iterations"); 168 if (_verbosity >= 4) 169 std::cout << " linear solver iterations: " 170 << std::setw(12) << _linearSolver.result().iterations << std::endl 171 << " linear defect reduction: " 172 << std::setw(12) << std::setprecision(4) << std::scientific 173 << _linearSolver.result().reduction << std::endl; 174 } 175 176 //! Solve the nonlinear problem using solution as initial guess and for storing the result apply(Domain & solution)177 virtual void apply(Domain& solution) 178 { 179 // Reset solver statistics 180 _result.clear(); 181 _resultValid = true; 182 183 // Store old ios flags (will be reset when this goes out of scope) 184 ios_base_all_saver restorer(std::cout); 185 186 // Prepare time measuring 187 using Clock = std::chrono::steady_clock; 188 using Duration = Clock::duration; 189 auto assembler_time = Duration::zero(); 190 auto linear_solver_time = Duration::zero(); 191 auto line_search_time = Duration::zero(); 192 auto to_seconds = 193 [](Duration duration){ 194 return std::chrono::duration<double>(duration).count(); 195 }; 196 auto start_solve = Clock::now(); 197 198 //========================= 199 // Calculate initial defect 200 //========================= 201 updateDefect(solution); 202 _result.first_defect = _result.defect; 203 _previousDefect = _result.defect; 204 205 if (_verbosity >= 2) 206 std::cout << " Initial defect: " 207 << std::setw(12) << std::setprecision(4) << std::scientific 208 << _result.defect << std::endl; 209 210 //========================== 211 // Calculate Jacobian matrix 212 //========================== 213 if constexpr (!linearSolverIsMatrixFree<LinearSolver>()){ 214 if (not _jacobian) 215 _jacobian = std::make_shared<Jacobian>(_gridOperator); 216 } 217 218 //========================= 219 // Nonlinear iteration loop 220 //========================= 221 while (not _terminate->terminate()){ 222 if(_verbosity >= 3) 223 std::cout << " Newton iteration " << _result.iterations 224 << " --------------------------------" << std::endl; 225 226 //============= 227 // Prepare step 228 //============= 229 auto start = Clock::now(); 230 try{ 231 prepareStep(solution); 232 } 233 catch (...) 234 { 235 // Keep track of statistics when the method fails. We record 236 // independently the time spent in non-converging attempts. 237 // Check OneStepMethod to see how these data are propagated. 238 auto end = Clock::now(); 239 assembler_time += end-start; 240 _result.assembler_time = to_seconds(assembler_time); 241 throw; 242 } 243 auto end = Clock::now(); 244 assembler_time += end -start; 245 _result.assembler_time = to_seconds(assembler_time); 246 247 // Store defect 248 _previousDefect = _result.defect; 249 250 //==================== 251 // Solve linear system 252 //==================== 253 start = Clock::now(); 254 255 // Important: In the matrix-free case we need to set the current linearization point! 256 if constexpr (linearSolverIsMatrixFree<LinearSolver>()){ 257 _linearSolver.setLinearizationPoint(solution); 258 } 259 try{ 260 linearSolve(); 261 } 262 catch (...) 263 { 264 // Separately catch statistics for linear solver failures. 265 end = Clock::now(); 266 linear_solver_time += end-start; 267 _result.linear_solver_time = to_seconds(linear_solver_time); 268 _result.linear_solver_iterations = _linearSolver.result().iterations; 269 throw; 270 } 271 end = Clock::now(); 272 linear_solver_time += end -start; 273 _result.linear_solver_time = to_seconds(linear_solver_time); 274 _result.linear_solver_iterations = _linearSolver.result().iterations; 275 276 //=================================== 277 // Do line search and update solution 278 //=================================== 279 start = Clock::now(); 280 _lineSearch->lineSearch(solution, _correction); 281 // lineSearch(solution); 282 end = Clock::now(); 283 line_search_time += end -start; 284 285 //======================================== 286 // Store statistics and create some output 287 //======================================== 288 _result.reduction = _result.defect/_result.first_defect; 289 _result.iterations++; 290 _result.conv_rate = std::pow(_result.reduction, 1.0/_result.iterations); 291 292 if (_verbosity >= 3) 293 std::cout << " linear solver time: " 294 << std::setw(12) << std::setprecision(4) << std::scientific 295 << to_seconds(linear_solver_time) << std::endl 296 << " defect reduction (this iteration):" 297 << std::setw(12) << std::setprecision(4) << std::scientific 298 << _result.defect/_previousDefect << std::endl 299 << " defect reduction (total): " 300 << std::setw(12) << std::setprecision(4) << std::scientific 301 << _result.reduction << std::endl 302 << " new defect: " 303 << std::setw(12) << std::setprecision(4) << std::scientific 304 << _result.defect << std::endl; 305 if (_verbosity == 2) 306 std::cout << " Newton iteration " 307 << std::setw(2) 308 << _result.iterations 309 << ". New defect: " 310 << std::setw(12) << std::setprecision(4) << std::scientific 311 << _result.defect 312 << ". Reduction (this): " 313 << std::setw(12) << std::setprecision(4) << std::scientific 314 << _result.defect/_previousDefect 315 << ". Reduction (total): " 316 << std::setw(12) << std::setprecision(4) << std::scientific 317 << _result.reduction 318 << std::endl; 319 } // end while loop of nonlinear iterations 320 321 auto end_solve = Clock::now(); 322 auto solve_time = end_solve - start_solve; 323 _result.elapsed = to_seconds(solve_time); 324 325 if (_verbosity == 1) 326 std::cout << " Newton converged after " 327 << std::setw(2) 328 << _result.iterations 329 << " iterations. Reduction: " 330 << std::setw(12) << std::setprecision(4) << std::scientific 331 << _result.reduction 332 << " (" << std::setprecision(4) << _result.elapsed << "s)" 333 << std::endl; 334 335 if constexpr (!linearSolverIsMatrixFree<LinearSolver>()){ 336 if (not _keepMatrix) 337 _jacobian.reset(); 338 } 339 } 340 341 //! Update _residual and defect in _result updateDefect(Domain & solution)342 virtual void updateDefect(Domain& solution) 343 { 344 if (_hangingNodeModifications){ 345 auto dirichletValues = solution; 346 // Set all non dirichlet values to zero 347 Dune::PDELab::set_shifted_dofs(_gridOperator.localAssembler().trialConstraints(), 0.0, dirichletValues); 348 // Set all constrained DOFs to zero in solution 349 Dune::PDELab::set_constrained_dofs(_gridOperator.localAssembler().trialConstraints(), 0.0, solution); 350 // Copy correct Dirichlet values back into solution vector 351 Dune::PDELab::copy_constrained_dofs(_gridOperator.localAssembler().trialConstraints(), dirichletValues, solution); 352 // Interpolate periodic constraints / hanging nodes 353 _gridOperator.localAssembler().backtransform(solution); 354 } 355 356 _residual = 0.0; 357 _gridOperator.residual(solution, _residual); 358 359 // Use the maximum norm as a stopping criterion. This helps loosen the tolerance 360 // when solving for stationary solutions of nonlinear time-dependent problems. 361 // The default is to use the Euclidean norm (in the else-block) as before 362 if (_useMaxNorm){ 363 auto rankMax = Backend::native(_residual).infinity_norm(); 364 _result.defect = _gridOperator.testGridFunctionSpace().gridView().comm().max(rankMax); 365 } 366 else 367 _result.defect = _linearSolver.norm(_residual); 368 } 369 370 //! Set how much output you get setVerbosityLevel(unsigned int verbosity)371 void setVerbosityLevel(unsigned int verbosity) 372 { 373 if (_gridOperator.trialGridFunctionSpace().gridView().comm().rank()>0) 374 _verbosity = 0; 375 else 376 _verbosity = verbosity; 377 } 378 379 //! Get verbosity level getVerbosityLevel() const380 unsigned int getVerbosityLevel() const 381 { 382 return _verbosity; 383 } 384 385 //! Set reduction Newton needs to achieve setReduction(Real reduction)386 void setReduction(Real reduction) 387 { 388 _reduction = reduction; 389 } 390 391 //! Get reduction getReduction() const392 Real getReduction() const 393 { 394 return _reduction; 395 } 396 397 //! Set absolute convergence limit setAbsoluteLimit(Real absoluteLimit)398 void setAbsoluteLimit(Real absoluteLimit) 399 { 400 _absoluteLimit = absoluteLimit; 401 } 402 getAbsoluteLimit() const403 Real getAbsoluteLimit() const 404 { 405 return _absoluteLimit; 406 } 407 408 //! Set whether the jacobian matrix should be kept across calls to apply(). setKeepMatrix(bool b)409 void setKeepMatrix(bool b) 410 { 411 _keepMatrix = b; 412 } 413 414 //! Set whether to use the maximum norm for stopping criteria. setUseMaxNorm(bool b)415 void setUseMaxNorm(bool b) 416 { 417 _useMaxNorm = b; 418 } 419 420 //! Does the problem have hanging nodes setHangingNodeModifications(bool b)421 void setHangingNodeModifications(bool b) 422 { 423 _hangingNodeModifications = b; 424 } 425 426 427 //! Return whether the jacobian matrix is kept across calls to apply(). keepMatrix() const428 bool keepMatrix() const 429 { 430 return _keepMatrix; 431 } 432 433 //! Discard the stored Jacobian matrix. discardMatrix()434 void discardMatrix() 435 { 436 if(_jacobian) 437 _jacobian.reset(); 438 } 439 440 /**\brief Set the minimal reduction in the linear solver 441 * 442 * \note with minLinearReduction > 0, the linear reduction will be 443 * determined as mininum of the minLinearReduction and the linear reduction 444 * needed to achieve second order Newton convergence. (As long as you are 445 * not using a fixed linear reduction) 446 */ setMinLinearReduction(Real minLinearReduction)447 void setMinLinearReduction(Real minLinearReduction) 448 { 449 _minLinearReduction = minLinearReduction; 450 } 451 452 /** \brief Set wether to use a fixed reduction in the linear solver 453 * 454 * \note If fixedLinearReduction is true, the linear reduction rate will 455 * always be fixed to minLinearReduction. 456 */ setFixedLinearReduction(bool fixedLinearReduction)457 void setFixedLinearReduction(bool fixedLinearReduction) 458 { 459 _fixedLinearReduction = fixedLinearReduction; 460 } 461 462 /** \brief Set a threshold, when the linear operator is reassembled 463 * 464 * We allow to keep the linear operator over several newton iterations. If 465 * the reduction in the newton drops below a given threshold the linear 466 * operator is reassembled to ensure convergence. 467 */ setReassembleThreshold(Real reassembleThreshold)468 void setReassembleThreshold(Real reassembleThreshold) 469 { 470 _reassembleThreshold = reassembleThreshold; 471 } 472 473 /** \brief Interpret a parameter tree as a set of options for the newton solver 474 * 475 * Possible parameters: 476 * 477 * example configuration: 478 * 479 * \code 480 * [newton_parameters] 481 * ReassembleThreshold = 0.1 482 * AbsoluteLimit = 1e-6 483 * Reduction = 1e-4 484 * MinLinearReduction = 1e-3 485 * MaxIterations = 15 486 * LineSearchDampingFactor = 0.7 487 * \endcode 488 * 489 * and invocation in the code: 490 * \code 491 * newton.setParameters(param.sub("NewtonParameters")); 492 * \endcode 493 * 494 * This can also be used to set single parameters like this 495 * 496 * \code 497 * Dune::ParameterTree ptree; 498 * ptree["verbosity"] = "4"; 499 * newton.setParameters(ptree); 500 * \endcode 501 */ setParameters(const ParameterTree & parameterTree)502 void setParameters(const ParameterTree& parameterTree){ 503 _verbosity = parameterTree.get("VerbosityLevel", _verbosity); 504 _reduction = parameterTree.get("Reduction", _reduction); 505 _absoluteLimit = parameterTree.get("AbsoluteLimit", _absoluteLimit); 506 _keepMatrix = parameterTree.get("KeepMatrix", _keepMatrix); 507 _useMaxNorm = parameterTree.get("UseMaxNorm", _useMaxNorm); 508 _hangingNodeModifications = parameterTree.get("HangingNodeModifications", _hangingNodeModifications); 509 _minLinearReduction = parameterTree.get("MinLinearReduction", _minLinearReduction); 510 _fixedLinearReduction = parameterTree.get("FixedLinearReduction", _fixedLinearReduction); 511 _reassembleThreshold = parameterTree.get("ReassembleThreshold", _reassembleThreshold); 512 513 // first create the linesearch, depending on the parameter 514 std::string lineSearchStrategy = parameterTree.get("LineSearchStrategy","hackbuschReusken"); 515 auto strategy = lineSearchStrategyFromString(lineSearchStrategy); 516 _lineSearch = createLineSearch(*this, strategy); 517 518 // now set parameters 519 if (parameterTree.hasSub("Terminate")){ 520 _terminate->setParameters(parameterTree.sub("Terminate")); 521 } 522 else{ 523 ParameterTree terminateTree; 524 terminateTree["MaxIterations"] = std::to_string(parameterTree.get("MaxIterations", 40)); 525 terminateTree["ForceIteration"] = std::to_string(parameterTree.get("ForceIteration", false)); 526 _terminate->setParameters(terminateTree); 527 } 528 if (parameterTree.hasSub("LineSearch")){ 529 _lineSearch->setParameters(parameterTree.sub("LineSearch")); 530 } 531 else{ 532 ParameterTree lineSearchTree; 533 lineSearchTree["MaxIterations"] = std::to_string(parameterTree.get("LineSearchMaxIterations", 10)); 534 lineSearchTree["DampingFactor"] = std::to_string(parameterTree.get("LineSearchDampingFactor", 0.5)); 535 lineSearchTree["AcceptBest"] = std::to_string(parameterTree.get("LineSearchAcceptBest", false)); 536 _lineSearch->setParameters(lineSearchTree); 537 } 538 } 539 540 //! Set the termination criterion setTerminate(std::shared_ptr<TerminateInterface> terminate)541 void setTerminate(std::shared_ptr<TerminateInterface> terminate) 542 { 543 _terminate = terminate; 544 } 545 546 //! Return a pointer to the stored termination criterion getTerminate() const547 std::shared_ptr<TerminateInterface> getTerminate() const 548 { 549 return _terminate; 550 } 551 552 /**\brief Set the line search 553 * 554 * See getLineSearch() for already implemented line searches 555 */ setLineSearch(std::shared_ptr<LineSearch> lineSearch)556 void setLineSearch(std::shared_ptr<LineSearch> lineSearch) 557 { 558 _lineSearch = lineSearch; 559 } 560 561 //! Return a pointer to the stored line search getLineSearch() const562 std::shared_ptr<LineSearch> getLineSearch() const 563 { 564 return _lineSearch; 565 } 566 567 /**\brief Output NewtonMethod parameters 568 * 569 * Setting parameters using ParameterTree is quite error prone. 570 * Checking parameters without setting up the debugger can be useful. 571 */ printParameters(const std::string & _name="NewtonMethod") const572 void printParameters(const std::string& _name = "NewtonMethod") const 573 { 574 // Change boolalpha flag to output true/false in full, not 0/1. 575 // Restoring to previous setting is guaranteed. 576 auto ioflags = std::cout.flags(); 577 std::cout.setf(std::ios_base::boolalpha); 578 std::cout << _name << " parameters:\n"; 579 std::cout << "Verbosity............... " << _verbosity << std::endl; 580 std::cout << "Reduction............... " << _reduction << std::endl; 581 std::cout << "AbsoluteLimit........... " << _absoluteLimit << std::endl; 582 std::cout << "KeepMatrix.............. " << _keepMatrix << std::endl; 583 std::cout << "UseMaxNorm.............. " << _useMaxNorm << std::endl; 584 std::cout << "MinLinearReduction...... " << _minLinearReduction << std::endl; 585 std::cout << "FixedLinearReduction.... " << _fixedLinearReduction << std::endl; 586 std::cout << "ReassembleThreshold..... " << _reassembleThreshold << std::endl; 587 std::cout << "HangingNodeModifications " << _hangingNodeModifications << std::endl; 588 try 589 { 590 _terminate->printParameters(); 591 _lineSearch->printParameters(); 592 } 593 catch (...) 594 { 595 // guarantee restoring previous std::cout flags 596 std::cout.flags(ioflags); 597 throw; 598 } 599 std::cout.flags(ioflags); 600 } 601 602 //! Construct Newton using default parameters with default parameters 603 /** 604 in p 605 */ NewtonMethod(const GridOperator & gridOperator,LinearSolver & linearSolver)606 NewtonMethod( 607 const GridOperator& gridOperator, 608 LinearSolver& linearSolver) 609 : _gridOperator(gridOperator) 610 , _linearSolver(linearSolver) 611 , _residual(gridOperator.testGridFunctionSpace()) 612 , _correction(gridOperator.trialGridFunctionSpace()) 613 { 614 _terminate = std::make_shared<DefaultTerminate<NewtonMethod>> (*this); 615 _lineSearch = createLineSearch(*this, LineSearchStrategy::hackbuschReusken); 616 } 617 618 //! Construct Newton passing a parameter tree NewtonMethod(const GridOperator & gridOperator,LinearSolver & linearSolver,const ParameterTree & parameterTree)619 NewtonMethod( 620 const GridOperator& gridOperator, 621 LinearSolver& linearSolver, 622 const ParameterTree& parameterTree) 623 : _gridOperator(gridOperator) 624 , _linearSolver(linearSolver) 625 , _residual(gridOperator.testGridFunctionSpace()) 626 , _correction(gridOperator.trialGridFunctionSpace()) 627 628 { 629 _terminate = std::make_shared<DefaultTerminate<NewtonMethod>> (*this); 630 setParameters(parameterTree); 631 } 632 ~NewtonMethod()633 virtual ~NewtonMethod() {} 634 635 private: 636 const GridOperator& _gridOperator; 637 LinearSolver& _linearSolver; 638 639 // Vectors and Jacobi matrix we set up only once 640 Range _residual; 641 Domain _correction; 642 std::shared_ptr<Jacobian> _jacobian; 643 std::shared_ptr<Domain> _previousSolution; 644 645 std::shared_ptr<TerminateInterface> _terminate; 646 std::shared_ptr<LineSearch> _lineSearch; 647 648 // Class for storing results 649 Result _result; 650 bool _resultValid = false; // result class only valid after calling apply 651 Real _previousDefect = 0.0; 652 653 // Remember if jacobian was reassembled in prepareStep 654 bool _reassembled = true; // will be set in prepare step 655 Real _linearReduction = 0.0; // will be set in prepare step 656 657 // User parameters 658 unsigned int _verbosity = 0; 659 Real _reduction = 1e-8; 660 Real _absoluteLimit = 1e-12; 661 bool _keepMatrix = true; 662 bool _useMaxNorm = false; 663 664 // Special treatment if we have hanging nodes 665 bool _hangingNodeModifications = false; 666 667 // User parameters for prepareStep() 668 Real _minLinearReduction = 1e-3; 669 bool _fixedLinearReduction = false; 670 Real _reassembleThreshold = 0.0; 671 }; 672 673 } // namespace Dune::PDELab 674 675 #endif 676