21#ifndef B2BOUNDARY_CONDITION_NLR_COUPLING_H_ 
   22#define B2BOUNDARY_CONDITION_NLR_COUPLING_H_ 
   26#include "b2model_database.H" 
   27#include "b2solution_database.H" 
   30#include "model/b2element.H" 
   31#include "model_imp/b2boundary_condition_component.H" 
   32#include "utils/b2linear_algebra.H" 
   37namespace b2000::b2dbv3 {
 
   39class StaticResidueFunctionNLRCoupling {
 
   42    typedef b2linalg::Msymmetric MATRIX_FORMAT;
 
   43    typedef TypedNaturalBoundaryConditionListComponent<T, MATRIX_FORMAT::sparse_inversible>
 
   45    typedef TypedEssentialBoundaryConditionListComponent<T> ebc_list_t;
 
   46    typedef TypedModelReductionBoundaryConditionListComponent<T> mrbc_list_t;
 
   48    StaticResidueFunctionNLRCoupling()
 
   50          number_of_non_lagrang_dof(0),
 
   56          constraint_has_penalty(false),
 
   58          lagrange_mult_scale(0) {}
 
   60    virtual ~StaticResidueFunctionNLRCoupling() {}
 
   62    void init(Model& model_, 
const AttributeList& attribute) {
 
   64        domain = &model->get_domain();
 
   65        ebc = &
dynamic_cast<ebc_list_t::typed_base_t&
>(
 
   66              model->get_essential_boundary_condition(&ebc_list_t::type));
 
   67        mrbc = &
dynamic_cast<mrbc_list_t::typed_base_t&
>(
 
   68              model->get_model_reduction_boundary_condition(&mrbc_list_t::type));
 
   69        nbc = &
dynamic_cast<nbc_list_t::typed_base_t&
>(
 
   70              model->get_natural_boundary_condition(&nbc_list_t::type));
 
   71        nbc_sol.resize(domain->get_number_of_dof());
 
   72        fi.resize(domain->get_number_of_dof());
 
   74        constraint_has_penalty =
 
   75              attribute.get_string(
"CONSTRAINT_METHOD", 
"REDUCTION") == 
"PENALTY";
 
   77        constraint_has_penalty |=
 
   78              attribute.get_string(
"NONLINEAR_CONSTRAINT_METHOD", 
"OTHER") == 
"PENALTY";
 
   80        number_of_dof = number_of_non_lagrang_dof =
 
   81              mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1);
 
   82        if (constraint_has_penalty) {
 
   83            penalty_factor = attribute.get_double(
"CONSTRAINT_PENALTY", 1e10);
 
   85            number_of_dof += ebc->get_size(
false);
 
   86            penalty_factor = attribute.get_double(
"CONSTRAINT_PENALTY", 1);
 
   87            if (attribute.get_string(
"NONLINEAR_CONSTRAINT_METHOD", 
"OTHER") == 
"LAGRANGE") {
 
   90            lagrange_mult_scale = attribute.get_double(
"LAGRANGE_MULT_SCALE_PENALTY", 1.0);
 
   94    size_t get_number_of_dof() { 
return number_of_dof; }
 
   96    size_t get_number_of_non_lagrange_dof() { 
return number_of_non_lagrang_dof; }
 
   99          const b2linalg::Vector<T, b2linalg::Vdense_constref> dof, 
const double time,
 
  100          EquilibriumSolution equilibrium_solution,
 
  101          b2linalg::Vector<T, b2linalg::Vdense_ref> dof_sol) {
 
  102        mrbc_get_nonlinear_value(
 
  103              dof(b2linalg::Interval(
 
  104                    0, mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1))),
 
  105              time, equilibrium_solution, dof_sol,
 
  106              b2linalg::Matrix<T, b2linalg::Mcompressed_col>::null,
 
  107              b2linalg::Vector<T, b2linalg::Vdense_ref>::null, 
nullptr);
 
  110    const b2linalg::Vector<T, b2linalg::Vdense_constref> get_residuum_sol() { 
return fi; }
 
  112    const b2linalg::Vector<T, b2linalg::Vdense_constref> get_nbc_sol() { 
return nbc_sol; }
 
  114    T get_residue_normalization() { 
return std::max(fi * fi, nbc_sol * nbc_sol); }
 
  116    double get_energy_normalisation1() {
 
  118        for (
size_t i = 0; i != r.size(); ++i) {
 
  119            res += std::max(
norm(r[i] * nbc_sol[i]), 
norm(r[i] * fi[i]));
 
  124    double get_energy() {
 
  126        for (
size_t i = 0; i != r.size(); ++i) { res += r[i] * (fi[i] + nbc_sol[i]); }
 
  131          const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof_global,
 
  132          const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof, 
const double time,
 
  133          const double delta_time, 
const EquilibriumSolution equilibrium_solution,
 
  134          b2linalg::Vector<T, b2linalg::Vdense_ref> residue,
 
  135          b2linalg::Matrix<T, MATRIX_FORMAT::sparse_inversible>& d_residue_d_dof,
 
  136          const b2linalg::Matrix<T>& C, b2linalg::Matrix<T>& RtKC,
 
  137          b2linalg::Matrix<T, b2linalg::Mrectangle>& CtKC,
 
  138          b2linalg::Vector<T, b2linalg::Vdense_ref> d_residue_d_time, SolverHints* solver_hints) {
 
  139        b2linalg::Interval disp_range(
 
  140              0, mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1));
 
  141        b2linalg::Interval lagrange_mult_range(
 
  142              mrbc->get_size(
false, b2linalg::Vector<T, b2linalg::Vdense>::null, 1), number_of_dof);
 
  144        const size_t nb_dof = domain->get_number_of_dof();
 
  146        if (!d_residue_d_dof.is_null()) {
 
  147            if (d_residue_d_dof.size1() != dof.size()) { d_residue_d_dof.resize(dof.size()); }
 
  148            d_residue_d_dof.set_zero_same_struct();
 
  149            RtKC.resize(dof.size(), C.size2());
 
  154        b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_r_d_dof;
 
  155        b2linalg::Vector<T, b2linalg::Vdense> d_r_d_time(domain->get_number_of_dof());
 
  156        mrbc_get_nonlinear_value(
 
  157              dof(disp_range), time, equilibrium_solution, r, trans_d_r_d_dof, d_r_d_time,
 
  161        b2linalg::Matrix<T, MATRIX_FORMAT::sparse_inversible> d_fe_d_dof;
 
  162        b2linalg::Vector<T, b2linalg::Vdense> d_fe_d_time(domain->get_number_of_dof());
 
  164        nbc->get_nonlinear_value(
 
  165              r, time, equilibrium_solution, residue,
 
  166              (d_residue_d_dof.is_null()
 
  167                     ? b2linalg::Matrix<T, MATRIX_FORMAT::sparse_inversible>::null
 
  169              (d_residue_d_time.is_null() ? d_residue_d_time
 
  170                                          : b2linalg::Vector<T, b2linalg::Vdense_ref>(d_fe_d_time)),
 
  173        d_fe_d_time = -d_fe_d_time;
 
  174        if (d_fe_d_dof.size1() != 0) {
 
  175            d_residue_d_dof += -trans_d_r_d_dof * d_fe_d_dof * transposed(trans_d_r_d_dof);
 
  178        b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_d_l_d_dof;
 
  179        b2linalg::Vector<T> l;
 
  181        if (constraint_has_penalty) {
 
  182            l.resize(ebc->get_size(
false));
 
  183            ebc->get_nonlinear_value(
 
  184                  r, time, equilibrium_solution, l, trans_d_l_d_dof,
 
  185                  b2linalg::Vector<T, b2linalg::Vdense_ref>::null, solver_hints);
 
  187            ebc->get_nonlinear_value(
 
  188                  r, time, equilibrium_solution, residue(lagrange_mult_range), trans_d_l_d_dof,
 
  189                  d_residue_d_time.is_null() ? d_residue_d_time
 
  190                                             : d_residue_d_time(lagrange_mult_range),
 
  192            if (!d_residue_d_time.is_null()) {
 
  193                d_residue_d_time(lagrange_mult_range) +=
 
  194                      b2linalg::transposed(trans_d_l_d_dof) * d_r_d_time;
 
  198        if (!d_residue_d_time.is_null() && d_fe_d_dof.size1()) {
 
  199            d_fe_d_time -= d_fe_d_dof * d_r_d_time;
 
  205            b2linalg::Index index;
 
  206            b2linalg::Vector<T, b2linalg::Vdense> value_e;
 
  207            b2linalg::Vector<T, b2linalg::Vdense> d_value_d_time_e;
 
  208            std::vector<bool> d_value_d_dof_e_flags(
 
  209                  d_residue_d_dof.is_null() && d_residue_d_time.is_null() ? 0 : 1, true);
 
  210            std::vector<b2linalg::Matrix<T, MATRIX_FORMAT::dense> > d_value_d_dof_e(
 
  211                  d_value_d_dof_e_flags.size());
 
  212            std::unique_ptr<b2000::Domain::ElementIterator> i = domain->get_element_iterator();
 
  213            if (K.size1() == 0) { K.resize(nb_dof, nb_dof); }
 
  214            K.set_zero_same_struct();
 
  215            for (Element* element = i->next(); element != 
nullptr; element = i->next()) {
 
  216                if (
auto te = 
dynamic_cast<TypedElement<T>*
>(element); te != 
nullptr) {
 
  218                          *model, 
false, equilibrium_solution, time, delta_time,
 
  219                          b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(r),
 
  221                          solver_hints, index, value_e, d_value_d_dof_e_flags, d_value_d_dof_e,
 
  222                          (d_residue_d_time.is_null() ? b2linalg::Vector<T, b2linalg::Vdense>::null
 
  223                                                      : d_value_d_time_e));
 
  225                fi(index) += value_e;
 
  227                if (!d_residue_d_time.is_null()) {
 
  228                    d_value_d_time_e += d_value_d_dof_e[0] * d_r_d_time(index);
 
  229                    d_residue_d_time(index) += d_value_d_time_e;
 
  231                if (!d_residue_d_dof.is_null()) {
 
  233                          T, b2linalg::Mstructured_constref<b2linalg::Mpacked_st_constref> >
 
  234                          Kelem = b2linalg::StructuredMatrix(nb_dof, index, d_value_d_dof_e[0]);
 
  236                          trans_d_r_d_dof * Kelem * b2linalg::transposed(trans_d_r_d_dof);
 
  241                b2linalg::Vector<double> KCi;
 
  242                b2linalg::Matrix<T, b2linalg::Msym_compressed_col_st_constref> Kref(K);
 
  243                for (
size_t j = 0; j != C.size2(); ++j) {
 
  245                    RtKC[j] += trans_d_r_d_dof * KCi;
 
  246                    CtKC[j] += b2linalg::transposed(C) * KCi;
 
  252            b2linalg::Vector<T> tmp = fi;
 
  253            if (constraint_has_penalty) {
 
  254                tmp += (trans_d_l_d_dof * l) * penalty_factor;
 
  256                if (MATRIX_FORMAT::symmetric && penalty_factor != 0) {
 
  259                    b2linalg::Vector<T> tmp1;
 
  260                    tmp1 = residue(lagrange_mult_range) * penalty_factor;
 
  261                    tmp1 += dof(lagrange_mult_range) * lagrange_mult_scale;
 
  262                    tmp += trans_d_l_d_dof * tmp1;
 
  263                    residue(lagrange_mult_range) *= lagrange_mult_scale;
 
  265                    tmp += lagrange_mult_scale * trans_d_l_d_dof * dof(lagrange_mult_range);
 
  268            residue(disp_range) = trans_d_r_d_dof * tmp;
 
  271        if (!d_residue_d_dof.is_null()) {
 
  272            b2linalg::Matrix<T, b2linalg::Mcompressed_col> trans_LR;
 
  273            trans_LR = trans_d_r_d_dof * trans_d_l_d_dof;
 
  274            if (penalty_factor != 0 && (constraint_has_penalty || MATRIX_FORMAT::symmetric)) {
 
  277                d_residue_d_dof(disp_range, disp_range) +=
 
  278                      (trans_LR * transposed(trans_LR)) * penalty_factor;
 
  280            if (!constraint_has_penalty) {
 
  281                trans_LR *= lagrange_mult_scale;
 
  282                b2linalg::Matrix<T, b2linalg::Mcompressed_col> LR = transposed(trans_LR);
 
  283                d_residue_d_dof(lagrange_mult_range, disp_range) += LR;
 
  284                if (!MATRIX_FORMAT::symmetric) {
 
  285                    d_residue_d_dof(disp_range, lagrange_mult_range) += trans_LR;
 
  290        if (!d_residue_d_time.is_null()) {
 
  291            d_residue_d_time(disp_range) = trans_d_r_d_dof * d_fe_d_time;
 
  295    void mrbc_get_nonlinear_inverse_value(
 
  296          const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof, 
double time,
 
  297          b2linalg::Vector<T, b2linalg::Vdense_ref> reduced_dof) {
 
  298        mrbc->get_nonlinear_inverse_value(
 
  299              b2linalg::Matrix<T, b2linalg::Mrectangle_constref>(dof), time,
 
  300              b2linalg::Matrix<T, b2linalg::Mrectangle_ref>(reduced_dof));
 
  304    virtual void mrbc_get_nonlinear_value(
 
  305          const b2linalg::Vector<T, b2linalg::Vdense_constref>& dof, 
double time,
 
  306          EquilibriumSolution equilibrium_solution, b2linalg::Vector<T, b2linalg::Vdense_ref> value,
 
  307          b2linalg::Matrix<T, b2linalg::Mcompressed_col>& d_value_d_dof_trans,
 
  308          b2linalg::Vector<T, b2linalg::Vdense_ref> d_value_d_time, SolverHints* solver_hints) {
 
  309        mrbc->get_nonlinear_value(
 
  310              dof, time, equilibrium_solution, value, d_value_d_dof_trans,
 
  311              b2linalg::Matrix<T, b2linalg::Mrectangle_ref>(d_value_d_time), solver_hints);
 
  314    size_t number_of_dof;
 
  315    size_t number_of_non_lagrang_dof;
 
  318    TypedModelReductionBoundaryCondition<T>* mrbc;
 
  319    ebc_list_t::typed_base_t* ebc;
 
  320    nbc_list_t::typed_base_t* nbc;
 
  321    b2linalg::Vector<T, b2linalg::Vdense> fi;
 
  322    b2linalg::Vector<T, b2linalg::Vdense> nbc_sol;
 
  323    b2linalg::Vector<T, b2linalg::Vdense> r;
 
  324    bool constraint_has_penalty;
 
  325    double penalty_factor;
 
  326    double lagrange_mult_scale;
 
  327    b2linalg::Matrix<T, MATRIX_FORMAT::sparse_inversible> K;
 
  330class NBC_NLR_Coupling;
 
  332class SolutionStaticNonlinearNLRCoupling : 
public b2000::SolutionStaticNonlinear<double> {
 
  334    SolutionStaticNonlinearNLRCoupling()
 
  335        : nlr_coupling(nullptr), local_solution(nullptr), subcase_id(0) {}
 
  337    void set_nlr_coupling(NBC_NLR_Coupling& nlr_coupling);
 
  343    void set_subcase_id(
const int subcase_id_)
 override { subcase_id = subcase_id_; }
 
  345    void set_need_refinement()
 override {}
 
  347    b2000::SolutionStaticNonlinear<double>::gradient_container get_gradient_container()
 override {
 
  348        return local_solution->get_gradient_container();
 
  351    void new_cycle(
bool end_of_stage = 
false)
 override { local_solution->new_cycle(end_of_stage); }
 
  353    void terminate_cycle(
double time, 
double dtime, 
const RTable& attributes)
 override {
 
  354        local_solution->terminate_cycle(time, dtime, attributes);
 
  357    void terminate_stage(
bool success = 
true) 
override;
 
  359    void terminate_case(
bool success, 
const RTable& attributes) 
override;
 
  361    int get_subcase_id()
 const { 
return subcase_id; }
 
  363    size_t get_cycle_id()
 override { 
return local_solution->get_cycle_id(); }
 
  365    size_t get_subcycle_id()
 override { 
return local_solution->get_subcycle_id(); }
 
  367    std::string get_domain_state_id()
 override { 
return local_solution->get_domain_state_id(); }
 
  370          double time, 
const b2linalg::Vector<double, b2linalg::Vdense_constref>& dof,
 
  371          const b2linalg::Vector<double, b2linalg::Vdense_constref>& nbc,
 
  372          const b2linalg::Vector<double, b2linalg::Vdense_constref>& residue,
 
  373          bool unconverged_subcycle = 
false) 
override;
 
  375    void set_equilibrium(
 
  376          double time, 
const b2linalg::Vector<double, b2linalg::Vdense_constref>& dof)
 override {}
 
  378    void get_dof(
double& time, b2linalg::Vector<double, b2linalg::Vdense_ref> dof)
 override {
 
  383    NBC_NLR_Coupling* nlr_coupling;
 
  384    b2000::b2dbv3::SolutionStaticNonlinear<double>* local_solution;
 
  388class NBC_NLR_Coupling : 
public TypedNaturalBoundaryConditionComponent<
 
  389                               double, b2linalg::Msym_compressed_col_update_inv> {
 
  391    NBC_NLR_Coupling() : local_case(nullptr), global_model(nullptr), C_linear(true) {}
 
  394          const std::string& id_, TimeFunction* scalef_, 
b2000::Model& model_,
 
  395          const b2000::Case& case_, 
const int subcase_id_)
 override {
 
  397        global_model = &model_;
 
  398        subcase_id = subcase_id_;
 
  401    std::string get_id()
 const override { 
return id; }
 
  403    int get_subcase_id()
 const override { 
return subcase_id; }
 
  409    void add_nonlinear_nbc_value(
 
  410          const b2linalg::Vector<double, b2linalg::Vdense_constref>& global_dof_all, 
double time,
 
  411          EquilibriumSolution equilibrium_solution,
 
  412          b2linalg::Vector<double, b2linalg::Vdense_ref> value_,
 
  413          b2linalg::Matrix<double, b2linalg::Msym_compressed_col_update_inv>& d_value_d_dof,
 
  414          b2linalg::Vector<double, b2linalg::Vdense_ref> d_value_d_time,
 
  415          SolverHints* solver_hints)
 override {
 
  418        if (C.size1() == 0) { update_local_model(); }
 
  420        if (equilibrium_solution.input_level == 0) {
 
  421            prev_global_dof = conv_global_dof;
 
  422            prev_local_dof = conv_local_dof;
 
  424        b2linalg::Vector<double> local_dof = prev_local_dof;
 
  426        b2linalg::Vector<double> global_dof = global_dof_all(C_index);
 
  429            if (prev_global_dof.size() != 0) {
 
  430                b2linalg::Vector<double> delta_global_dof;
 
  431                delta_global_dof = prev_global_dof - global_dof;
 
  432                b2linalg::Vector<double> delta_d;
 
  433                delta_d = local_RtKC * delta_global_dof;
 
  434                delta_d = b2linalg::inverse(local_RtKR) * delta_d;
 
  435                local_dof += delta_d;
 
  437            if (equilibrium_solution.output_level == 0) { conv_global_dof = global_dof; }
 
  438            if (equilibrium_solution.output_level != -1) { prev_global_dof = global_dof; }
 
  441        b2linalg::Matrix<double, b2linalg::Mrectangle> local_CtKC(C.size2(), C.size2());
 
  444        b2linalg::Vector<double> residue(local_model_residue.get_number_of_dof());
 
  446            b2linalg::Vector<double> global_dof_on_local;
 
  448                global_dof_on_local = C * global_dof;
 
  450                get_global_to_local_dof(global_dof_all, global_dof_on_local, C);
 
  452            local_model_residue.get_residue(
 
  453                  global_dof_on_local, local_dof, time, 0, equilibrium_solution, residue,
 
  454                  (d_value_d_dof.is_null()
 
  455                         ? b2linalg::Matrix<double, b2linalg::Msym_compressed_col_update_inv>::null
 
  457                  C, local_RtKC, local_CtKC, b2linalg::Vector<double, b2linalg::Vdense_ref>::null,
 
  462        if (!d_value_d_dof.is_null() && local_RtKR.size1() != 0) {
 
  463            b2linalg::Matrix<double> M;
 
  464            M = inverse(local_RtKR) * local_RtKC;
 
  465            local_CtKC -= (b2linalg::transposed(local_RtKC) * M);
 
  492        b2linalg::Vector<double> delta_d;
 
  494        if (equilibrium_solution.output_level != -1 || !value_.is_null()) {
 
  495            delta_d = b2linalg::inverse(local_RtKR) * residue;
 
  496            if (equilibrium_solution.output_level != -1) {
 
  497                local_dof -= delta_d;
 
  498                prev_local_dof = local_dof;
 
  503        if (!value_.is_null()) {
 
  504            b2linalg::Vector<double> tmp;
 
  505            tmp = -transposed(C) * local_model_residue.get_residuum_sol();
 
  506            tmp += transposed(local_RtKC) * delta_d;
 
  507            value_(C_index) += tmp;
 
  511        if (!d_value_d_dof.is_null()) {
 
  512            if (d_value_d_dof.size1() == 0) {
 
  513                d_value_d_dof.resize(global_dof_all.size(), global_dof_all.size());
 
  515            b2linalg::Matrix<double, b2linalg::Mupper_packed> local_CtKC_sym;
 
  516            local_CtKC_sym = -local_CtKC;
 
  518                  b2linalg::StructuredMatrix(d_value_d_dof.size1(), C_index, local_CtKC_sym);
 
  523            b2linalg::Index index_e;
 
  524            b2linalg::Vector<double, b2linalg::Vdense> value_e;
 
  525            b2linalg::Vector<double, b2linalg::Vdense> d_value_d_time_e;
 
  526            std::vector<bool> d_value_d_dof_e_flags(
 
  527                  d_value_d_dof.is_null() && d_value_d_time.is_null() ? 0 : 1, true);
 
  528            std::vector<b2linalg::Matrix<double, b2linalg::Mpacked> > d_value_d_dof_e(
 
  529                  d_value_d_dof_e_flags.size());
 
  530            for (global_elements_t::iterator e = global_elements.begin();
 
  531                 e != global_elements.end(); ++e) {
 
  532                if (
auto te = 
dynamic_cast<TypedElement<double>*
>(*e); te != 
nullptr) {
 
  534                          *global_model, 
false, equilibrium_solution, time, 0,
 
  535                          b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(global_dof_all),
 
  537                          solver_hints, index_e,
 
  538                          (value_.is_null() ? b2linalg::Vector<double, b2linalg::Vdense>::null
 
  540                          d_value_d_dof_e_flags, d_value_d_dof_e,
 
  541                          (d_value_d_time.is_null()
 
  542                                 ? b2linalg::Vector<double, b2linalg::Vdense>::null
 
  543                                 : d_value_d_time_e));
 
  545                if (!value_.is_null()) { value_(index_e) += value_e; }
 
  546                if (!d_value_d_dof.is_null()) {
 
  547                    d_value_d_dof += b2linalg::StructuredMatrix(
 
  548                          d_value_d_dof.size1(), index_e, d_value_d_dof_e[0]);
 
  554    typedef ObjectTypeComplete<
 
  555          NBC_NLR_Coupling, TypedNaturalBoundaryConditionComponent<double>::type_t>
 
  560    using global_elements_t = std::set<TypedElement<double>*>;
 
  561    friend class SolutionStaticNonlinearNLRCoupling;
 
  562    SolutionStaticNonlinearNLRCoupling solution;
 
  567    b2000::CaseList::case_iterator local_case_iterator;
 
  582    b2linalg::Matrix<double> C;
 
  583    b2linalg::Index C_index;
 
  585    std::map<size_t, size_t> C_index_set;
 
  589    void update_local_model() {
 
  590        local_model.
init(
id);
 
  592        local_case_iterator = local_model.
get_case_list().get_case_iterator();
 
  593        local_case = local_case_iterator->next();
 
  596        solution.set_nlr_coupling(*
this);
 
  597        dynamic_cast<b2000::b2dbv3::SolutionStaticNonlinear<double>&
>(global_model->
get_solution())
 
  598              .add_sub_solution(solution);
 
  604            global_elements.clear();
 
  605            std::unique_ptr<b2000::Domain::ElementIterator> local_element_iter =
 
  607            Element* element = 
nullptr;
 
  608            for (element = local_element_iter->next(); element != 
nullptr;
 
  609                 element = local_element_iter->next()) {
 
  611                      global_domain, *element, b2linalg::Matrix<double>::null);
 
  612                TypedElement<double>& global_element_typed =
 
  613                      dynamic_cast<TypedElement<double>&
>(*global_element);
 
  614                global_elements.insert(&global_element_typed);
 
  624            std::unique_ptr<b2000::Domain::NodeIterator> local_node_iter =
 
  626            const std::string field_name = 
"DISP";
 
  627            for (Node* local_node = local_node_iter->next(); local_node != 
nullptr;
 
  628                 local_node = local_node_iter->next()) {
 
  629                b2linalg::Vector<double> global_icoor;
 
  631                      global_domain, *local_node, global_icoor);
 
  632                b2linalg::Index dof_numbering;
 
  633                b2linalg::Matrix<double, b2linalg::Mrectangle> d_value_d_dof;
 
  634                TypedElement<double>& e = 
dynamic_cast<TypedElement<double>&
>(*global_element);
 
  635#ifdef CHECK_GLOBAL_TO_LOCAL_MAPPING 
  637                    b2linalg::Vector<double> global_coor;
 
  639                          global_icoor, global_coor,
 
  640                          b2linalg::Matrix<double, b2linalg::Mrectangle>::null);
 
  641                    std::pair<int, const coor_type*> local_coor = local_node->get_coor();
 
  642                    for (
int i = 0; i != local_coor.first; ++i) {
 
  643                        if (
norm(local_coor.second[i] - global_coor[i])
 
  644                            > CHECK_GLOBAL_TO_LOCAL_MAPPING) {
 
  646                                  << 
"The local mapping for the local node " 
  647                                  << local_node->get_object_name() << 
" is not correct." << 
THROW;
 
  652                if (!e.body_field_linear_on_dof(field_name)) { C_linear = 
false; }
 
  654                      field_name, global_icoor,
 
  655                      b2linalg::Matrix<double, b2linalg::Mrectangle_constref>::null, 1,
 
  656                      b2linalg::Vector<double, b2linalg::Vdense>::null,
 
  657                      b2linalg::Matrix<double, b2linalg::Mrectangle>::null, dof_numbering,
 
  659                for (
size_t i = 0; i != dof_numbering.size(); ++i) {
 
  660                    C_index_set[dof_numbering[i]] = 0;
 
  664            C_index.resize(C_index_set.size());
 
  667                for (std::map<size_t, size_t>::iterator i = C_index_set.begin();
 
  668                     i != C_index_set.end(); ++i, ++ii) {
 
  669                    C_index[ii] = i->first;
 
  679                get_global_to_local_dof(
 
  680                      b2linalg::Vector<double, b2linalg::Vdense_constref>::null,
 
  681                      b2linalg::Vector<double, b2linalg::Vdense>::null, C);
 
  686        local_model_residue.init(local_model, *local_case);
 
  687        conv_local_dof.clear();
 
  688        conv_local_dof.resize(local_model_residue.get_number_of_dof());
 
  689        prev_local_dof = conv_local_dof;
 
  692    void get_global_to_local_dof(
 
  693          const b2linalg::Vector<double, b2linalg::Vdense_constref>& dof_global,
 
  694          b2linalg::Vector<double, b2linalg::Vdense>& dof_local,
 
  695          b2linalg::Matrix<double, b2linalg::Mrectangle_ref> C) {
 
  698        const std::string field_name = 
"DISP";
 
  699        if (!dof_local.is_null()) {
 
  700            dof_local.set_zero();
 
  703        if (!C.is_null()) { C.set_zero(); }
 
  704        std::unique_ptr<b2000::Domain::NodeIterator> local_node_iter =
 
  707        for (Node* local_node = local_node_iter->next(); local_node != 
nullptr;
 
  708             local_node = local_node_iter->next()) {
 
  709            b2linalg::Vector<double> global_icoor;
 
  710            Element* global_element =
 
  712            b2linalg::Index dof_numbering;
 
  713            b2linalg::Vector<double, b2linalg::Vdense> value;
 
  714            b2linalg::Matrix<double, b2linalg::Mrectangle> d_value_d_dof;
 
  715            dynamic_cast<TypedElement<double>&
>(*global_element)
 
  717                        field_name, global_icoor,
 
  718                        (dof_global.is_null()
 
  719                               ? b2linalg::Matrix<double, b2linalg::Mrectangle_constref>::null
 
  720                               : b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(
 
  723                        (dof_local.is_null() ? b2linalg::Vector<double, b2linalg::Vdense>::null
 
  725                        b2linalg::Matrix<double, b2linalg::Mrectangle>::null, dof_numbering,
 
  726                        (C.is_null() ? b2linalg::Matrix<double, b2linalg::Mrectangle>::null
 
  728            if (!dof_local.is_null()) {
 
  729                for (
size_t i = 0; i != value.size(); ++i) { dof_local[ii + i] = value[i]; }
 
  732#if BCNC_CHECK_DERIVATIVE 
  733                if (!dof_global.is_null()) {
 
  734                    const double h = 1e-4;
 
  735                    const double inv_12h = 1.0 / (12 * h);
 
  736                    b2linalg::Vector<double> dof_h = dof_global;
 
  737                    b2linalg::Vector<double> diff;
 
  738                    b2linalg::Vector<double> value_tmp;
 
  739                    TypedElement<double>& e = 
dynamic_cast<TypedElement<double>&
>(*global_element);
 
  740                    bool first_error = 
true;
 
  741                    for (
size_t j = 0; j != dof_numbering.size(); ++j) {
 
  742                        const size_t jj = dof_numbering[j];
 
  743                        dof_h[jj] = dof_global[jj] - 2 * h;
 
  745                              field_name, global_icoor,
 
  746                              b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(dof_h), 1,
 
  747                              value_tmp, b2linalg::Matrix<double, b2linalg::Mrectangle>::null,
 
  748                              b2linalg::Index::null,
 
  749                              b2linalg::Matrix<double, b2linalg::Mrectangle>::null);
 
  750                        diff = inv_12h * value_tmp;
 
  752                        dof_h[jj] = dof_global[jj] + 2 * h;
 
  754                              field_name, global_icoor,
 
  755                              b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(dof_h), 1,
 
  756                              value_tmp, b2linalg::Matrix<double, b2linalg::Mrectangle>::null,
 
  757                              b2linalg::Index::null,
 
  758                              b2linalg::Matrix<double, b2linalg::Mrectangle>::null);
 
  759                        diff += -inv_12h * value_tmp;
 
  761                        dof_h[jj] = dof_global[jj] - h;
 
  763                              field_name, global_icoor,
 
  764                              b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(dof_h), 1,
 
  765                              value_tmp, b2linalg::Matrix<double, b2linalg::Mrectangle>::null,
 
  766                              b2linalg::Index::null,
 
  767                              b2linalg::Matrix<double, b2linalg::Mrectangle>::null);
 
  768                        diff += (-8.0 * inv_12h) * value_tmp;
 
  770                        dof_h[jj] = dof_global[jj] + h;
 
  772                              field_name, global_icoor,
 
  773                              b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(dof_h), 1,
 
  774                              value_tmp, b2linalg::Matrix<double, b2linalg::Mrectangle>::null,
 
  775                              b2linalg::Index::null,
 
  776                              b2linalg::Matrix<double, b2linalg::Mrectangle>::null);
 
  777                        diff += (8.0 * inv_12h) * value_tmp;
 
  779                        dof_h[jj] = dof_global[jj];
 
  781                        for (
size_t i = 0; i != diff.size(); ++i) {
 
  782                            if (std::abs(diff[i] - d_value_d_dof(i, j)) > 1e-6) {
 
  785                                              << 
", local node=" << local_node->get_object_name()
 
  786                                              << 
", coor=" << global_icoor[0] << 
", " 
  787                                              << global_icoor[1] << 
", " << global_icoor[2]
 
  791                                std::cerr << 
"    d_value_d_dof(" << i << 
", " << j
 
  792                                          << 
")=" << d_value_d_dof(i, j) << 
", numeric=" << diff[i]
 
  799                for (
size_t j = 0; j != d_value_d_dof.size2(); ++j) {
 
  800                    const size_t jj = C_index_set[dof_numbering[j]];
 
  801                    for (
size_t i = 0; i != d_value_d_dof.size1(); ++i) {
 
  802                        C(ii + i, jj) = d_value_d_dof(i, j);
 
  806            ii += dof_local.is_null() ? d_value_d_dof.size1() : value.size();
 
  811    b2linalg::Vector<double> conv_global_dof;
 
  812    b2linalg::Vector<double> prev_global_dof;
 
  813    b2linalg::Vector<double> conv_local_dof;
 
  814    b2linalg::Vector<double> prev_local_dof;
 
  815    b2linalg::Matrix<double, b2linalg::Msym_compressed_col_update_inv> local_RtKR;
 
  816    b2linalg::Matrix<double> local_RtKC;
 
  818    global_elements_t global_elements;
 
  820    StaticResidueFunctionNLRCoupling local_model_residue;
 
  823inline void SolutionStaticNonlinearNLRCoupling::set_nlr_coupling(NBC_NLR_Coupling& nlr_coupling_) {
 
  824    nlr_coupling = &nlr_coupling_;
 
  825    local_solution = &
dynamic_cast<b2000::b2dbv3::SolutionStaticNonlinear<double>&
>(
 
  826          nlr_coupling->local_model.get_solution());
 
  829inline void SolutionStaticNonlinearNLRCoupling::set_dof(
 
  830      double time, 
const b2linalg::Vector<double, b2linalg::Vdense_constref>& global_dof_all,
 
  831      const b2linalg::Vector<double, b2linalg::Vdense_constref>& nbc,
 
  832      const b2linalg::Vector<double, b2linalg::Vdense_constref>& residue,
 
  833      bool unconverged_subcycle) {
 
  835    b2000::Domain& local_domain = nlr_coupling->local_model.get_domain();
 
  836    b2linalg::Vector<double, b2linalg::Vdense> g;
 
  838    nlr_coupling->conv_local_dof = nlr_coupling->prev_local_dof;
 
  839    nlr_coupling->local_model_residue.get_solution(nlr_coupling->conv_local_dof, time, 
true, g);
 
  843        SetName name = nlr_coupling->local_case->get_string(
"DOF_SOL", 
"DISP") + 
"_H1";
 
  844        if (unconverged_subcycle) {
 
  845            name.cycle(local_solution->get_cycle_id() + 1);
 
  846            name.subcycle(local_solution->get_subcycle_id() + 1);
 
  848            name.cycle(local_solution->get_cycle_id());
 
  850        if (name.case_undef()) { name.case_(nlr_coupling->local_case->get_id()); }
 
  851        name.subcase(subcase_id);
 
  852        dynamic_cast<DataBaseFieldSet&
>(nlr_coupling->local_model)
 
  854                    "DOF Solution", name.get_gname(), 
"NODE", 
"BRANCH", 
false, 
false, 
false);
 
  856        rtable.set(
"STAGE_ID", nlr_coupling->local_case->get_stage_id());
 
  857        rtable.set(
"STAGE", nlr_coupling->local_case->get_stage_number());
 
  858        rtable.set(
"LAMBDA", time);
 
  859        dynamic_cast<b2dbv3::Domain&
>(nlr_coupling->local_model.get_domain())
 
  861                    name, b2linalg::Vector<double, b2linalg::Vdense_constref>(g), rtable);
 
  866        if (nlr_coupling->C_linear) {
 
  867            b2linalg::Vector<double> global_dof = global_dof_all(nlr_coupling->C_index);
 
  868            g += nlr_coupling->C * global_dof;
 
  870            b2linalg::Vector<double> global_dof_on_local;
 
  871            nlr_coupling->get_global_to_local_dof(
 
  872                  global_dof_all, global_dof_on_local, nlr_coupling->C);
 
  873            g += global_dof_on_local;
 
  878    local_solution->set_dof(
 
  879          time, g, nlr_coupling->local_model_residue.get_nbc_sol(),
 
  880          nlr_coupling->local_model_residue.get_residuum_sol(), unconverged_subcycle);
 
  883    b2000::SolutionStaticNonlinear<double>::gradient_container gc =
 
  884          local_solution->get_gradient_container();
 
  886        local_domain.set_dof(g);
 
  888        b2linalg::Index index;
 
  889        for (Element* e = ii->next(); e != 
nullptr; e = ii->next()) {
 
  890            if (
auto te = 
dynamic_cast<TypedElement<double>*
>(e); te != 
nullptr) {
 
  892                      nlr_coupling->local_model,
 
  897                      b2linalg::Matrix<double, b2linalg::Mrectangle_constref>(g),
 
  898                      gc.get() != 
nullptr && gc->set_current_element(*e) ? gc.get() : 
nullptr,
 
  900                      index, b2linalg::Vector<double, b2linalg::Vdense>::null,
 
  901                      TypedElement<double>::d_value_d_dof_flags_null,
 
  902                      TypedElement<double>::d_value_d_dof_null,
 
  903                      b2linalg::Vector<double, b2linalg::Vdense>::null);
 
  909inline void SolutionStaticNonlinearNLRCoupling::terminate_stage(
bool success) {
 
  910    local_solution->terminate_stage(success);
 
  911    if (nlr_coupling->local_case->next_stage()) {
 
  912        nlr_coupling->local_model.set_case(*nlr_coupling->local_case);
 
  916inline void SolutionStaticNonlinearNLRCoupling::terminate_case(
 
  917      bool success, 
const RTable& attributes) {
 
  918    local_solution->terminate_case(success, attributes);
 
  919    nlr_coupling->local_case = nlr_coupling->local_case_iterator->next();
 
  920    if (nlr_coupling->local_case) { nlr_coupling->local_model.set_case(*nlr_coupling->local_case); }
 
csda< T > norm(const csda< T > &a)
Definition b2csda.H:343
 
#define THROW
Definition b2exception.H:198
 
virtual Element * get_parent_element_and_nodes_mapping(Domain &parent_domain, const Element &element, b2linalg::Matrix< double > &parent_nodes_internal_coor)
Definition b2domain.H:431
 
virtual size_t get_number_of_dof() const =0
 
virtual element_iterator get_element_iterator()=0
 
virtual node_iterator get_node_iterator()=0
 
virtual Element * get_parent_element_mapping(Domain &parent_domain, const Node &node, b2linalg::Vector< double > &parent_internal_coor)
Definition b2domain.H:453
 
const std::string & get_object_name() const override
Definition b2element.H:220
 
virtual void body_geom(const b2linalg::Vector< double, b2linalg::Vdense_constref > &internal_coor, b2linalg::Vector< double > &geom, b2linalg::Matrix< double, b2linalg::Mrectangle > &d_geom_d_icoor)
Definition b2element.H:963
 
virtual Solution & get_solution()=0
 
virtual Domain & get_domain()=0
 
Type
Definition b2boundary_condition.H:49
 
@ conservative
Definition b2boundary_condition.H:60
 
Definition b2model_database.H:44
 
Domain & get_domain() override
Definition b2model_database.C:164
 
void init(const std::string &dbname="", Dictionary *cmdline_set_=nullptr) override
Definition b2model_database.C:47
 
CaseList & get_case_list() override
Definition b2model_database.C:154
 
void set_case(b2000::Case &case_) override
Definition b2model_database.C:81
 
GenericException< UnimplementedError_name > UnimplementedError
Definition b2exception.H:314