HermesCommon  3.0
picard_matrix_solver.cpp
1 // This file is part of HermesCommon
2 //
3 // Copyright (c) 2009 hp-FEM group at the University of Nevada, Reno (UNR).
4 // Email: hpfem-group@unr.edu, home page: http://www.hpfem.org/.
5 //
6 // Hermes2D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the License,
9 // or (at your option) any later version.
10 //
11 // Hermes2D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with Hermes2D; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 #include "picard_matrix_solver.h"
22 #include "util/memory_handling.h"
23 
24 using namespace Hermes::Algebra;
26 
27 namespace Hermes
28 {
29  namespace Solvers
30  {
31  template<typename Scalar>
33  {
34  init_picard();
35  }
36 
37  template<typename Scalar>
39  {
40  this->min_allowed_damping_coeff = 1E-4;
41  this->manual_damping = false;
42  this->auto_damping_ratio = 2.0;
43  this->manual_damping_factor = 1.0;
44  this->initial_auto_damping_factor = 1.0;
45  this->sufficient_improvement_factor = 1.05;
46  this->necessary_successful_steps_to_increase = 3;
47  this->damping_factor_condition_overloaded = true;
48 
49  this->sufficient_improvement_factor_jacobian = 1e-1;
50  this->max_steps_with_reused_jacobian = 0;
51 
52  this->set_tolerance(1e-3, SolutionChangeRelative);
53 
54  this->num_last_vectors_used = 3;
55  this->anderson_beta = 1.0;
56  this->anderson_is_on = false;
57  this->vec_in_memory = 0;
58 
59  this->use_initial_guess_for_iterative_solvers = true;
60  }
61 
62  template<typename Scalar>
64  {
65  this->damping_factor_condition_overloaded = onOff;
66  }
67 
68  template<typename Scalar>
70  {
71  double current_damping_factor = this->get_parameter_value(this->p_damping_factors).back();
72 
73  double solution_change_norm = 0.;
74  for (int i = 0; i < this->problem_size; i++)
75  {
76  solution_change_norm += std::pow(std::abs(linear_system_solution[i] - this->sln_vector[i]), 2.);
77  this->sln_vector[i] += current_damping_factor * (linear_system_solution[i] - this->sln_vector[i]);
78  }
79 
80  return std::sqrt(solution_change_norm) * current_damping_factor;
81  }
82 
83  template<typename Scalar>
85  {
86  Scalar* temp = malloc_with_check<PicardMatrixSolver<Scalar>, Scalar>(this->problem_size, this);
87  if (this->previous_jacobian)
88  this->previous_jacobian->multiply_with_vector(this->sln_vector, temp, true);
89  else
90  this->get_jacobian()->multiply_with_vector(this->sln_vector, temp, true);
91  Vector<Scalar>* residual = this->get_residual();
92  for (int i = 0; i < this->problem_size; i++)
93  temp[i] = temp[i] - residual->get(i);
94 
95  double residual_norm = get_l2_norm(temp, this->problem_size);
96  free_with_check(temp);
97 
98  return residual_norm;
99  }
100 
101  template<typename Scalar>
103  {
105  this->handle_previous_vectors();
106  }
107 
108  template<typename Scalar>
110  {
111  if (damping_factor_condition_overloaded)
112  {
113  if (this->get_parameter_value(this->solution_change_norms()).size() == 1)
114  return true;
115 
116  double sln_change_norm = *(this->get_parameter_value(this->solution_change_norms()).end() - 1);
117  double previous_sln_change_norm = *(this->get_parameter_value(this->solution_change_norms()).end() - 2);
118  return (sln_change_norm < previous_sln_change_norm * this->sufficient_improvement_factor);
119  }
120  else
122  }
123 
124  template<typename Scalar>
126  {
128  this->init_anderson();
129  }
130 
131  template<typename Scalar>
133  {
134  this->deinit_anderson();
136  }
137 
138  template<typename Scalar>
140  {
141  this->num_last_vectors_used = num;
142  }
143 
144  template<typename Scalar>
146  {
147  this->anderson_beta = beta;
148  }
149 
150  template<typename Scalar>
152  {
153  anderson_is_on = to_set;
154  }
155 
156  template<typename Scalar>
158  {
159  if (anderson_is_on)
160  {
161  previous_Anderson_sln_vector = malloc_with_check<PicardMatrixSolver<Scalar>, Scalar>(this->problem_size, this);
162  previous_vectors = malloc_with_check<PicardMatrixSolver<Scalar>, Scalar*>(num_last_vectors_used, this);
163  for (int i = 0; i < num_last_vectors_used; i++)
164  previous_vectors[i] = malloc_with_check<PicardMatrixSolver<Scalar>, Scalar>(this->problem_size, this);
165  anderson_coeffs = malloc_with_check<PicardMatrixSolver<Scalar>, Scalar>(num_last_vectors_used - 1, this);
166  memcpy(previous_vectors[0], this->sln_vector, this->problem_size*sizeof(Scalar));
167  this->vec_in_memory = 1;
168  }
169  }
170 
171  template<typename Scalar>
173  {
174  if (anderson_is_on)
175  {
176  free_with_check(previous_Anderson_sln_vector);
177  for (int i = 0; i < num_last_vectors_used; i++)
178  free_with_check(previous_vectors[i]);
179  free_with_check(previous_vectors);
180  free_with_check(anderson_coeffs);
181  }
182  }
183 
184  template<typename Scalar>
186  {
187  // If Anderson is used, store the new_ vector in the memory.
188  if (anderson_is_on)
189  {
190  // If memory not full, just add the vector.
191  if (this->vec_in_memory < num_last_vectors_used)
192  memcpy(previous_vectors[this->vec_in_memory++], this->sln_vector, this->problem_size * sizeof(Scalar));
193  else
194  {
195  // If memory full, shift all vectors back, forgetting the oldest one.
196  // Save this->sln_vector[] as the newest one.
197  Scalar* oldest_vec = previous_vectors[0];
198 
199  for (int i = 0; i < num_last_vectors_used - 1; i++)
200  previous_vectors[i] = previous_vectors[i + 1];
201 
202  previous_vectors[num_last_vectors_used - 1] = oldest_vec;
203 
204  memcpy(oldest_vec, this->sln_vector, this->problem_size*sizeof(Scalar));
205  }
206 
207  if (this->vec_in_memory >= num_last_vectors_used)
208  {
209  // Calculate Anderson coefficients.
210  this->calculate_anderson_coeffs();
211 
212  // Calculate new_ vector and store it in this->Picard.
213  for (int i = 0; i < this->problem_size; i++)
214  {
215  this->previous_Anderson_sln_vector[i] = 0.;
216  for (int j = 1; j < num_last_vectors_used; j++)
217  this->previous_Anderson_sln_vector[i] += anderson_coeffs[j - 1] * previous_vectors[j][i] - (1.0 - anderson_beta) * anderson_coeffs[j - 1] * (previous_vectors[j][i] - previous_vectors[j - 1][i]);
218  }
219  }
220  }
221  }
222 
223  template<typename Scalar>
225  {
226  // If num_last_vectors_used is 2, then there is only one residual, and thus only one alpha coeff which is 1.0.
227  if (num_last_vectors_used == 2)
228  {
229  anderson_coeffs[0] = 1.0;
230  return;
231  }
232 
233  // In the following, num_last_vectors_used is at least three.
234  // Thematrix problem will have problem_size num_last_vectors_used - 2.
235  int n = num_last_vectors_used - 2;
236 
237  // Allocate the matrix system for the Anderson coefficients.
238  Scalar** mat = new_matrix<Scalar>(n, n);
239  Scalar* rhs = malloc_with_check<PicardMatrixSolver<Scalar>, Scalar>(n, this);
240  // Set up the matrix and rhs vector.
241  for (int i = 0; i < n; i++)
242  {
243  // Calculate i-th entry of the rhs vector.
244  rhs[i] = 0;
245  for (int k = 0; k < this->problem_size; k++)
246  {
247  Scalar residual_n_k = previous_vectors[n + 1][k] - previous_vectors[n][k];
248  Scalar residual_i_k = previous_vectors[i + 1][k] - previous_vectors[i][k];
249  rhs[i] += residual_n_k * (residual_n_k - residual_i_k);
250  }
251  for (int j = 0; j < n; j++)
252  {
253  Scalar val = 0;
254  for (int k = 0; k < this->problem_size; k++)
255  {
256  Scalar residual_n_k = previous_vectors[n + 1][k] - previous_vectors[n][k];
257  Scalar residual_i_k = previous_vectors[i + 1][k] - previous_vectors[i][k];
258  Scalar residual_j_k = previous_vectors[j + 1][k] - previous_vectors[j][k];
259  val += (residual_n_k - residual_i_k) * (residual_n_k - residual_j_k);
260  }
261 
262  mat[i][j] = val;
263  }
264  }
265  // Solve the matrix system.
266  double d;
267  int* perm = malloc_with_check<PicardMatrixSolver<Scalar>, int>(n, this);
268  ludcmp(mat, n, perm, &d);
269  lubksb<Scalar>(mat, n, perm, rhs);
270  // Use the result to define the Anderson coefficients. Remember that
271  // n were computed and the last one is 1.0 minus the sum of the 'n' numbers.
272  Scalar sum = 0;
273  for (int i = 0; i < n; i++)
274  {
275  anderson_coeffs[i] = rhs[i];
276  sum += rhs[i];
277  }
278  anderson_coeffs[n] = 1.0 - sum;
279 
280  // Clean up.
281  free_with_check(mat);
282  free_with_check(rhs);
283  }
284 
285  template class HERMES_API PicardMatrixSolver < double > ;
286  template class HERMES_API PicardMatrixSolver < std::complex<double> > ;
287  }
288 }
HERMES_API void ludcmp(T **a, Int n, Int *indx, double *d)
General namespace for the Hermes library.
General (abstract) vector representation in Hermes.
virtual Scalar get(unsigned int idx) const =0
void calculate_anderson_coeffs()
Calcualte the coefficients.
Namespace containing classes for vector / matrix operations.
File containing common definitions, and basic global enums etc. for HermesCommon. ...
Base class for defining interface for nonlinear solvers.
virtual double update_solution_return_change_norm(Scalar *linear_system_solution)
Contains operation on dense matrices.
virtual void init_solving(Scalar *&coeff_vec)
Initialization - called at the beginning of solving.
virtual bool damping_factor_condition()
Returns iff the damping factor condition is fulfilled.
virtual void init_solving(Scalar *coeff_vec)
void use_Anderson_acceleration(bool to_set)
Turn on / off the Anderson acceleration. By default it is off.
virtual bool damping_factor_condition()
Returns iff the damping factor condition is fulfilled.
void handle_previous_vectors()
Handle the previous vectors.
Dense (small) simply stored matrix operations.
virtual double calculate_residual_norm()
Norm for convergence.
virtual void solve_linear_system()
Solve the step's linear system.