32 template<
typename Scalar>
35 this->init_nonlinear();
38 template<
typename Scalar>
41 this->handleMultipleTolerancesAnd =
false;
42 this->max_allowed_iterations = 20;
43 this->max_allowed_residual_norm = 1E9;
45 this->previous_sln_vector =
nullptr;
46 this->use_initial_guess_for_iterative_solvers =
false;
47 this->clear_tolerances();
50 template<
typename Scalar>
56 template<
typename Scalar>
59 free_with_check(this->sln_vector,
true);
62 template<
typename Scalar>
65 bool toleranceSet =
false;
67 if (this->tolerance_set[i])
77 template<
typename Scalar>
80 if (max_allowed_iterations_ < 1)
82 this->max_allowed_iterations = max_allowed_iterations_;
85 template<
typename Scalar>
88 return get_l2_norm(this->get_residual());
91 template<
typename Scalar>
98 assert(this->problem_size > 0);
100 free_with_check(this->sln_vector,
true);
101 this->sln_vector = malloc_with_check<NonlinearMatrixSolver<Scalar>, Scalar>(this->problem_size,
this,
true);
103 if (coeff_vec ==
nullptr)
104 memset(this->sln_vector, 0, this->problem_size*
sizeof(Scalar));
106 memcpy(this->sln_vector, coeff_vec, this->problem_size*
sizeof(Scalar));
109 this->previous_sln_vector = calloc_with_check<NonlinearMatrixSolver<Scalar>, Scalar>(this->problem_size,
this,
true);
112 residual_back = create_vector<Scalar>();
113 residual_back->alloc(this->problem_size);
115 this->previous_jacobian =
nullptr;
116 this->previous_residual =
nullptr;
118 this->on_initialization();
121 template<
typename Scalar>
124 this->handleMultipleTolerancesAnd = handleMultipleTolerancesAnd;
126 if (tolerance_ < 0.0)
129 switch (toleranceType)
131 case ResidualNormRelativeToPrevious:
133 this->tolerance[0] = tolerance_;
134 this->tolerance_set[0] =
true;
137 case ResidualNormRatioToInitial:
139 this->tolerance[1] = tolerance_;
140 this->tolerance_set[1] =
true;
143 case ResidualNormRatioToPrevious:
145 this->tolerance[2] = tolerance_;
146 this->tolerance_set[2] =
true;
149 case ResidualNormAbsolute:
151 this->tolerance[3] = tolerance_;
152 this->tolerance_set[3] =
true;
155 case SolutionChangeAbsolute:
157 this->tolerance[4] = tolerance_;
158 this->tolerance_set[4] =
true;
161 case SolutionChangeRelative:
163 this->tolerance[5] = tolerance_;
164 this->tolerance_set[5] =
true;
168 throw Exceptions::Exception(
"Unknown NonlinearConvergenceMeasurementType in NonlinearMatrixSolver::set_tolerance.");
172 template<
typename Scalar>
175 if (max_allowed_residual_norm_to_set < 0.0)
177 this->max_allowed_residual_norm = max_allowed_residual_norm_to_set;
180 template<
typename Scalar>
183 return this->num_iters;
186 template<
typename Scalar>
189 if (this->get_current_iteration_number() >= this->max_allowed_iterations)
190 return AboveMaxIterations;
200 template<
typename Scalar>
204 this->tolerance[i] = std::numeric_limits<double>::max();
205 memset(this->tolerance_set, 0,
sizeof(
bool)*NonlinearConvergenceMeasurementTypeCount);
208 template<
typename Scalar>
213 this->sufficient_improvement_factor_jacobian = ratio;
216 template<
typename Scalar>
219 this->max_steps_with_reused_jacobian = steps;
222 template<
typename Scalar>
225 if (min_allowed_damping_coeff_to_set < 0.0)
227 this->min_allowed_damping_coeff = min_allowed_damping_coeff_to_set;
230 template<
typename Scalar>
233 if (coeff <= 0.0 || coeff > 1.0)
237 this->manual_damping =
true;
238 this->manual_damping_factor = coeff;
241 this->manual_damping =
false;
244 template<
typename Scalar>
247 if (coeff <= 0.0 || coeff > 1.0)
249 if (this->manual_damping)
250 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);");
252 this->initial_auto_damping_factor = coeff;
255 template<
typename Scalar>
260 if (this->manual_damping)
261 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);");
262 this->auto_damping_ratio = ratio;
265 template<
typename Scalar>
270 if (this->manual_damping)
271 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);");
272 this->sufficient_improvement_factor = ratio;
275 template<
typename Scalar>
280 if (this->manual_damping)
281 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);");
282 this->necessary_successful_steps_to_increase = steps;
285 template<
typename Scalar>
289 if (state == NotConverged)
296 this->info(
"\tNonlinearSolver: done.\n");
298 case AboveMaxIterations:
301 case BelowMinDampingCoeff:
304 case AboveMaxAllowedResidualNorm:
316 this->finalize_solving();
322 template<
typename Scalar>
325 std::vector<double>& damping_factors_vector = this->get_parameter_value(p_damping_factors);
327 if (this->manual_damping)
329 damping_factors_vector.push_back(this->manual_damping_factor);
333 if (this->damping_factor_condition())
335 if (++successful_steps >= this->necessary_successful_steps_to_increase)
337 double new_damping_factor = std::min(this->initial_auto_damping_factor, this->auto_damping_ratio * damping_factors_vector.back());
338 this->info(
"\t\tstep successful, new damping factor: %g.", new_damping_factor);
339 damping_factors_vector.push_back(new_damping_factor);
343 this->info(
"\t\tstep successful, keep damping factor: %g.", damping_factors_vector.back());
344 damping_factors_vector.push_back(damping_factors_vector.back());
351 double current_damping_factor = damping_factors_vector.back();
352 damping_factors_vector.pop_back();
353 successful_steps = 0;
354 if (current_damping_factor <= this->min_allowed_damping_coeff)
356 this->warn(
"\t\tNOT successful, damping factor at minimum level: %g.", min_allowed_damping_coeff);
357 this->info(
"\t\tto decrease the minimum level, use set_min_allowed_damping_coeff()");
362 double new_damping_factor = (1. / this->auto_damping_ratio) * current_damping_factor;
363 this->warn(
"\t\tNOT successful, step restarted with factor: %g.", new_damping_factor);
364 damping_factors_vector.push_back(new_damping_factor);
371 template<
typename Scalar>
374 free_with_check(this->previous_sln_vector,
true);
375 delete residual_back;
376 this->problem_size = -1;
377 if (this->previous_jacobian)
378 delete this->previous_jacobian;
379 if (this->previous_residual)
380 delete this->previous_residual;
383 template<
typename Scalar>
387 this->num_iters = this->get_current_iteration_number();
388 this->info(
"\tNonlinearSolver: solution duration: %f s.\n", this->last());
390 this->deinit_solving();
393 template<
typename Scalar>
396 if (successful_steps_with_reused_jacobian >= this->max_steps_with_reused_jacobian)
398 successful_steps_with_reused_jacobian = 0;
401 successful_steps_with_reused_jacobian++;
405 template<
typename Scalar>
409 this->get_parameter_value(this->p_solution_norms).push_back(get_l2_norm(this->sln_vector, this->problem_size));
412 if (this->jacobian_reusable && this->constant_jacobian)
415 this->assemble_residual(
false);
416 this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(
false);
421 this->assemble(
false,
false);
422 this->jacobian_reusable =
true;
423 this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(
true);
427 double residual_norm = this->calculate_residual_norm();
428 this->info(
"\n\tNonlinearSolver: initial residual norm: %g", residual_norm);
429 this->get_parameter_value(this->p_residual_norms).push_back(residual_norm);
431 this->solve_linear_system();
433 if (this->handle_convergence_state_return_finished(this->get_convergence_state()))
436 if (this->on_initial_step_end() ==
false)
438 this->info(
"\tNonlinearSolver: aborted.");
439 this->finalize_solving();
446 template<
typename Scalar>
450 memcpy(this->previous_sln_vector, this->sln_vector,
sizeof(Scalar)*this->problem_size);
453 this->linear_matrix_solver->solve(this->use_initial_guess_for_iterative_solvers ? this->sln_vector :
nullptr);
456 double solution_change_norm = this->update_solution_return_change_norm(this->linear_matrix_solver->get_sln_vector());
459 this->get_parameter_value(this->p_solution_change_norms).push_back(solution_change_norm);
462 this->get_parameter_value(this->p_solution_norms).push_back(get_l2_norm(this->sln_vector, this->problem_size));
465 template<
typename Scalar>
469 this->info(
"\n\tNonlinearSolver: iteration %d,", this->get_current_iteration_number());
470 this->info(
"\t\tresidual norm: %g,", this->get_parameter_value(this->p_residual_norms).back());
472 double solution_norm = this->get_parameter_value(this->p_solution_norms).back();
473 double previous_solution_norm = this->get_parameter_value(this->p_solution_norms)[this->get_parameter_value(this->p_solution_norms).size() - 2];
474 double solution_change_norm = this->get_parameter_value(this->p_solution_change_norms).back();
475 this->info(
"\t\tsolution norm: %g,", solution_norm);
476 this->info(
"\t\tsolution change norm: %g.", solution_change_norm);
477 this->info(
"\t\trelative solution change: %g.", solution_change_norm / previous_solution_norm);
480 template<
typename Scalar>
484 this->init_solving(coeff_vec);
486 #pragma region parameter_setup
488 unsigned int successful_steps_damping = 0;
489 unsigned int successful_steps_jacobian = 0;
490 std::vector<bool> iterations_with_recalculated_jacobian;
491 std::vector<double> residual_norms;
492 std::vector<double> solution_norms;
493 std::vector<double> solution_change_norms;
494 std::vector<double> damping_factors;
495 bool residual_norm_drop;
496 unsigned int iteration = 1;
499 damping_factors.push_back(this->manual_damping ? manual_damping_factor : initial_auto_damping_factor);
502 this->set_parameter_value(this->p_residual_norms, &residual_norms);
503 this->set_parameter_value(this->p_solution_norms, &solution_norms);
504 this->set_parameter_value(this->p_solution_change_norms, &solution_change_norms);
505 this->set_parameter_value(this->p_successful_steps_damping, &successful_steps_damping);
506 this->set_parameter_value(this->p_successful_steps_jacobian, &successful_steps_jacobian);
507 this->set_parameter_value(this->p_residual_norm_drop, &residual_norm_drop);
508 this->set_parameter_value(this->p_damping_factors, &damping_factors);
509 this->set_parameter_value(this->p_iterations_with_recalculated_jacobian, &iterations_with_recalculated_jacobian);
510 this->set_parameter_value(this->p_iteration, &iteration);
514 if (this->do_initial_step_return_finished())
521 if (!this->on_step_begin())
523 this->info(
"\tNonlinearSolver: aborted.");
524 this->finalize_solving();
528 #pragma region damping_factor_loop
529 this->info(
"\n\tNonlinearSolver: Damping factor handling:");
534 this->assemble_residual(
false);
536 this->get_parameter_value(this->p_residual_norms).push_back(this->calculate_residual_norm());
539 this->info(
"\tNonlinearSolver: Convergence test...");
540 if (this->handle_convergence_state_return_finished(this->get_convergence_state()))
544 this->info(
"\tNonlinearSolver: Probing the damping factor...");
548 residual_norm_drop = this->calculate_damping_factor(successful_steps_damping);
552 this->finalize_solving();
557 if (!residual_norm_drop)
560 residual_norms.pop_back();
561 solution_norms.pop_back();
564 solution_change_norms.back() /= this->auto_damping_ratio;
569 for (
int i = 0; i < this->problem_size; i++)
570 this->sln_vector[i] = this->previous_sln_vector[i] + (this->sln_vector[i] - this->previous_sln_vector[i]) / this->auto_damping_ratio;
573 solution_norms.push_back(get_l2_norm(this->sln_vector, this->problem_size));
575 }
while (!residual_norm_drop);
579 this->on_damping_factor_updated();
581 #pragma region jacobian_reusage_loop
582 this->info(
"\n\tNonlinearSolver: Jacobian handling:");
585 while (this->jacobian_reusable && (this->constant_jacobian || force_reuse_jacobian_values(successful_steps_jacobian)))
587 this->residual_back->set_vector(this->get_residual());
590 this->info(
"\tNonlinearSolver: Reusing Jacobian.");
591 this->on_reused_jacobian_step_begin();
595 this->solve_linear_system();
598 this->assemble_residual(
false);
600 this->get_parameter_value(this->p_residual_norms).push_back(this->calculate_residual_norm());
603 if (!this->jacobian_reused_okay(successful_steps_jacobian))
605 this->warn(
"\tNonlinearSolver: Reused Jacobian disapproved.");
606 this->get_parameter_value(this->p_residual_norms).pop_back();
607 this->get_parameter_value(this->p_solution_norms).pop_back();
608 this->get_parameter_value(this->p_solution_change_norms).pop_back();
609 memcpy(this->sln_vector, this->previous_sln_vector,
sizeof(Scalar)*this->problem_size);
610 this->get_residual()->set_vector(residual_back);
615 this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(
false);
616 this->get_parameter_value(this->p_iteration)++;
622 this->on_reused_jacobian_step_end();
623 if (!this->on_step_end())
625 this->info(
"\tNonlinearSolver: aborted.");
626 this->finalize_solving();
631 if (this->handle_convergence_state_return_finished(this->get_convergence_state()))
637 this->info(
"\tNonlinearSolver: Re-calculating Jacobian.");
640 this->assemble_jacobian(
true);
644 this->solve_linear_system();
645 this->jacobian_reusable =
true;
648 this->get_parameter_value(this->p_iterations_with_recalculated_jacobian).push_back(
true);
649 this->get_parameter_value(this->p_iteration)++;
655 if (!this->on_step_end())
657 this->info(
"\tNonlinearSolver: aborted.");
658 this->finalize_solving();
663 if (this->handle_convergence_state_return_finished(this->get_convergence_state()))
668 template<
typename Scalar>
671 double residual_norm = *(this->get_parameter_value(this->residual_norms()).end() - 1);
672 double previous_residual_norm = *(this->get_parameter_value(this->residual_norms()).end() - 2);
674 return (residual_norm < previous_residual_norm * this->sufficient_improvement_factor);
677 template<
typename Scalar>
680 return this->get_parameter_value(this->p_iteration);
683 template<
typename Scalar>
686 double residual_norm = *(this->get_parameter_value(this->p_residual_norms).end() - 1);
687 double previous_residual_norm = *(this->get_parameter_value(this->p_residual_norms).end() - 2);
689 if ((residual_norm / previous_residual_norm) > this->sufficient_improvement_factor_jacobian)
691 successful_steps_with_reused_jacobian = 0;
698 template<
typename Scalar>
703 template<
typename Scalar>
708 template<
typename Scalar>
725 return this->convergenceState;
General namespace for the Hermes library.
void set_max_allowed_residual_norm(double max_allowed_residual_norm_to_set)
virtual bool isOkay() const
State querying helpers.
Exception interface Basically a std::exception, but with a constructor with string and with print_msg...
NonlinearConvergenceMeasurementType
This specifies the quantity that is compared to newton_tolerance (settable by set_tolerance()).
bool force_reuse_jacobian_values(unsigned int &successful_steps_with_reused_jacobian)
For deciding if the jacobian is reused at this point.
virtual void on_reused_jacobian_step_end()
void set_initial_auto_damping_coeff(double coeff)
int get_current_iteration_number()
Shortcut method for getting the current iteration.
void set_manual_damping_coeff(bool onOff, double coeff)
Namespace containing classes for vector / matrix operations.
File containing common definitions, and basic global enums etc. for HermesCommon. ...
virtual void on_damping_factor_updated()
virtual void solve(Scalar *coeff_vec)
void finalize_solving()
Internal.
virtual void free()
Frees the instances.
void set_min_allowed_damping_coeff(double min_allowed_damping_coeff_to_set)
void set_sufficient_improvement_factor(double ratio)
bool do_initial_step_return_finished()
Initial step.
Base class for defining interface for nonlinear solvers.
int get_num_iters() const
Get the number of iterations.
virtual double calculate_residual_norm()
Norm for convergence.
virtual bool handle_convergence_state_return_finished(NonlinearConvergenceState state)
NonlinearConvergenceState
Nonlinear Convergence state.
interface for both linear and nonlinear algebraic solvers.
bool calculate_damping_factor(unsigned int &successful_steps)
Calculates the new_ damping coefficient.
void set_auto_damping_ratio(double ratio)
void set_max_allowed_iterations(int max_allowed_iterations)
Set the maximum number of iterations, thus co-determine when to stop iterations.
existing factorization data.
factorization / operator.
void step_info()
Output info about the step.
virtual void on_reused_jacobian_step_begin()
virtual void init_solving(Scalar *coeff_vec)
virtual bool damping_factor_condition()
Returns iff the damping factor condition is fulfilled.
virtual void deinit_solving()
Internal.
virtual NonlinearConvergenceState get_convergence_state()
Find out the convergence state.
File containing common definitions, and basic global enums etc. for HermesCommon. ...
bool jacobian_reused_okay(unsigned int &successful_steps_with_reused_jacobian)
For deciding if the reused jacobian did not bring residual increase at this point.
const int NonlinearConvergenceMeasurementTypeCount
Numeric value is out of allowed range.
void init_nonlinear()
Shared code for constructors.
void set_necessary_successful_steps_to_increase(unsigned int steps)
virtual void clear_tolerances()
Clear (reset) all tolerances.
void set_tolerance(double newton_tol, NonlinearConvergenceMeasurementType toleranceType, bool handleMultipleTolerancesAnd=false)
General nonlinear solver functionality.
void set_max_steps_with_reused_jacobian(unsigned int steps)
virtual void solve_linear_system()
Solve the step's linear system.
void set_sufficient_improvement_factor_jacobian(double ratio)