23#ifndef B2STATIC_NONLINEAR_UTILE_H_
24#define B2STATIC_NONLINEAR_UTILE_H_
29#include "b2ppconfig.h"
33#include "model/b2element.H"
37#include "solvers/b2constraint_util.H"
38#include "solvers/b2solver_utils.H"
39#include "utils/b2linear_algebra.H"
41#include "utils/b2numerical_differentiation.H"
45namespace b2000 {
namespace solver {
47template <
typename T,
typename MATRIX_FORMAT>
48class StaticResidueFunction;
50template <
typename T,
typename MATRIX_FORMAT>
51class IncrementConstraintStrategy;
53template <
typename T,
typename MATRIX_FORMAT>
54class CorrectionStrategy;
57class CorrectionTerminationTest;
61class StaticResidueFunctionForTerminationTest :
public Object {
63 virtual double get_energy_normalisation1() {
68 virtual void mrbc_get_nonlinear_value(
69 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
double time,
70 EquilibriumSolution equilibrium_solution, b2linalg::Vector<T, b2linalg::Vdense_ref> value,
71 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& d_value_d_dof_trans,
72 b2linalg::Vector<T, b2linalg::Vdense_ref> d_value_d_time, SolverHints* solver_hints) = 0;
74 virtual size_t get_number_of_dof() = 0;
76 virtual size_t get_number_of_non_lagrange_dof() = 0;
80class StaticResidueFunctionGeneric :
public StaticResidueFunctionForTerminationTest<T> {
82 virtual void init(Model& model,
const AttributeList& attribute) = 0;
84 virtual Model& get_model() = 0;
86 virtual T get_residue_normalization() {
91 virtual double get_energy() = 0;
93 virtual double get_energy_increment(
const b2linalg::Vector<T>& dof_increment) = 0;
95 virtual const b2linalg::Vector<T, b2linalg::Vdense_constref> get_nbc_sol() = 0;
97 virtual const b2linalg::Vector<T, b2linalg::Vdense_constref> get_residuum_sol(
98 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
const double time) = 0;
100 virtual void get_solution(
101 const b2linalg::Vector<T, b2linalg::Vdense_constref> dof_red,
const double time,
102 EquilibriumSolution equilibrium_solution,
103 b2linalg::Vector<T, b2linalg::Vdense_ref> dof) = 0;
106template <
typename T,
typename MATRIX_FORMAT>
107class StaticResidueFunction :
public StaticResidueFunctionGeneric<T> {
109 StaticResidueFunction()
110 : logger(logging::
get_logger(
"solver.static_nonlinear.ResidueFunction")) {}
112 virtual const b2linalg::Vector<T, b2linalg::Vindex1_constref> get_matrix_diagonal(
113 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof) = 0;
115 virtual void get_residue(
116 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
const double time,
117 const double delta_time, EquilibriumSolution& equilibrium_solution,
118 b2linalg::Vector<T, b2linalg::Vdense_ref> residue,
119 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof,
120 b2linalg::Vector<T, b2linalg::Vdense_ref> d_residue_d_time, SolverHints* solver_hints,
121 CorrectionTerminationTest<T>* termination_test = 0,
122 GradientContainer* gradient_container =
nullptr) = 0;
124 void get_d_dof_d_path(
125 const b2linalg::Vector<T, b2linalg::Vdense_constref> dof,
const double time,
126 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
127 b2linalg::Vector<T, b2linalg::Vdense_ref> q,
128 b2linalg::Vector<T, b2linalg::Vdense_ref> arc,
129 b2linalg::Matrix<T, b2linalg::Mrectangle_ref> d_dof_and_time_d_path,
130 int approximation_order = 1,
double h_scale = 1.0) {
131 const size_t rs = K.size1();
132 d_dof_and_time_d_path.set_zero();
133 if (d_dof_and_time_d_path.size2() > 0) {
134 EquilibriumSolution est(
true);
136 dof, time, 0, est, b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, 0);
137 d_dof_and_time_d_path(rs - 1, 0) = 1;
138 StaticResidueFunction<T, MATRIX_FORMAT>::logger
140 <<
"get_d_dof_d_path: Factorize tangent "
142 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
143 d_dof_and_time_d_path[0] = update_extension_and_inverse(
144 K, q, arc(b2linalg::Interval(0, rs - 1)), arc[rs - 1])
145 * d_dof_and_time_d_path[0];
146 d_dof_and_time_d_path[0] *= 1.0 / (d_dof_and_time_d_path[0] * d_dof_and_time_d_path[0]);
147 arc = d_dof_and_time_d_path[0];
148 h_scale /= d_dof_and_time_d_path[0](b2linalg::Interval(0, rs - 1)).norm2();
172 static const int J[18][10][3] = {
176 {{-3, 3, 3}, {-4, 2, 4}},
177 {{-10, 3, 4}, {-5, 2, 5}},
178 {{-6, 2, 6}, {-10, 4, 4}, {-15, 3, 5}},
179 {{-7, 2, 7}, {-35, 4, 5}, {-21, 3, 6}},
180 {{-28, 3, 7}, {-56, 4, 6}, {-35, 5, 5}, {-8, 2, 8}},
181 {{-36, 3, 8}, {-126, 5, 6}, {-84, 4, 7}, {-9, 2, 9}},
182 {{-126, 6, 6}, {-210, 5, 7}, {-10, 2, 10}, {-120, 4, 8}, {-45, 3, 9}},
183 {{-165, 4, 9}, {-55, 3, 10}, {-11, 2, 11}, {-462, 6, 7}, {-330, 5, 8}},
184 {{-495, 5, 9}, {-792, 6, 8}, {-220, 4, 10}, {-66, 3, 11}, {-462, 7, 7}, {-12, 2, 12}},
232 int ao = approximation_order + d_dof_and_time_d_path.size2() - 2;
233 for (
size_t i = 1; i < d_dof_and_time_d_path.size2(); ++i, --ao) {
234 for (
int j = 0; J[i - 1][j][0] != 0; ++j) {
235 d_dof_and_time_d_path(rs - 1, i) += J[i - 1][j][0]
236 * (d_dof_and_time_d_path[J[i - 1][j][1] - 1]
237 * d_dof_and_time_d_path[J[i - 1][j][2] - 1]);
239 TaylorPathResidue tpr = {dof, time, d_dof_and_time_d_path, i, *
this, arc};
240 std::vector<b2linalg::Vector<T, b2linalg::Vdense_ref> > res;
241 res.push_back(d_dof_and_time_d_path[i](b2linalg::Interval(0, rs - 1)));
243#ifdef TEST_D_DOF_D_PATH
244 for (
size_t ii = 1; ii != i + 2; ++ii) {
246 TaylorPathResidue, Vector<T, Vdense_ref>, Vector<T, Vdense> >(
247 tpr, 0, res, ii, ao, ii, std::pow(1e-15, 1.0 / (ao + ii)));
248 std::cout <<
"ii=" << ii <<
", " << res[0][0] << std::endl;
252 for (
int ii = 0; ii != 10; ++ii) {
253 Vector<T, Vdense> tmp;
255 std::cout <<
"x=" << 0.5 * ii <<
", " << tmp[0] << std::endl;
258 const int aoo = ao + ao % 2;
260 TaylorPathResidue, b2linalg::Vector<T, b2linalg::Vdense_ref>,
261 b2linalg::Vector<T, b2linalg::Vdense> >(
262 tpr, 0, res, i + 1, aoo, i + 1, std::pow(1e-15, 1.0 / (aoo + i + 1)) * h_scale);
264 StaticResidueFunction<T, MATRIX_FORMAT>::logger
266 <<
"get_d_dof_d_path: Factorize tangent "
268 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
269 d_dof_and_time_d_path[i] =
270 update_extension_and_inverse(
271 K, q, arc(b2linalg::Interval(0, rs - 1)), arc[rs - 1])
272 * d_dof_and_time_d_path[i];
274 d_dof_and_time_d_path[i] = inverse(K) * d_dof_and_time_d_path[i];
276 d_dof_and_time_d_path[i] *= -1;
280 void get_d2_residue_d_dof_d_path(
281 const b2linalg::Vector<T, b2linalg::Vdense_constref> dof,
const double time,
282 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K,
283 b2linalg::Matrix<T, b2linalg::Mrectangle_ref> d_dof_and_time_d_path,
284 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> >&
285 d2_residue_d_dof_d_path,
286 int approximation_order = 1,
double h_scale = 1.0) {
287 for (
size_t i = 0; i != d2_residue_d_dof_d_path.size(); ++i) {
288 d2_residue_d_dof_d_path[i].set_same_structure(K);
290 TaylorPath_d_value_d_dof tpdvdd = {dof, time, d_dof_and_time_d_path, *
this, K};
292 TaylorPath_d_value_d_dof,
293 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>,
294 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> >(
295 tpdvdd, 0, d2_residue_d_dof_d_path, 1, approximation_order, 0,
296 std::pow(1e-15, 1.0 / (approximation_order + d2_residue_d_dof_d_path.size() + 1))
300 using type_t = ObjectTypeIncomplete<StaticResidueFunction>;
304 logging::Logger& logger;
307 struct TaylorPathResidue {
308 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof;
310 const b2linalg::Matrix<T, b2linalg::Mrectangle_ref>& d_dof_and_time_d_path;
312 StaticResidueFunction& residue;
313 const b2linalg::Vector<T, b2linalg::Vdense_constref> arc;
314 void operator()(
double x, b2linalg::Vector<T, b2linalg::Vdense>& res) {
315 const b2linalg::Interval inter = b2linalg::Interval(0, dof.size());
316 b2linalg::Vector<T, b2linalg::Vdense> d(d_dof_and_time_d_path.size1());
318 d[dof.size()] = time;
319 b2linalg::Vector<T, b2linalg::Vdense> p(s);
323 for (
size_t i = 0; i != s; ++i) {
329 d += d_dof_and_time_d_path(b2linalg::Interval(0, s)) * p;
330 res.resize(d_dof_and_time_d_path.size1() - 1);
332 EquilibriumSolution esf(
false);
334 d(inter), d[dof.size()], 0, esf, res,
335 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null,
336 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0);
340 struct TaylorPath_d_value_d_dof {
341 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof;
343 const b2linalg::Matrix<T, b2linalg::Mrectangle_ref>& d_dof_and_time_d_path;
344 StaticResidueFunction& residue;
345 const b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& K;
348 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_value_d_dof) {
349 d_value_d_dof.set_same_structure(K);
350 const b2linalg::Interval inter = b2linalg::Interval(0, dof.size());
351 b2linalg::Vector<T, b2linalg::Vdense> d(d_dof_and_time_d_path.size1());
353 d[dof.size()] = time;
354 b2linalg::Vector<T, b2linalg::Vdense> p(d_dof_and_time_d_path.size2());
358 for (
size_t i = 0; i != p.size(); ++i) {
364 d += d_dof_and_time_d_path * p;
365 EquilibriumSolution esf(
false);
366 d_value_d_dof.set_same_structure(K);
368 d(inter), d[dof.size()], 0, esf, b2linalg::Vector<T, b2linalg::Vdense_ref>::null,
369 d_value_d_dof, b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0);
374template <
typename T,
typename MATRIX_FORMAT>
375typename StaticResidueFunction<T, MATRIX_FORMAT>::type_t
376 StaticResidueFunction<T, MATRIX_FORMAT>::type(
377 "StaticResidueFunction", type_name<T, MATRIX_FORMAT>(),
378 StringList(
"STATIC_RESIDUE_FUNCTION"), module);
380template <
typename T,
typename MATRIX_FORMAT>
381class IncrementConstraintStrategy :
public Object {
386 end_of_stage_with_success,
387 end_of_stage_with_error
390 IncrementConstraintStrategy()
392 logger(logging::
get_logger(
"solver.static_nonlinear.increment_constraint_strategy")) {}
394 virtual void init(Model& model,
const AttributeList& attribute) {}
396 void set_max_time(
double time) { max_time = time; }
398 virtual Result set_increment(
399 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
400 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
401 b2linalg::Vector<T, b2linalg::Vdense_ref> q, b2linalg::Vector<T, b2linalg::Vdense_ref> d,
402 double& time, EquilibriumSolution& equilibrium_solution) = 0;
404 virtual void get_constraint(
405 const b2linalg::Vector<T, b2linalg::Vdense>& dof,
const double time, T* constraint,
406 b2linalg::Vector<T, b2linalg::Vdense>* d_constraint_d_dof, T* d_constraint_d_time) = 0;
408 virtual Result set_correction_result(
409 b2linalg::Vector<T, b2linalg::Vdense>& dof,
double& time,
bool converged,
410 int number_of_iteration) = 0;
412 virtual double get_delta_time()
const = 0;
414 using type_t = ObjectTypeIncomplete<IncrementConstraintStrategy>;
419 logging::Logger& logger;
422template <
typename T,
typename MATRIX_FORMAT>
423typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t
424 IncrementConstraintStrategy<T, MATRIX_FORMAT>::type(
425 "IncrementConstraintStrategy", type_name<T, MATRIX_FORMAT>(),
426 StringList(
"INCREMENT_CONSRAINT_STRATEGY"), module);
428template <
typename T,
typename MATRIX_FORMAT>
429class CorrectionStrategy :
public Object {
431 virtual void init(Model& model,
const AttributeList& attribute) {}
433 virtual typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result compute_correction(
434 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
435 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
436 b2linalg::Vector<T, b2linalg::Vdense>& q,
437 IncrementConstraintStrategy<T, MATRIX_FORMAT>& constraint,
438 b2linalg::Vector<T, b2linalg::Vdense>& d,
double& time,
439 EquilibriumSolution& equilibrium_solution) = 0;
441 using type_t = ObjectTypeIncomplete<CorrectionStrategy>;
445 logging::Logger& logger{
logging::get_logger(
"solver.static_nonlinear.correction_strategy")};
448template <
typename T,
typename MATRIX_FORMAT>
449typename CorrectionStrategy<T, MATRIX_FORMAT>::type_t CorrectionStrategy<T, MATRIX_FORMAT>::type(
450 "CorrectionStrategy", type_name<T, MATRIX_FORMAT>(), StringList(
"CORRECTION_STRATEGY"),
454class CorrectionTerminationTest :
public DofFieldFlux<T> {
456 enum Termination { converged, diverged, max_iteration, unfinished };
458 virtual void init(Model& model,
const AttributeList& attribute) {}
460 virtual void new_step() {}
462 virtual void new_iteration() {}
464 virtual void new_evaluation() {}
466 virtual void converged_step() {}
468 virtual bool need_flux() {
return false; }
470 virtual void add_flux(b2linalg::Index& index,
const b2linalg::Vector<T, b2linalg::Vdense>& v) {}
472 virtual void add_flux(
const b2linalg::Vector<T, b2linalg::Vdense_constref>& v) {}
474 virtual double norm_termination(
475 const b2linalg::Vector<T, b2linalg::Vdense_constref>& r,
476 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
477 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
478 const double constraint,
const double d_constraint_d_time,
const double delta_time,
479 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
480 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K) {
484 virtual Termination is_terminated(
485 int number_of_iteration,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& r,
486 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
487 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
488 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof_at_start_step,
489 const double constraint,
const double d_constraint_d_time,
const double delta_time,
490 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
491 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K,
492 double& distance_to_iterative_convergence,
const SolverHints* solver_hints) = 0;
494 virtual int get_nb_divergence()
const {
return 0; }
496 using type_t = ObjectTypeIncomplete<CorrectionTerminationTest>;
500 logging::Logger& logger{
505typename CorrectionTerminationTest<T>::type_t CorrectionTerminationTest<T>::type(
506 "CorrectionTerminationTest", type_name<T>(), StringList(
"CORRECTION_TERMINATION_TEST"),
509class LineSearch :
public Object {
512 virtual ~Function() {}
513 virtual double operator()(
double h) = 0;
516 virtual void init(Model& model,
const AttributeList& attribute) = 0;
518 virtual double get_minimum(Function& g,
double g0,
double g1) = 0;
520 using type_t = ObjectTypeIncomplete<LineSearch>;
531template <
typename T,
typename MATRIX_FORMAT>
532class DefaultStaticResidueFunction :
public StaticResidueFunction<T, MATRIX_FORMAT> {
534 using nbc_t = TypedNaturalBoundaryCondition<T, typename MATRIX_FORMAT::sparse_inversible>;
535 using ebc_t = TypedEssentialBoundaryCondition<T>;
536 using mrbc_t = TypedModelReductionBoundaryCondition<T>;
538 DefaultStaticResidueFunction()
540 number_of_non_lagrang_dof(0),
546 constraint_has_penalty(false),
548 lagrange_mult_scale(0),
550 rcfo_only_spc(false),
551 elements_linear(false) {}
553 void init(Model& model_,
const AttributeList& attribute) {
555 domain = &model->get_domain();
556 ebc = &
dynamic_cast<ebc_t&
>(model->get_essential_boundary_condition(ebc_t::type.get_subtype(
557 "TypedEssentialBoundaryConditionListComponent" + type_name<T>())));
558 mrbc = &
dynamic_cast<mrbc_t&
>(
559 model->get_model_reduction_boundary_condition(mrbc_t::type.get_subtype(
560 "TypedModelReductionBoundaryConditionListComponent" + type_name<T>())));
561 nbc = &
dynamic_cast<nbc_t&
>(model->get_natural_boundary_condition(nbc_t::type.get_subtype(
562 "TypedNaturalBoundaryConditionListComponent"
563 + type_name<T, typename MATRIX_FORMAT::sparse_inversible>())));
564 nbc_sol.resize(domain->get_number_of_dof());
565 fi.resize(domain->get_number_of_dof());
567 constraint_has_penalty =
568 attribute.get_string(
"CONSTRAINT_METHOD",
"REDUCTION") ==
"PENALTY";
570 constraint_has_penalty |=
571 attribute.get_string(
"NONLINEAR_CONSTRAINT_METHOD",
"OTHER") ==
"PENALTY";
573 number_of_dof = number_of_non_lagrang_dof =
574 mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1);
575 if (constraint_has_penalty) {
576 penalty_factor = attribute.get_double(
"CONSTRAINT_PENALTY", 1e10);
578 if (attribute.get_bool(
"REMOVE_DEPENDENT_CONSTRAINTS",
false)) {
580 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_r_d_dof_lin;
581 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::mrbc->get_linear_value(
582 b2linalg::Vector<T, b2linalg::Vdense>::null, trans_d_r_d_dof_lin);
585 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_l_d_dof;
586 r.resize(domain->get_number_of_dof());
587 ebc->get_nonlinear_value(
588 r, 0,
false, b2linalg::Vector<T, b2linalg::Vdense_ref>::null, trans_d_l_d_dof,
589 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0);
592 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_l_d_dof_red;
593 trans_d_l_d_dof_red = trans_d_r_d_dof_lin * trans_d_l_d_dof;
595 get_dependent_columns(trans_d_l_d_dof_red, ebc_to_remove);
597 if (!ebc_to_remove.empty()) {
598 StaticResidueFunction<T, MATRIX_FORMAT>::logger
600 <<
" dependent constraints." << logging::LOGFLUSH;
603 number_of_dof += ebc->get_size(
false) - ebc_to_remove.size();
604 penalty_factor = attribute.get_double(
"CONSTRAINT_PENALTY", 1);
605 if (attribute.get_string(
"NONLINEAR_CONSTRAINT_METHOD",
"OTHER") ==
"LAGRANGE") {
608 lagrange_mult_scale = attribute.get_double(
"LAGRANGE_MULT_SCALE_PENALTY", 1.0);
610 autospc = attribute.get_bool(
"AUTOSPC",
false);
612 rcfo_only_spc = attribute.get_bool(
"RCFO_ONLY_SPC",
false);
614 && attribute.get_string(
"CONSTRAINT_METHOD",
"REDUCTION") ==
"REDUCTION") {
615 Exception() <<
"This is not possible to compute reaction force "
616 "only due to the single point constraint with the reduction "
617 "method. Use Lagrange, augmented Lagrange or penalty method "
621 elements_linear = attribute.get_bool(
"ELEMENTS_LINEAR",
false);
624 Model& get_model() {
return *model; }
626 size_t get_number_of_dof() {
return number_of_dof; }
628 size_t get_number_of_non_lagrange_dof() {
return number_of_non_lagrang_dof; }
631 const b2linalg::Vector<T, b2linalg::Vdense_constref> dof,
const double time,
632 EquilibriumSolution equilibrium_solution,
633 b2linalg::Vector<T, b2linalg::Vdense_ref> dof_sol) {
634 mrbc_get_nonlinear_value(
635 dof(b2linalg::Interval(
636 0, mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1))),
637 time, equilibrium_solution, dof_sol,
638 b2linalg::Matrix<T, b2linalg::Mcompressed_col>::null,
639 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0);
642 const b2linalg::Vector<T, b2linalg::Vdense_constref> get_residuum_sol(
643 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
const double time) {
647 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_l_d_dof;
648 b2linalg::Vector<T> l(ebc->get_size(
false));
649 ebc->get_nonlinear_value(
650 r, time,
false, l, trans_d_l_d_dof,
651 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0);
652 if (!ebc_to_remove.empty()) {
653 l.remove(ebc_to_remove);
654 trans_d_l_d_dof.remove_col(ebc_to_remove);
657 if (constraint_has_penalty) {
658 l *= -penalty_factor;
660 b2linalg::Interval lagrange_mult_range(
661 mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1),
663 if (MATRIX_FORMAT::symmetric && penalty_factor != 0) {
666 l *= -penalty_factor;
667 l += -lagrange_mult_scale * dof(lagrange_mult_range);
669 l = -lagrange_mult_scale * dof(lagrange_mult_range);
672 for (
size_t j = 0; j != trans_d_l_d_dof.size2(); ++j) {
673 if (trans_d_l_d_dof.get_nb_nonzero(j) != 1) { l[j] = 0; }
675 fi = trans_d_l_d_dof * l;
680 const b2linalg::Vector<T, b2linalg::Vdense_constref> get_nbc_sol() {
return nbc_sol; }
682 T get_residue_normalization() {
return std::max(fi * fi, nbc_sol * nbc_sol); }
684 double get_energy_normalisation1() {
686 for (
size_t i = 0; i != r.size(); ++i) {
687 res += std::max(
norm(r[i] * nbc_sol[i]),
norm(r[i] * fi[i]));
692 double get_energy() {
694 for (
size_t i = 0; i != r.size(); ++i) { res += r[i] * (fi[i] + nbc_sol[i]); }
698 double get_energy_increment(
const b2linalg::Vector<T>& dof_increment) {
700 for (
size_t i = 0; i != dof_increment.size(); ++i) {
701 res += dof_increment[i] * (fi[i] + nbc_sol[i]);
706 const b2linalg::Vector<T, b2linalg::Vindex1_constref> get_matrix_diagonal(
707 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof) {
708 b2linalg::Vector<T, b2linalg::Vindex1_constref> res = d_residue_d_dof.get_diagonal();
709 res.set_default_value(lagrange_mult_scale);
714 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
const double time,
715 const double delta_time, EquilibriumSolution& equilibrium_solution,
716 b2linalg::Vector<T, b2linalg::Vdense_ref> residue,
717 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof,
718 b2linalg::Vector<T, b2linalg::Vdense_ref> d_residue_d_time, SolverHints* solver_hints,
719 CorrectionTerminationTest<T>* termination_test, GradientContainer* gradient_container) {
723 b2linalg::Interval disp_range(
724 0, mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1));
725 b2linalg::Interval lagrange_mult_range(
726 mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1), number_of_dof);
728 if (!d_residue_d_time.is_null()) { d_residue_d_dof.set_zero_same_struct(); }
730 r.resize(domain->get_number_of_dof());
731 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_r_d_dof;
732 b2linalg::Vector<T, b2linalg::Vdense> d_r_d_time(domain->get_number_of_dof());
733 mrbc_get_nonlinear_value(
734 dof(disp_range), time, equilibrium_solution, r, trans_d_r_d_dof, d_r_d_time,
740 if (residue.is_null() && d_residue_d_dof.is_null() && d_residue_d_time.is_null()) {
741 solver_utile.get_elements_values(
742 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(r), time, delta_time,
743 equilibrium_solution, elements_linear, trans_d_r_d_dof, d_r_d_time,
744 b2linalg::Vector<double, b2linalg::Vdense_constref>::null, *model,
745 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, d_residue_d_dof,
746 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, gradient_container, solver_hints,
747 StaticResidueFunction<T, MATRIX_FORMAT>::logger, termination_test);
748 nbc->get_nonlinear_value(
749 r, time, equilibrium_solution, b2linalg::Vector<T, b2linalg::Vdense_ref>::null,
750 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null,
751 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, solver_hints);
755 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> d_fe_d_dof;
756 b2linalg::Vector<T, b2linalg::Vdense> d_fe_d_time(domain->get_number_of_dof());
758 nbc->get_nonlinear_value(
759 r, time, equilibrium_solution,
760 (residue.is_null() ? residue : b2linalg::Vector<T, b2linalg::Vdense_ref>(nbc_sol)),
761 d_residue_d_dof.is_null()
762 ? b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>::null
764 (d_residue_d_time.is_null() ? d_residue_d_time
765 : b2linalg::Vector<T, b2linalg::Vdense_ref>(d_fe_d_time)),
767 if (termination_test) { termination_test->add_flux(nbc_sol); }
769 d_fe_d_time = -d_fe_d_time;
770 if (!d_residue_d_dof.is_null() && d_fe_d_dof.size1() != 0) {
771 d_residue_d_dof += -(trans_d_r_d_dof * d_fe_d_dof * transposed(trans_d_r_d_dof));
777 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_l_d_dof;
778 b2linalg::Vector<T> l;
779 b2linalg::Vector<T> d_l_d_time;
781 if (constraint_has_penalty) {
782 if (!residue.is_null()) { l.resize(ebc->get_size(
false)); }
783 if (!d_residue_d_time.is_null()) { d_l_d_time.resize(ebc->get_size(
false)); }
784 ebc->get_nonlinear_value(
785 r, time, equilibrium_solution,
786 (residue.is_null() ? b2linalg::Vector<T>::null : l), trans_d_l_d_dof,
787 (d_residue_d_time.is_null()
788 ? b2linalg::Vector<T, b2linalg::Vdense_ref>::null
789 : b2linalg::Vector<T, b2linalg::Vdense_ref>(d_l_d_time)),
792 const size_t num_lm_full = lagrange_mult_range.size() + ebc_to_remove.size();
793 assert(ebc->get_size(
false) == num_lm_full);
795 b2linalg::Vector<T> residue_lm_tmp;
796 if (!residue.is_null()) { residue_lm_tmp.resize(num_lm_full); }
799 b2linalg::Vector<T> d_residue_d_time_lm_tmp;
800 if (!d_residue_d_time.is_null()) { d_residue_d_time_lm_tmp.resize(num_lm_full); }
802 ebc->get_nonlinear_value(
803 r, time, equilibrium_solution,
805 (residue.is_null() ? b2linalg::Vector<T, b2linalg::Vdense_ref>::null
806 : b2linalg::Vector<T, b2linalg::Vdense_ref>(residue_lm_tmp)),
809 (d_residue_d_time.is_null()
810 ? b2linalg::Vector<T, b2linalg::Vdense_ref>::null
811 : b2linalg::Vector<T, b2linalg::Vdense_ref>(d_residue_d_time_lm_tmp)),
813 if (!residue.is_null()) {
814 if (!ebc_to_remove.empty()) { residue_lm_tmp.remove(ebc_to_remove); }
815 residue(lagrange_mult_range) = residue_lm_tmp;
817 if (!ebc_to_remove.empty()) { trans_d_l_d_dof.remove_col(ebc_to_remove); }
818 if (!d_residue_d_time.is_null()) {
819 if (!ebc_to_remove.empty()) { d_residue_d_time_lm_tmp.remove(ebc_to_remove); }
820 d_residue_d_time(lagrange_mult_range) = d_residue_d_time_lm_tmp;
821 d_residue_d_time(lagrange_mult_range) += transposed(trans_d_l_d_dof) * d_r_d_time;
825 if (!d_residue_d_time.is_null() && d_fe_d_dof.size1()) {
826 d_fe_d_time -= d_fe_d_dof * d_r_d_time;
833 StaticResidueFunction<T, MATRIX_FORMAT>::logger
835 << (d_residue_d_dof.is_null() ?
"first" :
"second") <<
" variation)"
836 << logging::LOGFLUSH;
837 solver_utile.get_elements_values(
838 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(r), time, delta_time,
839 equilibrium_solution, elements_linear, trans_d_r_d_dof, d_r_d_time,
840 b2linalg::Vector<double, b2linalg::Vdense_constref>::null, *model,
841 (residue.is_null() ? b2linalg::Vector<T, b2linalg::Vdense_ref>::null
842 : b2linalg::Vector<T, b2linalg::Vdense_ref>(fi)),
844 (d_residue_d_time.is_null() ? b2linalg::Vector<T, b2linalg::Vdense_ref>::null
845 : b2linalg::Vector<T, b2linalg::Vdense_ref>(d_fe_d_time)),
846 gradient_container, solver_hints, StaticResidueFunction<T, MATRIX_FORMAT>::logger,
848 if (equilibrium_solution.input_level == 0) { equilibrium_solution.input_level = 1; }
850 if (StaticResidueFunction<T, MATRIX_FORMAT>::logger.is_enabled_for(
logging::data)) {
851 StaticResidueFunction<T, MATRIX_FORMAT>::logger <<
logging::data <<
"dof "
852 << logging::DBName(
"DOF.GLOB") << r
853 << logging::LOGFLUSH;
854 if (!residue.is_null()) {
855 StaticResidueFunction<T, MATRIX_FORMAT>::logger
856 <<
logging::data <<
"value " << logging::DBName(
"VALUE.GLOB") << fi
857 << logging::LOGFLUSH;
859 if (!d_residue_d_dof.is_null()) {
860 StaticResidueFunction<T, MATRIX_FORMAT>::logger
861 <<
logging::data <<
"d_value_d_dof " << logging::DBName(
"D_VALUE_D_DOF.GLOB")
862 << d_residue_d_dof << logging::LOGFLUSH;
866 if (!residue.is_null()) {
867 b2linalg::Vector<T, b2linalg::Vdense> tmp;
869 if (constraint_has_penalty) {
870 tmp += (trans_d_l_d_dof * l) * penalty_factor;
872 if (MATRIX_FORMAT::symmetric && penalty_factor != 0) {
875 b2linalg::Vector<T> tmp1;
876 tmp1 = residue(lagrange_mult_range) * penalty_factor;
877 tmp1 += dof(lagrange_mult_range) * lagrange_mult_scale;
878 tmp += trans_d_l_d_dof * tmp1;
880 tmp += lagrange_mult_scale * (trans_d_l_d_dof * dof(lagrange_mult_range));
882 residue(lagrange_mult_range) *= lagrange_mult_scale;
884 residue(disp_range) = trans_d_r_d_dof * tmp;
885 if (StaticResidueFunction<T, MATRIX_FORMAT>::logger.is_enabled_for(
logging::data)) {
888 dynamic_cast<SolutionStaticNonlinear<T>&
>(model->get_solution())
889 .set_equilibrium(time, tmp);
893 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_LR;
894 trans_LR = trans_d_r_d_dof * trans_d_l_d_dof;
895 if (!d_residue_d_dof.is_null()) {
896 if (penalty_factor != 0 && (constraint_has_penalty || MATRIX_FORMAT::symmetric)) {
900 d_residue_d_dof(disp_range, disp_range) +=
901 (trans_LR * b2linalg::transposed(trans_LR)) * penalty_factor;
903 if (!constraint_has_penalty) {
904 trans_LR *= lagrange_mult_scale;
905 b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = b2linalg::transposed(trans_LR);
906 d_residue_d_dof(lagrange_mult_range, disp_range) += LR;
907 if (!MATRIX_FORMAT::symmetric) {
908 d_residue_d_dof(disp_range, lagrange_mult_range) += trans_LR;
917 std::set<size_t> zero_columns_r;
918 for (
size_t i = 0; i != disp_range.get_end() ; ++i) {
919 if (d_residue_d_dof(i, i) == T(0)) {
920 bool all_zero =
true;
921 for (
size_t j = 0; all_zero && j != d_residue_d_dof.size2(); ++j) {
922 if (d_residue_d_dof(i, j) != T(0)) { all_zero =
false; }
925 zero_columns_r.insert(i);
926 if (autospc) { d_residue_d_dof(i, i) += T(1); }
931 if (!zero_columns_r.empty()) {
932 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
933 nks_r.resize(d_residue_d_dof.size1(), 1);
935 for (
auto i : zero_columns_r) { nks_r(i, 0) = T(1); }
936 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
937 model->get_domain().get_number_of_dof(), nks_r.size2());
938 for (
size_t i = 0; i != nks_r.size2(); ++i) {
939 get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
941 for (
size_t i = 0; i != nks.size1(); ++i) {
942 nks(i, 0) = (nks(i, 0) != T(0) ? T(1) : T(0));
944 model->get_solution().set_system_null_space(nks,
false,
"NS_STRUCTURE");
949 if (!d_residue_d_time.is_null()) {
950 d_residue_d_time(disp_range) = trans_d_r_d_dof * d_fe_d_time;
951 if (constraint_has_penalty) {
952 d_residue_d_time(disp_range) +=
953 penalty_factor * (trans_LR * d_l_d_time);
955 d_residue_d_time(lagrange_mult_range) *= lagrange_mult_scale;
960 void mrbc_get_nonlinear_value(
961 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
double time,
962 EquilibriumSolution equilibrium_solution, b2linalg::Vector<T, b2linalg::Vdense_ref> value,
963 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& d_value_d_dof_trans,
964 b2linalg::Vector<T, b2linalg::Vdense_ref> d_value_d_time, SolverHints* solver_hints) {
965 mrbc->get_nonlinear_value(
966 dof, time, equilibrium_solution, value, d_value_d_dof_trans,
967 b2linalg::Matrix<T, b2linalg::Mrectangle_ref>(d_value_d_time), solver_hints);
970 using type_t = ObjectTypeComplete<
971 DefaultStaticResidueFunction,
typename StaticResidueFunction<T, MATRIX_FORMAT>::type_t>;
975 size_t number_of_dof;
976 size_t number_of_non_lagrang_dof;
982 b2linalg::Vector<T, b2linalg::Vdense> fi;
983 b2linalg::Vector<T, b2linalg::Vdense> nbc_sol;
984 b2linalg::Vector<T, b2linalg::Vdense> r;
985 b2linalg::Index ebc_to_remove;
986 SolverUtils<T, MATRIX_FORMAT> solver_utile;
987 bool constraint_has_penalty;
988 double penalty_factor;
989 double lagrange_mult_scale;
992 bool elements_linear;
995template <
typename T,
typename MATRIX_FORMAT>
996typename DefaultStaticResidueFunction<T, MATRIX_FORMAT>::type_t
997 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::type(
998 "DefaultStaticResidueFunction", type_name<T, MATRIX_FORMAT>(),
999 StringList(
"DEFAULT_STATIC_RESIDUE_FUNCTION"), module);
1001template <
typename T,
typename MATRIX_FORMAT>
1002class ScaledStaticResidueFunction :
public DefaultStaticResidueFunction<T, MATRIX_FORMAT> {
1004 using base_class = DefaultStaticResidueFunction<T, MATRIX_FORMAT>;
1006 T get_residue_normalization() {
return 1; }
1009 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
const double time,
1010 const double delta_time, EquilibriumSolution& equilibrium_solution,
1011 b2linalg::Vector<T, b2linalg::Vdense_ref> residue,
1012 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof,
1013 b2linalg::Vector<T, b2linalg::Vdense_ref> d_residue_d_time, SolverHints* solver_hints,
1014 CorrectionTerminationTest<T>* termination_test, GradientContainer* gradient_container) {
1015 if (scale_vector.empty()) {
1016 if (d_residue_d_dof.is_null() || d_residue_d_time.is_null()) {
1019 scale_vector.reserve(d_residue_d_dof.size1());
1020 for (
size_t i = 0; i != d_residue_d_dof.size1(); ++i) { scale_vector.push_back(1); }
1021 b2linalg::Vector<T, b2linalg::Vdense> dof_tmp(dof.size());
1022 base_class::get_residue(
1023 dof_tmp, time, delta_time, equilibrium_solution, residue, d_residue_d_dof,
1024 d_residue_d_time, solver_hints, termination_test, gradient_container);
1025 for (
size_t i = 0; i != d_residue_d_dof.size1(); ++i) {
1026 scale_vector[i] = 1 / std::sqrt(std::abs(d_residue_d_dof(i, i)));
1029 d_residue_d_time = inverse(d_residue_d_dof) * d_residue_d_time;
1031 for (
size_t i = 0; i != d_residue_d_time.size(); ++i) {
1032 const T tt = d_residue_d_time[i] / scale_vector[i];
1035 scale_vector *= std::sqrt(t);
1038 base_class::get_residue(
1039 dof, time, delta_time, equilibrium_solution, residue, d_residue_d_dof,
1040 d_residue_d_time, solver_hints, termination_test, gradient_container);
1043 void mrbc_get_nonlinear_value(
1044 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
double time,
1045 EquilibriumSolution equilibrium_solution, b2linalg::Vector<T, b2linalg::Vdense_ref> value,
1046 b2linalg::Matrix<T, b2linalg::Mcompressed_col>& d_value_d_dof_trans,
1047 b2linalg::Vector<T, b2linalg::Vdense_ref> d_value_d_time, SolverHints* solver_hints) {
1048 b2linalg::Vector<T, b2linalg::Vdense> dof_tmp;
1050 dof_tmp.scale(scale_vector);
1051 base_class::mrbc->get_nonlinear_value(
1052 dof_tmp, time, equilibrium_solution, value, d_value_d_dof_trans,
1053 b2linalg::Matrix<T, b2linalg::Mrectangle_ref>(d_value_d_time), solver_hints);
1054 if (!d_value_d_dof_trans.is_null()) { d_value_d_dof_trans.scale_row(scale_vector); }
1057 using type_t = ObjectTypeComplete<
1058 ScaledStaticResidueFunction,
1059 typename DefaultStaticResidueFunction<T, MATRIX_FORMAT>::type_t>;
1063 b2linalg::Vector<T, b2linalg::Vdense> scale_vector;
1066template <
typename T,
typename MATRIX_FORMAT>
1067typename ScaledStaticResidueFunction<T, MATRIX_FORMAT>::type_t
1068 ScaledStaticResidueFunction<T, MATRIX_FORMAT>::type(
1069 "ScaledStaticResidueFunction", type_name<T, MATRIX_FORMAT>(),
1070 StringList(
"SCALED_STATIC_RESIDUE_FUNCTION"), module);
1072template <
typename T,
typename MATRIX_FORMAT>
1073class ArtificialDampingStaticResidueFunction
1074 :
public DefaultStaticResidueFunction<T, MATRIX_FORMAT> {
1076 ArtificialDampingStaticResidueFunction()
1077 : DefaultStaticResidueFunction<T, MATRIX_FORMAT>(),
1078 rayleigh_damping_alpha(0.0),
1079 rayleigh_damping_beta(0.0),
1080 dissipated_energy_fraction(0.0),
1084 void init(Model& model,
const AttributeList& attribute) {
1085 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::init(model, attribute);
1087 const char* alpha_s =
"RAYLEIGH_ALPHA";
1088 const char* beta_s =
"RAYLEIGH_BETA";
1089 const char* def_s =
"DISSIPATED_ENERGY_FRACTION";
1091 if (attribute.has_key(alpha_s) && attribute.has_key(beta_s)) {
1092 rayleigh_damping_alpha = attribute.get_double(alpha_s);
1093 rayleigh_damping_beta = attribute.get_double(beta_s);
1096 rayleigh_damping_alpha = 1;
1097 rayleigh_damping_beta = 0;
1098 dissipated_energy_fraction = attribute.get_double(def_s, 1.e-4);
1100 if (d_residue_d_dofdot.size1() == 0) { sfactor = 0; }
1106 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
const double time,
1107 const double delta_time, EquilibriumSolution& equilibrium_solution,
1108 b2linalg::Vector<T, b2linalg::Vdense_ref> residue,
1109 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof,
1110 b2linalg::Vector<T, b2linalg::Vdense_ref> d_residue_d_time, SolverHints* solver_hints,
1111 CorrectionTerminationTest<T>* termination_test, GradientContainer* gradient_container) {
1112 EquilibriumSolution equilibrium_solution_input = equilibrium_solution;
1116 if (d_residue_d_dofdot.size1()
1117 != DefaultStaticResidueFunction<T, MATRIX_FORMAT>::number_of_dof
1119 compute_damping_matrix(b2linalg::Vector<T, b2linalg::Vdense>::null);
1121 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_residue(
1122 dof, time, delta_time, equilibrium_solution, residue, d_residue_d_dof,
1123 d_residue_d_time, solver_hints, termination_test, gradient_container);
1124 if (old_dof.size() == 0) {
1129 if (delta_time <= 0) {
1130 Exception() <<
"Artificial damping can only be used with a load-controlled constraint "
1131 "strategy (e.g. increment_control_type=load)."
1134 const double i_delta_time = 1.0 / delta_time;
1136 b2linalg::Vector<T, b2linalg::Vdense> tmp;
1137 if (d_residue_d_dofdot.size1()
1138 == DefaultStaticResidueFunction<T, MATRIX_FORMAT>::number_of_dof
1139 && (!residue.is_null() || !d_residue_d_time.is_null())
1140 && d_residue_d_dofdot.size1() != 0) {
1141 b2linalg::Vector<T, b2linalg::Vdense> delta_dof;
1142 delta_dof = dof - old_dof;
1143 tmp = sfactor * i_delta_time * (d_residue_d_dofdot * delta_dof);
1145 if (d_residue_d_dofdot.size1()
1146 == DefaultStaticResidueFunction<T, MATRIX_FORMAT>::number_of_dof
1147 && !residue.is_null() && !tmp.empty()) {
1150 if (!d_residue_d_dof.is_null()
1151 && d_residue_d_dofdot.size1()
1152 == DefaultStaticResidueFunction<T, MATRIX_FORMAT>::number_of_dof
1154 d_residue_d_dof += sfactor * i_delta_time * d_residue_d_dofdot;
1156 if (d_residue_d_dofdot.size1()
1157 == DefaultStaticResidueFunction<T, MATRIX_FORMAT>::number_of_dof
1158 && !d_residue_d_time.is_null() && !tmp.empty()) {
1159 d_residue_d_time += i_delta_time * tmp;
1161 if (equilibrium_solution_input && time > old_time) {
1162 if (d_residue_d_dofdot.size1() == 0) {
1163 b2linalg::Vector<T, b2linalg::Vdense> dof_ur(
1164 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::model->get_domain()
1165 .get_number_of_dof());
1166 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_solution(
1167 dof, time, equilibrium_solution_input, dof_ur);
1168 b2linalg::Vector<T, b2linalg::Vdense> old_dof_ur(dof_ur.size());
1169 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_solution(
1170 old_dof, old_time, equilibrium_solution_input, old_dof_ur);
1171 dof_ur -= old_dof_ur;
1172 const double s1 = DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_energy();
1173 const double s2 = compute_damping_matrix(dof_ur) / delta_time;
1174 sfactor = dissipated_energy_fraction * s1 / s2;
1175 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::logger
1176 <<
logging::debug <<
"scale factor for the stabilised method " << sfactor
1177 << logging::LOGFLUSH;
1180 b2linalg::Vector<T, b2linalg::Vdense> delta_dof;
1181 delta_dof = dof - old_dof;
1182 b2linalg::Vector<T> tmp;
1183 tmp = sfactor * i_delta_time * (d_residue_d_dofdot * delta_dof);
1184 const double dissipated_energy =
norm(tmp * delta_dof);
1185 double energy_increment;
1187 b2linalg::Vector<T, b2linalg::Vdense> dof_ur(
1188 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::model->get_domain()
1189 .get_number_of_dof());
1190 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_solution(
1191 dof, time, equilibrium_solution_input, dof_ur);
1192 b2linalg::Vector<T, b2linalg::Vdense> old_dof_ur(dof_ur.size());
1193 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_solution(
1194 old_dof, old_time, equilibrium_solution_input, old_dof_ur);
1195 dof_ur -= old_dof_ur;
1197 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::get_energy_increment(
1200 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::logger
1201 <<
logging::debug <<
"dissipated energy in the step = " << dissipated_energy
1202 <<
", by increment unit = " << dissipated_energy * i_delta_time
1203 <<
", energy increment = " << energy_increment <<
"." << logging::LOGFLUSH;
1204 Solution& solution =
1205 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::model->get_solution();
1206 solution.set_value(
"AD_DISSIPATED_ENERGY_IN_STEP", dissipated_energy);
1207 solution.set_value(
"MODEL_ENERGY_INCREMENT", energy_increment);
1214 using type_t = ObjectTypeComplete<
1215 ArtificialDampingStaticResidueFunction,
1216 typename StaticResidueFunction<T, MATRIX_FORMAT>::type_t>;
1220 double rayleigh_damping_alpha;
1221 double rayleigh_damping_beta;
1222 double dissipated_energy_fraction;
1225 b2linalg::Vector<T, b2linalg::Vdense> old_dof;
1226 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible> d_residue_d_dofdot;
1228 double compute_damping_matrix(b2linalg::Vector<T, b2linalg::Vdense>& dof) {
1229 b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_r_d_dof;
1230 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::mrbc->get_linear_value(
1231 b2linalg::Vector<T, b2linalg::Vdense>::null, trans_d_r_d_dof);
1232 d_residue_d_dofdot.resize(DefaultStaticResidueFunction<T, MATRIX_FORMAT>::number_of_dof);
1233 b2linalg::Index index;
1234 std::vector<b2linalg::Matrix<T, typename MATRIX_FORMAT::dense> > d_fe_d_dof_elem(3);
1235 std::vector<bool> d_value_d_dof_flags(3,
true);
1236 d_value_d_dof_flags[1] =
false;
1237 std::unique_ptr<Domain::ElementIterator> i =
1238 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::domain->get_element_iterator();
1239 DefaultStaticResidueFunction<T, MATRIX_FORMAT>::domain->set_dof(
1240 b2linalg::Vector<double, b2linalg::Vdense_constref>::null);
1241 b2linalg::Vector<T, b2linalg::Vdense> dof_res(dof.size());
1242 double norm_inf_mass_matrix = 0;
1243 for (Element* e = i->next(); e !=
nullptr; e = i->next()) {
1244 if (
auto te =
dynamic_cast<TypedElement<T>*
>(e); te !=
nullptr) {
1246 *DefaultStaticResidueFunction<T, MATRIX_FORMAT>::model,
1251 b2linalg::Matrix<T, b2linalg::Mrectangle_constref>::null,
1254 index, b2linalg::Vector<T, b2linalg::Vdense>::null, d_value_d_dof_flags,
1255 d_fe_d_dof_elem, b2linalg::Vector<T, b2linalg::Vdense>::null);
1257 norm_inf_mass_matrix += d_fe_d_dof_elem[2].norm_inf();
1258 d_fe_d_dof_elem[0] *= T(rayleigh_damping_beta);
1259 d_fe_d_dof_elem[0] += T(rayleigh_damping_alpha) * d_fe_d_dof_elem[2];
1260 if (!dof.is_null()) { dof_res(index) += d_fe_d_dof_elem[0] * dof(index); }
1261 d_residue_d_dofdot +=
1263 * StructuredMatrix(trans_d_r_d_dof.size2(), index, d_fe_d_dof_elem[0])
1264 * transposed(trans_d_r_d_dof);
1266 if (norm_inf_mass_matrix < 1e-15 && rayleigh_damping_alpha != 0) {
1267 Exception() <<
"Artificial damping on a zero mass model." <<
THROW;
1269 return dof * dof_res;
1273template <
typename T,
typename MATRIX_FORMAT>
1274typename ArtificialDampingStaticResidueFunction<T, MATRIX_FORMAT>::type_t
1275 ArtificialDampingStaticResidueFunction<T, MATRIX_FORMAT>::type(
1276 "ArtificialDampingStaticResidueFunction", type_name<T, MATRIX_FORMAT>(),
1277 StringList(
"ARTIFICIAL_DAMPING_STATIC_RESIDUE_FUNCTION"), module);
1279template <
typename T,
typename MATRIX_FORMAT>
1280class LoadControlConstraintStrategy :
public IncrementConstraintStrategy<T, MATRIX_FORMAT> {
1282 LoadControlConstraintStrategy()
1287 time_at_start_step(0),
1289 corrector_nb_newton_iteration(0),
1290 refactorization(true) {}
1292 void init(Model& model,
const AttributeList& attribute) {
1293 step_size = attribute.get_double(
"STEP_SIZE_INIT", 0.1);
1294 step_size_min = attribute.get_double(
"STEP_SIZE_MIN", 1e-12);
1295 step_size_max = attribute.get_double(
"STEP_SIZE_MAX", 1e100);
1296 step_size_match = attribute.get_double(
"STEP_SIZE_MATCH", 0);
1298 attribute.get_int(
"NB_ITERATION", attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50) / 2);
1299 corrector_nb_newton_iteration = attribute.get_double(
"NB_ITERATION_CORRECTION", 0.5);
1300 refactorization =
true;
1303 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_increment(
1304 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
1305 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
1306 b2linalg::Vector<T, b2linalg::Vdense_ref> q, b2linalg::Vector<T, b2linalg::Vdense_ref> d,
1307 double& time_, EquilibriumSolution& equilibrium_solution) {
1308 dof_at_start_step = d;
1309 time_at_start_step = time_;
1310 time = time_ + step_size;
1311 if (step_size_match != 0
1312 &&
int(time_at_start_step / step_size_match) <
int(time / step_size_match)) {
1313 time = (int(time_at_start_step / step_size_match) + 1) * step_size_match;
1315 if (time > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - step_size_min) {
1316 time = IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
1319 Solution& solution = residue_function.get_model().get_solution();
1320 if (refactorization) {
1321 residue_function.get_residue(
1322 d, time_, step_size, equilibrium_solution,
1323 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, 0);
1326 b2linalg::Vector<T, b2linalg::Vdense> v(q.size() + 1);
1328 Model& model = residue_function.get_model();
1329 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
1330 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
1331 b2linalg::SingularMatrixError ee;
1332 bool is_singular =
false;
1334 if (refactorization) {
1335 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1337 <<
"Compute prediction and factorize tangent "
1338 "stiffness matrix ("
1339 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
1340 v = update_extension_and_inverse(
1341 K, q, v(b2linalg::Interval(0, q.size())), 1.0, nks_r, nbnsv)
1344 v = inverse(K, nks_r, nbnsv) * v;
1346 }
catch (b2linalg::SingularMatrixError& e) {
1349 if (!e.singular_dofs.empty()) {
1350 if (nks_r.size2() == 0) {
1351 nks_r.resize(K.size1(), 1);
1354 for (
auto i : e.singular_dofs) {
1355 assert(i < nks_r.size1());
1356 for (
size_t j = 0; j != nks_r.size2(); ++j) { nks_r(i, j) = T(1); }
1360 if (nks_r.size2() != 0) {
1361 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1362 model.get_domain().get_number_of_dof(), nks_r.size2());
1363 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1364 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1366 solution.set_system_null_space(nks);
1368 if (is_singular) { ee <<
THROW; }
1370 d += (time - time_) * v(b2linalg::Interval(0, q.size()));
1372 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
1375 void get_constraint(
1376 const b2linalg::Vector<T, b2linalg::Vdense>& dof,
const double time_, T* constraint,
1377 b2linalg::Vector<T, b2linalg::Vdense>* d_constraint_d_dof, T* d_constraint_d_time) {
1378 if (constraint) { *constraint = time_ - time; }
1379 if (d_constraint_d_dof) { d_constraint_d_dof->set_zero(); }
1380 if (d_constraint_d_time) { *d_constraint_d_time = 1; }
1383 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_correction_result(
1384 b2linalg::Vector<T, b2linalg::Vdense>& dof,
double& time_,
bool converged,
1385 int number_of_iteration) {
1387 if (time > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - 1e-8) {
1388 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success;
1390 const double step_size_scale = std::pow(
1391 corrector_nb_newton_iteration,
1392 double(number_of_iteration - nb_iteration) / (nb_iteration - 1));
1393 step_size *= step_size_scale;
1394 step_size = std::max(step_size, step_size_min);
1395 if (step_size > step_size_max) {
1396 step_size = step_size_max;
1397 refactorization =
false;
1398 }
else if (step_size_scale > 1) {
1399 refactorization =
false;
1401 refactorization =
true;
1403 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1404 <<
logging::debug <<
"new step size = " << step_size << logging::LOGFLUSH;
1405 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
1407 refactorization =
true;
1409 if (step_size < step_size_min) {
1410 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1411 <<
logging::error <<
"Cannot continue, the step size (" << step_size
1412 <<
") is below the minimum step size(" << step_size_min <<
")."
1413 << logging::LOGFLUSH;
1414 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
1416 dof = dof_at_start_step;
1417 time_ = time = time_at_start_step;
1418 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1419 <<
logging::debug <<
"new step size = " << step_size << logging::LOGFLUSH;
1420 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry;
1423 double get_delta_time()
const {
return step_size; }
1425 using type_t = ObjectTypeComplete<
1426 LoadControlConstraintStrategy,
1427 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t>;
1433 double step_size_min;
1434 double step_size_max;
1435 double step_size_match;
1436 b2linalg::Vector<T, b2linalg::Vdense> dof_at_start_step;
1437 double time_at_start_step;
1439 double corrector_nb_newton_iteration;
1440 bool refactorization;
1444template <
typename T,
typename MATRIX_FORMAT>
1445typename LoadControlConstraintStrategy<T, MATRIX_FORMAT>::type_t
1446 LoadControlConstraintStrategy<T, MATRIX_FORMAT>::type(
1447 "LoadControlConstraintStrategy", type_name<T, MATRIX_FORMAT>(),
1448 StringList(
"LOAD_CONTROL_CONSTRAINT_STRATEGY"), module);
1450template <
typename T,
typename MATRIX_FORMAT>
1451class StateControlConstraintStrategy :
public IncrementConstraintStrategy<T, MATRIX_FORMAT> {
1453 StateControlConstraintStrategy()
1454 : stage_termination_procedure(false),
1458 time_at_start_step(0),
1460 corrector_nb_newton_iteration(0) {}
1462 void init(Model& model,
const AttributeList& attribute) {
1463 step_size = attribute.get_double(
"STEP_SIZE_INIT", 0.1);
1464 step_size_min = attribute.get_double(
"STEP_SIZE_MIN", 1e-12);
1465 step_size_max = attribute.get_double(
"STEP_SIZE_MAX", 1e100);
1467 attribute.get_int(
"NB_ITERATION", attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50) / 2);
1468 corrector_nb_newton_iteration = attribute.get_double(
"NB_ITERATION_CORRECTION", 0.5);
1469 stage_termination_procedure =
false;
1472 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_increment(
1473 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
1474 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
1475 b2linalg::Vector<T, b2linalg::Vdense_ref> q, b2linalg::Vector<T, b2linalg::Vdense_ref> d,
1476 double& time, EquilibriumSolution& equilibrium_solution) {
1477 dof_at_start_step = d;
1478 time_at_start_step = time;
1479 residue_function.get_residue(
1480 d, time, step_size, equilibrium_solution,
1481 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, 0);
1482 b2linalg::Vector<T, b2linalg::Vdense> v(q.size() + 1);
1484 Model& model = residue_function.get_model();
1485 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
1486 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
1488 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1490 <<
"Compute prediction and factorize tangent "
1491 "stiffness matrix ("
1492 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
1493 v = update_extension_and_inverse(
1494 K, q, v(b2linalg::Interval(0, q.size())), 1.0, nks_r, nbnsv)
1496 }
catch (b2linalg::SingularMatrixError& e) {
1497 if (nks_r.size2() != 0) {
1498 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1499 model.get_domain().get_number_of_dof(), nks_r.size2());
1500 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1501 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1503 residue_function.get_model().get_solution().set_system_null_space(nks);
1507 if (nks_r.size2() != 0) {
1508 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1509 model.get_domain().get_number_of_dof(), nks_r.size2());
1510 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1511 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1513 residue_function.get_model().get_solution().set_system_null_space(nks);
1516 double d_time = std::sqrt(step_size / ((v * v) - 1));
1517 if (stage_termination_procedure
1519 > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - step_size_min) {
1520 stage_termination_procedure =
true;
1521 d += (time - IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time)
1522 * v(b2linalg::Interval(0, q.size()));
1523 time = IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
1525 d += d_time * v(b2linalg::Interval(0, q.size()));
1528 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
1531 void get_constraint(
1532 const b2linalg::Vector<T, b2linalg::Vdense>& dof,
const double time, T* constraint,
1533 b2linalg::Vector<T, b2linalg::Vdense>* d_constraint_d_dof, T* d_constraint_d_time) {
1534 if (stage_termination_procedure) {
1536 *constraint = time - IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
1538 if (d_constraint_d_dof) { d_constraint_d_dof->set_zero(); }
1539 if (d_constraint_d_time) { *d_constraint_d_time = 1; }
1541 b2linalg::Vector<T, b2linalg::Vdense> d_dof;
1542 d_dof = dof - dof_at_start_step;
1543 if (constraint) { *constraint = d_dof * d_dof - step_size * step_size; }
1544 if (d_constraint_d_dof) { *d_constraint_d_dof = 2.0 * d_dof; }
1545 if (d_constraint_d_time) { *d_constraint_d_time = 0; }
1549 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_correction_result(
1550 b2linalg::Vector<T, b2linalg::Vdense>& dof,
double& time,
bool converged,
1551 int number_of_iteration) {
1553 if (time > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - 1e-8
1554 || stage_termination_procedure) {
1555 stage_termination_procedure =
false;
1556 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success;
1558 step_size *= std::pow(
1559 corrector_nb_newton_iteration,
1560 double(number_of_iteration - nb_iteration) / (nb_iteration - 1));
1561 step_size = std::min(std::max(step_size, step_size_min), step_size_max);
1562 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
1564 stage_termination_procedure =
false;
1566 if (step_size < step_size_min) {
1567 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1568 <<
logging::error <<
"Cannot continue, the step size (" << step_size
1569 <<
") is below the minimum step size(" << step_size_min <<
")."
1570 << logging::LOGFLUSH;
1571 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
1573 dof = dof_at_start_step;
1574 time = time_at_start_step;
1575 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1576 <<
logging::debug <<
"new step size = " << step_size << logging::LOGFLUSH;
1577 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry;
1580 double get_delta_time()
const {
return step_size; }
1582 using type_t = ObjectTypeComplete<
1583 StateControlConstraintStrategy,
1584 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t>;
1588 bool stage_termination_procedure;
1590 double step_size_min;
1591 double step_size_max;
1592 b2linalg::Vector<T, b2linalg::Vdense> dof_at_start_step;
1593 double time_at_start_step;
1595 double corrector_nb_newton_iteration;
1598template <
typename T,
typename MATRIX_FORMAT>
1599typename StateControlConstraintStrategy<T, MATRIX_FORMAT>::type_t
1600 StateControlConstraintStrategy<T, MATRIX_FORMAT>::type(
1601 "StateControlConstraintStrategy", type_name<T, MATRIX_FORMAT>(),
1602 StringList(
"STATE_CONTROL_CONSTRAINT_STRATEGY"), module);
1604template <
typename T,
typename MATRIX_FORMAT>
1605class HyperplaneControlConstraintStrategy :
public IncrementConstraintStrategy<T, MATRIX_FORMAT> {
1607 HyperplaneControlConstraintStrategy()
1608 : stage_termination_procedure(false),
1612 step_size_lambda_min(0),
1613 step_size_lambda_max(0),
1614 step_size_dof_min(0),
1615 step_size_dof_max(0),
1616 step_size_dof_lambda_fact(-1),
1617 step_size_lambda_fact(-1),
1618 step_size_dof_fact(-1),
1619 time_at_start_step(0),
1621 corrector_nb_newton_iteration(0) {}
1623 void init(Model& model,
const AttributeList& attribute) {
1624 step_size = attribute.get_double(
"STEP_SIZE_INIT", 0.1);
1625 step_size_min = attribute.get_double(
1626 "STEP_SIZE_PATH_MIN", attribute.get_double(
"STEP_SIZE_MIN", 1e-12));
1627 step_size_max = attribute.get_double(
1628 "STEP_SIZE_PATH_MAX", attribute.get_double(
"STEP_SIZE_MAX", 1e100));
1629 step_size_lambda_min = attribute.get_double(
"STEP_SIZE_LAMBDA_MIN", 1e-12);
1630 step_size_lambda_max = attribute.get_double(
1631 "STEP_SIZE_LAMBDA_MAX", IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time);
1632 step_size_dof_min = attribute.get_double(
"STEP_SIZE_DOF_MIN", 1e-12);
1633 step_size_dof_max = attribute.get_double(
"STEP_SIZE_DOF_MAX", 1e100);
1635 attribute.get_int(
"NB_ITERATION", attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50) / 2);
1636 corrector_nb_newton_iteration = attribute.get_double(
"NB_ITERATION_CORRECTION", 0.5);
1637 stage_termination_procedure =
false;
1638 predictor_taylor_order_path =
1639 attribute.get_int(
"TAYLOR_ORDER_PATH", attribute.get_int(
"TAYLOR_ORDER", 1));
1640 predictor_approximation_order_path = attribute.get_int(
1641 "APPROXIMATION_ORDER_PATH", attribute.get_int(
"APPROXIMATION_ORDER", 2));
1644 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_increment(
1645 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
1646 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
1647 b2linalg::Vector<T, b2linalg::Vdense_ref> q, b2linalg::Vector<T, b2linalg::Vdense_ref> d,
1648 double& time, EquilibriumSolution& equilibrium_solution) {
1649 residue_function.get_residue(
1650 d, time, step_size, equilibrium_solution,
1651 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, 0);
1652 size_t rs = residue_function.get_number_of_dof();
1653 if (dof_at_start_step.size() == 0) {
1654 d_dof_d_time_at_previous_step.resize(rs + 1);
1655 d_dof_d_time_at_previous_step[rs] = 1;
1656 velocity_at_start_step.resize(rs + 1);
1657 velocity_at_start_step[rs] = 1;
1659 velocity_at_start_step.set_zero();
1660 velocity_at_start_step[rs] =
1661 d_dof_d_time_at_previous_step * d_dof_d_time_at_previous_step;
1663 dof_at_start_step = d;
1664 time_at_start_step = time;
1665 Model& model = residue_function.get_model();
1666 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
1667 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
1669 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1671 <<
"Compute prediction and factorize tangent "
1672 "stiffness matrix ("
1673 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
1674 velocity_at_start_step =
1675 update_extension_and_inverse(
1676 K, q, d_dof_d_time_at_previous_step(b2linalg::Interval(0, rs)),
1677 d_dof_d_time_at_previous_step[rs], nks_r, nbnsv)
1678 * velocity_at_start_step;
1679 }
catch (b2linalg::SingularMatrixError& e) {
1680 if (nks_r.size2() != 0) {
1681 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1682 model.get_domain().get_number_of_dof(), nks_r.size2());
1683 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1684 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1686 residue_function.get_model().get_solution().set_system_null_space(nks);
1690 if (nks_r.size2() != 0) {
1691 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1692 model.get_domain().get_number_of_dof(), nks_r.size2());
1693 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1694 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1696 residue_function.get_model().get_solution().set_system_null_space(nks);
1699 const size_t nnld = residue_function.get_number_of_non_lagrange_dof();
1700 double norm_nld = velocity_at_start_step(b2linalg::Interval(0, nnld)).norm2();
1701 double norm_ld = velocity_at_start_step(b2linalg::Interval(nnld, rs - 1)).norm2();
1702 double norm_lambda = std::abs(velocity_at_start_step[rs]);
1706 / std::sqrt(norm_nld * norm_nld + norm_ld * norm_ld + norm_lambda * norm_lambda);
1707 velocity_at_start_step *= v;
1713 if (step_size_lambda_fact == -1) {
1714 if (velocity_at_start_step[rs] == velocity_at_start_step[rs]) {
1715 step_size /= velocity_at_start_step[rs];
1720 step_size_dof_lambda_fact = std::sqrt(norm_nld * norm_nld + norm_lambda * norm_lambda);
1721 if (step_size_dof_lambda_fact * step_size > step_size_max) {
1722 step_size = step_size_max / step_size_dof_lambda_fact;
1724 if (step_size_dof_lambda_fact * step_size < step_size_min) {
1725 step_size = step_size_min / step_size_dof_lambda_fact;
1728 if (norm_lambda > 0) {
1729 step_size_lambda_fact = norm_lambda;
1730 if (step_size_lambda_fact * step_size > step_size_lambda_max) {
1731 step_size = step_size_lambda_max / step_size_lambda_fact;
1733 if (step_size_lambda_fact * step_size < step_size_lambda_min) {
1734 step_size = step_size_lambda_min / step_size_lambda_fact;
1738 step_size_dof_fact = norm_nld;
1739 if (step_size_dof_fact * step_size > step_size_dof_max) {
1740 step_size = step_size_dof_max / step_size_dof_fact;
1742 if (step_size_dof_fact * step_size < step_size_dof_min) {
1743 step_size = step_size_dof_min / step_size_dof_fact;
1746 if (time + step_size * step_size_lambda_fact
1747 > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time
1748 - std::max(step_size_lambda_min, step_size_min * step_size_lambda_fact)) {
1749 stage_termination_procedure =
true;
1751 if (stage_termination_procedure) {
1752 d += ((IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - time)
1753 / velocity_at_start_step[rs])
1754 * velocity_at_start_step(b2linalg::Interval(0, rs));
1755 time = IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
1757 d += step_size * velocity_at_start_step(b2linalg::Interval(0, rs));
1758 time += step_size * velocity_at_start_step[rs];
1760 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
1763 void get_constraint(
1764 const b2linalg::Vector<T, b2linalg::Vdense>& dof,
const double time, T* constraint,
1765 b2linalg::Vector<T, b2linalg::Vdense>* d_constraint_d_dof, T* d_constraint_d_time) {
1766 if (stage_termination_procedure
1767 || time >= IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time) {
1769 *constraint = time - IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
1771 if (d_constraint_d_dof) { d_constraint_d_dof->set_zero(); }
1772 if (d_constraint_d_time) { *d_constraint_d_time = 1; }
1774 b2linalg::Vector<T, b2linalg::Vdense> d_dof;
1775 d_dof = dof - dof_at_start_step;
1776 size_t rs = velocity_at_start_step.size() - 1;
1778 *constraint = velocity_at_start_step(b2linalg::Interval(0, rs)) * d_dof
1779 + velocity_at_start_step[rs] * (time - time_at_start_step)
1782 if (d_constraint_d_dof) {
1783 *d_constraint_d_dof = velocity_at_start_step(b2linalg::Interval(0, rs));
1785 if (d_constraint_d_time) { *d_constraint_d_time = velocity_at_start_step[rs]; }
1789 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_correction_result(
1790 b2linalg::Vector<T, b2linalg::Vdense>& dof,
double& time,
bool converged,
1791 int number_of_iteration) {
1793 d_dof_d_time_at_previous_step(b2linalg::Interval(0, dof.size())) =
1794 dof - dof_at_start_step;
1795 d_dof_d_time_at_previous_step[dof.size()] = time - time_at_start_step;
1796 if (time > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - 1e-8
1797 || stage_termination_procedure) {
1798 stage_termination_procedure =
false;
1799 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success;
1801 step_size *= std::pow(
1802 corrector_nb_newton_iteration,
1803 double(number_of_iteration - nb_iteration) / (nb_iteration - 1));
1804 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
1807 stage_termination_procedure =
false;
1808 if (step_size * step_size_dof_lambda_fact < step_size_min) {
1809 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1811 <<
"Cannot continue, the step size along the continuation "
1813 << step_size * step_size_dof_lambda_fact <<
") is below the minimum ("
1814 << step_size_min <<
")." << logging::LOGFLUSH;
1815 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
1817 if (step_size * step_size_lambda_fact < step_size_lambda_min) {
1818 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1820 <<
"Cannot continue, the step size on the lambda parameter "
1822 << step_size * step_size_lambda_fact <<
") is below the minimum ("
1823 << step_size_lambda_min <<
")." << logging::LOGFLUSH;
1824 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
1826 if (step_size * step_size_dof_fact < step_size_dof_min) {
1827 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1829 <<
"Cannot continue, the step size on the norm of the "
1831 << step_size * step_size_dof_fact <<
") is below the minimum ("
1832 << step_size_dof_min <<
")." << logging::LOGFLUSH;
1833 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
1835 dof = dof_at_start_step;
1836 time = time_at_start_step;
1837 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1838 <<
logging::debug <<
"new step size = " << step_size << logging::LOGFLUSH;
1839 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry;
1842 double get_delta_time()
const {
return step_size; }
1844 using type_t = ObjectTypeComplete<
1845 HyperplaneControlConstraintStrategy,
1846 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t>;
1850 bool stage_termination_procedure;
1852 double step_size_min;
1853 double step_size_max;
1854 double step_size_lambda_min;
1855 double step_size_lambda_max;
1856 double step_size_dof_min;
1857 double step_size_dof_max;
1858 double step_size_dof_lambda_fact;
1859 double step_size_lambda_fact;
1860 double step_size_dof_fact;
1861 int predictor_taylor_order_path;
1862 int predictor_approximation_order_path;
1863 b2linalg::Vector<T, b2linalg::Vdense> dof_at_start_step;
1864 double time_at_start_step;
1865 b2linalg::Vector<T, b2linalg::Vdense> velocity_at_start_step;
1866 b2linalg::Vector<T, b2linalg::Vdense> d_dof_d_time_at_previous_step;
1868 double corrector_nb_newton_iteration;
1871template <
typename T,
typename MATRIX_FORMAT>
1872typename HyperplaneControlConstraintStrategy<T, MATRIX_FORMAT>::type_t
1873 HyperplaneControlConstraintStrategy<T, MATRIX_FORMAT>::type(
1874 "HyperplaneControlConstraintStrategy", type_name<T, MATRIX_FORMAT>(),
1875 StringList(
"HYPERPLANE_CONTROL_CONSTRAINT_STRATEGY"), module);
1877template <
typename T,
typename MATRIX_FORMAT>
1878class NormalFlowControlConstraintStrategy :
public IncrementConstraintStrategy<T, MATRIX_FORMAT> {
1880 NormalFlowControlConstraintStrategy()
1881 : stage_termination_procedure(false),
1885 step_size_lambda_min(0),
1886 step_size_lambda_max(0),
1887 step_size_dof_min(0),
1888 step_size_dof_max(0),
1889 step_size_dof_lambda_fact(-1),
1890 step_size_lambda_fact(-1),
1891 step_size_dof_fact(-1),
1892 time_at_start_step(0),
1894 corrector_nb_newton_iteration(0),
1898 void init(Model& model,
const AttributeList& attribute) {
1899 step_size = attribute.get_double(
"STEP_SIZE_INIT", 0.1);
1900 step_size_min = attribute.get_double(
1901 "STEP_SIZE_PATH_MIN", attribute.get_double(
"STEP_SIZE_MIN", 1e-12));
1902 step_size_max = attribute.get_double(
1903 "STEP_SIZE_PATH_MAX", attribute.get_double(
"STEP_SIZE_MAX", 1e100));
1904 step_size_lambda_min = attribute.get_double(
"STEP_SIZE_LAMBDA_MIN", 1e-12);
1905 step_size_lambda_max = attribute.get_double(
1906 "STEP_SIZE_LAMBDA_MAX", IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time);
1907 step_size_dof_min = attribute.get_double(
"STEP_SIZE_DOF_MIN", 1e-12);
1908 step_size_dof_max = attribute.get_double(
"STEP_SIZE_DOF_MAX", 1e100);
1910 attribute.get_int(
"NB_ITERATION", attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50) / 2);
1911 corrector_nb_newton_iteration = attribute.get_double(
"NB_ITERATION_CORRECTION", 0.5);
1912 stage_termination_procedure =
false;
1913 predictor_taylor_order_path =
1914 attribute.get_int(
"TAYLOR_ORDER_PATH", attribute.get_int(
"TAYLOR_ORDER", 1));
1915 predictor_approximation_order_path = attribute.get_int(
1916 "APPROXIMATION_ORDER_PATH", attribute.get_int(
"APPROXIMATION_ORDER", 2));
1919 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_increment(
1920 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
1921 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
1922 b2linalg::Vector<T, b2linalg::Vdense_ref> q, b2linalg::Vector<T, b2linalg::Vdense_ref> d,
1923 double& time, EquilibriumSolution& equilibrium_solution) {
1924 residue_function.get_residue(
1925 d, time, step_size, equilibrium_solution,
1926 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, 0);
1929 size_t rs = residue_function.get_number_of_dof();
1930 if (dof_at_start_step.size() == 0) {
1931 d_dof_d_time_at_previous_step.resize(rs + 1);
1932 d_dof_d_time_at_previous_step[rs] = 1;
1933 velocity_at_start_step.resize(rs + 1);
1934 velocity_at_start_step[rs] = 1;
1936 velocity_at_start_step.set_zero();
1937 velocity_at_start_step[rs] =
1938 d_dof_d_time_at_previous_step * d_dof_d_time_at_previous_step;
1940 dof_at_start_step = d;
1941 time_at_start_step = time;
1942 Model& model = residue_function.get_model();
1943 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
1944 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
1946 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
1948 <<
"Compute prediction and factorize tangent "
1949 "stiffness matrix ("
1950 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
1951 velocity_at_start_step =
1952 update_extension_and_inverse(
1953 K, q, d_dof_d_time_at_previous_step(b2linalg::Interval(0, rs)),
1954 d_dof_d_time_at_previous_step[rs], nks_r, nbnsv)
1955 * velocity_at_start_step;
1956 }
catch (b2linalg::SingularMatrixError& e) {
1957 if (nks_r.size2() != 0) {
1958 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1959 model.get_domain().get_number_of_dof(), nks_r.size2());
1960 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1961 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1963 residue_function.get_model().get_solution().set_system_null_space(nks);
1967 if (nks_r.size2() != 0) {
1968 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
1969 model.get_domain().get_number_of_dof(), nks_r.size2());
1970 for (
size_t i = 0; i != nks_r.size2(); ++i) {
1971 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
1973 residue_function.get_model().get_solution().set_system_null_space(nks);
1975 const size_t nnld = residue_function.get_number_of_non_lagrange_dof();
1976 double norm_nld = velocity_at_start_step(b2linalg::Interval(0, nnld)).norm2();
1977 double norm_ld = velocity_at_start_step(b2linalg::Interval(nnld, rs - 1)).norm2();
1978 double norm_lambda = std::abs(velocity_at_start_step[rs]);
1982 / std::sqrt(norm_nld * norm_nld + norm_ld * norm_ld + norm_lambda * norm_lambda);
1983 velocity_at_start_step *= v;
1989 if (step_size_lambda_fact == -1) {
1990 if (velocity_at_start_step[rs] == velocity_at_start_step[rs]) {
1991 step_size /= velocity_at_start_step[rs];
1996 step_size_dof_lambda_fact = std::sqrt(norm_nld * norm_nld + norm_lambda * norm_lambda);
1997 if (step_size_dof_lambda_fact * step_size > step_size_max) {
1998 step_size = step_size_max / step_size_dof_lambda_fact;
2000 if (step_size_dof_lambda_fact * step_size < step_size_min) {
2001 step_size = step_size_min / step_size_dof_lambda_fact;
2004 if (norm_lambda > 0) {
2005 step_size_lambda_fact = norm_lambda;
2006 if (step_size_lambda_fact * step_size > step_size_lambda_max) {
2007 step_size = step_size_lambda_max / step_size_lambda_fact;
2009 if (step_size_lambda_fact * step_size < step_size_lambda_min) {
2010 step_size = step_size_lambda_min / step_size_lambda_fact;
2014 step_size_dof_fact = norm_nld;
2015 if (step_size_dof_fact * step_size > step_size_dof_max) {
2016 step_size = step_size_dof_max / step_size_dof_fact;
2018 if (step_size_dof_fact * step_size < step_size_dof_min) {
2019 step_size = step_size_dof_min / step_size_dof_fact;
2022 if (time + step_size * step_size_lambda_fact
2023 > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time
2024 - std::max(step_size_lambda_min, step_size_min * step_size_lambda_fact)) {
2025 stage_termination_procedure =
true;
2027 if (stage_termination_procedure) {
2028 d += ((IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - time)
2029 / velocity_at_start_step[rs])
2030 * velocity_at_start_step(b2linalg::Interval(0, rs));
2031 time = IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
2033 d += step_size * velocity_at_start_step(b2linalg::Interval(0, rs));
2034 time += step_size * velocity_at_start_step[rs];
2036 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
2039 void get_constraint(
2040 const b2linalg::Vector<T, b2linalg::Vdense>& dof,
const double time, T* constraint,
2041 b2linalg::Vector<T, b2linalg::Vdense>* d_constraint_d_dof, T* d_constraint_d_time) {
2042 if (stage_termination_procedure
2043 || time >= IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time) {
2045 *constraint = time - IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
2047 if (d_constraint_d_dof) { d_constraint_d_dof->set_zero(); }
2048 if (d_constraint_d_time) { *d_constraint_d_time = 1; }
2050 b2linalg::Vector<T, b2linalg::Vdense> d_dof;
2051 d_dof = dof - dof_at_start_step;
2052 size_t rs = velocity_at_start_step.size() - 1;
2053 if (constraint) { *constraint = 0; }
2054 if (d_constraint_d_dof || d_constraint_d_time) {
2055 velocity_at_start_step(b2linalg::Interval(0, rs)) =
2057 b2linalg::Matrix<T, b2linalg::Msym_compressed_col_update_inv>&)(*K_ptr))
2059 velocity_at_start_step[rs] = 1;
2060 velocity_at_start_step.normalize();
2061 velocity_at_start_step *= -1;
2062 if (d_constraint_d_dof) {
2063 *d_constraint_d_dof = velocity_at_start_step(b2linalg::Interval(0, rs));
2065 if (d_constraint_d_time) { *d_constraint_d_time = velocity_at_start_step[rs]; }
2070 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_correction_result(
2071 b2linalg::Vector<T, b2linalg::Vdense>& dof,
double& time,
bool converged,
2072 int number_of_iteration) {
2074 d_dof_d_time_at_previous_step(b2linalg::Interval(0, dof.size())) =
2075 dof - dof_at_start_step;
2076 d_dof_d_time_at_previous_step[dof.size()] = time - time_at_start_step;
2077 if (time > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - 1e-8
2078 || stage_termination_procedure) {
2079 stage_termination_procedure =
false;
2080 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success;
2082 step_size *= std::pow(
2083 corrector_nb_newton_iteration,
2084 double(number_of_iteration - nb_iteration) / (nb_iteration - 1));
2085 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
2088 stage_termination_procedure =
false;
2089 if (step_size * step_size_dof_lambda_fact < step_size_min) {
2090 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2092 <<
"Cannot continue, the step size along the continuation "
2094 << step_size * step_size_dof_lambda_fact <<
") is below the minimum ("
2095 << step_size_min <<
")." << logging::LOGFLUSH;
2096 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
2098 if (step_size * step_size_lambda_fact < step_size_lambda_min) {
2099 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2101 <<
"Cannot continue, the step size on the lambda parameter "
2103 << step_size * step_size_lambda_fact <<
") is below the minimum ("
2104 << step_size_lambda_min <<
")." << logging::LOGFLUSH;
2105 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
2107 if (step_size * step_size_dof_fact < step_size_dof_min) {
2108 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2110 <<
"Cannot continue, the step size on the norm of the "
2112 << step_size * step_size_dof_fact <<
") is below the minimum ("
2113 << step_size_dof_min <<
")." << logging::LOGFLUSH;
2114 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
2116 dof = dof_at_start_step;
2117 time = time_at_start_step;
2118 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2119 <<
logging::debug <<
"new step size = " << step_size << logging::LOGFLUSH;
2120 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry;
2123 double get_delta_time()
const {
return step_size; }
2125 using type_t = ObjectTypeComplete<
2126 NormalFlowControlConstraintStrategy,
2127 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t>;
2131 bool stage_termination_procedure;
2133 double step_size_min;
2134 double step_size_max;
2135 double step_size_lambda_min;
2136 double step_size_lambda_max;
2137 double step_size_dof_min;
2138 double step_size_dof_max;
2139 double step_size_dof_lambda_fact;
2140 double step_size_lambda_fact;
2141 double step_size_dof_fact;
2142 int predictor_taylor_order_path;
2143 int predictor_approximation_order_path;
2144 b2linalg::Vector<T, b2linalg::Vdense> dof_at_start_step;
2145 double time_at_start_step;
2146 b2linalg::Vector<T, b2linalg::Vdense> velocity_at_start_step;
2147 b2linalg::Vector<T, b2linalg::Vdense> d_dof_d_time_at_previous_step;
2149 double corrector_nb_newton_iteration;
2150 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>* K_ptr;
2151 b2linalg::Vector<T, b2linalg::Vdense_ref>* q_ptr;
2154template <
typename T,
typename MATRIX_FORMAT>
2155typename NormalFlowControlConstraintStrategy<T, MATRIX_FORMAT>::type_t
2156 NormalFlowControlConstraintStrategy<T, MATRIX_FORMAT>::type(
2157 "NormalFlowControlConstraintStrategy", type_name<T, MATRIX_FORMAT>(),
2158 StringList(
"NORMALFLOW_CONTROL_CONSTRAINT_STRATEGY"), module);
2160template <
typename T,
typename MATRIX_FORMAT>
2161class LocalHyperellipticControlConstraintStrategy
2162 :
public IncrementConstraintStrategy<T, MATRIX_FORMAT> {
2164 LocalHyperellipticControlConstraintStrategy()
2165 : stage_termination_procedure(false),
2169 step_size_lambda_min(0),
2170 step_size_lambda_max(0),
2171 step_size_dof_min(0),
2172 step_size_dof_max(0),
2173 step_size_dof_lambda_fact(-1),
2174 step_size_lambda_fact(-1),
2175 step_size_dof_fact(-1),
2178 time_at_start_step(0),
2180 corrector_nb_newton_iteration(0) {}
2182 void init(Model& model,
const AttributeList& attribute) {
2183 step_size = attribute.get_double(
"STEP_SIZE_INIT", 0.1);
2184 step_size_min = attribute.get_double(
2185 "STEP_SIZE_PATH_MIN", attribute.get_double(
"STEP_SIZE_MIN", 1e-12));
2186 step_size_max = attribute.get_double(
2187 "STEP_SIZE_PATH_MAX", attribute.get_double(
"STEP_SIZE_MAX", 1e100));
2188 step_size_lambda_min = attribute.get_double(
"STEP_SIZE_LAMBDA_MIN", 1e-12);
2189 step_size_lambda_max = attribute.get_double(
2190 "STEP_SIZE_LAMBDA_MAX", IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time);
2191 step_size_dof_min = attribute.get_double(
"STEP_SIZE_DOF_MIN", 1e-12);
2192 step_size_dof_max = attribute.get_double(
"STEP_SIZE_DOF_MAX", 1e100);
2194 attribute.get_int(
"NB_ITERATION", attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50) / 2);
2195 corrector_nb_newton_iteration = attribute.get_double(
"NB_ITERATION_CORRECTION", 0.5);
2196 ellipse_a_2 = attribute.get_double(
"HYPERELLIPTIC_A", 1.0);
2197 ellipse_a_2 *= ellipse_a_2;
2198 ellipse_b_2 = attribute.get_double(
"HYPERELLIPTIC_B", 1.0);
2199 ellipse_b_2 *= ellipse_b_2;
2200 stage_termination_procedure =
false;
2203 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_increment(
2204 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
2205 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
2206 b2linalg::Vector<T, b2linalg::Vdense_ref> q, b2linalg::Vector<T, b2linalg::Vdense_ref> d,
2207 double& time, EquilibriumSolution& equilibrium_solution) {
2208 residue_function.get_residue(
2209 d, time, step_size, equilibrium_solution,
2210 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, 0);
2211 size_t rs = residue_function.get_number_of_dof();
2212 if (dof_at_start_step.size() == 0) {
2213 dof_at_start_step = d;
2214 time_at_start_step = time;
2215 d_dof_d_time_at_previous_step.resize(rs + 1);
2216 d_dof_d_time_at_previous_step[rs] = 1;
2217 velocity_at_start_step.resize(rs + 1);
2218 velocity_at_start_step[rs] = 1;
2220 velocity_at_start_step.set_zero();
2221 velocity_at_start_step[rs] =
2222 d_dof_d_time_at_previous_step * d_dof_d_time_at_previous_step;
2224 dof_at_start_step = d;
2225 time_at_start_step = time;
2227 Model& model = residue_function.get_model();
2228 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
2229 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
2231 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2233 <<
"Compute prediction and factorize tangent "
2234 "stiffness matrix ("
2235 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
2236 velocity_at_start_step =
2237 update_extension_and_inverse(
2238 K, q, d_dof_d_time_at_previous_step(b2linalg::Interval(0, rs)),
2239 d_dof_d_time_at_previous_step[rs], nks_r, nbnsv)
2240 * velocity_at_start_step;
2241 }
catch (b2linalg::SingularMatrixError& e) {
2242 if (nks_r.size2() != 0) {
2243 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
2244 model.get_domain().get_number_of_dof(), nks_r.size2());
2245 for (
size_t i = 0; i != nks_r.size2(); ++i) {
2246 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
2248 residue_function.get_model().get_solution().set_system_null_space(nks);
2252 if (nks_r.size2() != 0) {
2253 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
2254 model.get_domain().get_number_of_dof(), nks_r.size2());
2255 for (
size_t i = 0; i != nks_r.size2(); ++i) {
2256 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
2258 residue_function.get_model().get_solution().set_system_null_space(nks);
2260 const size_t nnld = residue_function.get_number_of_non_lagrange_dof();
2261 double norm_nld = velocity_at_start_step(b2linalg::Interval(0, nnld)).norm2();
2262 double norm_ld = velocity_at_start_step(b2linalg::Interval(nnld, rs - 1)).norm2();
2263 double norm_lambda = std::abs(velocity_at_start_step[rs]);
2267 / std::sqrt(norm_nld * norm_nld + norm_ld * norm_ld + norm_lambda * norm_lambda);
2268 velocity_at_start_step *= v;
2274 if (step_size_lambda_fact == -1) {
2275 if (velocity_at_start_step[rs] == velocity_at_start_step[rs]) {
2276 step_size /= velocity_at_start_step[rs];
2280 step_size_dof_lambda_fact = std::sqrt(norm_nld * norm_nld + norm_lambda * norm_lambda);
2281 if (step_size_dof_lambda_fact * step_size > step_size_max) {
2282 step_size = step_size_max / step_size_dof_lambda_fact;
2284 if (step_size_dof_lambda_fact * step_size < step_size_min) {
2285 step_size = step_size_min / step_size_dof_lambda_fact;
2288 if (norm_lambda > 0) {
2289 step_size_lambda_fact = norm_lambda;
2290 if (step_size_lambda_fact * step_size > step_size_lambda_max) {
2291 step_size = step_size_lambda_max / step_size_lambda_fact;
2293 if (step_size_lambda_fact * step_size < step_size_lambda_min) {
2294 step_size = step_size_lambda_min / step_size_lambda_fact;
2298 step_size_dof_fact = norm_nld;
2299 if (step_size_dof_fact * step_size > step_size_dof_max) {
2300 step_size = step_size_dof_max / step_size_dof_fact;
2302 if (step_size_dof_fact * step_size < step_size_dof_min) {
2303 step_size = step_size_dof_min / step_size_dof_fact;
2306 if (time + step_size * step_size_lambda_fact
2307 > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time
2308 - std::max(step_size_lambda_min, step_size_min * step_size_lambda_fact)) {
2309 stage_termination_procedure =
true;
2311 if (stage_termination_procedure) {
2312 d += ((IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - time)
2313 / velocity_at_start_step[rs])
2314 * velocity_at_start_step(b2linalg::Interval(0, rs));
2315 time = IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
2317 d += step_size * velocity_at_start_step(b2linalg::Interval(0, rs));
2318 time += step_size * velocity_at_start_step[rs];
2320 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
2323 void get_constraint(
2324 const b2linalg::Vector<T, b2linalg::Vdense>& dof,
const double time, T* constraint,
2325 b2linalg::Vector<T, b2linalg::Vdense>* d_constraint_d_dof, T* d_constraint_d_time) {
2326 if (stage_termination_procedure
2327 || time >= IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time) {
2329 *constraint = time - IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time;
2331 if (d_constraint_d_dof) { d_constraint_d_dof->set_zero(); }
2332 if (d_constraint_d_time) { *d_constraint_d_time = 1; }
2334 size_t rs = velocity_at_start_step.size() - 1;
2335 b2linalg::Vector<T, b2linalg::Vdense> d_dof(rs + 1);
2336 d_dof(b2linalg::Interval(0, rs)) = dof - dof_at_start_step;
2337 d_dof[rs] = time - time_at_start_step;
2338 T v_dd = velocity_at_start_step * d_dof;
2339 b2linalg::Vector<T, b2linalg::Vdense> d_dof_s;
2340 d_dof_s = d_dof - velocity_at_start_step * v_dd;
2342 *constraint = ellipse_a_2 * v_dd + ellipse_b_2 * (d_dof_s * d_dof_s) - step_size;
2344 if (d_constraint_d_dof || d_constraint_d_time) {
2346 for (
size_t i = 0; i != d_dof_s.size(); ++i) {
2347 s += d_dof_s[i] * (velocity_at_start_step[i] * velocity_at_start_step[i]);
2349 if (d_constraint_d_dof) {
2350 for (
size_t i = 0; i != rs; ++i) {
2351 (*d_constraint_d_dof)[i] = 2 * ellipse_a_2 * velocity_at_start_step[i]
2352 + 2 * ellipse_b_2 * (d_dof_s[i] - s);
2355 if (d_constraint_d_time) {
2356 *d_constraint_d_time = 2 * ellipse_a_2 * velocity_at_start_step[rs]
2357 + 2 * ellipse_b_2 * (d_dof_s[rs] - s);
2363 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result set_correction_result(
2364 b2linalg::Vector<T, b2linalg::Vdense>& dof,
double& time,
bool converged,
2365 int number_of_iteration) {
2366 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2367 <<
logging::debug <<
"Insertion of the correction result in the predictor";
2369 d_dof_d_time_at_previous_step(b2linalg::Interval(0, dof.size())) =
2370 dof - dof_at_start_step;
2371 d_dof_d_time_at_previous_step[dof.size()] = time - time_at_start_step;
2372 if (time > IncrementConstraintStrategy<T, MATRIX_FORMAT>::max_time - 1e-8
2373 || stage_termination_procedure) {
2374 stage_termination_procedure =
false;
2375 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2376 <<
", end of stage with success." << logging::LOGFLUSH;
2377 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_success;
2379 step_size *= std::pow(
2380 corrector_nb_newton_iteration,
2381 double(number_of_iteration - nb_iteration) / (nb_iteration - 1));
2382 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2383 <<
", next step with step size=" << step_size <<
"." << logging::LOGFLUSH;
2384 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage;
2387 stage_termination_procedure =
false;
2388 if (step_size * step_size_dof_lambda_fact < step_size_min) {
2389 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2391 <<
"Cannot continue, the step size along the continuation "
2393 << step_size * step_size_dof_lambda_fact <<
") is below the minimum ("
2394 << step_size_min <<
")." << logging::LOGFLUSH;
2395 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
2397 if (step_size * step_size_lambda_fact < step_size_lambda_min) {
2398 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2400 <<
"Cannot continue, the step size on the lambda parameter "
2402 << step_size * step_size_lambda_fact <<
") is below the minimum ("
2403 << step_size_lambda_min <<
")." << logging::LOGFLUSH;
2404 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
2406 if (step_size * step_size_dof_fact < step_size_dof_min) {
2407 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2409 <<
"Cannot continue, the step size on the norm of the "
2411 << step_size * step_size_dof_fact <<
") is below the minimum ("
2412 << step_size_dof_min <<
")." << logging::LOGFLUSH;
2413 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::end_of_stage_with_error;
2415 dof = dof_at_start_step;
2416 time = time_at_start_step;
2417 IncrementConstraintStrategy<T, MATRIX_FORMAT>::logger
2418 <<
", retry step with step size=" << step_size <<
"." << logging::LOGFLUSH;
2419 return IncrementConstraintStrategy<T, MATRIX_FORMAT>::in_stage_and_retry;
2422 double get_delta_time()
const {
return step_size; }
2424 using type_t = ObjectTypeComplete<
2425 LocalHyperellipticControlConstraintStrategy,
2426 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::type_t>;
2430 bool stage_termination_procedure;
2432 double step_size_min;
2433 double step_size_max;
2434 double step_size_lambda_min;
2435 double step_size_lambda_max;
2436 double step_size_dof_min;
2437 double step_size_dof_max;
2438 double step_size_dof_lambda_fact;
2439 double step_size_lambda_fact;
2440 double step_size_dof_fact;
2443 b2linalg::Vector<T, b2linalg::Vdense> dof_at_start_step;
2444 double time_at_start_step;
2445 b2linalg::Vector<T, b2linalg::Vdense> velocity_at_start_step;
2446 b2linalg::Vector<T, b2linalg::Vdense> d_dof_d_time_at_previous_step;
2448 double corrector_nb_newton_iteration;
2451template <
typename T,
typename MATRIX_FORMAT>
2452typename LocalHyperellipticControlConstraintStrategy<T, MATRIX_FORMAT>::type_t
2453 LocalHyperellipticControlConstraintStrategy<T, MATRIX_FORMAT>::type(
2454 "LocalHyperellipticControlConstraintStrategy", type_name<T, MATRIX_FORMAT>(),
2456 "LOCAL_HYPERELLIPTIC_CONTROL_CONSTRAINT_STRATEGY",
2457 "HYPERELLIPTIC_CONTROL_CONSTRAINT_STRATEGY"),
2460template <
typename T,
typename MATRIX_FORMAT>
2461class NewtonMethod :
public CorrectionStrategy<T, MATRIX_FORMAT> {
2463 enum Method { conventional, modified, delayed_modified };
2465 NewtonMethod() : termination_test(0), method(modified), periodic_update(100) {}
2467 virtual ~NewtonMethod() {
2468 if (termination_test) { termination_test->free(); }
2471 void init(Model& model,
const AttributeList& attribute) {
2472 std::string termination_s =
2473 attribute.get_string(
"CORRECTION_TERMINATION_TEST",
"FLUX_NORMALISED");
2474 if (termination_s !=
"") { termination_s +=
"_CORRECTION_TERMINATION_TEST"; }
2475 termination_s = type_name<T>(termination_s);
2476 typename CorrectionTerminationTest<T>::type_t* termination_t =
2477 CorrectionTerminationTest<T>::type.get_subtype(termination_s, solver::module);
2478 if (termination_test) { termination_test->free(); }
2479 termination_test = termination_t->new_object(allocator);
2480 termination_test->init(model, attribute);
2481 std::string method_s = attribute.get_string(
"NEWTON_METHOD",
"CONVENTIONAL");
2482 if (method_s ==
"CONVENTIONAL") {
2483 method = conventional;
2485 periodic_update = attribute.get_int(
"NEWTON_PERIODIC_UPDATE", 100);
2486 if (method_s ==
"MODIFIED") {
2488 }
else if (method_s ==
"DELAYED_MODIFIED") {
2489 method = delayed_modified;
2492 if (attribute.get_int(
"FULLNEWTON", 0) != 0) { method = conventional; }
2495 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result compute_correction(
2496 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
2497 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
2498 b2linalg::Vector<T, b2linalg::Vdense>& q,
2499 IncrementConstraintStrategy<T, MATRIX_FORMAT>& constraint,
2500 b2linalg::Vector<T, b2linalg::Vdense>& d,
double& time,
2501 EquilibriumSolution& equilibrium_solution) {
2502 const size_t number_of_dof = residue_function.get_number_of_dof();
2503 typename CorrectionTerminationTest<T>::Termination result;
2504 b2linalg::Vector<T, b2linalg::Vdense> r(number_of_dof + 1);
2505 b2linalg::Interval residu_int(0, number_of_dof);
2506 b2linalg::Vector<T, b2linalg::Vdense> c_d(number_of_dof);
2509 int nb_iter_first = 0;
2510 bool has_degradation =
false;
2511 b2linalg::Vector<T, b2linalg::Vdense> d_old = d;
2512 double time_old = time;
2513 double e_old = std::numeric_limits<double>::max();
2514 bool always_refactorization =
false;
2515 bool refactorization =
false;
2517 if (CorrectionStrategy<T, MATRIX_FORMAT>::logger.is_enabled_for(
logging::data)) {
2518 Model& model = residue_function.get_model();
2519 b2linalg::Vector<T, b2linalg::Vdense> g(model.get_domain().get_number_of_dof());
2520 residue_function.get_solution(d, time, equilibrium_solution, g);
2521 SolutionStaticNonlinear<T>& solution =
2522 dynamic_cast<SolutionStaticNonlinear<T>&
>(model.get_solution());
2524 time, g, residue_function.get_nbc_sol(),
2525 residue_function.get_residuum_sol(d, time),
true);
2528 int nb_iter_without_refactorization = 0;
2529 SolverHints solver_hints;
2530 termination_test->new_step();
2532 termination_test->new_iteration();
2533 termination_test->new_evaluation();
2534 refactorization = always_refactorization || (method == conventional)
2535 || (method == delayed_modified && nb_iter == 0)
2536 || (method == modified
2537 && ++nb_iter_without_refactorization % periodic_update == 0);
2539 if (refactorization) {
2540 nb_iter_without_refactorization = 0;
2541 solver_hints.clear();
2542 residue_function.get_residue(
2543 d, time, constraint.get_delta_time(), equilibrium_solution, r(residu_int), K,
2544 q, &solver_hints, (termination_test->need_flux() ? termination_test : 0));
2545#ifdef CHECK_RESIDUE_DERIVATIVE
2547 const double h = 1e-5;
2548 const double espilon = 1e-2;
2549 b2linalg::Vector<T> d_tmp(d);
2550 b2linalg::Vector<T> r_tmp1(d.size());
2551 b2linalg::Vector<T> r_tmp2(d.size());
2552 EquilibriumSolution qs(1, -1) for (
size_t j = 0; j != d.size(); ++j) {
2554 residue_function.get_residue(
2555 d_tmp, time, constraint.get_delta_time(), es, r_tmp1,
2556 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2557 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0);
2559 residue_function.get_residue(
2560 d_tmp, time, constraint.get_delta_time(), es, r_tmp2,
2561 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2562 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0);
2576 for (
size_t i = 0; i != d.size(); ++i) {
2577 if (
norm(K(i, j) - r_tmp2[i])
2578 > std::max(espilon, espilon *
norm(r_tmp2[i]))) {
2580 <<
"Error: K(" << i <<
", " << j <<
")=" << K(i, j)
2581 <<
", computed =" << r_tmp2[i] <<
", diff=" << K(i, j) - r_tmp2[i]
2582 <<
", n_diff=" << (K(i, j) - r_tmp2[i]) / r_tmp2[i] << std::endl;
2586 double time_tmp = time;
2588 residue_function.get_residue(
2589 d, time_tmp, constraint.get_delta_time(), es, r_tmp1,
2590 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2591 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0, 0);
2593 residue_function.get_residue(
2594 d, time_tmp, constraint.get_delta_time(), es, r_tmp2,
2595 Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2596 Vector<T, Vdense_ref>::null, 0, 0);
2599 for (
size_t i = 0; i != d.size(); ++i) {
2600 if (
norm(q[i] - r_tmp2[i]) > std::max(espilon, espilon *
norm(r_tmp2[i]))) {
2601 std::cout <<
"Error: d_K_d_time[" << i <<
"]=" << q[i]
2602 <<
", computed =" << r_tmp2[i] <<
", diff=" << q[i] - r_tmp2[i]
2603 <<
", n_diff=" << (q[i] - r_tmp2[i]) / r_tmp2[i] << std::endl;
2608 solver_hints.clear();
2609 residue_function.get_residue(
2610 d, time, constraint.get_delta_time(), equilibrium_solution, r(residu_int),
2611 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2612 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, &solver_hints,
2613 (termination_test->need_flux() ? termination_test : 0));
2615 constraint.get_constraint(
2616 d, time, &r[number_of_dof], refactorization || nb_iter == 0 ? &c_d : 0, &c_c);
2618 b2linalg::Vector<T> delta_d;
2619 Model& model = residue_function.get_model();
2620 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
2621 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
2623 if (refactorization || nb_iter == 0) {
2624 CorrectionStrategy<T, MATRIX_FORMAT>::logger
2626 <<
"Compute correction and factorize "
2627 "tangent stiffness matrix ("
2628 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
2629 delta_d = update_extension_and_inverse(K, q, c_d, c_c, nks_r, nbnsv) * r;
2631 delta_d = inverse(K, nks_r, nbnsv) * r;
2633 }
catch (b2linalg::SingularMatrixError& e) {
2634 if (nks_r.size2() != 0) {
2635 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
2636 model.get_domain().get_number_of_dof(), nks_r.size2());
2637 for (
size_t i = 0; i != nks_r.size2(); ++i) {
2638 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
2640 residue_function.get_model().get_solution().set_system_null_space(nks);
2644 if (nks_r.size2() != 0) {
2645 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
2646 model.get_domain().get_number_of_dof(), nks_r.size2());
2647 for (
size_t i = 0; i != nks_r.size2(); ++i) {
2648 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
2650 residue_function.get_model().get_solution().set_system_null_space(nks);
2653 d += -delta_d(residu_int);
2654 time += -delta_d[number_of_dof];
2657 if (!has_degradation) { ++nb_iter_first; }
2659 result = termination_test->is_terminated(
2660 ++nb_iter, r(residu_int), delta_d(residu_int), 1, d, d_old, r[number_of_dof], c_c,
2661 delta_d[number_of_dof], time, residue_function,
2662 residue_function.get_matrix_diagonal(K),
2663 equilibrium_solution.distance_to_iterative_convergence, &solver_hints);
2665 if (CorrectionStrategy<T, MATRIX_FORMAT>::logger.is_enabled_for(
logging::data)) {
2666 Model& model = residue_function.get_model();
2667 b2linalg::Vector<T, b2linalg::Vdense> g(model.get_domain().get_number_of_dof());
2668 residue_function.get_solution(d, time,
false, g);
2669 SolutionStaticNonlinear<T>& solution =
2670 dynamic_cast<SolutionStaticNonlinear<T>&
>(model.get_solution());
2672 time, g, residue_function.get_nbc_sol(),
2673 residue_function.get_residuum_sol(d, time),
true);
2676 if (!always_refactorization) {
2677 if (nb_iter > 0 && !refactorization
2678 && result == CorrectionTerminationTest<T>::diverged) {
2681 CorrectionStrategy<T, MATRIX_FORMAT>::logger
2683 <<
"Bad convergence, re-factorize the matrix from "
2684 "the last good obtained solution at time="
2685 << time <<
"." << logging::LOGFLUSH;
2686 }
else if (result == CorrectionTerminationTest<T>::unfinished) {
2687 if ((equilibrium_solution.distance_to_iterative_convergence >= 0
2688 && equilibrium_solution.distance_to_iterative_convergence < e_old)
2692 e_old = equilibrium_solution.distance_to_iterative_convergence;
2696 }
while (result == CorrectionTerminationTest<T>::unfinished);
2698 if (result == CorrectionTerminationTest<T>::converged) {
2699 termination_test->converged_step();
2701 return constraint.set_correction_result(
2702 d, time, result == CorrectionTerminationTest<T>::converged, nb_iter_first);
2706 ObjectTypeComplete<NewtonMethod, typename CorrectionStrategy<T, MATRIX_FORMAT>::type_t>;
2710 CorrectionTerminationTest<T>* termination_test;
2711 Allocator allocator;
2713 int periodic_update;
2716template <
typename T,
typename MATRIX_FORMAT>
2717typename NewtonMethod<T, MATRIX_FORMAT>::type_t NewtonMethod<T, MATRIX_FORMAT>::type(
2718 "NewtonMethod", type_name<T, MATRIX_FORMAT>(), StringList(
"NEWTON_METHOD"), module);
2720template <
typename T,
typename MATRIX_FORMAT>
2721class AcceleratedNewtonMethod :
public CorrectionStrategy<T, MATRIX_FORMAT> {
2723 enum Method { conventional, modified, delayed_modified };
2725 AcceleratedNewtonMethod() : termination_test(0), line_search(nullptr), method(modified) {}
2727 ~AcceleratedNewtonMethod() {
2728 if (termination_test) { termination_test->free(); }
2731 void init(Model& model,
const AttributeList& attribute) {
2732 std::string termination_s =
2733 attribute.get_string(
"CORRECTION_TERMINATION_TEST",
"FLUX_NORMALISED");
2734 if (termination_s !=
"") { termination_s +=
"_CORRECTION_TERMINATION_TEST"; }
2735 termination_s = type_name<T>(termination_s);
2736 typename CorrectionTerminationTest<T>::type_t* termination_t =
2737 CorrectionTerminationTest<T>::type.get_subtype(termination_s, solver::module);
2738 if (termination_test) { termination_test->free(); }
2739 termination_test = termination_t->new_object(allocator);
2740 termination_test->init(model, attribute);
2742 std::string line_search_s = attribute.get_string(
"LINE_SEARCH_ALGORITHM",
"STRONG_WOLFE");
2743 if (line_search_s !=
"") { line_search_s +=
"_LINE_SEARCH"; }
2744 typename LineSearch::type_t* line_search_t =
2745 LineSearch::type.get_subtype(line_search_s, solver::module);
2746 line_search = line_search_t->new_object(allocator);
2747 line_search->init(model, attribute);
2748 std::string method_s = attribute.get_string(
"NEWTON_METHOD",
"CONVENTIONAL");
2749 if (method_s ==
"CONVENTIONAL") {
2750 method = conventional;
2751 }
else if (method_s ==
"MODIFIED") {
2753 }
else if (method_s ==
"DELAYED_MODIFIED") {
2754 method = delayed_modified;
2758 if (attribute.get_int(
"FULLNEWTON", 0) == 1) { method = conventional; }
2761 typename IncrementConstraintStrategy<T, MATRIX_FORMAT>::Result compute_correction(
2762 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function,
2763 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>& K,
2764 b2linalg::Vector<T, b2linalg::Vdense>& q,
2765 IncrementConstraintStrategy<T, MATRIX_FORMAT>& constraint,
2766 b2linalg::Vector<T, b2linalg::Vdense>& d,
double& time,
2767 EquilibriumSolution& equilibrium_solution) {
2768 typename CorrectionTerminationTest<T>::Termination result;
2769 int nb_dof = residue_function.get_number_of_dof();
2770 b2linalg::Vector<T, b2linalg::Vdense> d_old = d;
2771 b2linalg::Vector<T, b2linalg::Vdense> r(nb_dof + 1);
2772 b2linalg::Vector<T, b2linalg::Vdense> director(nb_dof + 1);
2773 b2linalg::Vector<T, b2linalg::Vdense> d_test(nb_dof);
2774 b2linalg::Vector<T, b2linalg::Vdense> r_test(nb_dof + 1);
2776 b2linalg::Interval residu_int(0, nb_dof);
2777 b2linalg::Vector<T, b2linalg::Vdense> c_d(nb_dof);
2779 int refactorization;
2782 SolverHints solver_hints;
2783 if (method == delayed_modified || method == conventional) {
2784 residue_function.get_residue(
2785 d, time, constraint.get_delta_time(), equilibrium_solution, r(residu_int), K, q,
2787 constraint.get_constraint(d, time, &r[nb_dof], &c_d, &c_c);
2788 refactorization = 1;
2790 residue_function.get_residue(
2791 d, time, constraint.get_delta_time(), equilibrium_solution, r(residu_int),
2792 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2793 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, &solver_hints);
2794 constraint.get_constraint(d, time, &r[nb_dof], 0, &c_c);
2795 refactorization = 0;
2799 for (
size_t i = 0; i != d.size(); ++i) { r0_norm +=
norm(r[i] * r[i] * d[i]); }
2800 r0_norm +=
norm(r[nb_dof] * r[nb_dof] * time);
2803 int nb_iter_first = 0;
2804 bool has_degradation =
false;
2806 bool hard_conv =
false;
2808 if (CorrectionStrategy<T, MATRIX_FORMAT>::logger.is_enabled_for(
logging::data)) {
2809 Model& model = residue_function.get_model();
2810 b2linalg::Vector<T, b2linalg::Vdense> g(model.get_domain().get_number_of_dof());
2811 residue_function.get_solution(d, time, equilibrium_solution, g);
2812 SolutionStaticNonlinear<T>& solution =
2813 dynamic_cast<SolutionStaticNonlinear<T>&
>(model.get_solution());
2815 time, g, residue_function.get_nbc_sol(),
2816 residue_function.get_residuum_sol(d, time),
true);
2819 int nb_divergence = 0;
2820 Model& model = residue_function.get_model();
2821 const ssize_t nbnsv = model.get_case()->get_int(
"COMPUTE_NULL_SPACE_VECTOR", 0);
2822 termination_test->new_step();
2824 termination_test->new_iteration();
2825 termination_test->new_evaluation();
2827 b2linalg::Matrix<T, b2linalg::Mrectangle> nks_r;
2829 if (refactorization > 0 || method == conventional || hard_conv || nb_divergence > 2
2831 if (refactorization == 2 || method == conventional || hard_conv
2832 || nb_divergence > 2) {
2833 solver_hints.clear();
2834 residue_function.get_residue(
2835 d, time, constraint.get_delta_time(), equilibrium_solution,
2836 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, K, q, &solver_hints,
2838 constraint.get_constraint(d, time, &r[nb_dof], &c_d, &c_c);
2839 refactorization = 2;
2841 CorrectionStrategy<T, MATRIX_FORMAT>::logger
2843 <<
"Compute correction and factorize "
2844 "tangent stiffness matrix ("
2845 << K.size1() <<
" rows and columns)." << logging::LOGFLUSH;
2846 director = update_extension_and_inverse(K, q, c_d, c_c, nks_r, nbnsv) * r;
2848 director = inverse(K, nks_r, nbnsv) * r;
2850 }
catch (b2linalg::SingularMatrixError& e) {
2851 if (nks_r.size2() != 0) {
2852 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
2853 model.get_domain().get_number_of_dof(), nks_r.size2());
2854 for (
size_t i = 0; i != nks_r.size2(); ++i) {
2855 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
2857 residue_function.get_model().get_solution().set_system_null_space(nks);
2861 if (nks_r.size2() != 0) {
2862 b2linalg::Matrix<T, b2linalg::Mrectangle> nks(
2863 model.get_domain().get_number_of_dof(), nks_r.size2());
2864 for (
size_t i = 0; i != nks_r.size2(); ++i) {
2865 residue_function.get_solution(nks_r[i], time, equilibrium_solution, nks[i]);
2867 residue_function.get_model().get_solution().set_system_null_space(nks);
2870 d_test = d - director(residu_int);
2871 time_test = time - director[nb_dof];
2873 solver_hints.clear();
2874 residue_function.get_residue(
2875 d_test, time_test, constraint.get_delta_time(), equilibrium_solution,
2877 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2878 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, &solver_hints,
2879 termination_test->need_flux() ? termination_test : 0);
2880 constraint.get_constraint(d_test, time_test, &r_test[nb_dof], 0, 0);
2883 for (
size_t i = 0; i != d_test.size(); ++i) {
2884 r1_norm +=
norm(r_test[i] * r_test[i] * d_test[i]);
2886 r1_norm +=
norm(r_test[nb_dof] * r_test[nb_dof] * time_test);
2887 double rh_norm = r1_norm;
2889 if (r1_norm > r0_norm + 1e-5) {
2890 b2linalg::Vector<T> r_tmp = r_test;
2892 solver_hints.clear();
2894 residue_function, constraint, director, d, d_test, r_test, time, time_test,
2895 rh_norm, &solver_hints);
2896 h = line_search->get_minimum(f, r0_norm, r1_norm);
2900 CorrectionStrategy<T, MATRIX_FORMAT>::logger
2901 <<
logging::debug <<
"line search h = " << h << logging::LOGFLUSH;
2904 if (refactorization == 2) {
2906 d_test = d - director(residu_int);
2908 time_test = time - director[nb_dof];
2910 result = CorrectionTerminationTest<T>::unfinished;
2914 refactorization = 2;
2915 result = CorrectionTerminationTest<T>::unfinished;
2919 refactorization = 0;
2922 refactorization = 0;
2931 if (!has_degradation) { nb_iter_first++; }
2933 result = termination_test->is_terminated(
2934 ++nb_iter, r(residu_int), director(residu_int), h, d, d_old, r[nb_dof], c_c,
2935 director[nb_dof] * h, time, residue_function,
2936 residue_function.get_matrix_diagonal(K),
2937 equilibrium_solution.distance_to_iterative_convergence, &solver_hints);
2938 nb_divergence = termination_test->get_nb_divergence();
2940 if (CorrectionStrategy<T, MATRIX_FORMAT>::logger.is_enabled_for(
logging::data)) {
2941 Model& model = residue_function.get_model();
2942 b2linalg::Vector<T, b2linalg::Vdense> g(model.get_domain().get_number_of_dof());
2943 residue_function.get_solution(d, time, equilibrium_solution, g);
2944 SolutionStaticNonlinear<T>& solution =
2945 dynamic_cast<SolutionStaticNonlinear<T>&
>(model.get_solution());
2947 time, g, residue_function.get_nbc_sol(),
2948 residue_function.get_residuum_sol(d, time),
true);
2950 }
while (result == CorrectionTerminationTest<T>::unfinished);
2952 if (result == CorrectionTerminationTest<T>::converged) {
2953 termination_test->converged_step();
2955 return constraint.set_correction_result(
2956 d, time, result == CorrectionTerminationTest<T>::converged, nb_iter_first);
2959 using type_t = ObjectTypeComplete<
2960 AcceleratedNewtonMethod,
typename CorrectionStrategy<T, MATRIX_FORMAT>::type_t>;
2964 struct Function :
public LineSearch::Function {
2966 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function_,
2967 IncrementConstraintStrategy<T, MATRIX_FORMAT>& constraint_,
2968 b2linalg::Vector<T, b2linalg::Vdense>& director_,
2969 b2linalg::Vector<T, b2linalg::Vdense>& d_,
2970 b2linalg::Vector<T, b2linalg::Vdense>& d_test_,
2971 b2linalg::Vector<T, b2linalg::Vdense>& r_test_,
double time_,
double& time_test_,
2972 double& rh_norm_, SolverHints* solver_hints_)
2973 : residue_function(residue_function_),
2974 constraint(constraint_),
2975 director(director_),
2980 time_test(time_test_),
2982 solver_hints(solver_hints_) {}
2984 double operator()(
double h)
override {
2985 size_t nb_dof = r_test.size() - 1;
2986 b2linalg::Interval residu_int(0, r_test.size() - 1);
2987 d_test = d - h * director(residu_int);
2988 time_test = time - h * director[nb_dof];
2989 EquilibriumSolution es(1, -1);
2990 residue_function.get_residue(
2991 d_test, time_test, constraint.get_delta_time(), es, r_test(residu_int),
2992 b2linalg::Matrix<T, typename MATRIX_FORMAT::sparse_inversible_ext>::null,
2993 b2linalg::Vector<T, b2linalg::Vdense_ref>::null, solver_hints);
2994 constraint.get_constraint(d_test, time_test, &r_test[nb_dof], 0, 0);
2996 for (
size_t i = 0; i != d_test.size(); ++i) {
2997 rh_norm +=
norm(r_test[i] * r_test[i] * d_test[i]);
2999 rh_norm +=
norm(r_test[nb_dof] * r_test[nb_dof] * time_test);
3003 StaticResidueFunction<T, MATRIX_FORMAT>& residue_function;
3004 IncrementConstraintStrategy<T, MATRIX_FORMAT>& constraint;
3005 b2linalg::Vector<T, b2linalg::Vdense>& director;
3006 b2linalg::Vector<T, b2linalg::Vdense>& d;
3007 b2linalg::Vector<T, b2linalg::Vdense>& d_test;
3008 b2linalg::Vector<T, b2linalg::Vdense>& r_test;
3012 SolverHints* solver_hints;
3015 CorrectionTerminationTest<T>* termination_test;
3016 LineSearch* line_search;
3017 Allocator allocator;
3021template <
typename T,
typename MATRIX_FORMAT>
3022typename AcceleratedNewtonMethod<T, MATRIX_FORMAT>::type_t
3023 AcceleratedNewtonMethod<T, MATRIX_FORMAT>::type(
3024 "AcceleratedNewtonMethod", type_name<T, MATRIX_FORMAT>(),
3025 StringList(
"ACCELERATED_NEWTON_METHOD"), module);
3027template <
typename T>
3028class DofAndResidueCorrectionTerminationTest :
public CorrectionTerminationTest<T> {
3030 void init(Model& model,
const AttributeList& attribute) {
3031 e_r = attribute.get_double(
"TOL_RESIDUUM", 1e-3);
3032 e_d = attribute.get_double(
"TOL_SOLUTION", 1e-3);
3033 g_r = std::max(e_r, attribute.get_double(
"MAX_RESIDUUM", 1.0e8));
3034 g_d = std::max(e_d, attribute.get_double(
"MAX_SOLUTION", 1.0e8));
3035 max_number_of_iterations = attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50);
3036 max_additional_iterations = 0;
3037 max_number_of_divergences = attribute.get_int(
"MAX_DIVERGENCES", 4);
3038 number_of_divergences = 0;
3039 last_rn = std::numeric_limits<double>::max();
3040 best_rn = std::numeric_limits<double>::max();
3043 typename CorrectionTerminationTest<T>::Termination is_terminated(
3044 int number_of_iteration,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& res,
3045 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
3046 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
3047 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof_at_start_step,
3048 const double constraint,
const double d_constraint_d_time,
const double delta_time,
3049 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
3050 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K,
3051 double& distance_to_iterative_convergence,
const SolverHints* solver_hints) {
3052 double r = res.norm2();
3053 double d = delta_dof.norm2() * delta_dof_scale;
3054 if (number_of_iteration == 1) {
3055 max_additional_iterations = 0;
3056 number_of_divergences = 0;
3057 last_rn = std::numeric_limits<double>::max();
3058 best_rn = std::numeric_limits<double>::max();
3059 return CorrectionTerminationTest<T>::unfinished;
3061 double rn =
norm(r);
3062 double dn =
norm(d);
3063 CorrectionTerminationTest<T>::logger
3064 <<
logging::debug <<
"termination test: residue=" << rn <<
", last correction=" << dn
3065 <<
", number of correction iterations=" << number_of_iteration;
3067 CorrectionTerminationTest<T>::logger
3068 <<
", diverged because the residue is not a number." << logging::LOGFLUSH;
3069 distance_to_iterative_convergence = -1;
3070 return CorrectionTerminationTest<T>::diverged;
3073 CorrectionTerminationTest<T>::logger
3074 <<
", diverged because the last correction is not a number." << logging::LOGFLUSH;
3075 distance_to_iterative_convergence = -1;
3076 return CorrectionTerminationTest<T>::diverged;
3079 distance_to_iterative_convergence = -1;
3080 CorrectionTerminationTest<T>::logger <<
", elements/materials/boundary conditions "
3081 "indicated divergence."
3082 << logging::LOGFLUSH;
3083 return CorrectionTerminationTest<T>::diverged;
3085 distance_to_iterative_convergence = std::max(rn / e_r, dn / e_d);
3086 if ((rn < e_r) && (dn < e_d)
3088 CorrectionTerminationTest<T>::logger <<
", converged." << logging::LOGFLUSH;
3089 return CorrectionTerminationTest<T>::converged;
3091 if (number_of_iteration > 1 && rn > g_r) {
3092 CorrectionTerminationTest<T>::logger <<
", diverged because the residue exceeds the "
3094 << g_r <<
")." << logging::LOGFLUSH;
3095 return CorrectionTerminationTest<T>::diverged;
3097 if (number_of_iteration > 1 && dn > g_d) {
3098 CorrectionTerminationTest<T>::logger
3099 <<
", diverged because the last correction exceeds "
3101 << g_d <<
")." << logging::LOGFLUSH;
3102 return CorrectionTerminationTest<T>::diverged;
3105 const int remaining = std::max(
3106 0, max_number_of_iterations + max_additional_iterations - number_of_iteration);
3107 max_additional_iterations += std::max(0, max_number_of_iterations - remaining);
3108 number_of_divergences = 0;
3109 last_rn = std::numeric_limits<double>::max();
3110 best_rn = std::numeric_limits<double>::max();
3113 || (number_of_iteration + max_number_of_divergences > 5 && rn > best_rn)) {
3114 if (++number_of_divergences > max_number_of_divergences) {
3115 CorrectionTerminationTest<T>::logger
3117 <<
", diverged because the maximum number of consecutive "
3119 << max_number_of_divergences <<
") has been exceeded (last=" << last_rn
3120 <<
", best=" << best_rn <<
")." << logging::LOGFLUSH;
3121 distance_to_iterative_convergence = -1;
3122 return CorrectionTerminationTest<T>::diverged;
3125 best_rn = std::min(best_rn, rn);
3127 number_of_divergences = 0;
3129 best_rn = std::min(best_rn, rn);
3132 if (number_of_iteration > max_number_of_iterations + max_additional_iterations) {
3133 CorrectionTerminationTest<T>::logger
3134 <<
", diverged because the number of correction iterations "
3135 "exceeds the maximum ("
3136 << max_number_of_iterations;
3137 if (max_additional_iterations > 0) {
3138 CorrectionTerminationTest<T>::logger <<
"+" << max_additional_iterations;
3140 CorrectionTerminationTest<T>::logger <<
")." << logging::LOGFLUSH;
3141 return CorrectionTerminationTest<T>::max_iteration;
3144 CorrectionTerminationTest<T>::logger
3145 <<
", elements/materials/boundary conditions indicated "
3148 distance_to_iterative_convergence >= 0.0 && distance_to_iterative_convergence <= 1.0
3150 CorrectionTerminationTest<T>::logger
3151 <<
", elements/materials/boundary conditions indicated "
3152 "need for further Newton iterations";
3154 CorrectionTerminationTest<T>::logger <<
", unfinished." << logging::LOGFLUSH;
3155 return CorrectionTerminationTest<T>::unfinished;
3158 using type_t = ObjectTypeComplete<
3159 DofAndResidueCorrectionTerminationTest,
typename CorrectionTerminationTest<T>::type_t>;
3169 int max_number_of_iterations;
3170 int max_additional_iterations;
3171 int number_of_divergences;
3172 int max_number_of_divergences;
3175template <
typename T>
3176typename DofAndResidueCorrectionTerminationTest<T>::type_t
3177 DofAndResidueCorrectionTerminationTest<T>::type(
3178 "DofAndResidueCorrectionTerminationTest", type_name<T>(),
3179 StringList(
"DOF_AND_RESIDUE_CORRECTION_TERMINATION_TEST"), module);
3181template <
typename T>
3182class NormalizedDofAndResidueCorrectionTerminationTest :
public CorrectionTerminationTest<T> {
3184 void init(Model& model,
const AttributeList& attribute) {
3185 e_r = attribute.get_double(
"TOL_RESIDUUM", 1e-3);
3187 e_d = attribute.get_double(
"TOL_SOLUTION", 1e-3);
3189 g_r = std::max(e_r, attribute.get_double(
"MAX_RESIDUUM", 10.0e10));
3190 g_d = std::max(e_d, attribute.get_double(
"MAX_SOLUTION", 10.0e10));
3191 max_number_of_iteration = attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50);
3192 max_additional_iterations = 0;
3193 max_number_of_divergences = attribute.get_int(
"MAX_DIVERGENCES", 4);
3194 number_of_divergences = 0;
3195 last_rn = std::numeric_limits<double>::max();
3196 best_rn = std::numeric_limits<double>::max();
3199 typename CorrectionTerminationTest<T>::Termination is_terminated(
3200 int number_of_iteration,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& res,
3201 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
3202 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
3203 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof_at_start_step,
3204 const double constraint,
const double d_constraint_d_time,
const double delta_time,
3205 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
3206 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K,
3207 double& distance_to_iterative_convergence,
const SolverHints* solver_hints) {
3208 double r = res.norm2();
3209 double d = delta_dof.norm2() * delta_dof_scale;
3210 if (number_of_iteration == 1) {
3213 number_of_divergences = 0;
3214 last_rn = std::numeric_limits<double>::max();
3215 best_rn = std::numeric_limits<double>::max();
3216 return CorrectionTerminationTest<T>::unfinished;
3219 if (
norm(r_0) < 10e-15) {
3225 if (
norm(d) < 10e-15) {
3230 CorrectionTerminationTest<T>::logger
3232 <<
", normalised residue (scale=" << r_0 <<
")=" << rn <<
", last correction=" << d
3233 <<
", normalised last correction (scale=" << d_0 <<
")=" << dn
3234 <<
", number of correction iterations=" << number_of_iteration;
3236 CorrectionTerminationTest<T>::logger
3237 <<
", diverged because the normalised residue is not a "
3239 << logging::LOGFLUSH;
3240 distance_to_iterative_convergence = -1;
3241 return CorrectionTerminationTest<T>::diverged;
3244 CorrectionTerminationTest<T>::logger
3245 <<
", diverged because the normalised last correction is not "
3247 << logging::LOGFLUSH;
3248 distance_to_iterative_convergence = -1;
3249 return CorrectionTerminationTest<T>::diverged;
3252 distance_to_iterative_convergence = -1;
3253 CorrectionTerminationTest<T>::logger <<
", elements/materials/boundary conditions "
3254 "indicated divergence."
3255 << logging::LOGFLUSH;
3256 return CorrectionTerminationTest<T>::diverged;
3258 distance_to_iterative_convergence = std::max(rn / e_r, dn / e_d);
3259 if ((rn < e_r) && (dn < e_d)
3261 CorrectionTerminationTest<T>::logger <<
", converged." << logging::LOGFLUSH;
3262 return CorrectionTerminationTest<T>::converged;
3265 const int remaining = std::max(
3266 0, max_number_of_iteration + max_additional_iterations - number_of_iteration);
3267 max_additional_iterations += std::max(0, max_number_of_iteration - remaining);
3268 number_of_divergences = 0;
3269 last_rn = std::numeric_limits<double>::max();
3270 best_rn = std::numeric_limits<double>::max();
3271 }
else if ((number_of_iteration > 2 && rn > last_rn)) {
3272 if (++number_of_divergences > max_number_of_divergences) {
3273 CorrectionTerminationTest<T>::logger
3275 <<
", diverged because the maximum number of consecutive "
3277 << max_number_of_divergences <<
") has been exceeded." << logging::LOGFLUSH;
3278 distance_to_iterative_convergence = -1;
3279 return CorrectionTerminationTest<T>::diverged;
3282 best_rn = std::min(best_rn, rn);
3284 number_of_divergences = 0;
3286 best_rn = std::min(best_rn, rn);
3289 if (number_of_iteration > max_number_of_iteration + max_additional_iterations) {
3290 CorrectionTerminationTest<T>::logger
3291 <<
", diverged because the number of correction iterations "
3292 "exceeds the maximum ("
3293 << max_number_of_iteration;
3294 if (max_additional_iterations > 0) {
3295 CorrectionTerminationTest<T>::logger <<
"+" << max_additional_iterations;
3297 CorrectionTerminationTest<T>::logger <<
")." << logging::LOGFLUSH;
3298 return CorrectionTerminationTest<T>::max_iteration;
3300 if (number_of_iteration > 1 && rn > g_r) {
3301 CorrectionTerminationTest<T>::logger
3302 <<
", diverged because the normalised residue exceeds the "
3304 << g_r <<
")." << logging::LOGFLUSH;
3305 return CorrectionTerminationTest<T>::diverged;
3307 if (number_of_iteration > 1 && dn > g_d) {
3308 CorrectionTerminationTest<T>::logger
3309 <<
", diverged because the normalised last correction exceeds "
3311 << g_d <<
")." << logging::LOGFLUSH;
3312 return CorrectionTerminationTest<T>::diverged;
3315 CorrectionTerminationTest<T>::logger
3316 <<
", elements/materials/boundary conditions indicated "
3319 distance_to_iterative_convergence >= 0.0 && distance_to_iterative_convergence <= 1.0
3321 CorrectionTerminationTest<T>::logger
3322 <<
", elements/materials/boundary conditions indicated "
3323 "need for further Newton iterations";
3325 CorrectionTerminationTest<T>::logger <<
", unfinished." << logging::LOGFLUSH;
3326 return CorrectionTerminationTest<T>::unfinished;
3329 using type_t = ObjectTypeComplete<
3330 NormalizedDofAndResidueCorrectionTerminationTest,
3331 typename CorrectionTerminationTest<T>::type_t>;
3343 int max_number_of_iteration;
3344 int max_additional_iterations;
3345 int number_of_divergences;
3346 int max_number_of_divergences;
3349template <
typename T>
3350typename NormalizedDofAndResidueCorrectionTerminationTest<T>::type_t
3351 NormalizedDofAndResidueCorrectionTerminationTest<T>::type(
3352 "NormalizedDofAndResidueCorrectionTerminationTest", type_name<T>(),
3353 StringList(
"NORMALISED_DOF_AND_RESIDUE_CORRECTION_TERMINATION_TEST"), module);
3355template <
typename T>
3356class RegularizedCorrectionTerminationTest :
public CorrectionTerminationTest<T> {
3358 void init(Model& model,
const AttributeList& attribute) {
3359 e_r = attribute.get_double(
"TOL_RESIDUUM", 1e-3);
3360 e_d = attribute.get_double(
"TOL_SOLUTION", 1e-3);
3361 e_w = attribute.get_double(
"TOL_WORK", 1e-7);
3362 max_number_of_iteration = attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50);
3363 max_divergence = attribute.get_int(
"MAX_DIVERGENCES", 4);
3364 max_additional_iterations = 0;
3367 double norm_termination(
3368 const b2linalg::Vector<T, b2linalg::Vdense_constref>& r,
3369 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
3370 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
3371 const double constraint,
const double d_constraint_d_time,
const double delta_time,
3372 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
3373 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K) {
3374 const double w_normalization = residue.get_energy_normalisation1();
3377 double norm1_d_dof = 0;
3378 double diag_d_dof = 0;
3379 double diag_dof = 0;
3380 for (
size_t i = 0; i != delta_dof.size(); ++i) {
3381 const double ddof = delta_dof[i] * delta_dof_scale;
3382 w +=
norm(r[i] * ddof);
3383 p +=
norm(r[i] * dof[i]);
3384 norm1_d_dof +=
norm(ddof);
3385 const double sqrt_diag_K = std::sqrt(
norm(diag_K[i]));
3386 diag_d_dof +=
norm(sqrt_diag_K * ddof);
3387 diag_dof +=
norm(sqrt_diag_K * dof[i]);
3389 w +=
norm(constraint * delta_time);
3390 p +=
norm(constraint * time);
3391 norm1_d_dof +=
norm(delta_time);
3392 diag_d_dof +=
norm(std::sqrt(
norm(d_constraint_d_time)) * delta_time);
3393 diag_dof +=
norm(std::sqrt(
norm(d_constraint_d_time)) * time);
3395 if (last_norm1_d_dof < 1e-15) {
3398 q = 2 * norm1_d_dof / (3 * last_norm1_d_dof) + last_q / 3;
3401 if (diag_dof < 1e-15) {
3403 }
else if (q >= 0.99) {
3404 e_dof = q * diag_d_dof / (0.01 * diag_dof);
3406 e_dof = q * diag_d_dof / ((1 - q) * diag_dof);
3409 const double e_work = w / (w_normalization * e_w);
3410 const double e_res = p / (w_normalization * e_r);
3412 return std::max(e_work, std::max(e_res, e_dof));
3415 typename CorrectionTerminationTest<T>::Termination is_terminated(
3416 int number_of_iteration,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& r,
3417 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
3418 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
3419 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof_at_start_step,
3420 const double constraint,
const double d_constraint_d_time,
const double delta_time,
3421 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
3422 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K,
3423 double& distance_to_iterative_convergence,
const SolverHints* solver_hints) {
3425 for (
size_t i = 0; i != dof.size(); ++i) { w2 +=
norm(r[i] * r[i] * dof[i]); }
3426 w2 +=
norm(constraint * constraint * time);
3428 CorrectionTerminationTest<T>::logger
3430 <<
"diverged because a term of the residue or the correction is "
3432 << logging::LOGFLUSH;
3433 return CorrectionTerminationTest<T>::diverged;
3436 distance_to_iterative_convergence = -1;
3438 <<
"elements/materials/boundary conditions "
3439 <<
"indicated divergence." << logging::LOGFLUSH;
3440 return CorrectionTerminationTest<T>::diverged;
3442 if (number_of_iteration == 1) {
3446 last_norm1_d_dof = 0;
3447 for (
size_t i = 0; i != delta_dof.size(); ++i) {
3448 last_norm1_d_dof +=
norm(delta_dof[i] * delta_dof_scale);
3450 distance_to_iterative_convergence = -1;
3451 return CorrectionTerminationTest<T>::unfinished;
3454 const double divergence = w2 == 0 ? 0 : (last_w2 == 0 ? w2 : w2 / last_w2);
3457 }
else if (divergence > 1 + 1e-5 || divergence < -1e12) {
3459 }
else if (divergence < -1) {
3466 if (nb_divergence > max_divergence) {
3467 CorrectionTerminationTest<T>::logger
3469 <<
"diverged because the maximum number of consecutive "
3471 << max_divergence <<
") has been exceeded." << logging::LOGFLUSH;
3472 distance_to_iterative_convergence = -1;
3473 return CorrectionTerminationTest<T>::diverged;
3477 const double w_normalization = residue.get_energy_normalisation1();
3480 double norm1_d_dof = 0;
3481 double diag_d_dof = 0;
3482 double diag_dof = 0;
3483 for (
size_t i = 0; i != delta_dof.size(); ++i) {
3484 const double ddof = delta_dof[i] * delta_dof_scale;
3485 w +=
norm(r[i] * ddof);
3486 p +=
norm(r[i] * dof[i]);
3487 norm1_d_dof +=
norm(ddof);
3488 const double sqrt_diag_K = std::sqrt(
norm(diag_K[i]));
3489 diag_d_dof +=
norm(sqrt_diag_K * ddof);
3490 diag_dof +=
norm(sqrt_diag_K * dof[i]);
3492 w +=
norm(constraint * delta_time);
3493 p +=
norm(constraint * time);
3494 norm1_d_dof +=
norm(delta_time);
3495 diag_d_dof +=
norm(std::sqrt(
norm(d_constraint_d_time)) * delta_time);
3496 diag_dof +=
norm(std::sqrt(
norm(d_constraint_d_time)) * time);
3498 if (last_norm1_d_dof < 1e-15) {
3501 q = 2 * norm1_d_dof / (3 * last_norm1_d_dof) + last_q / 3;
3504 if (diag_dof < 1e-15) {
3506 }
else if (q >= 0.99) {
3507 e_dof = q * diag_d_dof / (0.01 * diag_dof);
3509 e_dof = q * diag_d_dof / ((1 - q) * diag_dof);
3511 const double e_work = w / w_normalization;
3512 const double e_res = p / w_normalization;
3513 distance_to_iterative_convergence =
3514 std::max(e_work / e_w, std::max(e_res / e_r, e_dof / e_d));
3515 if (e_work < e_w && e_res < e_r && e_dof < e_d
3517 CorrectionTerminationTest<T>::logger <<
logging::debug <<
"converged."
3518 << logging::LOGFLUSH;
3519 return CorrectionTerminationTest<T>::converged;
3522 const int remaining = std::max(
3523 0, max_number_of_iteration + max_additional_iterations - number_of_iteration);
3524 max_additional_iterations += std::max(0, max_number_of_iteration - remaining);
3526 if (number_of_iteration > max_number_of_iteration + max_additional_iterations) {
3527 CorrectionTerminationTest<T>::logger
3529 <<
"diverged because the number of correction iterations "
3530 "exceeds the maximum ("
3531 << max_number_of_iteration;
3532 if (max_additional_iterations > 0) {
3533 CorrectionTerminationTest<T>::logger <<
"+" << max_additional_iterations;
3535 CorrectionTerminationTest<T>::logger <<
")." << logging::LOGFLUSH;
3536 return CorrectionTerminationTest<T>::max_iteration;
3539 last_norm1_d_dof = norm1_d_dof;
3542 CorrectionTerminationTest<T>::logger
3544 <<
"elements/materials/boundary conditions indicated "
3547 distance_to_iterative_convergence >= 0.0 && distance_to_iterative_convergence <= 1.0
3549 CorrectionTerminationTest<T>::logger
3551 <<
"elements/materials/boundary conditions indicated "
3552 "need for further Newton iterations, ";
3554 CorrectionTerminationTest<T>::logger
3556 <<
", e_work=" << e_work <<
", e_residue=" << e_res <<
", e_dof=" << e_dof <<
"."
3557 << logging::LOGFLUSH;
3558 return CorrectionTerminationTest<T>::unfinished;
3561 int get_nb_divergence()
const {
return nb_divergence; }
3563 using type_t = ObjectTypeComplete<
3564 RegularizedCorrectionTerminationTest,
typename CorrectionTerminationTest<T>::type_t>;
3572 double last_norm1_d_dof;
3576 int max_number_of_iteration;
3577 int max_additional_iterations;
3580template <
typename T>
3581typename RegularizedCorrectionTerminationTest<T>::type_t
3582 RegularizedCorrectionTerminationTest<T>::type(
3583 "RegularizedCorrectionTerminationTest", type_name<T>(),
3584 StringList(
"REGULARISED_CORRECTION_TERMINATION_TEST"), module);
3586template <
typename T>
3587class FluxNormalizedCorrectionTerminationTest :
public CorrectionTerminationTest<T> {
3589 void init(Model& model,
const AttributeList& attribute) {
3590 min_number_of_iteration = attribute.get_int(
"MIN_NEWTON_ITERATIONS", 0);
3591 max_number_of_iteration = attribute.get_int(
"MAX_NEWTON_ITERATIONS", 50);
3592 max_additional_iteration = 0;
3593 max_divergence = attribute.get_int(
"MAX_DIVERGENCES", 4);
3594 I0 = attribute.get_int(
"MIN_NEWTON_ITERATIONS_CHECK_DIVERGENCE", 4);
3596 tol_work_lagrange = attribute.get_double(
3597 "TOL_WORK.LAGRANGE_MULTIPLIER",
3598 attribute.get_double(
"TOL_WORK.LAGRANGE", attribute.get_double(
"TOL_WORK", 1e-7)));
3599 const std::pair<std::map<std::string, size_t>, b2linalg::Index>& df =
3600 model.get_domain().get_dof_field();
3601 df_index = &df.second;
3604 for (std::map<std::string, size_t>::const_iterator i = df.first.begin();
3605 i != df.first.end(); ++i) {
3606 s = std::max(s, i->second);
3609 list_field.resize(s + 1);
3610 for (std::map<std::string, size_t>::const_iterator i = df.first.begin();
3611 i != df.first.end(); ++i) {
3612 list_field[i->second].init(i->first, attribute);
3617 for (
typename std::vector<Field>::iterator i = list_field.begin(); i != list_field.end();
3623 void new_iteration() {
3624 for (
typename std::vector<Field>::iterator i = list_field.begin(); i != list_field.end();
3630 void new_evaluation() {
3631 for (
typename std::vector<Field>::iterator i = list_field.begin(); i != list_field.end();
3633 i->new_evaluation();
3637 void converged_step() {
3638 for (
typename std::vector<Field>::iterator i = list_field.begin(); i != list_field.end();
3640 i->converged_step();
3644 bool need_flux() {
return true; }
3646 void add_flux(b2linalg::Index& index,
const b2linalg::Vector<T, b2linalg::Vdense>& v) {
3647 for (
size_t i = 0; i != index.size(); ++i) {
3648 list_field[(*df_index)[index[i]]].add_flux(
norm(v[i]));
3652 void add_flux(
const b2linalg::Vector<T, b2linalg::Vdense_constref>& v) {
3653 for (
size_t i = 0; i != v.size(); ++i) { list_field[(*df_index)[i]].add_flux(
norm(v[i])); }
3656 typename CorrectionTerminationTest<T>::Termination is_terminated(
3657 int number_of_iteration,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& r,
3658 const b2linalg::Vector<T, b2linalg::Vdense_constref>& delta_dof,
3659 const double delta_dof_scale,
const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof,
3660 const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof_at_start_step,
3661 const double constraint,
const double d_constraint_d_time,
const double delta_time,
3662 const double time, StaticResidueFunctionForTerminationTest<T>& residue,
3663 const b2linalg::Vector<T, b2linalg::Vindex1_constref>& diag_K,
3664 double& distance_to_iterative_convergence,
const SolverHints* solver_hints) {
3665 distance_to_iterative_convergence = 0;
3667 b2linalg::Matrix<T, b2linalg::Mcompressed_col> d_value_d_dof_trans;
3668 residue.mrbc_get_nonlinear_value(
3669 dof, time,
false, b2linalg::Vector<T, b2linalg::Vdense_ref>::null,
3670 d_value_d_dof_trans, b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 0);
3671 b2linalg::Vector<T> tmp(d_value_d_dof_trans.size2());
3672 b2linalg::Interval dof_int(0, d_value_d_dof_trans.size1());
3674 tmp = transposed(d_value_d_dof_trans) * r(dof_int);
3675 std::vector<T> r_max(list_field.size());
3676 for (
size_t i = 0; i != df_index->size(); ++i) {
3677 const size_t j = (*df_index)[i];
3678 if (r_max[j] == r_max[j]) {
3679 if (tmp[i] == tmp[i]) {
3680 r_max[j] = std::max(r_max[j],
norm(tmp[i]));
3682 r_max[j] =
norm(tmp[i]);
3687 tmp = transposed(d_value_d_dof_trans) * delta_dof(dof_int);
3688 std::vector<T> delta_dof_max(list_field.size());
3689 for (
size_t i = 0; i != df_index->size(); ++i) {
3690 const size_t j = (*df_index)[i];
3691 if (delta_dof_max[j] == delta_dof_max[j]) {
3692 if (tmp[i] == tmp[i]) {
3693 delta_dof_max[j] = std::max(delta_dof_max[j],
norm(tmp[i]));
3695 delta_dof_max[j] =
norm(tmp[i]);
3700 tmp = transposed(d_value_d_dof_trans) * dof_at_start_step(dof_int);
3701 std::vector<T> step_dof_max(list_field.size());
3702 for (
size_t i = 0; i != df_index->size(); ++i) {
3703 const size_t j = (*df_index)[i];
3704 if (step_dof_max[j] == step_dof_max[j]) {
3705 if (tmp[i] == tmp[i]) {
3706 step_dof_max[j] = std::max(step_dof_max[j],
norm(tmp[i]));
3708 step_dof_max[j] =
norm(tmp[i]);
3713 bool degradation =
false;
3714 bool diverged =
false;
3715 bool unfinished =
false;
3718 CorrectionTerminationTest<T>::logger
3719 <<
logging::debug <<
"Number of correction iterations = " << number_of_iteration;
3721 degradation = unfinished =
true;
3724 const int remaining = std::max(
3725 0, max_number_of_iteration + max_additional_iteration - number_of_iteration);
3726 max_additional_iteration += std::max(0, max_number_of_iteration - remaining);
3729 I0_effective = I0 + number_of_iteration;
3731 CorrectionTerminationTest<T>::logger
3732 <<
", elements/materials/boundary conditions indicated "
3736 CorrectionTerminationTest<T>::logger
3737 <<
", elements/materials/boundary conditions indicated "
3738 "need for further Newton iterations";
3740 CorrectionTerminationTest<T>::logger <<
"." << logging::LOGFLUSH;
3743 for (
size_t i = 0; i != list_field.size(); ++i) {
3744 if (!list_field[i].is_init()) {
continue; }
3745 typename CorrectionTerminationTest<T>::Termination r = list_field[i].is_terminated(
3746 *
this, number_of_iteration, r_max[i], step_dof_max[i],
3747 delta_dof_max[i] * delta_dof_scale, distance_to_iterative_convergence,
3749 if (!degradation && r == CorrectionTerminationTest<T>::diverged) { diverged =
true; }
3750 if (r == CorrectionTerminationTest<T>::unfinished) { unfinished =
true; }
3754 if (residue.get_number_of_non_lagrange_dof() != dof.size()) {
3755 double max_l_work = 0;
3756 for (
size_t i = residue.get_number_of_non_lagrange_dof(); i != dof.size(); ++i) {
3757 max_l_work = std::max(max_l_work,
norm(r[i] * delta_dof[i]));
3759 max_l_work *= delta_dof_scale;
3760 CorrectionTerminationTest<T>::logger
3761 <<
logging::debug <<
"Field Lagrange multiplier, work_max = " << max_l_work;
3762 if (max_l_work > tol_work_lagrange) {
3764 CorrectionTerminationTest<T>::logger <<
", unfinished.";
3766 CorrectionTerminationTest<T>::logger <<
", converged.";
3768 CorrectionTerminationTest<T>::logger << logging::LOGFLUSH;
3769 distance_to_iterative_convergence =
3770 std::max(distance_to_iterative_convergence, max_l_work / tol_work_lagrange);
3774 distance_to_iterative_convergence = -1;
3775 return CorrectionTerminationTest<T>::diverged;
3777 if (!unfinished && number_of_iteration < min_number_of_iteration) { unfinished =
true; }
3779 if (number_of_iteration > max_number_of_iteration + max_additional_iteration) {
3780 CorrectionTerminationTest<T>::logger
3782 <<
"diverged because the number of correction iterations "
3783 "exceeds the maximum ("
3784 << max_number_of_iteration;
3785 if (max_additional_iteration > 0) {
3786 CorrectionTerminationTest<T>::logger <<
"+" << max_additional_iteration;
3788 CorrectionTerminationTest<T>::logger <<
")." << logging::LOGFLUSH;
3789 return CorrectionTerminationTest<T>::diverged;
3791 return CorrectionTerminationTest<T>::unfinished;
3793 return CorrectionTerminationTest<T>::converged;
3796 int get_nb_divergence()
const {
return 0; }
3798 using type_t = ObjectTypeComplete<
3799 FluxNormalizedCorrectionTerminationTest,
typename CorrectionTerminationTest<T>::type_t>;
3805 int min_number_of_iteration;
3806 int max_number_of_iteration;
3807 int max_additional_iteration;
3809 double tol_work_lagrange;
3810 const b2linalg::Index* df_index;
3829 delta_dof_max_in_step(0),
3833 q_time_nb_flux_active(0),
3834 q_averaged_nb_step(0),
3835 q_averaged_time_nb_step(0),
3838 nonquadratic_convergence(0),
3840 divergence_in_step(false) {}
3842 void init(
const std::string& name_,
const AttributeList& attribute) {
3845 Rn = attribute.get_double(
3846 "TOL_RESIDUUM." + name_, attribute.get_double(
"TOL_RESIDUUM", 1e-5));
3848 Rn, attribute.get_double(
3849 "MAX_RESIDUUM." + name_, attribute.get_double(
"MAX_RESIDUUM", 1e16)));
3850 Rp = attribute.get_double(
3851 "TOL_RESIDUUM_NONQUADRATIC_CONVERGENCE." + name_,
3852 attribute.get_double(
"TOL_RESIDUUM_NONQUADRATIC_CONVERGENCE", 2e-2));
3853 Ip = attribute.get_int(
3854 "NB_ITER_NONQUADRATIC_CONVERGENCE." + name_,
3855 attribute.get_int(
"NB_ITER_NONQUADRATIC_CONVERGENCE", 9));
3856 Ip = std::max(
size_t(3), Ip);
3857 Rl = attribute.get_double(
3858 "TOL_RESIDUUM_LINEAR_PROBLEM." + name_,
3859 attribute.get_double(
"TOL_RESIDUUM_LINEAR_PROBLEM", 1e-8));
3860 Cn = attribute.get_double(
3861 "TOL_SOLUTION." + name_, attribute.get_double(
"TOL_SOLUTION", 1e-5));
3863 Cn, attribute.get_double(
3864 "MAX_SOLUTION." + name_, attribute.get_double(
"MAX_SOLUTION", 1e16)));
3865 q_averaged_0 = attribute.get_double(
3866 "INITIAL_AVERAGE_FLUX." + name_,
3867 attribute.get_double(
"INITIAL_AVERAGE_FLUX", 1e-2));
3868 q_averaged_n = attribute.get_double(
3869 "AVERAGE_FLUX." + name, attribute.get_double(
"AVERAGE_FLUX", -1));
3870 epsilon = attribute.get_double(
3871 "ZERO_FLUX_CRITERION." + name_,
3872 attribute.get_double(
"ZERO_FLUX_CRITERION", 1e-5));
3873 epsilon_l = attribute.get_double(
3874 "ZERO_FLUX_RELATIVE_CRITERION." + name_,
3875 attribute.get_double(
"ZERO_FLUX_RELATIVE_CRITERION", 1e-5));
3876 Cepsilon = attribute.get_double(
3877 "TOL_SOLUTION_ZERO_FLUX." + name_,
3878 attribute.get_double(
"TOL_SOLUTION_ZERO_FLUX", 1e-5));
3879 q_averaged_nb_step = 0;
3882 bool is_init()
const {
return is_init_; }
3885 delta_dof_max_in_step = 0;
3886 std::fill_n(last_r_max, 3, 0);
3887 std::fill_n(best_r_max, 3, std::numeric_limits<double>::max());
3888 nonquadratic_convergence =
false;
3890 divergence_in_step =
false;
3893 void new_iteration() {
3894 last_r_max[0] = last_r_max[1];
3895 last_r_max[1] = last_r_max[2];
3896 best_r_max[0] = best_r_max[1];
3897 best_r_max[1] = best_r_max[2];
3900 void new_evaluation() {
3904 q_time_nb_flux_active = 0;
3908 void converged_step() {
3909 if (nb_flux == 0) {
return; }
3910 if (q_averaged_n < 0) {
3912 if (q_max >= 0.1 * q_max_averaged) {
3913 q = q_time_nb_flux_active / nb_flux_active;
3915 q = q_time_nb_flux / nb_flux;
3917 if (q_averaged_time_nb_step == 0) {
3918 if (q > epsilon * q_averaged_0) {
3919 q_averaged_nb_step = 1;
3920 q_averaged_time_nb_step = q;
3922 }
else if (q > epsilon * q_averaged_time_nb_step / q_averaged_nb_step) {
3923 ++q_averaged_nb_step;
3924 q_averaged_time_nb_step += q;
3927 q_max_averaged = std::max(q_max_averaged, q_max);
3930 void add_flux(
const double flux) {
3932 q_time_nb_flux += flux;
3933 if (flux >= epsilon_l * q_max_averaged) {
3935 q_time_nb_flux_active += flux;
3937 q_max = std::max(q_max, flux);
3940 typename CorrectionTerminationTest<T>::Termination is_terminated(
3941 FluxNormalizedCorrectionTerminationTest& parent,
size_t nb_iteration,
double r_max,
3942 double step_dof_max,
double delta_dof_max,
double& distance_to_iterative_convergence,
3943 const SolverHints* solver_hints) {
3945 std::fill_n(best_r_max, 3, std::numeric_limits<double>::max());
3948 if (nb_flux == 0) {
return CorrectionTerminationTest<T>::converged; }
3951 if (r_max != r_max || delta_dof_max != delta_dof_max) {
3952 parent.logger <<
logging::debug <<
"Field " << name <<
" diverged due to nan"
3953 << logging::LOGFLUSH;
3954 return CorrectionTerminationTest<T>::diverged;
3956 if (std::isinf(r_max) || std::isinf(delta_dof_max)) {
3957 parent.logger <<
logging::debug <<
"Field " << name <<
" diverged due to inf"
3958 << logging::LOGFLUSH;
3959 return CorrectionTerminationTest<T>::diverged;
3962 if (nb_iteration >
size_t(parent.I0_effective) && r_max > best_r_max[1] * 1.00001) {
3964 if (nb_divergence > parent.max_divergence) {
3966 <<
", r_max = " << std::min(r_max, last_r_max[1])
3967 <<
", previous r_max = " << last_r_max[1]
3968 <<
", best r_max = " << best_r_max[1] <<
", diverged after "
3969 << nb_divergence <<
" consecutive divergence(s)."
3970 << logging::LOGFLUSH;
3971 return CorrectionTerminationTest<T>::diverged;
3973 divergence_in_step =
true;
3978 if (nb_iteration > 1 && r_max > Rm) {
3980 <<
", r_max = " << std::min(r_max, last_r_max[1])
3981 <<
", previous r_max = " << last_r_max[1]
3982 <<
", best r_max = " << best_r_max[1]
3983 <<
", diverged because the residue exceeds the "
3984 <<
"maximum (" << Rm <<
")." << logging::LOGFLUSH;
3985 return CorrectionTerminationTest<T>::diverged;
3987 if (nb_iteration > 1 && step_dof_max > Cm) {
3989 <<
", r_max = " << std::min(r_max, last_r_max[1])
3990 <<
", previous r_max = " << last_r_max[1]
3991 <<
", best r_max = " << best_r_max[1]
3992 <<
", diverged because the last correction exceeds "
3993 <<
"the maximum (" << Cm <<
")." << logging::LOGFLUSH;
3994 return CorrectionTerminationTest<T>::diverged;
3997 last_r_max[2] = r_max;
3998 if (nb_iteration >=
size_t(parent.I0_effective)) {
3999 best_r_max[2] = std::min(best_r_max[1], r_max);
4002 if (q_averaged_n > 0) {
4003 q_averaged = q_averaged_n;
4006 if (q_max >= 0.1 * q_max_averaged) {
4007 q = q_time_nb_flux_active / nb_flux_active;
4009 q = q_time_nb_flux / nb_flux;
4011 if (q_averaged_nb_step == 0) {
4012 if (q > epsilon * q_averaged_0) {
4015 q_averaged = q_averaged_0;
4017 }
else if (q > epsilon * q_averaged_time_nb_step / q_averaged_nb_step) {
4018 q_averaged = (q + q_averaged_time_nb_step) / (q_averaged_nb_step + 1);
4020 q_averaged = q_averaged_time_nb_step / q_averaged_nb_step;
4024 parent.logger <<
logging::debug <<
"Field " << name <<
", r_max = " << r_max
4025 <<
", averaged flux = " << q_averaged <<
", c_max = " << delta_dof_max
4026 <<
", delta_dof_max = " << step_dof_max <<
", ";
4029 if (r_max <= Rl * q_averaged) {
4030 parent.logger <<
"linear increment, converged." << logging::LOGFLUSH;
4032 return CorrectionTerminationTest<T>::converged;
4036 if (q_max <= epsilon * q_averaged
4037 && (r_max <= epsilon * q_averaged || delta_dof_max <= Cepsilon * step_dof_max)) {
4038 parent.logger <<
"zero flux, converged" << logging::LOGFLUSH;
4040 return CorrectionTerminationTest<T>::converged;
4044 if (nb_iteration > Ip) {
4045 if (!nonquadratic_convergence
4046 && std::min(r_max, last_r_max[1]) < 2 * (last_r_max[0] * last_r_max[0])) {
4047 nonquadratic_convergence =
true;
4049 if (nonquadratic_convergence && r_max <= Rp * q_averaged
4050 && delta_dof_max <= Cn * step_dof_max) {
4051 parent.logger <<
"nonquadratic convergence, converged." << logging::LOGFLUSH;
4053 return CorrectionTerminationTest<T>::converged;
4057 distance_to_iterative_convergence =
4058 std::max(distance_to_iterative_convergence, r_max / (Rn * q_averaged));
4059 distance_to_iterative_convergence = std::max(
4060 distance_to_iterative_convergence,
4061 delta_dof_max * std::min(1.0, r_max / std::min(last_r_max[0], last_r_max[1]))
4062 / (Cn * step_dof_max));
4064 if (r_max <= Rn * q_averaged
4065 && (delta_dof_max <= Cn * step_dof_max
4066 || (!divergence_in_step && nb_iteration > 2
4067 && r_max / std::min(last_r_max[0], last_r_max[1]) * delta_dof_max
4068 <= Cn * step_dof_max))) {
4069 parent.logger <<
"converged." << logging::LOGFLUSH;
4071 return CorrectionTerminationTest<T>::converged;
4074 parent.logger <<
"unfinished." << logging::LOGFLUSH;
4075 return CorrectionTerminationTest<T>::unfinished;
4088 double q_averaged_0;
4089 double q_averaged_n;
4094 double delta_dof_max;
4095 double delta_dof_max_in_step;
4098 double q_time_nb_flux;
4099 size_t nb_flux_active;
4100 double q_time_nb_flux_active;
4101 size_t q_averaged_nb_step;
4102 double q_averaged_time_nb_step;
4104 double q_max_averaged;
4105 bool nonquadratic_convergence;
4106 double last_r_max[3];
4107 double best_r_max[3];
4109 bool divergence_in_step;
4113 std::vector<Field> list_field;
4116template <
typename T>
4117typename FluxNormalizedCorrectionTerminationTest<T>::type_t
4118 FluxNormalizedCorrectionTerminationTest<T>::type(
4119 "FluxNormalizedCorrectionTerminationTest", type_name<T>(),
4120 StringList(
"FLUX_NORMALISED_CORRECTION_TERMINATION_TEST"), module);
4122class StrongWolfeLineSearch :
public LineSearch {
4124 StrongWolfeLineSearch() : max_iter(8), c1(0.3), c2(0.9), h_derivative(0.01) {}
4126 void init(Model& model,
const AttributeList& attribute)
override;
4128 double get_minimum(LineSearch::Function& g,
double g0,
double g1)
override;
4130 using type_t = ObjectTypeComplete<StrongWolfeLineSearch, LineSearch::type_t>;
4134 void clear_interpolation() { value.clear(); }
4136 void add_value(
double h,
double v) { value[h] = v; }
4138 double get_minimum_interpolation(
double low,
double hig);
4140 using value_t = std::map<double, double>;
4143 static double quadratic_interpolation_minimisation(
4144 double a1,
double g_a1,
double dg_a1,
double a2,
double g_a2) {
4145 double a2_ = a2 - a1;
4146 return a1 + dg_a1 * a2_ * a2_ * 0.5 / (g_a2 - g_a1 - dg_a1 * a2_);
4149 static double cubic_interpolation_minimisation(
4150 double a1,
double g_a1,
double dg_a1,
double a2,
double g_a2,
double a3,
double g_a3) {
4158 double h_derivative;
csda< T > norm(const csda< T > &a)
Definition b2csda.H:343
#define THROW
Definition b2exception.H:198
Interface to C++ representations of FE solvers.
@ diverge
Definition b2solver.H:183
@ none
Definition b2solver.H:173
@ unfinished
Definition b2solver.H:179
@ degradation
Definition b2solver.H:188
Logger & get_logger(const std::string &logger_name="")
Definition b2logging.H:829
Contains the base classes for implementing Finite Elements.
Definition b2boundary_condition.H:32
GenericException< KeyError_name > KeyError
Definition b2exception.H:320
void central_numerical_differentiation(FUNCTION &f, const double x, std::vector< T > &res, int derivative_order=1, int approximation_order=2, int first_nonzero_derivative_order=0, double h=0)
Definition b2numerical_differentiation.H:79
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314