ug4
auto_linear_solver.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2015: G-CSC, Goethe University Frankfurt
3  * Author: Martin Rupp
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__AUTO_LINEAR_OPERATOR__LINEAR_SOLVER__
34 #define __H__UG__LIB_DISC__OPERATOR__AUTO_LINEAR_OPERATOR__LINEAR_SOLVER__
35 #include <iostream>
36 #include <string>
37 
40 #ifdef UG_PARALLEL
42 #endif
44 namespace ug{
45 
46 // this is for matrix operators which recalculate their "real" operator
47 // if necessary
49 {
50 public:
52  virtual void calculate_matrix() = 0;
53 };
54 
56 
62 template <typename TVector>
64  : public IPreconditionedLinearOperatorInverse<TVector>
65 {
66  public:
68  typedef TVector vector_type;
69 
72 
73  protected:
78 
79  public:
80  AutoLinearSolver //(double reductionAlwaysAccept, double worseThenAverage, double desiredDefect)
81  (double desiredDefect, double desiredReduction)
82  {
83  m_bInited=-1;
84 // m_N = 0;
85 // m_reductionAlwaysAccept = reductionAlwaysAccept;
86 // m_worseThenAverage = worseThenAverage;
87  m_desiredDefect = desiredDefect;
88  m_desiredReduction = desiredReduction;
90  m_savedTime = 0.0;
91  }
93  {
94  m_bInited=-1;
95 // m_N = 0;
97  m_worseThenAverage = 2.0;
99  m_savedTime = 0.0;
100  }
101 
103  virtual bool supports_parallel() const
104  {
105  if(preconditioner().valid())
106  return preconditioner()->supports_parallel();
107  else return true;
108  }
109 
110 private:
114 // size_t m_N;
118  size_t m_initsDone;
119  size_t m_initCalled;
120 
124  double m_savedTime;
125 
126  public:
127 
129  {
131  }
132 
134  {
135  m_worseThenAverage = d;
136  }
137 
139  virtual const char* name() const {return "Auto Iterative Linear Solver";}
140 
141 
143  {
144  m_u = u;
145  return init_op(J);
146  }
148  {
149  m_u.resize(0);
150  return init_op(J);
151  }
152 
154  {
156  //UG_LOG("ALS:init\n");
157  m_initCalled++;
158  if(m_bInited == -1)
159  {
160  m_bInited=false;
161  pJ = J;
162  reinit();
163  }
164  else
165  {
166  m_bInited=false;
167  pJ = J;
168 // if(u.size() != m_N)
169 // reinit(u);
170 // else
171 // m_u = u;
172  }
173 
174  return true;
175  }
176 
177  bool reinit()
178  {
179  if(m_bInited) return true;
180  m_bInited = true;
181  //UG_LOG("ALS:reinit\n");
182 
183  double tStart = get_clock_s();
184  // this does not work with stuff.
185  SmartPtr<UpdateableMatrixOperator> uo = pJ.template cast_dynamic<UpdateableMatrixOperator> ();
186  if(uo.valid()) uo->calculate_matrix();
187  if(m_u.size() != 0.0)
188  { if(!base_type::init(pJ, m_u)) return false; }
189  else if(!base_type::init(pJ)) return false;
190  m_lastInitTime = get_clock_s()-tStart;
191 
192  m_initsDone++;
193 
194 // m_N = u.size();
195 
196  return true;
197  }
198 
200  {
201  // Compute a correction c := B*d using one iterative step
202  // Internally the defect is updated d := d - A*c = b - A*(x+c)
203  if(preconditioner().valid()) {
204  LS_PROFILE_BEGIN(LS_ApplyPrecond);
205 
206  if(!preconditioner()->apply(c, d))
207  {
208  UG_LOG("ERROR in 'LinearSolver::apply': Iterator "
209  "Operator applied incorrectly. Aborting.\n");
210  return false;
211  }
212  linear_operator()->apply_sub(d, c);
213  LS_PROFILE_END(LS_ApplyPrecond);
214  }
215 
216  return true;
217  }
218 
219  virtual bool apply(vector_type& x, const vector_type& b)
220  {
221  //UG_LOG("ALS:apply\n");
222  SmartPtr<vector_type> spB = b.clone_without_values();
223  *spB = b;
224  return apply_return_defect(x, *spB);
225  }
228  {
229  //UG_LOG("ALS:return_defect\n");
230  LS_PROFILE_BEGIN(LS_ApplyReturnDefect);
231 
232  #ifdef UG_PARALLEL
233  if(!b.has_storage_type(PST_ADDITIVE) || !x.has_storage_type(PST_CONSISTENT))
234  UG_THROW("LinearSolver::apply: Inadequate storage format of Vectors.");
235  #endif
236 
237  // rename b as d (for convenience)
238  vector_type& d = b;
239 
240  // build defect: d := b - J(u)*x
241  LS_PROFILE_BEGIN(LS_BuildDefect);
242  linear_operator()->apply_sub(d, x);
243  LS_PROFILE_END(LS_BuildDefect);
244 
245  // create correction
246  LS_PROFILE_BEGIN(LS_CreateCorrection);
247  SmartPtr<vector_type> spC = x.clone_without_values();
248  vector_type& c = *spC;
249  LS_PROFILE_END(LS_CreateCorrection);
250 
251  LS_PROFILE_BEGIN(LS_ComputeStartDefect);
253  convergence_check()->start(d);
254  LS_PROFILE_END(LS_ComputeStartDefect);
255 
256  int loopCnt = 0;
257  char ext[20]; snprintf(ext, 20, "_iter%03d", loopCnt);
258  std::string name("LS_Defect_"); name.append(ext).append(".vec");
259  write_debug(d, name.c_str());
260  name = std::string("LS_Solution_"); name.append(ext).append(".vec");
261  write_debug(x, name.c_str());
262 
263  // Iteration loop
264 
265  if(m_bInited == false)
266  {
267  vector_type x2 = x;
268  vector_type d2 = d;
269  try{
270  double tStartIterationTime = get_clock_s();
271  while(!convergence_check()->iteration_ended())
272  {
273  //double tComputeTime = get_clock_s();
274  if( !compute_correction(c, d) ) return false;
275  x += c;
276  convergence_check()->update(d);
277 
278 
279  double r = convergence_check()->rate();
280  double reduction = convergence_check()->reduction();
281  double defect = convergence_check()->defect();
282  double steps = convergence_check()->step();
283 // if(r > m_reductionAlwaysAccept
284 // && (r >= 1 || r * m_worseThenAverage > m_avgReduction))
285  double spentTime = get_clock_s() - tStartIterationTime;
286 
287  double tComputeTime = spentTime/steps; //get_clock_s()-tComputeTime;
288 
289 // double timeForOriginalAlgorithm = reduction/m_reductionPerTime + m_lastInitTime;
290  double approxSteps =
291  std::min(log(m_desiredDefect/defect)/log(r),
292  log(m_desiredReduction/reduction)/log(r) );
293  double approxRemainingTimeForSolution = approxSteps*tComputeTime;
294  /*UG_LOG("\n");
295  UG_LOG("m_lastCallReduction = " << reset_floats << m_lastCallReduction << "\n");
296  UG_LOG("reduction = " << reset_floats << reduction << "\n");
297  UG_LOG("reduction remain = " << reset_floats << m_lastCallReduction/reduction << "\n");
298  UG_LOG("approxSteps = " << reset_floats << approxSteps << "\n");
299  UG_LOG("approxTimeForSolution = " << approxTimeForSolution << "\n");
300  UG_LOG("spentTime = " << spentTime << "\n");
301  UG_LOG("tComputeTime = " << tComputeTime << "\n");
302  UG_LOG("rate = " << r << "\n");
303  UG_LOG("reduction = " << reduction << "\n");*/
304  if(r > 1)
305  {
306  m_savedTime -= spentTime;
307  UG_LOG("AutoLinearSolver: REINIT because reduction rate >= 1.")
308  UG_LOG(" [ Inits called: " << m_initCalled << ", inits done: " << reset_floats << m_initsDone+1
309  << " (" << (100.0*(m_initsDone+1))/m_initCalled << " %), Total Time saved: " << m_savedTime << " s]\n");
310 
311 
312  reinit();
313  break;
314  }
315  double approxResolveTime = m_lastCallTime + m_lastInitTime;
316  if(approxResolveTime < approxRemainingTimeForSolution)
317  {
318  m_savedTime -= spentTime;
319  UG_LOG("AutoLinearSolver: REINIT because\n" << reset_floats )
320  UG_LOG(" approximated remaining Time for Solution with old preconditioner = " << approxRemainingTimeForSolution << " s\n");
321  UG_LOG(" > approximated Time for Reinit preconditioner and solve = " << approxResolveTime << " s\n");
322  UG_LOG(" with old preconditioner:\n");
323  UG_LOG(" reduction rate = " << r << " avg reduction = " << convergence_check()->avg_rate() << "\n")
324  UG_LOG(" steps = " << steps << ", reduction = " << reduction << "\n")
325  UG_LOG(" spentTime = " << spentTime << ", time per Step = " << tComputeTime << "\n");
326  UG_LOG(" approximation of solution with old:\n")
327  UG_LOG(" reduction remain = " << reset_floats << m_lastCallReduction/reduction << "\n");
328  UG_LOG(" approxSteps with last reduction rate = " << approxSteps << "\n");
329  UG_LOG(" [ Inits called: " << m_initCalled << ", inits done: " << reset_floats << m_initsDone+1
330  << " (" << (100.0*(m_initsDone+1))/m_initCalled << " %), Total Time saved: " << m_savedTime << " s]\n");
331  reinit();
332 
333  break;
334  }
335  else
336  {
337  x2 = x;
338  d2 = d;
339  }
340  }
341  if(!m_bInited)
342  {
343  double spentTime = get_clock_s() - tStartIterationTime;
345  UG_LOG("AutoLinearSolver solved with old preconditioner [")
346  UG_LOG(" Inits called: " << m_initCalled << ", inits done: " << reset_floats << m_initsDone+1
347  << " (" << (100.0*(m_initsDone+1))/m_initCalled << " %), Total Time saved: " << m_savedTime << " s]\n");
348  UG_LOG(" time spent with old = " << reset_floats << spentTime << " s, ");
349  UG_LOG(" last time init + solve = " << m_lastCallTime+m_lastInitTime << " s, ");
350 
351  if(m_lastCallTime+m_lastInitTime > spentTime)
352  { UG_LOG("saved " << m_lastCallTime+m_lastInitTime - spentTime << " s!.\n"); }
353  else
354  { UG_LOG("spent too much time with old! " << spentTime - m_lastCallTime+m_lastInitTime<< " s!\n"); }
355 
356  }
357 
358  }
359  catch(...)
360  {
361 
362  }
363  x = x2;
364  d = d2;
365  }
366 
367  if(!convergence_check()->iteration_ended())
368  {
369  double T = get_clock_s();
370  convergence_check()->start(d);
371  while(!convergence_check()->iteration_ended())
372  {
373  if( !compute_correction(c, d) ) return false;
374  x += c;
375  convergence_check()->update(d);
376  }
377  m_avgReduction = convergence_check()->avg_rate();
378  T = get_clock_s() - T;
379  m_reductionPerTime = convergence_check()->reduction()/T;
380  m_lastCallTime = T;
381  m_lastCallReduction = convergence_check()->reduction();
382  }
383 
384 
385  // write some information when ending the iteration
386  if(!convergence_check()->post())
387  {
388  UG_LOG("ERROR in 'LinearSolver::apply': post-convergence-check "
389  "signaled failure. Aborting.\n");
390  return false;
391  }
392 
393  // end profiling of whole function
394  LS_PROFILE_END(LS_ApplyReturnDefect);
395 
396  // we're done
397  return true;
398  }
399 
401  {
402  UG_LOG("AutoLinearSolver:\n");
403  UG_LOG(" avg reduction is " << m_avgReduction << "\n");
404  UG_LOG(" Inits called: " << m_initCalled << ", inits done: " << reset_floats << m_initsDone
405  << " (" << (100.0*(m_initsDone))/m_initCalled << " %)\n");
406  UG_LOG(" m_reductionPerTime = " << m_reductionPerTime << " s\n");
407  UG_LOG(" reductionTime for 0.1 reduction = " << 0.1/m_reductionPerTime << " s\n");
408  UG_LOG(" m_lastInitTime = " << m_lastInitTime << " s\n");
409  UG_LOG(" SAVED TIME: " << m_savedTime << " s\n");
410  }
411 
412  protected:
415  {
416  convergence_check()->set_name(name());
417  convergence_check()->set_symbol('%');
418  if(preconditioner().valid())
419  {
420  std::string s;
421  if(preconditioner().valid())
422  s = std::string(" (Precond: ") + preconditioner()->name() + ")";
423  else
424  s = " (No Preconditioner) ";
425  convergence_check()->set_info(s);
426  }
427  }
428 };
429 
430 } // end namespace ug
431 
432 #endif /* __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__LINEAR_SOLVER__ */
parameterString s
Definition: smart_pointer.h:108
bool valid() const
returns true if the pointer is valid, false if not.
Definition: smart_pointer.h:206
linear solver using abstract preconditioner interface
Definition: auto_linear_solver.h:65
int m_bInited
Definition: auto_linear_solver.h:113
void set_reinit_when_worse_then_average(double d)
Definition: auto_linear_solver.h:133
void prepare_conv_check()
prepares the convergence check output
Definition: auto_linear_solver.h:414
double m_savedTime
Definition: auto_linear_solver.h:124
AutoLinearSolver()
Definition: auto_linear_solver.h:92
vector_type m_u
Definition: auto_linear_solver.h:116
virtual bool apply(vector_type &x, const vector_type &b)
compute new correction c = B*d
Definition: auto_linear_solver.h:219
bool init_op(SmartPtr< ILinearOperator< vector_type, vector_type > > J)
Definition: auto_linear_solver.h:153
void set_reduction_always_accept(double d)
Definition: auto_linear_solver.h:128
double m_reductionPerTime
Definition: auto_linear_solver.h:122
size_t m_initCalled
Definition: auto_linear_solver.h:119
double m_lastCallTime
Definition: auto_linear_solver.h:122
bool reinit()
Definition: auto_linear_solver.h:177
SmartPtr< ILinearOperator< vector_type, vector_type > > pJ
Definition: auto_linear_solver.h:115
IPreconditionedLinearOperatorInverse< vector_type > base_type
Base type.
Definition: auto_linear_solver.h:71
double m_reductionAlwaysAccept
Definition: auto_linear_solver.h:111
bool compute_correction(vector_type &c, vector_type &d)
Definition: auto_linear_solver.h:199
virtual const char * name() const
returns the name of the solver
Definition: auto_linear_solver.h:139
double m_worseThenAverage
Definition: auto_linear_solver.h:112
double m_desiredReduction
Definition: auto_linear_solver.h:123
virtual bool apply_return_defect(vector_type &x, vector_type &b)
solves the system and returns the last defect
Definition: auto_linear_solver.h:227
SmartPtr< ILinearIterator< X, X > > preconditioner()
Definition: preconditioned_linear_operator_inverse.h:118
double m_avgReduction
Definition: auto_linear_solver.h:117
TVector vector_type
Vector type.
Definition: auto_linear_solver.h:68
double m_lastCallReduction
Definition: auto_linear_solver.h:122
size_t m_initsDone
Definition: auto_linear_solver.h:118
virtual bool supports_parallel() const
returns if parallel solving is supported
Definition: auto_linear_solver.h:103
virtual bool init(SmartPtr< ILinearOperator< vector_type, vector_type > > J)
initializes the solver for an operator
Definition: auto_linear_solver.h:147
double m_desiredDefect
Definition: auto_linear_solver.h:123
double m_lastInitTime
Definition: auto_linear_solver.h:121
virtual bool init(SmartPtr< ILinearOperator< vector_type, vector_type > > J, const vector_type &u)
initializes the solver for an operator
Definition: auto_linear_solver.h:142
void print_information()
Definition: auto_linear_solver.h:400
describes a linear mapping X->Y
Definition: linear_operator.h:80
ConstSmartPtr< IConvergenceCheck< X > > convergence_check() const
returns the convergence check
Definition: linear_operator_inverse.h:202
number reduction() const
returns the current relative reduction
Definition: linear_operator_inverse.h:214
number defect() const
returns the current defect
Definition: linear_operator_inverse.h:208
SmartPtr< ILinearOperator< Y, X > > linear_operator()
returns the current Operator this Inverse Operator is initialized for
Definition: linear_operator_inverse.h:227
virtual bool init(SmartPtr< ILinearOperator< Y, X > > L)
initializes for the inverse for a linear operator
Definition: linear_operator_inverse.h:135
describes an inverse linear mapping X->X
Definition: preconditioned_linear_operator_inverse.h:63
virtual bool init(SmartPtr< ILinearOperator< X, X > > J, const X &u)
initializes the solver for an operator
Definition: preconditioned_linear_operator_inverse.h:123
SmartPtr< ILinearIterator< X, X > > preconditioner()
Definition: preconditioned_linear_operator_inverse.h:118
Definition: auto_linear_solver.h:49
virtual void calculate_matrix()=0
virtual ~UpdateableMatrixOperator()
Definition: auto_linear_solver.h:51
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_ADDITIVE
Definition: parallel_storage_type.h:69
static std::ios_base & reset_floats(std::ios_base &o)
used to unset flags set by std::scientific or std::fixed.
Definition: ostream_util.h:52
#define UG_THROW(msg)
Definition: error.h:57
#define UG_LOG(msg)
Definition: log.h:367
#define LS_PROFILE_BEGIN(name)
Definition: linear_solver_profiling.h:40
#define LS_PROFILE_END(name)
Definition: linear_solver_profiling.h:41
the ug namespace
double get_clock_s()
Definition: stopwatch.h:103