19 #include "newton_solver.h"
20 #include "projections/ogprojection.h"
21 #include "hermes_common.h"
27 template<
typename Scalar>
28 NewtonSolver<Scalar>::NewtonSolver() : NonlinearSolver<Scalar>(new DiscreteProblem<Scalar>()), own_dp(true), kept_jacobian(NULL)
34 template<
typename Scalar>
35 NewtonSolver<Scalar>::NewtonSolver(DiscreteProblem<Scalar>* dp) : NonlinearSolver<Scalar>(dp), own_dp(false), kept_jacobian(NULL)
41 template<
typename Scalar>
42 NewtonSolver<Scalar>::NewtonSolver(
const WeakForm<Scalar>* wf,
const Space<Scalar>* space) : NonlinearSolver<Scalar>(new DiscreteProblem<Scalar>(wf, space)), own_dp(true), kept_jacobian(NULL)
48 template<
typename Scalar>
49 NewtonSolver<Scalar>::NewtonSolver(
const WeakForm<Scalar>* wf, Hermes::vector<
const Space<Scalar> *> spaces) : NonlinearSolver<Scalar>(new DiscreteProblem<Scalar>(wf, spaces)), own_dp(true), kept_jacobian(NULL)
55 template<
typename Scalar>
65 template<
typename Scalar>
68 this->newton_tol = 1e-8;
69 this->newton_max_iter = 15;
70 this->residual_as_function =
false;
71 this->max_allowed_residual_norm = 1E9;
72 this->min_allowed_damping_coeff = 1E-4;
73 this->currentDampingCofficient = 1.0;
74 this->manual_damping =
false;
75 this->auto_damping_ratio = 2.0;
76 this->initial_auto_damping_ratio = 1.0;
77 this->sufficient_improvement_factor = 0.95;
78 this->necessary_successful_steps_to_increase = 1;
81 template<
typename Scalar>
84 this->newton_tol = newton_tol;
87 template<
typename Scalar>
93 template<
typename Scalar>
96 if(newton_max_iter < 1)
97 throw Exceptions::ValueException(
"newton_max_iter", newton_max_iter, 1);
98 this->newton_max_iter = newton_max_iter;
101 template<
typename Scalar>
104 if(max_allowed_residual_norm_to_set <= 0.0)
105 throw Exceptions::ValueException(
"max_allowed_residual_norm_to_set", max_allowed_residual_norm_to_set, 0.0);
106 this->max_allowed_residual_norm = max_allowed_residual_norm_to_set;
109 template<
typename Scalar>
112 if(min_allowed_damping_coeff_to_set <= 0.0)
113 throw Exceptions::ValueException(
"min_allowed_damping_coeff_to_set", min_allowed_damping_coeff_to_set, 0.0);
114 this->min_allowed_damping_coeff = min_allowed_damping_coeff_to_set;
117 template<
typename Scalar>
120 this->residual_as_function =
true;
123 template<
typename Scalar>
126 Hermes::vector<Space<Scalar>*> spaces;
127 for(
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
134 template<
typename Scalar>
140 template<
typename Scalar>
144 if(kept_jacobian != NULL)
145 delete kept_jacobian;
146 kept_jacobian = NULL;
149 template<
typename Scalar>
153 if(kept_jacobian != NULL)
154 delete kept_jacobian;
155 kept_jacobian = NULL;
158 template<
typename Scalar>
164 template<
typename Scalar>
168 jacobian = create_matrix<Scalar>();
169 residual = create_vector<Scalar>();
170 linear_solver = create_linear_solver<Scalar>(jacobian, residual);
173 template<
typename Scalar>
174 NewtonSolver<Scalar>::~NewtonSolver()
176 if(kept_jacobian != NULL)
177 delete kept_jacobian;
180 delete linear_solver;
184 static_cast<DiscreteProblem<Scalar>*
>(this->dp)->have_matrix =
false;
187 template<
typename Scalar>
190 if(coeff <= 0.0 || coeff > 1.0)
191 throw Exceptions::ValueException(
"coeff", coeff, 0.0, 1.0);
194 this->manual_damping =
true;
195 this->currentDampingCofficient = coeff;
198 this->manual_damping =
false;
201 template<
typename Scalar>
204 if(coeff <= 0.0 || coeff > 1.0)
205 throw Exceptions::ValueException(
"coeff", coeff, 0.0, 1.0);
206 if(this->manual_damping)
207 this->warn(
"Manual damping is turned on and you called set_initial_auto_damping_coeff(), turn off manual damping first by set_manual_damping_coeff(false);");
209 this->currentDampingCofficient = coeff;
212 template<
typename Scalar>
216 throw Exceptions::ValueException(
"ratio", ratio, 0.0);
217 if(this->manual_damping)
218 this->warn(
"Manual damping is turned on and you called set_initial_auto_damping_coeff(), turn off manual damping first by set_manual_damping_coeff(false);");
219 this->auto_damping_ratio = ratio;
222 template<
typename Scalar>
226 throw Exceptions::ValueException(
"ratio", ratio, 0.0);
227 if(this->manual_damping)
228 this->warn(
"Manual damping is turned on and you called set_initial_auto_damping_coeff(), turn off manual damping first by set_manual_damping_coeff(false);");
229 this->sufficient_improvement_factor = ratio;
232 template<
typename Scalar>
236 throw Exceptions::ValueException(
"steps", steps, 0.0);
237 if(this->manual_damping)
238 this->warn(
"Manual damping is turned on and you called set_initial_auto_damping_coeff(), turn off manual damping first by set_manual_damping_coeff(false);");
239 this->necessary_successful_steps_to_increase = steps;
242 template<
typename Scalar>
245 Hermes::vector<Solution<Scalar>*> vectorToPass;
246 vectorToPass.push_back(initial_guess);
247 this->solve(vectorToPass);
250 template<
typename Scalar>
253 int ndof = this->dp->get_num_dofs();
254 Scalar* coeff_vec =
new Scalar[ndof];
257 this->solve(coeff_vec);
260 template<
typename Scalar>
268 int ndof = this->dp->get_num_dofs();
271 bool delete_coeff_vec =
false;
272 if(coeff_vec == NULL)
274 coeff_vec =
new Scalar[ndof];
275 memset(coeff_vec, 0, ndof*
sizeof(Scalar));
276 delete_coeff_vec =
true;
280 Scalar* coeff_vec_back =
new Scalar[ndof];
281 memset(coeff_vec_back, 0, ndof*
sizeof(Scalar));
284 if(this->sln_vector != NULL)
286 delete [] this->sln_vector;
287 this->sln_vector = NULL;
291 double residual_norm;
292 double last_residual_norm;
294 int successfulSteps = 0;
296 this->on_initialization();
300 this->on_step_begin();
303 this->dp->assemble(coeff_vec, residual);
304 if(this->output_rhsOn && (this->output_rhsIterations == -1 || this->output_rhsIterations >= it))
306 char* fileName =
new char[this->RhsFilename.length() + 5];
307 if(this->RhsFormat == Hermes::Algebra::DF_MATLAB_SPARSE)
308 sprintf(fileName,
"%s%i.m", this->RhsFilename.c_str(), it);
310 sprintf(fileName,
"%s%i", this->RhsFilename.c_str(), it);
311 FILE* rhs_file = fopen(fileName,
"w+");
312 residual->dump(rhs_file, this->RhsVarname.c_str(), this->RhsFormat, this->rhs_number_format);
318 for(
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
323 if(residual_as_function)
326 Hermes::vector<Solution<Scalar>*> solutions;
327 Hermes::vector<bool> dir_lift_false;
328 for (
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
331 dir_lift_false.push_back(
false);
340 for (
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
350 last_residual_norm = residual_norm;
357 this->info(
"\tNewton: initial residual norm: %g", residual_norm);
360 this->info(
"\tNewton: iteration %d, residual norm: %g", it - 1, residual_norm);
361 if(!this->manual_damping && !((residual_norm > max_allowed_residual_norm) || (residual_norm < newton_tol && it > 1)))
363 if(residual_norm < last_residual_norm * this->sufficient_improvement_factor)
365 if(++successfulSteps >= this->necessary_successful_steps_to_increase)
366 this->currentDampingCofficient = std::min(this->initial_auto_damping_ratio, 2 * this->currentDampingCofficient);
367 if(residual_norm < last_residual_norm)
368 this->info(
"\t Newton: step successful, calculation continues with damping coefficient: %g.", this->currentDampingCofficient);
373 if(this->currentDampingCofficient < this->min_allowed_damping_coeff)
375 this->warn(
"\t Newton: results NOT improved, current damping coefficient is at the minimum possible level: %g.", min_allowed_damping_coeff);
376 this->info(
"\t If you want to decrease the minimum level, use the method set_min_allowed_damping_coeff()");
383 delete [] coeff_vec_back;
385 throw Exceptions::Exception(
"Newton NOT converged because of damping coefficient could not be decreased anymore to possibly handle non-converging process.");
389 this->currentDampingCofficient = (1 / this->auto_damping_ratio) * this->currentDampingCofficient;
390 this->warn(
" Newton: results NOT improved, step restarted with damping coefficient: %g.", this->currentDampingCofficient);
397 if(residual_norm > max_allowed_residual_norm)
400 this->info(
"\tNewton: solution duration: %f s.\n", this->last());
409 delete [] coeff_vec_back;
411 throw Exceptions::ValueException(
"residual norm", residual_norm, max_allowed_residual_norm);
416 if(residual_norm < newton_tol && it > 1)
419 this->sln_vector =
new Scalar[ndof];
420 for (
int i = 0; i < ndof; i++)
421 this->sln_vector[i] = coeff_vec[i];
429 delete [] coeff_vec_back;
434 this->info(
"\tNewton: solution duration: %f s.\n", this->last());
440 this->dp->assemble(coeff_vec, jacobian);
441 if(this->output_matrixOn && (this->output_matrixIterations == -1 || this->output_matrixIterations >= it))
443 char* fileName =
new char[this->matrixFilename.length() + 5];
444 if(this->matrixFormat == Hermes::Algebra::DF_MATLAB_SPARSE)
445 sprintf(fileName,
"%s%i.m", this->matrixFilename.c_str(), it);
447 sprintf(fileName,
"%s%i", this->matrixFilename.c_str(), it);
448 FILE* matrix_file = fopen(fileName,
"w+");
450 jacobian->dump(matrix_file, this->matrixVarname.c_str(), this->matrixFormat, this->matrix_number_format);
459 residual->change_sign();
462 if(!linear_solver->solve())
463 throw Exceptions::LinearMatrixSolverException();
467 if(residual_norm < last_residual_norm * this->sufficient_improvement_factor || this->manual_damping || it == 1)
469 memcpy(coeff_vec_back, coeff_vec,
sizeof(Scalar)*ndof);
470 for (
int i = 0; i < ndof; i++)
471 coeff_vec[i] += currentDampingCofficient * linear_solver->get_sln_vector()[i];
475 for (
int i = 0; i < ndof; i++)
476 coeff_vec[i] = coeff_vec_back[i] + currentDampingCofficient * (coeff_vec[i] - coeff_vec_back[i]);
480 if(it++ >= newton_max_iter)
483 this->sln_vector =
new Scalar[ndof];
484 for (
int i = 0; i < ndof; i++)
485 this->sln_vector[i] = coeff_vec[i];
493 delete [] coeff_vec_back;
494 coeff_vec_back = NULL;
497 this->info(
"\tNewton: solution duration: %f s.\n", this->last());
500 throw Exceptions::ValueException(
"iterations", it, newton_max_iter);
505 template<
typename Scalar>
508 Hermes::vector<Solution<Scalar>*> vectorToPass;
509 vectorToPass.push_back(initial_guess);
510 this->solve_keep_jacobian(vectorToPass);
513 template<
typename Scalar>
516 int ndof = this->dp->get_num_dofs();
517 Scalar* coeff_vec =
new Scalar[ndof];
520 this->solve_keep_jacobian(coeff_vec);
523 template<
typename Scalar>
531 int ndof = this->dp->get_num_dofs();
534 bool delete_coeff_vec =
false;
535 if(coeff_vec == NULL)
537 coeff_vec =
new Scalar[ndof];
538 memset(coeff_vec, 0, ndof*
sizeof(Scalar));
539 delete_coeff_vec =
true;
543 Scalar* coeff_vec_back =
new Scalar[ndof];
544 memset(coeff_vec_back, 0, ndof*
sizeof(Scalar));
548 double residual_norm;
549 double last_residual_norm;
551 int successfulSteps = 0;
553 this->on_initialization();
557 this->on_step_begin();
560 this->dp->assemble(coeff_vec, residual);
561 if(this->output_rhsOn && (this->output_rhsIterations == -1 || this->output_rhsIterations >= it))
563 char* fileName =
new char[this->RhsFilename.length() + 5];
564 if(this->RhsFormat == Hermes::Algebra::DF_MATLAB_SPARSE)
565 sprintf(fileName,
"%s%i.m", this->RhsFilename.c_str(), it);
567 sprintf(fileName,
"%s%i", this->RhsFilename.c_str(), it);
568 FILE* rhs_file = fopen(fileName,
"w+");
569 residual->dump(rhs_file, this->RhsVarname.c_str(), this->RhsFormat, this->rhs_number_format);
574 for(
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
579 if(residual_as_function)
582 Hermes::vector<Solution<Scalar>* > solutions;
583 Hermes::vector<bool> dir_lift_false;
584 for (
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++) {
586 dir_lift_false.push_back(
false);
595 for (
unsigned int i = 0; i < static_cast<DiscreteProblem<Scalar>*>(this->dp)->get_spaces().size(); i++)
605 last_residual_norm = residual_norm;
612 this->info(
"\tNewton: initial residual norm: %g", residual_norm);
615 this->info(
"\tNewton: iteration %d, residual norm: %g", it - 1, residual_norm);
616 if(!this->manual_damping && !((residual_norm > max_allowed_residual_norm) || (residual_norm < newton_tol && it > 1)))
618 if(residual_norm < last_residual_norm * this->sufficient_improvement_factor)
620 if(++successfulSteps >= this->necessary_successful_steps_to_increase)
621 this->currentDampingCofficient = std::min(this->initial_auto_damping_ratio, 2 * this->currentDampingCofficient);
622 if(residual_norm < last_residual_norm)
623 this->info(
"\t Newton: step successful, calculation continues with damping coefficient: %g.", this->currentDampingCofficient);
628 if(this->currentDampingCofficient < this->min_allowed_damping_coeff)
630 this->warn(
"\t Newton: results NOT improved, current damping coefficient is at the minimum possible level: %g.", min_allowed_damping_coeff);
631 this->info(
"\t If you want to decrease the minimum level, use the method set_min_allowed_damping_coeff()");
639 delete [] coeff_vec_back;
641 throw Exceptions::Exception(
"Newton NOT converged because of damping coefficient could not be decreased anymore to possibly handle non-converging process.");
645 this->currentDampingCofficient = (1 / this->auto_damping_ratio) * this->currentDampingCofficient;
646 this->warn(
"\t Newton: results NOT improved, step restarted with damping coefficient: %g.", this->currentDampingCofficient);
653 if(residual_norm > max_allowed_residual_norm)
656 this->info(
"\tNewton: solution duration: %f s.", this->last());
664 delete [] coeff_vec_back;
668 throw Exceptions::ValueException(
"residual norm", residual_norm, max_allowed_residual_norm);
673 if(residual_norm < newton_tol && it > 1)
676 this->sln_vector =
new Scalar[ndof];
677 for (
int i = 0; i < ndof; i++)
678 this->sln_vector[i] = coeff_vec[i];
686 delete [] coeff_vec_back;
689 this->info(
"\tNewton: solution duration: %f s.", this->last());
699 if(kept_jacobian != NULL)
700 delete kept_jacobian;
702 kept_jacobian = create_matrix<Scalar>();
708 delete linear_solver;
710 linear_solver = create_linear_solver<Scalar>(kept_jacobian, residual);
712 this->dp->assemble(coeff_vec, kept_jacobian);
714 if(this->output_matrixOn && (this->output_matrixIterations == -1 || this->output_matrixIterations >= it))
716 char* fileName =
new char[this->matrixFilename.length() + 5];
717 if(this->matrixFormat == Hermes::Algebra::DF_MATLAB_SPARSE)
718 sprintf(fileName,
"%s%i.m", this->matrixFilename.c_str(), it);
720 sprintf(fileName,
"%s%i", this->matrixFilename.c_str(), it);
721 FILE* matrix_file = fopen(fileName,
"w+");
723 kept_jacobian->dump(matrix_file, this->matrixVarname.c_str(), this->matrixFormat, this->matrix_number_format);
727 linear_solver->set_factorization_scheme(HERMES_REUSE_FACTORIZATION_COMPLETELY);
734 residual->change_sign();
737 if(!linear_solver->solve())
739 throw Exceptions::LinearMatrixSolverException();
744 if(residual_norm < last_residual_norm * this->sufficient_improvement_factor || this->manual_damping || it == 1)
746 memcpy(coeff_vec_back, coeff_vec,
sizeof(Scalar)*ndof);
747 for (
int i = 0; i < ndof; i++)
748 coeff_vec[i] += currentDampingCofficient * linear_solver->get_sln_vector()[i];
752 for (
int i = 0; i < ndof; i++)
753 coeff_vec[i] = coeff_vec_back[i] + currentDampingCofficient * (coeff_vec[i] - coeff_vec_back[i]);
757 if(it++ >= newton_max_iter)
760 this->sln_vector =
new Scalar[ndof];
761 for (
int i = 0; i < ndof; i++)
762 this->sln_vector[i] = coeff_vec[i];
770 delete [] coeff_vec_back;
773 this->info(
"\tNewton: solution duration: %f s.\n", this->last());
776 throw Exceptions::ValueException(
"iterations", it, newton_max_iter);
781 template<
typename Scalar>
784 NonlinearSolver<Scalar>::set_iterative_method(iterative_method_name);
787 dynamic_cast<Hermes::Solvers::AztecOOSolver<Scalar>*
>(linear_solver)->set_solver(iterative_method_name);
789 this->warn(
"Trying to set iterative method without AztecOO present.");
793 template<
typename Scalar>
796 NonlinearSolver<Scalar>::set_preconditioner(preconditioner_name);
799 dynamic_cast<Hermes::Solvers::AztecOOSolver<Scalar> *
>(linear_solver)->set_precond(preconditioner_name);
801 this->warn(
"Trying to set iterative method without AztecOO present.");