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