ug4
gmres.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-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__LINEAR_OPERATOR__GMRES__
34 #define __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__GMRES__
35 
36 #include <iostream>
37 #include <string>
38 
42 #ifdef UG_PARALLEL
44 #endif
45 
46 namespace ug{
47 
49 
63 template <typename TVector>
64 class GMRES
65  : public IPreconditionedLinearOperatorInverse<TVector>
66 {
67  public:
69  typedef TVector vector_type;
70 
73 
74  protected:
79 
80  public:
82  GMRES(size_t restart) : m_restart(restart) {};
83 
85  GMRES( size_t restart,
88  : base_type(spPrecond, spConvCheck), m_restart(restart)
89  {};
90 
92  virtual const char* name() const {return "GMRES";}
93 
95  virtual bool supports_parallel() const
96  {
97  if(preconditioner().valid())
98  return preconditioner()->supports_parallel();
99  return true;
100  }
101 
102  // Solve J(u)*x = b, such that x = J(u)^{-1} b
104  {
105  // check correct storage type in parallel
106  #ifdef UG_PARALLEL
107  if(!b.has_storage_type(PST_ADDITIVE) || !x.has_storage_type(PST_CONSISTENT))
108  UG_THROW("GMRES: Inadequate storage format of Vectors.");
109  #endif
110 
111  // copy rhs
112  SmartPtr<vector_type> spR = b.clone();
113 
114  // build defect: b := b - A*x
115  linear_operator()->apply_sub(*spR, x);
116 
117  // prepare convergence check
119 
120  // compute start defect norm
121  convergence_check()->start(*spR);
122 
123  // storage for v, h, gamma
124  std::vector<SmartPtr<vector_type> > v(m_restart+1);
125  std::vector<std::vector<number> > h(m_restart+1);
126  for(size_t i = 0; i < h.size(); ++i) h[i].resize(m_restart+1);
127  std::vector<number> gamma(m_restart+1);
128  std::vector<number> c(m_restart+1);
129  std::vector<number> s(m_restart+1);
130 
131  // old norm
132  number oldNorm;
133 
134  // Iteration loop
135  while(!convergence_check()->iteration_ended())
136  {
137  // get storage for first vector v[0]
138  if(v[0].invalid()) v[0] = x.clone_without_values();
139 
140  // apply v[0] = M^-1 * (b-A*x)
141  if(preconditioner().valid()){
142  if(!preconditioner()->apply(*v[0], *spR)){
143  UG_LOG("GMRES: Cannot apply preconditioner to b-A*x0.\n");
144  return false;
145  }
146  }
147  // ... or reuse v[0] = (b-A*x)
148  else{
149  SmartPtr<vector_type> tmp = v[0]; v[0] = spR; spR = tmp;
150  }
151 
152  // make v[0] unique
153  #ifdef UG_PARALLEL
154  if(!v[0]->change_storage_type(PST_UNIQUE))
155  UG_THROW("GMRES: Cannot convert v0 to consistent vector.");
156  #endif
157 
158  // post-process the correction
159  m_corr_post_process.apply (*v[0]);
160 
161  // Compute norm of inital residuum:
162  oldNorm = gamma[0] = v[0]->norm();
163 
164  // normalize v[0] := v[0] / ||v[0]||
165  *v[0] *= 1./gamma[0];
166 
167  // loop gmres iterations
168  size_t numIter = 0;
169  for(size_t j = 0; j < m_restart; ++j)
170  {
171  numIter = j;
172 
173  // get storage for v[j+1]
174  if(v[j+1].invalid()) v[j+1] = x.clone_without_values();
175 
176 #ifdef UG_PARALLEL
177  if(!v[j]->change_storage_type(PST_CONSISTENT))
178  UG_THROW("GMRES: Cannot convert v["<<j+1<<"] to consistent vector.");
179 #endif
180 
181  // compute r = A*v[j]
182  linear_operator()->apply(*spR, *v[j]);
183 
184  // apply v[j+1] = M^-1 * A * v[j]
185  if(preconditioner().valid()){
186  if(!preconditioner()->apply(*v[j+1], *spR)){
187  UG_LOG("GMRES: Cannot apply preconditioner to A*v["<<j<<"].\n");
188  return false;
189  }
190  }
191  // ... or reuse v[j+1] = A * v[j]
192  else{
193  SmartPtr<vector_type> tmp = v[j+1]; v[j+1] = spR; spR = tmp;
194  }
195 
196  // make v[j], v[j+1] unique
197  #ifdef UG_PARALLEL
198  if(!v[j]->change_storage_type(PST_UNIQUE))
199  UG_THROW("GMRES: Cannot convert v0 to consistent vector.");
200  if(!v[j+1]->change_storage_type(PST_UNIQUE))
201  UG_THROW("GMRES: Cannot convert v["<<j<<"] to consistent vector.");
202  #endif
203 
204  // post-process the correction
205  m_corr_post_process.apply (*v[j+1]);
206 
207  // loop previous steps
208  for(size_t i = 0; i <= j; ++i)
209  {
210  // h_ij := (r, v[j])
211  h[i][j] = VecProd(*v[j+1], *v[i]);
212 
213  // v[j+1] -= h_ij * v[i]
214  VecScaleAppend(*v[j+1], *v[i], (-1)*h[i][j]);
215  }
216 
217  // compute h_{j+1,j}
218  h[j+1][j] = v[j+1]->norm();
219 
220  // update h
221  for(size_t i = 0; i < j; ++i)
222  {
223  const number hij = h[i][j];
224  const number hi1j = h[i+1][j];
225 
226  h[i][j] = c[i+1]*hij + s[i+1]*hi1j;
227  h[i+1][j] = s[i+1]*hij - c[i+1]*hi1j;
228  }
229 
230  // alpha := sqrt(h_jj ^2 + h_{j+1,j}^2)
231  const number alpha = sqrt(h[j][j]*h[j][j] + h[j+1][j]*h[j+1][j]);
232 
233  // update s, c
234  s[j+1] = h[j+1][j] / alpha;
235  c[j+1] = h[j][j] / alpha;
236  h[j][j] = alpha;
237 
238  // compute new norm
239  gamma[j+1] = s[j+1]*gamma[j];
240  gamma[j] = c[j+1]*gamma[j];
241 
242  if(preconditioner().valid()) {
243  UG_LOG(std::string(convergence_check()->get_offset(),' '));
244  UG_LOG("% GMRES "<<std::setw(4) <<j+1<<": "
245  << gamma[j+1] << " " << gamma[j+1] / oldNorm);
246  UG_LOG(" (in Precond-Norm) \n");
247  oldNorm = gamma[j+1];
248  }
249  else{
250  convergence_check()->update_defect(gamma[j+1]);
251  }
252 
253  // normalize v[j+1]
254  *v[j+1] *= 1./(h[j+1][j]);
255  }
256 
257  // compute current x
258  for(size_t i = numIter; ; --i){
259  for(size_t j = i+1; j <= numIter; ++j)
260  gamma[i] -= h[i][j] * gamma[j];
261 
262  gamma[i] /= h[i][i];
263 
264  // x = x + gamma[i] * v[i]
265  VecScaleAppend(x, *v[i], gamma[i]);
266 
267  if(i == 0) break;
268  }
269 
270  // compute fresh defect: b := b - A*x
271  *spR = b;
272  linear_operator()->apply_sub(*spR, x);
273 
274  if(preconditioner().valid())
275  convergence_check()->update(*spR);
276  }
277 
278  // print ending output
279  return convergence_check()->post();
280  }
281 
282  public:
283  virtual std::string config_string() const
284  {
285  std::stringstream ss;
286  ss << "GMRes ( restart = " << m_restart << ")\n";
288  return ss.str();
289  }
290 
293  {
295  }
296 
299  {
301  }
302 
303  protected:
306  {
307  // set iteration symbol and name
308  convergence_check()->set_name(name());
309  convergence_check()->set_symbol('%');
310 
311  // set preconditioner string
312  std::string s;
313  if(preconditioner().valid())
314  s = std::string(" (Precond: ") + preconditioner()->name() + ")";
315  else
316  s = " (No Preconditioner) ";
317  convergence_check()->set_info(s);
318  }
319 
320  protected:
322  size_t m_restart;
323 
325 
331 
334  {
335  #ifdef UG_PARALLEL
336  if(a.has_storage_type(PST_UNIQUE) && b.has_storage_type(PST_UNIQUE));
337  else if(a.has_storage_type(PST_CONSISTENT) && b.has_storage_type(PST_CONSISTENT));
338  else if (a.has_storage_type(PST_ADDITIVE) && b.has_storage_type(PST_ADDITIVE));
339  else
340  {
341  a.change_storage_type(PST_ADDITIVE);
342  b.change_storage_type(PST_ADDITIVE);
343  }
344  #endif
345 
346  for(size_t i = 0; i < a.size(); ++i)
347  {
348  // todo: move VecScaleAppend to ParallelVector
349  VecScaleAdd(a[i], 1.0, a[i], s, b[i]);
350  }
351  return true;
352  }
353 
356  {
357  return a.dotprod(b);
358  }
359 };
360 
361 } // end namespace ug
362 
363 #endif /* __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__GMRES__ */
parameterString p
parameterString s
Definition: smart_pointer.h:108
the GMREs method as a solver for linear operators
Definition: gmres.h:66
void remove_postprocess_corr(SmartPtr< IPProcessVector< vector_type > > p)
removes a post-process for the iterates
Definition: gmres.h:298
virtual std::string config_string() const
returns information about configuration parameters
Definition: gmres.h:283
TVector vector_type
Vector type.
Definition: gmres.h:69
number VecProd(vector_type &a, vector_type &b)
computes the vector product
Definition: gmres.h:355
virtual bool apply_return_defect(vector_type &x, vector_type &b)
Definition: gmres.h:103
size_t m_restart
restart parameter
Definition: gmres.h:322
void prepare_conv_check()
prepares the output of the convergence check
Definition: gmres.h:305
virtual const char * name() const
name of solver
Definition: gmres.h:92
GMRES(size_t restart, SmartPtr< ILinearIterator< vector_type > > spPrecond, SmartPtr< IConvergenceCheck< vector_type > > spConvCheck)
constructor setting the preconditioner and the convergence check
Definition: gmres.h:85
void add_postprocess_corr(SmartPtr< IPProcessVector< vector_type > > p)
adds a post-process for the iterates
Definition: gmres.h:292
virtual bool supports_parallel() const
returns if parallel solving is supported
Definition: gmres.h:95
PProcessChain< vector_type > m_corr_post_process
postprocessor for the correction in the iterations
Definition: gmres.h:330
GMRES(size_t restart)
default constructor
Definition: gmres.h:82
IPreconditionedLinearOperatorInverse< vector_type > base_type
Base type.
Definition: gmres.h:72
SmartPtr< ILinearIterator< X, X > > preconditioner()
Definition: preconditioned_linear_operator_inverse.h:118
bool VecScaleAppend(vector_type &a, vector_type &b, number s)
adds a scaled vector to a second one
Definition: gmres.h:333
Definition: convergence_check.h:72
describes a linear iterator
Definition: linear_iterator.h:81
ConstSmartPtr< IConvergenceCheck< X > > convergence_check() const
returns the convergence check
Definition: linear_operator_inverse.h:202
SmartPtr< ILinearOperator< Y, X > > linear_operator()
returns the current Operator this Inverse Operator is initialized for
Definition: linear_operator_inverse.h:227
interface for pre- and postprocess functions
Definition: pprocess.h:59
describes an inverse linear mapping X->X
Definition: preconditioned_linear_operator_inverse.h:63
virtual bool apply(TVector &x, const TVector &b)
Definition: preconditioned_linear_operator_inverse.h:152
SmartPtr< ILinearIterator< X, X > > preconditioner()
Definition: preconditioned_linear_operator_inverse.h:118
std::string config_string_preconditioner_convergence_check() const
returns config information of convergence check and preconditioner
Definition: preconditioned_linear_operator_inverse.h:200
void add(SmartPtr< p_process_type > p)
adds an operation at the end of the chain
Definition: pprocess.h:96
void apply(vector_type &v)
performs all the operations
Definition: pprocess.h:86
void remove(SmartPtr< p_process_type > p)
removes an operation from the chain
Definition: pprocess.h:108
void write_debug(const vector_type &vec, const char *filename)
writing debug output for a vector (if debug writer set)
Definition: debug_writer.h:293
TVector vector_type
type of vector
Definition: debug_writer.h:269
@ PST_CONSISTENT
Definition: parallel_storage_type.h:68
@ PST_UNIQUE
Definition: parallel_storage_type.h:70
@ PST_ADDITIVE
Definition: parallel_storage_type.h:69
number alpha
#define UG_THROW(msg)
Definition: error.h:57
#define UG_LOG(msg)
Definition: log.h:367
double number
Definition: types.h:124
void VecScaleAdd(vector_t &vOut, typename vector_t::value_type s1, const vector_t &v1, typename vector_t::value_type s2, const vector_t &v2)
Scales two Vectors, adds them and returns the sum in a third vector.
Definition: math_vector_functions_common_impl.hpp:265
the ug namespace
bool resize(size_t newRows, size_t newCols)