ug4
newton_impl.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt
3  * Author: Andreas Vogel
4  *
5  * This file is part of UG4.
6  *
7  * UG4 is free software: you can redistribute it and/or modify it under the
8  * terms of the GNU Lesser General Public License version 3 (as published by the
9  * Free Software Foundation) with the following additional attribution
10  * requirements (according to LGPL/GPL v3 §7):
11  *
12  * (1) The following notice must be displayed in the Appropriate Legal Notices
13  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
14  *
15  * (2) The following notice must be displayed at a prominent place in the
16  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
17  *
18  * (3) The following bibliography is recommended for citation and must be
19  * preserved in all covered files:
20  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
21  * parallel geometric multigrid solver on hierarchically distributed grids.
22  * Computing and visualization in science 16, 4 (2013), 151-164"
23  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
24  * flexible software system for simulating pde based models on high performance
25  * computers. Computing and visualization in science 16, 4 (2013), 165-179"
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30  * GNU Lesser General Public License for more details.
31  */
32 
33 #ifndef __H__UG__LIB_DISC__OPERATOR__NON_LINEAR_OPERATOR__NEWTON_SOLVER__NEWTON_IMPL__
34 #define __H__UG__LIB_DISC__OPERATOR__NON_LINEAR_OPERATOR__NEWTON_SOLVER__NEWTON_IMPL__
35 
36 #include <iostream>
37 #include <sstream>
38 
39 #include "newton.h"
42 
43 #define PROFILE_NEWTON
44 #ifdef PROFILE_NEWTON
45  #define NEWTON_PROFILE_FUNC() PROFILE_FUNC_GROUP("Newton")
46  #define NEWTON_PROFILE_BEGIN(name) PROFILE_BEGIN_GROUP(name, "Newton")
47  #define NEWTON_PROFILE_END() PROFILE_END()
48 #else
49  #define NEWTON_PROFILE_FUNC()
50  #define NEWTON_PROFILE_BEGIN(name)
51  #define NEWTON_PROFILE_END()
52 #endif
53 
54 namespace ug{
55 
56 template <typename TAlgebra>
60  SmartPtr<ILineSearch<vector_type> > spLineSearch) :
61  m_spLinearSolver(LinearSolver),
62  m_spConvCheck(spConvCheck),
63  m_spLineSearch(spLineSearch),
64  m_N(NULL),
65  m_J(NULL),
66  m_spAss(NULL),
67  m_reassembe_J_freq(0),
68  m_dgbCall(0),
69  m_lastNumSteps(0)
70 {};
71 
72 template <typename TAlgebra>
74 NewtonSolver() :
75  m_spLinearSolver(NULL),
76  m_spConvCheck(new StdConvCheck<vector_type>(10, 1e-8, 1e-10, true)),
77  m_spLineSearch(NULL),
78  m_N(NULL),
79  m_J(NULL),
80  m_spAss(NULL),
81  m_reassembe_J_freq(0),
82  m_dgbCall(0),
83  m_lastNumSteps(0)
84 {};
85 
86 template <typename TAlgebra>
89  m_spLinearSolver(NULL),
90  m_spConvCheck(new StdConvCheck<vector_type>(10, 1e-8, 1e-10, true)),
91  m_spLineSearch(NULL),
92  m_N(NULL),
93  m_J(NULL),
94  m_spAss(NULL),
95  m_reassembe_J_freq(0),
96  m_dgbCall(0),
97  m_lastNumSteps(0)
98 {
99  init(N);
100 };
101 
102 template <typename TAlgebra>
105  m_spLinearSolver(NULL),
106  m_spConvCheck(new StdConvCheck<vector_type>(10, 1e-8, 1e-10, true)),
107  m_spLineSearch(NULL),
108  m_N(NULL),
109  m_J(NULL),
110  m_spAss(NULL),
111  m_reassembe_J_freq(0),
112  m_dgbCall(0),
113  m_lastNumSteps(0)
114 {
115  m_spAss = spAss;
117 };
118 
119 template <typename TAlgebra>
122 {
123  m_spConvCheck = spConvCheck;
124  m_spConvCheck->set_offset(3);
125  m_spConvCheck->set_symbol('#');
126  m_spConvCheck->set_name("Newton Solver");
127 }
128 
129 template <typename TAlgebra>
131 {
132  NEWTON_PROFILE_BEGIN(NewtonSolver_init);
133  m_N = N.template cast_dynamic<AssembledOperator<TAlgebra> >();
134  if(m_N.invalid())
135  UG_THROW("NewtonSolver: currently only works for AssembledDiscreteOperator.");
136 
137  m_spAss = m_N->discretization();
138  return true;
139 }
140 
141 template <typename TAlgebra>
143 {
144 // todo: maybe remove this from interface
145  return true;
146 }
147 
148 template <typename TAlgebra>
150 {
151  NEWTON_PROFILE_BEGIN(NewtonSolver_apply);
152 // increase call count
153  m_dgbCall++;
154 
155 // Check for linear solver
156  if(m_spLinearSolver.invalid())
157  UG_THROW("NewtonSolver::apply: Linear Solver not set.");
158 
159 // Jacobian
160  if(m_J.invalid() || m_J->discretization() != m_spAss) {
161  m_J = make_sp(new AssembledLinearOperator<TAlgebra>(m_spAss));
162  }
163  m_J->set_level(m_N->level());
164 
165 // create tmp vectors
166  SmartPtr<vector_type> spD = u.clone_without_values();
167  SmartPtr<vector_type> spC = u.clone_without_values();
168 
169 // Set dirichlet values
170  try{
171  m_N->prepare(u);
172  }
173  UG_CATCH_THROW("NewtonSolver::prepare: Prepare of Operator failed.");
174 
175 // Compute first Defect
176  try{
177  NEWTON_PROFILE_BEGIN(NewtonComputeDefect1);
178  m_N->apply(*spD, u);
180  }UG_CATCH_THROW("NewtonSolver::apply: Computation of Start-Defect failed.");
181 
182 // loop counts (for the the convergence rate statistics etc.)
183  int loopCnt = 0;
184  m_lastNumSteps = 0;
185 
186 // write start defect for debug
187  char debug_name_ext[20];
188  if (this->debug_writer_valid())
189  {
190  sprintf(debug_name_ext, "_iter%03d", loopCnt);
191  write_debug(*spD, std::string("NEWTON_Defect") + debug_name_ext);
192  write_debug(u, "NEWTON_StartSolution");
193  }
194 
195 // increase offset of output for linear solver
196  const int stdLinOffset = m_spLinearSolver->standard_offset();
197  m_spLinearSolver->convergence_check()->set_offset(stdLinOffset + 3);
198 
199 // set info string indicating the used linear solver
200  std::stringstream ss; ss << "(Linear Solver: " << m_spLinearSolver->name() << ")";
201  m_spConvCheck->set_info(ss.str());
202 
203 // start convergence check
204  m_spConvCheck->start(*spD);
205 
206  for(size_t i = 0; i < m_stepUpdate.size(); ++i)
207  m_stepUpdate[i]->update();
208 
209 // loop iteration
210  while(!m_spConvCheck->iteration_ended())
211  {
212  m_lastNumSteps = loopCnt;
213 
214  // set c = 0
215  NEWTON_PROFILE_BEGIN(NewtonSetCorretionZero);
216  spC->set(0.0);
218 
219  for(size_t i = 0; i < m_innerStepUpdate.size(); ++i)
220  m_innerStepUpdate[i]->update();
221 
222  // Compute Jacobian
223  try{
224  if(m_reassembe_J_freq == 0 || loopCnt % m_reassembe_J_freq == 0) // if we need to reassemble
225  {
226  NEWTON_PROFILE_BEGIN(NewtonComputeJacobian);
227  m_J->init(u);
229  }
230  }UG_CATCH_THROW("NewtonSolver::apply: Initialization of Jacobian failed.");
231 
232  // Write the current Jacobian for debug and prepare the section for the lin. solver
233  if (this->debug_writer_valid())
234  {
235  write_debug(m_J->get_matrix(), std::string("NEWTON_Jacobian") + debug_name_ext);
236  this->enter_debug_writer_section(std::string("NEWTON_LinSolver") + debug_name_ext);
237  }
238 
239  // Init Jacobi Inverse
240  try{
241  NEWTON_PROFILE_BEGIN(NewtonPrepareLinSolver);
242  if(!m_spLinearSolver->init(m_J, u))
243  {
244  UG_LOG("ERROR in 'NewtonSolver::apply': Cannot init Inverse Linear "
245  "Operator for Jacobi-Operator.\n");
246  return false;
247  }
249  }UG_CATCH_THROW("NewtonSolver::apply: Initialization of Linear Solver failed.");
250 
251  // Solve Linearized System
252  try{
253  NEWTON_PROFILE_BEGIN(NewtonApplyLinSolver);
254  if(!m_spLinearSolver->apply(*spC, *spD))
255  {
256  UG_LOG("ERROR in 'NewtonSolver::apply': Cannot apply Inverse Linear "
257  "Operator for Jacobi-Operator.\n");
258  return false;
259  }
261  }UG_CATCH_THROW("NewtonSolver::apply: Application of Linear Solver failed.");
262 
263  this->leave_debug_writer_section();
264 
265  // store convergence history
266  const int numSteps = m_spLinearSolver->step();
267  if(loopCnt >= (int)m_vTotalLinSolverSteps.size()) m_vTotalLinSolverSteps.resize(loopCnt+1);
268  if(loopCnt >= (int)m_vLinSolverCalls.size()) m_vLinSolverCalls.resize(loopCnt+1, 0);
269  if(loopCnt >= (int)m_vLinSolverRates.size()) m_vLinSolverRates.resize(loopCnt+1, 0);
270  m_vTotalLinSolverSteps[loopCnt] += numSteps;
271  m_vLinSolverCalls[loopCnt] += 1;
272  m_vLinSolverRates[loopCnt] += m_spLinearSolver->convergence_check()->avg_rate();
273 
274  try{
275  // Line Search
276  if(m_spLineSearch.valid())
277  {
278  m_spLineSearch->set_offset(" # ");
279  NEWTON_PROFILE_BEGIN(NewtonLineSearch);
280  if(!m_spLineSearch->search(m_N, u, *spC, *spD, m_spConvCheck->defect()))
281  {
282  UG_LOG("ERROR in 'NewtonSolver::apply': "
283  "Newton Solver did not converge.\n");
284  return false;
285  }
287  }
288  // No line search: Compute new defect
289  else
290  {
291  // update solution
292  u -= *spC;
293 
294  // compute new Defect
295  NEWTON_PROFILE_BEGIN(NewtonComputeDefect);
296  m_N->prepare(u);
297  m_N->apply(*spD, u);
299  }
300  }UG_CATCH_THROW("NewtonSolver::apply: Line Search update failed.");
301 
302 
303  // update counter
304  loopCnt++;
305 
306  // check convergence
307  m_spConvCheck->update(*spD);
308  if(loopCnt-1 >= (int)m_vNonLinSolverRates.size()) m_vNonLinSolverRates.resize(loopCnt, 0);
309  m_vNonLinSolverRates[loopCnt-1] += m_spConvCheck->rate();
310 
311  // write defect for debug
312  if (this->debug_writer_valid())
313  {
314  sprintf(debug_name_ext, "_iter%03d", loopCnt);
315  write_debug(*spD, std::string("NEWTON_Defect") + debug_name_ext);
316  write_debug(*spC, std::string("NEWTON_Correction") + debug_name_ext);
317  write_debug(u, std::string("NEWTON_Solution") + debug_name_ext);
318  }
319  }
320 
321  // reset offset of output for linear solver to previous value
322  m_spLinearSolver->convergence_check()->set_offset(stdLinOffset);
323 
324  return m_spConvCheck->post();
325 }
326 
327 template <typename TAlgebra>
329 {
330  UG_LOG("\nNewton solver convergence history:\n");
331  UG_LOG("Newton Step | Num Calls | Total Lin Iters | Avg Lin Iters | Avg Nonlin Rates | Avg Lin Rates \n");
332  int allCalls = 0, allLinSteps = 0;
333  number allLinRatesProduct = 1.0, allNonLinRatesProduct = 1.0;
334  for(int call = 0; call < (int)m_vLinSolverCalls.size(); ++call)
335  {
336  UG_LOG( " " << std::setw(10) << call+1 << " | ");
337  UG_LOG(std::setw(9) << m_vLinSolverCalls[call] << " | ");
338  allCalls += m_vLinSolverCalls[call];
339  UG_LOG(std::setw(15) << m_vTotalLinSolverSteps[call] << " | ");
340  allLinSteps += m_vTotalLinSolverSteps[call];
341  UG_LOG(std::setw(13) << std::setprecision(2) << std::fixed << m_vTotalLinSolverSteps[call] / (double)m_vLinSolverCalls[call] << " | ");
342  allNonLinRatesProduct *= pow((number)m_vNonLinSolverRates[call]/(double)m_vLinSolverCalls[call],(double)m_vLinSolverCalls[call]);
343  UG_LOG(std::setw(16) << std::setprecision(6) << std::scientific << m_vNonLinSolverRates[call] / (double)m_vLinSolverCalls[call] << " | ");
344  allLinRatesProduct *= (number)std::pow((number)m_vLinSolverRates[call]/(double)m_vLinSolverCalls[call],(number)m_vTotalLinSolverSteps[call]);
345  UG_LOG(std::setw(13) << std::setprecision(6) << std::scientific << m_vLinSolverRates[call] / (double)m_vLinSolverCalls[call]);
346  UG_LOG("\n");
347  }
348  UG_LOG( " all | ");
349  UG_LOG(std::setw(9) << allCalls << " | ");
350  UG_LOG(std::setw(15) << allLinSteps << " | ");
351  UG_LOG(std::setw(13) << std::setprecision(2) << std::fixed << allLinSteps / (number)allCalls << " | ");
352  UG_LOG(std::setw(16) << std::setprecision(6) << std::scientific << std::pow((number)allNonLinRatesProduct,(number)1.0/(number)allCalls) << " | ");
353  UG_LOG(std::setw(13) << std::setprecision(6) << std::scientific << std::pow((number)allLinRatesProduct,(number)1.0/(number)allLinSteps));
354  UG_LOG("\n");
355 }
356 
357 template <typename TAlgebra>
359 {
360  return m_vLinSolverCalls.size();
361 }
362 
363 template <typename TAlgebra>
365 {
366  return m_vLinSolverCalls[call];
367 }
368 
369 template <typename TAlgebra>
371 {
372  return m_vTotalLinSolverSteps[call];
373 }
374 
375 template <typename TAlgebra>
377 {
378  return m_vTotalLinSolverSteps[call] / ((double)m_vLinSolverCalls[call]);
379 }
380 
381 template <typename TAlgebra>
383 {
384  int allCalls = 0;
385  for(size_t call = 0; call < m_vLinSolverCalls.size(); ++call)
386  allCalls += m_vLinSolverCalls[call];
387  return allCalls;
388 }
389 
390 template <typename TAlgebra>
392 {
393  int allSteps = 0;
394  for(size_t call = 0; call < m_vLinSolverCalls.size(); ++call)
395  allSteps += m_vTotalLinSolverSteps[call];
396  return allSteps;
397 }
398 
399 template <typename TAlgebra>
401 {
402  return total_linsolver_steps()/((double)total_linsolver_calls());
403 }
404 
405 
406 template <typename TAlgebra>
408 {
409  m_vLinSolverRates.clear();
410  m_vNonLinSolverRates.clear();
411  m_vLinSolverCalls.clear();
412  m_vTotalLinSolverSteps.clear();
413 }
414 
415 template <typename TAlgebra>
417 {
418 // add call count to name
419  char ext[20]; sprintf(ext, "_call%03d", m_dgbCall);
420 
421 // write
422  typedef DebugWritingObject<TAlgebra> base_writer_type;
423  base_writer_type::write_debug(vec, name + ext);
424 }
425 
426 template <typename TAlgebra>
428 {
429 // add call count to name
430  char ext[20]; sprintf(ext, "_call%03d", m_dgbCall);
431 
432 // write
433  typedef DebugWritingObject<TAlgebra> base_writer_type;
434  base_writer_type::write_debug(mat, name + ext);
435 }
436 
437 template <typename TAlgebra>
439 {
440  std::stringstream ss;
441  ss << "NewtonSolver\n";
442  ss << " LinearSolver: ";
443  if(m_spLinearSolver.valid()) ss << ConfigShift(m_spLinearSolver->config_string()) << "\n";
444  else ss << " NOT SET!\n";
445  ss << " ConvergenceCheck: ";
446  if(m_spConvCheck.valid()) ss << ConfigShift(m_spConvCheck->config_string()) << "\n";
447  else ss << " NOT SET!\n";
448  ss << " LineSearch: ";
449  if(m_spLineSearch.valid()) ss << ConfigShift(m_spLineSearch->config_string()) << "\n";
450  else ss << " not set.\n";
451  if(m_reassembe_J_freq != 0) ss << " Reassembling Jacobian only once per " << m_reassembe_J_freq << " step(s)\n";
452  return ss.str();
453 }
454 
455 
456 }
457 
458 #endif /* __H__UG__LIB_DISC__OPERATOR__NON_LINEAR_OPERATOR__NEWTON_SOLVER__NEWTON_IMPL__ */
459 
location name
Definition: checkpoint_util.lua:128
Definition: smart_pointer.h:108
matrix operator based on the assembling of a problem
Definition: assembled_linear_operator.h:60
Definition: assembled_non_linear_operator.h:43
Definition: debug_writer.h:354
TAlgebra::vector_type vector_type
type of vector
Definition: debug_writer.h:360
TAlgebra::matrix_type matrix_type
type of matrix
Definition: debug_writer.h:363
Interface providing Jacobian and Defect of a discretization.
Definition: assemble_interface.h:110
Definition: convergence_check.h:72
Definition: line_search.h:60
describes an inverse linear mapping X->Y
Definition: linear_operator_inverse.h:80
describes a mapping X->Y
Definition: operator.h:86
linear solver using abstract preconditioner interface
Definition: linear_solver.h:57
int total_linsolver_calls() const
Definition: newton_impl.h:382
void clear_average_convergence()
resets average linear solver convergence
Definition: newton_impl.h:407
virtual bool prepare(vector_type &u)
prepare Operator
Definition: newton_impl.h:142
virtual bool apply(vector_type &u)
apply Operator, i.e. N^{-1}(0) = u
Definition: newton_impl.h:149
NewtonSolver()
default constructor
Definition: newton_impl.h:74
virtual bool init(SmartPtr< IOperator< vector_type > > N)
This operator inverts the Operator N: Y -> X.
Definition: newton_impl.h:130
int num_linsolver_steps(size_t call) const
Definition: newton_impl.h:370
void write_debug(const vector_type &vec, std::string filename)
Definition: newton_impl.h:416
double total_average_linear_steps() const
Definition: newton_impl.h:400
virtual std::string config_string() const
returns information about configuration parameters
Definition: newton_impl.h:438
double average_linear_steps(size_t call) const
Definition: newton_impl.h:376
SmartPtr< AssembledOperator< algebra_type > > m_N
assembling routine
Definition: newton.h:173
void print_average_convergence() const
prints average linear solver convergence
Definition: newton_impl.h:328
size_t num_newton_steps() const
Definition: newton_impl.h:358
void set_convergence_check(SmartPtr< IConvergenceCheck< vector_type > > spConvCheck)
sets the convergence check
Definition: newton_impl.h:121
SmartPtr< IAssemble< TAlgebra > > m_spAss
assembling
Definition: newton.h:177
int num_linsolver_calls(size_t call) const
Definition: newton_impl.h:364
int total_linsolver_steps() const
Definition: newton_impl.h:391
Definition: convergence_check.h:179
function common sprintf(s,...)
#define UG_CATCH_THROW(msg)
Definition: error.h:64
#define UG_THROW(msg)
Definition: error.h:57
#define UG_LOG(msg)
Definition: log.h:367
double number
Definition: types.h:124
the ug namespace
string ConfigShift(string s)
Definition: string_util.cpp:457
#define NEWTON_PROFILE_END()
Definition: newton_impl.h:47
#define NEWTON_PROFILE_BEGIN(name)
Definition: newton_impl.h:46
SmartPtr< T, FreePolicy > make_sp(T *inst)
returns a SmartPtr for the passed raw pointer
Definition: smart_pointer.h:836