38   template <
class CONTAINER> 
class distro    43     void build_distro(gmm::abstract_matrix)
    45       for(
size_type thread = 1; thread < num_threads(); thread++)
    47         gmm::resize(distributed(thread), gmm::mat_nrows(original),gmm::mat_ncols(original));
    51     void build_distro(gmm::abstract_vector)
    54       for(
size_type thread = 1; thread < num_threads(); thread++)
    56         gmm::resize(distributed(thread), gmm::vect_size(original));
    60     bool not_multithreaded()
 const { 
return num_threads() == 1; }
    64     distro(CONTAINER& c) : original(c)
    66       if (not_multithreaded()) 
return;
    67       build_distro(
typename gmm::linalg_traits<CONTAINER>::linalg_type());
    72       if (not_multithreaded() || this_thread() == 0) 
return original;
    73       else return distributed(this_thread());
    78       if (not_multithreaded()) 
return;
    80       GMM_ASSERT1(!me_is_multithreaded_now(),
    81                   "List accumulation should not run in parallel");
    83       for(
size_type thread = 1; thread < num_threads(); thread++)
    85         gmm::add(distributed(thread), original);
    90   model::model(
bool comp_version) {
    91     init(); complex_version = comp_version;
    92     is_linear_ = is_symmetric_ = is_coercive_ = 
true;
    94     time_integration = 0; init_step = 
false; time_step = scalar_type(1);
    95     add_interpolate_transformation
    99   void model::var_description::set_size() {
   103       complex_value.resize(n_iter);
   105       real_value.resize(n_iter);
   106     v_num_var_iter.resize(n_iter);
   107     v_num_iter.resize(n_iter);
   108     size_type s = is_fem_dofs ? passociated_mf()->nb_dof()
   110          (pim_data->nb_filtered_index() * pim_data->nb_tensor_elem()) : 1);
   114         complex_value[i].resize(s);
   116         real_value[i].resize(s);
   117     if (is_affine_dependent) {
   119         affine_complex_value.resize(s);
   121         affine_real_value.resize(s);
   125   size_type model::var_description::add_temporary(gmm::uint64_type id_num) {
   127     for (; nit < n_iter + n_temp_iter ; ++nit)
   128       if (v_num_var_iter[nit] == id_num) 
break;
   129     if (nit >=  n_iter + n_temp_iter) {
   131       v_num_var_iter.resize(nit+1);
   132       v_num_var_iter[nit] = id_num;
   133       v_num_iter.resize(nit+1);
   137         complex_value.resize(n_iter + n_temp_iter);
   138         complex_value[nit].resize(s);
   141         real_value.resize(n_iter + n_temp_iter);
   142         real_value[nit].resize(s);
   148   void model::var_description::clear_temporaries() {
   152       complex_value.resize(n_iter);
   154       real_value.resize(n_iter);
   157   bool model::check_name_validity(
const std::string &name, 
bool assert)
 const {
   158     VAR_SET::const_iterator it = variables.find(name);
   159     if (it != variables.end()) {
   160       GMM_ASSERT1(!assert, 
"Variable " << name << 
" already exists");
   164     if (variable_groups.find(name) != variable_groups.end()) {
   166                   name << 
" corresponds to an already existing group of "   171     if (macro_exists(name)) {
   173                   name << 
" corresponds to an already existing macro");
   177     if (name.compare(
"X") == 0) {
   178       GMM_ASSERT1(!assert, 
"X is a reserved keyword of the generic "   179                   "assembly language");
   183     int ga_valid = ga_check_name_validity(name);
   185       GMM_ASSERT1(!assert, 
"Invalid variable name, corresponds to an "   186                 "operator or function name of the generic assembly language");
   191       GMM_ASSERT1(!assert, 
"Invalid variable name having a reserved "   192                   "prefix used by the generic assembly language");
   197       std::string org_name = sup_previous_and_dot_to_varname(name);
   198       if (org_name.size() < name.size() &&
   199           variables.find(org_name) != variables.end()) {
   201                     "Dot and Previous are reserved prefix used for time "   202                     "integration schemes");
   208     if (name.size() == 0) valid = 
false;
   210       if (!isalpha(name[0])) valid = 
false;
   211       for (
size_type i = 1; i < name.size(); ++i)
   212         if (!(isalnum(name[i]) || name[i] == 
'_')) valid = 
false;
   214     GMM_ASSERT1(!assert || valid,
   215                 "Illegal variable name : \"" << name << 
"\"");
   220     std::string res_name = name;
   221     bool valid = check_name_validity(res_name, 
false);
   222     for (
size_type i = 2; !valid && i < 50; ++i) {
   224       m << name << 
'_' << i;
   226       valid = check_name_validity(res_name, 
false);
   228     for (
size_type i = 2; !valid && i < 1000; ++i) {
   230       m << 
"new_" << name << 
'_' << i;
   232       valid = check_name_validity(res_name, 
false);
   234     GMM_ASSERT1(valid, 
"Illegal variable name: " << name);
   239   model::VAR_SET::const_iterator
   240   model::find_variable(
const std::string &name)
 const {
   241     VAR_SET::const_iterator it = variables.find(name);
   242     GMM_ASSERT1(it != variables.end(), 
"Undefined variable " << name);
   246   std::string sup_previous_and_dot_to_varname(std::string v) {
   247     if (!(v.compare(0, 8, 
"Previous")) && (v[8] == 
'_' || v[9] == 
'_')) {
   248       v = v.substr((v[8] == 
'_') ? 9 : 10);
   250     if (!(v.compare(0, 3, 
"Dot")) && (v[3] == 
'_' || v[4] == 
'_')) {
   251       v = v.substr((v[3] == 
'_') ? 4 : 5);
   258     return name.substr(0, PREFIX_OLD_LENGTH) == 
PREFIX_OLD;
   262     return is_old(name) ? name.substr(PREFIX_OLD_LENGTH) : name;
   265   bool model::is_disabled_variable(
const std::string &name)
 const {
   266     if (
is_old(name)) 
return false;
   267     VAR_SET::const_iterator it = find_variable(name);
   268     if (!(it->second.is_variable)) 
return false;
   269     if (it->second.is_affine_dependent)
   270       it = variables.find(it->second.org_name);
   271     return it->second.is_disabled;
   275     if (
is_old(name)) 
return true;
   276     VAR_SET::const_iterator it = find_variable(name);
   277     if (it->second.is_affine_dependent)
   278       it = variables.find(it->second.org_name);
   279     return (!(it->second.is_variable) || it->second.is_disabled);
   283     if (
is_old(name)) 
return true;
   284     VAR_SET::const_iterator it = find_variable(name);
   285     return (!(it->second.is_variable));
   288   bool model::is_affine_dependent_variable(
const std::string &name)
 const {
   289     if (
is_old(name)) 
return false;
   290     VAR_SET::const_iterator it = find_variable(name);
   291     return (it->second.is_affine_dependent);
   294   const std::string &model::org_variable(
const std::string &name)
 const {
   295     VAR_SET::const_iterator it = variables.find(name);
   296     GMM_ASSERT1(is_affine_dependent_variable(name),
   297                 "For affine dependent variables only");
   298     return (it->second.org_name);
   302   model::factor_of_variable(
const std::string &name)
 const {
   303     VAR_SET::const_iterator it = find_variable(name);
   304     return (it->second.alpha);
   307   void model::set_factor_of_variable(
const std::string &name,
   309     VAR_SET::iterator it = variables.find(name);
   310     GMM_ASSERT1(it != variables.end(), 
"Undefined variable " << name);
   311     if (it->second.alpha != a) {
   312       it->second.alpha = a;
   313       for (
auto &v_num : it->second.v_num_data) v_num = act_counter();
   317   bool model::is_im_data(
const std::string &name)
 const {
   319     return (it->second.pim_data != 0);
   323   model::pim_data_of_variable(
const std::string &name)
 const {
   325     return it->second.pim_data;
   328   const gmm::uint64_type &
   329   model::version_number_of_data_variable(
const std::string &name, 
size_type niter)
 const {
   330     VAR_SET::const_iterator it = find_variable(name);
   331     if (niter == 
size_type(-1)) niter = it->second.default_iter;
   332     return it->second.v_num_data[niter];
   337     if (act_size_to_be_done) actualize_sizes();
   338     return (complex_version) ? gmm::vect_size(crhs) : gmm::vect_size(rrhs);
   341   void model::resize_global_system()
 const {
   344     for (
auto && v : variables) {
   345       if (v.second.is_variable && v.second.is_disabled)
   346         v.second.I  = gmm::sub_interval(0,0);
   347       if (v.second.is_variable && !(v.second.is_affine_dependent)
   348           && !(v.second.is_disabled)) {
   349         v.second.I = gmm::sub_interval(tot_size, v.second.size());
   350         tot_size += v.second.size();
   354     for (
auto &&v : variables)
   355       if (v.second.is_affine_dependent) {
   356         v.second.I = variables.find(v.second.org_name)->second.I;
   360     if (complex_version) {
   361       gmm::resize(cTM, tot_size, tot_size);
   362       gmm::resize(crhs, tot_size);
   365       gmm::resize(rTM, tot_size, tot_size);
   366       gmm::resize(rrhs, tot_size);
   369     for (dal::bv_visitor ib(valid_bricks); !ib.finished(); ++ib)
   370       for (
const term_description &term : bricks[ib].tlist)
   371         if (term.is_global) {
   372           bricks[ib].terms_to_be_computed = 
true;
   377   void model::actualize_sizes()
 const {
   379     bool actualized = 
false;
   380     getfem::local_guard lock = locks_.get_lock();
   381     if (actualized) 
return; 
   383     act_size_to_be_done = 
false;
   385     std::map<std::string, std::vector<std::string> > multipliers;
   386     std::set<std::string> tobedone;
   398     for (dal::bv_visitor ib(valid_bricks); !ib.finished(); ++ib)
   399       bricks[ib].terms_to_be_computed = 
true;
   401     for (
auto &&v : variables) {
   402       const std::string &vname = v.first;
   403       var_description &vdescr = v.second;
   404       if (vdescr.is_fem_dofs && !(vdescr.is_affine_dependent)) {
   405         if ((vdescr.filter & VDESCRFILTER_CTERM)
   406             || (vdescr.filter & VDESCRFILTER_INFSUP)) {
   407           VAR_SET::iterator vfilt = variables.find(vdescr.filter_var);
   408           GMM_ASSERT1(vfilt != variables.end(), 
"The primal variable of the"   409                       " multiplier does not exist : " << vdescr.filter_var);
   410           GMM_ASSERT1(vfilt->second.is_fem_dofs, 
"The primal variable of "   411                       "the multiplier is not a fem variable");
   412           multipliers[vdescr.filter_var].push_back(vname);
   413           if (vdescr.v_num < vdescr.mf->version_number() ||
   414               vdescr.v_num < vfilt->second.mf->version_number()) {
   415             tobedone.insert(vdescr.filter_var);
   418         switch (vdescr.filter) {
   419         case VDESCRFILTER_NO:
   420           if (vdescr.v_num < vdescr.mf->version_number()) {
   422             vdescr.v_num = act_counter();
   425         case VDESCRFILTER_REGION:
   426           if (vdescr.v_num < vdescr.mf->version_number()) {
   428               = vdescr.mf->dof_on_region(vdescr.m_region);
   429             vdescr.partial_mf->adapt(dor);
   431             vdescr.v_num = act_counter();
   438       if (vdescr.pim_data != 0
   439           && vdescr.v_num < vdescr.pim_data->version_number()) {
   442         vdescr.v_num = act_counter();
   446     for (
auto &&v : variables) {
   447       var_description &vdescr = v.second;
   448       if (vdescr.is_fem_dofs && !(vdescr.is_affine_dependent) &&
   449           ((vdescr.filter & VDESCRFILTER_CTERM)
   450            || (vdescr.filter & VDESCRFILTER_INFSUP))) {
   451         if (tobedone.count(vdescr.filter_var)) {
   456           dal::bit_vector alldof; alldof.add(0, vdescr.mf->nb_dof());
   457           vdescr.partial_mf->adapt(alldof);
   459           vdescr.v_num = act_counter();
   464     resize_global_system();
   466     for (
const std::string &vname : tobedone) {
   473       const std::vector<std::string> &mults = multipliers[vname];
   474       const var_description &vdescr = variables.find(vname)->second;
   476       gmm::col_matrix< gmm::rsvector<scalar_type> > MGLOB;
   477       if (mults.size() > 1) {
   479         for (
const std::string &mult : mults)
   480           s += variables.find(mult)->second.mf->nb_dof();
   481         gmm::resize(MGLOB, vdescr.mf->nb_dof(), s);
   484       std::set<size_type> glob_columns;
   485       for (
const std::string &multname : mults) {
   486         var_description &multdescr = variables.find(multname)->second;
   492         gmm::col_matrix< gmm::rsvector<scalar_type> >
   493           MM(vdescr.associated_mf().nb_dof(), multdescr.mf->nb_dof());
   494         bool termadded = 
false;
   496         if (multdescr.filter & VDESCRFILTER_CTERM) {
   498           for (dal::bv_visitor ib(valid_bricks); !ib.finished(); ++ib) {
   499             const brick_description &brick = bricks[ib];
   501             bool cplx = is_complex() && brick.pbr->is_complex();
   503             if (brick.tlist.size() == 0) {
   504               bool varc = 
false, multc = 
false;
   505               for (
const std::string &var : brick.vlist) {
   506                 if (multname.compare(var) == 0) multc = 
true;
   507                 if (vname.compare(var) == 0) varc = 
true;
   510                 GMM_ASSERT1(!cplx, 
"Sorry, not taken into account");
   511                 generic_expressions.clear();
   512                 brick.terms_to_be_computed = 
true;
   513                 update_brick(ib, BUILD_MATRIX);
   514                 if (generic_expressions.size()) {
   515                   GMM_TRACE2(
"Generic assembly for actualize sizes");
   520                     open_mp_is_running_properly check;
   522                     #pragma omp parallel default(shared)   526                         ga_workspace workspace(*
this);
   527                         for (
const auto &ge : generic_expressions)
   528                           workspace.add_expression(ge.expr, ge.mim, ge.region);
   529                         workspace.set_assembled_matrix(distro_rTM);
   530                         workspace.assembly(2);
   536                     (gmm::sub_matrix(rTM, vdescr.I, multdescr.I), MM);
   537                   gmm::add(gmm::transposed
   538                            (gmm::sub_matrix(rTM, multdescr.I,
   546             for (
size_type j = 0; j < brick.tlist.size(); ++j) {
   547               const term_description &term = brick.tlist[j];
   549               if (term.is_matrix_term) {
   550                 if (term.is_global) {
   551                   bool varc = 
false, multc = 
false;
   552                   for (
const std::string var : brick.vlist) {
   553                     if (multname.compare(var) == 0) multc = 
true;
   554                     if (vname.compare(var) == 0) varc = 
true;
   557                     GMM_ASSERT1(!cplx, 
"Sorry, not taken into account");
   558                     generic_expressions.clear();
   560                       brick.terms_to_be_computed = 
true;
   561                       update_brick(ib, BUILD_MATRIX);
   564                     gmm::add(gmm::sub_matrix(brick.rmatlist[j],
   565                                              multdescr.I, vdescr.I),
   567                     gmm::add(gmm::transposed(gmm::sub_matrix
   569                                               vdescr.I, multdescr.I)),
   573                 } 
else if (multname.compare(term.var1) == 0 &&
   574                            vname.compare(term.var2) == 0) {
   576                     brick.terms_to_be_computed = 
true;
   577                     update_brick(ib, BUILD_MATRIX);
   582                       (gmm::transposed(gmm::real_part(brick.cmatlist[j])), MM);
   584                     gmm::add(gmm::transposed(brick.rmatlist[j]), MM);
   587                 } 
else if (multname.compare(term.var2) == 0 &&
   588                            vname.compare(term.var1) == 0) {
   590                     brick.terms_to_be_computed = 
true;
   591                     update_brick(ib, BUILD_MATRIX);
   595                     gmm::add(gmm::real_part(brick.cmatlist[j]), MM);
   597                     gmm::add(brick.rmatlist[j], MM);
   605             GMM_WARNING1(
"No term found to filter multiplier " << multname
   606                          << 
". Variable is cancelled");
   607         } 
else if (multdescr.filter & VDESCRFILTER_INFSUP) {
   609           multdescr.mim->linked_mesh().intersect_with_mpi_region(rg);
   611                           *(multdescr.mf), rg);
   614         MPI_SUM_SPARSE_MATRIX(MM);
   619         std::set<size_type> columns;
   620         gmm::range_basis(MM, columns);
   621         if (columns.size() == 0)
   622           GMM_WARNING1(
"Empty basis found for multiplier " << multname);
   624         if (mults.size() > 1) {
   625           gmm::copy(MM, gmm::sub_matrix
   627                      gmm::sub_interval(0, vdescr.associated_mf().nb_dof()),
   628                      gmm::sub_interval(s, multdescr.mf->nb_dof())));
   630             glob_columns.insert(s + icol);
   631           s += multdescr.mf->nb_dof();
   633           dal::bit_vector kept;
   636           if (multdescr.filter & VDESCRFILTER_REGION)
   637             kept &= multdescr.mf->dof_on_region(multdescr.m_region);
   638           multdescr.partial_mf->adapt(kept);
   639           multdescr.set_size();
   640           multdescr.v_num = act_counter();
   649       if (mults.size() > 1) {
   650         gmm::range_basis(MGLOB, glob_columns, 1E-12, gmm::col_major(), 
true);
   659         for (
const std::string &multname : mults) {
   660           var_description &multdescr = variables.find(multname)->second;
   661           dal::bit_vector kept;
   662           size_type nbdof = multdescr.mf->nb_dof();
   663           for (
const size_type &icol : glob_columns)
   664             if (icol >= s && icol < s + nbdof) kept.add(icol-s);
   665           if (multdescr.filter & VDESCRFILTER_REGION)
   666             kept &= multdescr.mf->dof_on_region(multdescr.m_region);
   667           multdescr.partial_mf->adapt(kept);
   668           multdescr.set_size();
   669           multdescr.v_num = act_counter();
   670           s += multdescr.mf->nb_dof();
   679     resize_global_system();
   691     if (variables.size() == 0)
   692       ost << 
"Model with no variable nor data" << endl;
   694       ost << 
"List of model variables and data:" << endl;
   695       for (
auto it = variables.begin(); it != variables.end(); ++it) {
   696         if (it->second.is_variable) ost << 
"Variable       ";
   698         ost << std::setw(30) << std::left << it->first;
   699         if (it->second.n_iter == 1)
   702           ost << std::setw(2) << std::right << it->second.n_iter
   704         if (it->second.is_fem_dofs) ost << 
"fem dependant ";
   705         else ost << 
"constant size ";
   707         ost << std::setw(8) << std::right << si;
   708         if (is_complex()) ost << 
" complex";
   709         ost << 
" double" << ((si > 1) ? 
"s." : 
".");
   710         if (it->second.is_variable &&
   711             is_disabled_variable(it->first)) ost << 
"\t (disabled)";
   713         if (it->second.pim_data != 0) ost << 
"\t (is im_data)";
   714         if (it->second.is_affine_dependent) ost << 
"\t (is affine dependent)";
   717       for (
auto it = variable_groups.begin();
   718            it != variable_groups.end(); ++it) {
   719         ost << 
"Variable group " << std::setw(30) << std::left
   721         if (it->second.size()) {
   722           auto it2 = it->second.begin();
   723           ost << 
" " << *it2; ++it2;
   724           for (; it2 != it->second.end(); ++it2) ost << 
", " << *it2;
   726         } 
else ost << 
" empty" << endl;
   731   void model::listresiduals(std::ostream &ost)
 const {
   732     if (variables.size() == 0)
   733       ost << 
"Model with no variable nor data" << endl;
   736       for (VAR_SET::const_iterator it = variables.begin();
   737            it != variables.end(); ++it) {
   738         if (it->second.is_variable) {
   739           const gmm::sub_interval &II = interval_of_variable(it->first);
   740           scalar_type res = gmm::vect_norm2(gmm::sub_vector(rrhs, II));
   741           if (!firstvar) cout << 
", ";
   742           ost << 
"res_" << it->first << 
"= " << std::setw(11) << res;
   752     check_name_validity(name);
   753     variables[name] = var_description(
true, is_complex(), 
false, niter);
   754     GMM_ASSERT1(size, 
"Variable of null size are not allowed");
   755     variables[name].qdims[0] = size;
   756     act_size_to_be_done = 
true;
   757     variables[name].set_size();
   761                                       const bgeot::multi_index &sizes,
   763     check_name_validity(name);
   764     variables[name] = var_description(
true, is_complex(), 
false, niter,
   767     act_size_to_be_done = 
true;
   768     variables[name].set_size();
   774     GMM_ASSERT1(!(variables[name].is_fem_dofs),
   775                 "Cannot explicitly resize a fem variable or data");
   776     GMM_ASSERT1(variables[name].pim_data == 0,
   777                 "Cannot explicitly resize an im data");
   778     GMM_ASSERT1(size, 
"Variable of null size are not allowed");
   779     variables[name].qdims.resize(1);
   780     variables[name].qdims[0] = size;
   781     variables[name].set_size();
   785                                          const bgeot::multi_index &sizes) {
   786     GMM_ASSERT1(!(variables[name].is_fem_dofs),
   787                 "Cannot explicitly resize a fem variable or data");
   788     GMM_ASSERT1(variables[name].pim_data == 0,
   789                 "Cannot explicitly resize an im data");
   790     variables[name].qdims = sizes;
   791     variables[name].set_size();
   797     check_name_validity(name);
   798     variables[name] = var_description(
false, is_complex(), 
false, niter);
   799     GMM_ASSERT1(size, 
"Data of null size are not allowed");
   800     variables[name].qdims[0] = size;
   801     variables[name].set_size();
   805                                   const bgeot::multi_index &sizes,
   807     check_name_validity(name);
   808     variables[name] = var_description(
false, is_complex(), 
false, niter);
   809     variables[name].qdims = sizes;
   810     GMM_ASSERT1(variables[name].qdim(), 
"Data of null size are not allowed");
   811     variables[name].set_size();
   815                                           const base_matrix &M) {
   816     this->add_fixed_size_data(name, bgeot::multi_index(gmm::mat_nrows(M),
   818     GMM_ASSERT1(!(this->is_complex()), 
"Sorry, complex version to be done");
   819     gmm::copy(M.as_vector(), this->set_real_variable(name));
   823                                           const base_complex_matrix &M) {
   824     this->add_fixed_size_data(name, bgeot::multi_index(gmm::mat_nrows(M),
   826     GMM_ASSERT1(!(this->is_complex()), 
"Sorry, complex version to be done");
   827     gmm::copy(M.as_vector(), this->set_complex_variable(name));
   831                                          const base_tensor &t) {
   832     this->add_fixed_size_data(name, t.sizes(), 1);
   833     GMM_ASSERT1(!(this->is_complex()), 
"Sorry, complex version to be done");
   834     gmm::copy(t.as_vector(), this->set_real_variable(name));
   838                                           const base_complex_tensor &t) {
   839     this->add_fixed_size_data(name, t.sizes(), 1);
   840     GMM_ASSERT1(!(this->is_complex()), 
"Sorry, complex version to be done");
   841     gmm::copy(t.as_vector(), this->set_complex_variable(name));
   846     check_name_validity(name);
   847     variables[name] = var_description(
false, is_complex(), 
false, niter);
   848     variables[name].pim_data = &im_data;
   849     variables[name].set_size();
   850     add_dependency(im_data);
   855     check_name_validity(name);
   856     variables[name] = var_description(
true, is_complex(), 
true, niter,
   857                                       VDESCRFILTER_NO, &mf);
   858     variables[name].set_size();
   860     act_size_to_be_done = 
true;
   861     leading_dim = std::max(leading_dim, mf.
linked_mesh().dim());
   867     check_name_validity(name);
   868     variables[name] = var_description(
true, is_complex(), 
true, niter,
   869                                       VDESCRFILTER_REGION, &mf, region);
   870     variables[name].set_size();
   871     act_size_to_be_done = 
true;
   876                                             const std::string &org_name,
   878     check_name_validity(name);
   879     VAR_SET::const_iterator it = find_variable(org_name);
   880     GMM_ASSERT1(it->second.is_variable && !(it->second.is_affine_dependent),
   881                 "The original variable should be a variable");
   882     variables[name] = variables[org_name];
   883     variables[name].is_affine_dependent = 
true;
   884     variables[name].org_name = org_name;
   885     variables[name].alpha = alpha;
   886     variables[name].set_size();
   891     check_name_validity(name);
   892     variables[name] = var_description(
false, is_complex(), 
true, niter,
   893                                       VDESCRFILTER_NO, &mf);
   894     variables[name].qdims[0] = qdim;
   895     GMM_ASSERT1(qdim, 
"Data of null size are not allowed");
   896     variables[name].set_size();
   901                            const bgeot::multi_index &sizes, 
size_type niter) {
   902     check_name_validity(name);
   903     variables[name] = var_description(
false, is_complex(), 
true, niter,
   904                                       VDESCRFILTER_NO, &mf);
   905     variables[name].qdims = sizes;
   906     GMM_ASSERT1(variables[name].qdim(), 
"Data of null size are not allowed");
   907     variables[name].set_size();
   912                              const std::string &primal_name,
   914     check_name_validity(name);
   915     variables[name] = var_description(
true, is_complex(), 
true, niter,
   916                                       VDESCRFILTER_CTERM, &mf, 0,
   917                                       bgeot::multi_index(), primal_name);
   918     variables[name].set_size();
   919     act_size_to_be_done = 
true;
   924                              size_type region, 
const std::string &primal_name,
   926     check_name_validity(name);
   927     variables[name] = var_description(
true, is_complex(), 
true, niter,
   928                                       VDESCRFILTER_REGION_CTERM, &mf, region,
   929                                       bgeot::multi_index(), primal_name);
   930     variables[name].set_size();
   931     act_size_to_be_done = 
true;
   936                              const std::string &primal_name,
const mesh_im &mim,
   938     check_name_validity(name);
   939     variables[name] = var_description(
true, is_complex(), 
true, niter,
   940                                       VDESCRFILTER_INFSUP, &mf, region,
   941                                       bgeot::multi_index(), primal_name, &mim);
   942     variables[name].set_size();
   943     act_size_to_be_done = 
true;
   948     VAR_SET::iterator it = variables.find(name);
   949     GMM_ASSERT1(it != variables.end(), 
"Undefined variable " << name);
   950     it->second.is_disabled = 
true;
   951     for (VAR_SET::iterator itv = variables.begin();
   952          itv != variables.end(); ++itv) {
   953       if (((itv->second.filter & VDESCRFILTER_INFSUP) ||
   954            (itv->second.filter & VDESCRFILTER_CTERM))
   955           && (name.compare(itv->second.filter_var) == 0)) {
   956         itv->second.is_disabled = 
true;
   958       if (itv->second.is_variable && itv->second.is_affine_dependent
   959           && name.compare(itv->second.org_name) == 0)
   960         itv->second.is_disabled = 
true;
   962     if (!act_size_to_be_done) resize_global_system();
   966     VAR_SET::iterator it = variables.find(name);
   967     GMM_ASSERT1(it != variables.end(), 
"Undefined variable " << name);
   968     it->second.is_disabled = 
false;
   969     for (VAR_SET::iterator itv = variables.begin();
   970          itv != variables.end(); ++itv) {
   971       if (((itv->second.filter & VDESCRFILTER_INFSUP) ||
   972            (itv->second.filter & VDESCRFILTER_CTERM))
   973           && (name.compare(itv->second.filter_var) == 0)) {
   974         itv->second.is_disabled = 
false;
   976       if (itv->second.is_variable && itv->second.is_affine_dependent
   977           && name.compare(itv->second.org_name) == 0)
   978         itv->second.is_disabled = 
false;
   980     if (!act_size_to_be_done) resize_global_system();
   988     check_name_validity(name.substr(0, name.find(
"(")));
   989     macro_dict.add_macro(name, expr);
   993   { macro_dict.del_macro(name); }
   996      GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
   997      valid_bricks.del(ib);
   998      active_bricks.del(ib);
  1000      for  (
size_type i = 0; i < bricks[ib].mims.size(); ++i) {
  1001        const mesh_im *mim = bricks[ib].mims[i];
  1003        for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
  1004          for  (
size_type j = 0; j < bricks[ibb].mims.size(); ++j)
  1005            if (bricks[ibb].mims[j] == mim) found = 
true;
  1007        for(VAR_SET::iterator it2 = variables.begin();
  1008            it2 != variables.end(); ++it2) {
  1009          if (it2->second.is_fem_dofs &&
  1010              (it2->second.filter & VDESCRFILTER_INFSUP) &&
  1011              mim == it2->second.mim) found = 
true;
  1013        if (!found) sup_dependency(*mim);
  1016      is_linear_ = is_symmetric_ = is_coercive_ = 
true;
  1017      for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
  1018        is_linear_ = is_linear_ && bricks[ibb].pbr->is_linear();
  1019        is_symmetric_ = is_symmetric_ &&  bricks[ibb].pbr->is_symmetric();
  1020        is_coercive_ = is_coercive_ &&  bricks[ibb].pbr->is_coercive();
  1023      bricks[ib] = brick_description();
  1027     for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
  1028       for (
size_type i = 0; i < bricks[ibb].vlist.size(); ++i)
  1029         GMM_ASSERT1(varname.compare(bricks[ibb].vlist[i]),
  1030                     "Cannot delete a variable which is still use by a brick");
  1031       for (
size_type i = 0; i < bricks[ibb].dlist.size(); ++i)
  1032         GMM_ASSERT1(varname.compare(bricks[ibb].dlist[i]),
  1033                     "Cannot delete a data which is still use by a brick");
  1036     VAR_SET::const_iterator it = find_variable(varname);
  1038     if (it->second.is_fem_dofs) {
  1039       const mesh_fem *mf = it->second.mf;
  1041       for(VAR_SET::iterator it2 = variables.begin();
  1042           it2 != variables.end(); ++it2) {
  1043         if (it != it2 && it2->second.is_fem_dofs && mf == it2->second.mf)
  1046       if (!found) sup_dependency(*mf);
  1048       if (it->second.filter & VDESCRFILTER_INFSUP) {
  1049         const mesh_im *mim = it->second.mim;
  1051         for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
  1052           for  (
size_type j = 0; j < bricks[ibb].mims.size(); ++j)
  1053             if (bricks[ibb].mims[j] == mim) found = 
true;
  1055         for(VAR_SET::iterator it2 = variables.begin();
  1056             it2 != variables.end(); ++it2) {
  1057           if (it != it2 && it2->second.is_fem_dofs &&
  1058               (it2->second.filter & VDESCRFILTER_INFSUP) &&
  1059               mim == it2->second.mim) found = 
true;
  1061         if (!found) sup_dependency(*mim);
  1065     if (it->second.pim_data != 0) sup_dependency(*(it->second.pim_data));
  1067     variables.erase(varname);
  1068     act_size_to_be_done = 
true;
  1072                              const varnamelist &datanames,
  1073                              const termlist &terms,
  1074                              const mimlist &mims, 
size_type region) {
  1075     size_type ib = valid_bricks.first_false();
  1077     for (
size_type i = 0; i < terms.size(); ++i)
  1078       if (terms[i].is_global && terms[i].is_matrix_term && pbr->is_linear())
  1079         GMM_ASSERT1(
false, 
"Global linear matrix terms are not allowed");
  1081     if (ib == bricks.size())
  1082       bricks.push_back(brick_description(pbr, varnames, datanames, terms,
  1085       bricks[ib] = brick_description(pbr, varnames, datanames, terms,
  1087     active_bricks.add(ib);
  1088     valid_bricks.add(ib);
  1091     for (
size_type i = 0; i < bricks[ib].mims.size(); ++i)
  1092       add_dependency(*(bricks[ib].mims[i]));
  1094     GMM_ASSERT1(pbr->is_real() || is_complex(),
  1095                 "Impossible to add a complex brick to a real model");
  1096     if (is_complex() && pbr->is_complex()) {
  1097       bricks[ib].cmatlist.resize(terms.size());
  1098       bricks[ib].cveclist[0].resize(terms.size());
  1099       bricks[ib].cveclist_sym[0].resize(terms.size());
  1101       bricks[ib].rmatlist.resize(terms.size());
  1102       bricks[ib].rveclist[0].resize(terms.size());
  1103       bricks[ib].rveclist_sym[0].resize(terms.size());
  1105     is_linear_ = is_linear_ && pbr->is_linear();
  1106     is_symmetric_ = is_symmetric_ && pbr->is_symmetric();
  1107     is_coercive_ = is_coercive_ && pbr->is_coercive();
  1109     for (
size_type i=0; i < varnames.size(); ++i)
  1110       GMM_ASSERT1(variables.find(varnames[i]) != variables.end(),
  1111                   "Undefined model variable " << varnames[i]);
  1113     for (
size_type i=0; i < datanames.size(); ++i)
  1114       GMM_ASSERT1(variables.find(datanames[i]) != variables.end(),
  1115                   "Undefined model data or variable " << datanames[i]);
  1121     GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
  1123     bricks[ib].mims.push_back(&mim);
  1124     add_dependency(mim);
  1128     GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
  1130     bricks[ib].tlist = terms;
  1131     if (is_complex() && bricks[ib].pbr->is_complex()) {
  1132       bricks.back().cmatlist.resize(terms.size());
  1133       bricks.back().cveclist[0].resize(terms.size());
  1134       bricks.back().cveclist_sym[0].resize(terms.size());
  1136       bricks.back().rmatlist.resize(terms.size());
  1137       bricks.back().rveclist[0].resize(terms.size());
  1138       bricks.back().rveclist_sym[0].resize(terms.size());
  1143     GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
  1145     bricks[ib].vlist = vl;
  1147       GMM_ASSERT1(variables.find(vl[i]) != variables.end(),
  1148                   "Undefined model variable " << vl[i]);
  1152     GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
  1154     bricks[ib].dlist = dl;
  1156       GMM_ASSERT1(variables.find(dl[i]) != variables.end(),
  1157                   "Undefined model variable " << dl[i]);
  1161     GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
  1163     bricks[ib].mims = ml;
  1164     for (
size_type i = 0; i < ml.size(); ++i) add_dependency(*(ml[i]));
  1168     GMM_ASSERT1(valid_bricks[ib], 
"Inexistent brick");
  1170     bricks[ib].is_update_brick = flag;
  1173   void model::set_time(scalar_type t, 
bool to_init) {
  1174     static const std::string varname(
"t");
  1175     VAR_SET::iterator it = variables.find(varname);
  1176     if (it == variables.end()) {
  1177       add_fixed_size_data(varname, 1);
  1179       GMM_ASSERT1(it->second.size() == 1, 
"Time data should be of size 1");
  1181     if (it == variables.end() || to_init) {
  1183         set_complex_variable(varname)[0] = complex_type(t);
  1185         set_real_variable(varname)[0] = t;
  1189   scalar_type model::get_time() {
  1190     static const std::string varname(
"t");
  1191     set_time(scalar_type(0), 
false);
  1193       return gmm::real(complex_variable(varname)[0]);
  1195       return real_variable(varname)[0];
  1198   void model::call_init_affine_dependent_variables(
int version) {
  1199     for (VAR_SET::iterator it = variables.begin();
  1200          it != variables.end(); ++it)
  1201       if (it->second.is_variable && it->second.ptsc) {
  1203           it->second.ptsc->init_affine_dependent_variables_precomputation(*
this);
  1205           it->second.ptsc->init_affine_dependent_variables(*
this);
  1209   void model::shift_variables_for_time_integration() {
  1210     for (VAR_SET::iterator it = variables.begin();
  1211          it != variables.end(); ++it)
  1212       if (it->second.is_variable && it->second.ptsc)
  1213         it->second.ptsc->shift_variables(*
this);
  1216   void model::add_time_integration_scheme(
const std::string &varname,
  1217                                           ptime_scheme ptsc) {
  1218     VAR_SET::iterator it = variables.find(varname);
  1219     GMM_ASSERT1(it != variables.end(), 
"Undefined variable " << varname);
  1220     GMM_ASSERT1(it->second.is_variable && !(it->second.is_affine_dependent),
  1221                 "Cannot apply an integration scheme to " << varname);
  1222     it->second.ptsc = ptsc;
  1229     time_integration = 1;
  1232   void model::copy_init_time_derivative() {
  1234     for (VAR_SET::iterator it = variables.begin();
  1235          it != variables.end(); ++it)
  1236       if (it->second.is_variable && it->second.ptsc) {
  1238         std::string name_v, name_previous_v;
  1239         it->second.ptsc->time_derivative_to_be_intialized(name_v,
  1242         if (name_v.size()) {
  1244             model_complex_plain_vector v0 = this->complex_variable(name_v);
  1245             gmm::copy(v0, this->set_complex_variable(name_previous_v));
  1247             const model_real_plain_vector &v0 = this->real_variable(name_v);
  1248             gmm::copy(v0, this->set_real_variable(name_previous_v));
  1260     class APIDECL first_order_theta_method_scheme
  1263       std::string U, U0, V, V0;
  1268       virtual void init_affine_dependent_variables(
model &md)
 const {
  1269         scalar_type dt = md.get_time_step();
  1270         scalar_type a = scalar_type(1)/(theta*dt);
  1271         scalar_type b = (scalar_type(1)-theta)/theta;
  1272         md.set_factor_of_variable(V, a);
  1276                     md.set_complex_constant_part(V));
  1281                    md.set_real_constant_part(V));
  1286       virtual void init_affine_dependent_variables_precomputation(
model &md)
  1288         scalar_type dt = md.get_time_step();
  1289         md.set_factor_of_variable(V, scalar_type(1)/dt);
  1292                     md.set_complex_constant_part(V));
  1295           gmm::copy(gmm::scaled(md.
real_variable(U0), -scalar_type(1)/dt),
  1296                     md.set_real_constant_part(V));
  1300       virtual void time_derivative_to_be_intialized
  1301       (std::string &name_v, std::string &name_previous_v)
 const  1302       { 
if (theta != scalar_type(1)) { name_v = V; name_previous_v = V0; } }
  1304       virtual void shift_variables(
model &md)
 const {
  1315       first_order_theta_method_scheme(
model &md, std::string varname,
  1318         U0 = 
"Previous_" + U;
  1320         V0 = 
"Previous_Dot_" + U;
  1322         GMM_ASSERT1(theta > scalar_type(0) && theta <=  scalar_type(1),
  1323                     "Invalid value of theta parameter for the theta-method");
  1343   void add_theta_method_for_first_order(
model &md, 
const std::string &varname,
  1344                                         scalar_type theta) {
  1346       = std::make_shared<first_order_theta_method_scheme>(md, varname,theta);
  1347     md.add_time_integration_scheme(varname, ptsc);
  1356   class APIDECL second_order_theta_method_scheme
  1359     std::string U, U0, V, V0, A, A0;
  1365     virtual void init_affine_dependent_variables(
model &md)
 const {
  1366       scalar_type dt = md.get_time_step();
  1367       md.set_factor_of_variable(V, scalar_type(1)/(theta*dt));
  1368       md.set_factor_of_variable(A, scalar_type(1)/(theta*theta*dt*dt));
  1371                              -complex_type(1)/(theta*dt)),
  1373                              -(complex_type(1)-complex_type(theta))/theta),
  1374                  md.set_complex_constant_part(V));
  1376                              -complex_type(1)/(theta*theta*dt*dt)),
  1378                              -(complex_type(1)-complex_type(theta))/theta),
  1379                  md.set_complex_constant_part(A));
  1381                              -complex_type(1)/(theta*theta*dt)),
  1382                  md.set_complex_constant_part(A));
  1387                              -scalar_type(1)/(theta*dt)),
  1389                              -(scalar_type(1)-theta)/theta),
  1390                  md.set_real_constant_part(V));
  1392                              -scalar_type(1)/(theta*theta*dt*dt)),
  1394                              -(scalar_type(1)-theta)/theta),
  1395                  md.set_real_constant_part(A));
  1397                              -scalar_type(1)/(theta*theta*dt)),
  1398                  md.set_real_constant_part(A));
  1405     virtual void init_affine_dependent_variables_precomputation(
model &md)
  1407       scalar_type dt = md.get_time_step();
  1408       md.set_factor_of_variable(V, scalar_type(1)/dt);
  1409       md.set_factor_of_variable(A, scalar_type(1)/(dt*dt));
  1412                               -complex_type(1)/dt),
  1413                   md.set_complex_constant_part(V));
  1415                              -complex_type(1)/(dt*dt)),
  1417                              -complex_type(1)/dt),
  1418                  md.set_complex_constant_part(A));
  1421                               -scalar_type(1)/dt),
  1422                   md.set_real_constant_part(V));
  1424                              -scalar_type(1)/(dt*dt)),
  1426                              -scalar_type(1)/dt),
  1427                  md.set_real_constant_part(A));
  1431     virtual void time_derivative_to_be_intialized
  1432     (std::string &name_v, std::string &name_previous_v)
 const  1433     { 
if (theta != scalar_type(1)) { name_v = A; name_previous_v = A0; } }
  1435     virtual void shift_variables(
model &md)
 const {
  1448     second_order_theta_method_scheme(
model &md, std::string varname,
  1451       U0 = 
"Previous_" + U;
  1453       V0 = 
"Previous_Dot_" + U;
  1455       A0 = 
"Previous_Dot2_" + U;
  1457       GMM_ASSERT1(theta > scalar_type(0) && theta <=  scalar_type(1),
  1458                   "Invalid value of theta parameter for the theta-method");
  1483   void add_theta_method_for_second_order(
model &md, 
const std::string &varname,
  1484                                          scalar_type theta) {
  1485     ptime_scheme ptsc = std::make_shared<second_order_theta_method_scheme>
  1487     md.add_time_integration_scheme(varname, ptsc);
  1497     class APIDECL Newmark_scheme
  1500       std::string U, U0, V, V0, A, A0;
  1501       scalar_type beta, gamma;
  1506       virtual void init_affine_dependent_variables(
model &md)
 const {
  1507         scalar_type dt = md.get_time_step();
  1508         scalar_type a0 = scalar_type(1)/(beta*dt*dt), a1 =  dt*a0;
  1509         scalar_type a2 = (scalar_type(1) - scalar_type(2)*beta)
  1510           / (scalar_type(2)*beta);
  1511         scalar_type b0 = gamma/(beta*dt), b1 = (beta-gamma)/beta;
  1512         scalar_type b2 = dt*(1-gamma/(scalar_type(2)*beta));
  1514         md.set_factor_of_variable(V, b0);
  1515         md.set_factor_of_variable(A, a0);
  1519                    md.set_complex_constant_part(V));
  1521                    md.set_complex_constant_part(V));
  1524                    md.set_complex_constant_part(A));
  1526                    md.set_complex_constant_part(A));
  1530                    md.set_real_constant_part(V));
  1532                    md.set_real_constant_part(V));
  1535                    md.set_real_constant_part(A));
  1537                    md.set_real_constant_part(A));
  1544       virtual void init_affine_dependent_variables_precomputation(
model &md)
  1546         scalar_type dt = md.get_time_step();
  1547         md.set_factor_of_variable(V, scalar_type(1)/dt);
  1548         md.set_factor_of_variable(A, scalar_type(1)/(dt*dt));
  1551                                 -complex_type(1)/dt),
  1552                     md.set_complex_constant_part(V));
  1554                                -complex_type(1)/(dt*dt)),
  1556                                -complex_type(1)/dt),
  1557                    md.set_complex_constant_part(A));
  1560                                 -scalar_type(1)/dt),
  1561                     md.set_real_constant_part(V));
  1563                                -scalar_type(1)/(dt*dt)),
  1565                                -scalar_type(1)/dt),
  1566                    md.set_real_constant_part(A));
  1570       virtual void time_derivative_to_be_intialized
  1571       (std::string &name_v, std::string &name_previous_v)
 const {
  1572         if (beta != scalar_type(0.5) || gamma != scalar_type(1))
  1573           { name_v = A; name_previous_v = A0; }
  1576       virtual void shift_variables(
model &md)
 const {
  1589       Newmark_scheme(
model &md, std::string varname,
  1590                      scalar_type be, scalar_type ga) {
  1592         U0 = 
"Previous_" + U;
  1594         V0 = 
"Previous_Dot_" + U;
  1596         A0 = 
"Previous_Dot2_" + U;
  1597         beta = be; gamma = ga;
  1598         GMM_ASSERT1(beta > scalar_type(0) && beta <=  scalar_type(1)
  1599                     && gamma >= scalar_type(0.5) && gamma <=  scalar_type(1),
  1600                     "Invalid parameter values for the Newmark scheme");
  1625   void add_Newmark_scheme(
model &md, 
const std::string &varname,
  1626                           scalar_type beta, scalar_type gamma) {
  1627     ptime_scheme ptsc = std::make_shared<Newmark_scheme>
  1628       (md, varname, beta, gamma);
  1629     md.add_time_integration_scheme(varname, ptsc);
  1642     GMM_ASSERT1(valid_bricks[ibrick], 
"Inexistent brick");
  1643     pbrick pbr = bricks[ibrick].pbr;
  1645     bricks[ibrick].pdispatch = pdispatch;
  1648       = std::max(
size_type(1), pdispatch->nbrhs());
  1650     gmm::resize(bricks[ibrick].coeffs, nbrhs);
  1652     if (is_complex() && pbr->is_complex()) {
  1653       bricks[ibrick].cveclist.resize(nbrhs);
  1654       bricks[ibrick].cveclist_sym.resize(nbrhs);
  1656         bricks[ibrick].cveclist[k] = bricks[ibrick].cveclist[0];
  1657         bricks[ibrick].cveclist_sym[k] = bricks[ibrick].cveclist_sym[0];
  1660       bricks[ibrick].rveclist.resize(nbrhs);
  1661       bricks[ibrick].rveclist_sym.resize(nbrhs);
  1663         bricks[ibrick].rveclist[k] = bricks[ibrick].rveclist[0];
  1664         bricks[ibrick].rveclist_sym[k] = bricks[ibrick].rveclist_sym[0];
  1671     GMM_ASSERT1(valid_bricks[ind_brick], 
"Inexistent brick");
  1672     GMM_ASSERT1(ind_var < bricks[ind_brick].vlist.size(),
  1673                "Inexistent brick variable");
  1674     return bricks[ind_brick].vlist[ind_var];
  1679     GMM_ASSERT1(valid_bricks[ind_brick], 
"Inexistent brick");
  1680     GMM_ASSERT1(ind_data < bricks[ind_brick].dlist.size(),
  1681                 "Inexistent brick data");
  1682     return bricks[ind_brick].dlist[ind_data];
  1686     if (valid_bricks.card() == 0)
  1687       ost << 
"Model with no bricks" << endl;
  1689       ost << 
"List of model bricks:" << endl;
  1690       for (dal::bv_visitor i(valid_bricks); !i.finished(); ++i) {
  1691         ost << 
"Brick " << std::setw(3) << std::right << i + base_id
  1692             << 
" " << std::setw(20) << std::right
  1693             << bricks[i].pbr->brick_name();
  1694         if (!(active_bricks[i])) ost << 
" (desactivated)";
  1695         if (bricks[i].pdispatch) ost << 
" (dispatched)";
  1696         ost << endl << 
"  concerned variables: " << bricks[i].vlist[0];
  1697         for (
size_type j = 1; j < bricks[i].vlist.size(); ++j)
  1698           ost << 
", " << bricks[i].vlist[j];
  1700         ost << 
"  brick with " << bricks[i].tlist.size() << 
" term";
  1701         if (bricks[i].tlist.size() > 1) ost << 
"s";
  1710   void model::brick_init(
size_type ib, build_version version,
  1712     const brick_description &brick = bricks[ib];
  1713     bool cplx = is_complex() && brick.pbr->is_complex();
  1716     for (
size_type j = 0; j < brick.tlist.size(); ++j) {
  1717       const term_description &term = brick.tlist[j];
  1718       bool isg = term.is_global;
  1720         gmm::vect_size(crhs) : gmm::vect_size(rrhs);
  1721       size_type nbd1 = isg ? nbgdof : variables[term.var1].size();
  1722       size_type nbd2 = isg ? nbgdof : (term.is_matrix_term ?
  1723                                       variables[term.var2].size() : 0);
  1724       if (term.is_matrix_term &&
  1725           (brick.pbr->is_linear() || (version | BUILD_MATRIX))) {
  1726         if (version | BUILD_ON_DATA_CHANGE) {
  1728             gmm::resize(brick.cmatlist[j], nbd1, nbd2);
  1730             gmm::resize(brick.rmatlist[j], nbd1, nbd2);
  1733             brick.cmatlist[j] = model_complex_sparse_matrix(nbd1, nbd2);
  1735             brick.rmatlist[j] = model_real_sparse_matrix(nbd1, nbd2);
  1738       if (brick.pbr->is_linear() || (version | BUILD_RHS)) {
  1739         for (
size_type k = 0; k < brick.nbrhs; ++k) {
  1741             if (k == rhs_ind) gmm::clear(brick.cveclist[k][j]);
  1742             gmm::resize(brick.cveclist[k][j], nbd1);
  1743             if (term.is_symmetric && term.var1.compare(term.var2)) {
  1744               if (k == rhs_ind) gmm::clear(brick.cveclist_sym[k][j]);
  1745               gmm::resize(brick.cveclist_sym[k][j], nbd2);
  1748             if (k == rhs_ind) gmm::clear(brick.rveclist[k][j]);
  1749             gmm::resize(brick.rveclist[k][j], nbd1);
  1750             if (term.is_symmetric && term.var1.compare(term.var2)) {
  1751               if (k == rhs_ind) gmm::clear(brick.rveclist_sym[k][j]);
  1752               gmm::resize(brick.rveclist_sym[k][j], nbd2);
  1760   void model::post_to_variables_step(){}
  1770     CONTAINER_LIST& original_list;
  1772     typedef typename CONTAINER_LIST::value_type value_type;
  1774     void build_distro(gmm::abstract_matrix)
  1778       for(
size_type thread = 1; thread < num_threads(); thread++)
  1780         auto it_original = original_list.begin();
  1781         auto it_distributed = distributed_list(thread).begin();
  1782         for(;it_original != original_list.end(); ++it_original, ++it_distributed)
  1784           gmm::resize(*it_distributed, gmm::mat_nrows(*it_original),gmm::mat_ncols(*it_original));
  1789     void build_distro(gmm::abstract_vector)
  1792       for(
size_type thread = 1; thread < num_threads(); thread++)
  1794         auto it_original = original_list.begin();
  1795         auto it_distributed = distributed_list(thread).begin();
  1796         for(;it_original != original_list.end(); ++it_original, ++it_distributed)
  1798           gmm::resize(*it_distributed, gmm::vect_size(*it_original));
  1803     bool not_multithreaded()
 const { 
return num_threads() == 1; }
  1809       if (not_multithreaded()) 
return;
  1811       for(
size_type thread=1; thread<num_threads(); thread++)
  1812           distributed_list(thread).resize(original_list.size());
  1814       build_distro(
typename gmm::linalg_traits<value_type>::linalg_type());
  1817     operator CONTAINER_LIST&()
  1819       if (not_multithreaded() || this_thread() == 0) 
return original_list;
  1820       else return distributed_list(this_thread());
  1825       if (not_multithreaded()) 
return;
  1827       GMM_ASSERT1(!me_is_multithreaded_now(),
  1828                   "List accumulation should not run in parallel");
  1830       using namespace std;
  1831       auto to_add = vector<CONTAINER_LIST*>{};
  1832       to_add.push_back(&original_list);
  1833       for (
size_type thread = 1; thread < num_threads(); ++thread)
  1834         to_add.push_back(&distributed_list(thread));
  1840       while (to_add.size() > 1)
  1842         #pragma omp parallel default(shared)  1844           auto i = this_thread() * 2;
  1845           if (i + 1 < to_add.size()){
  1846             auto &target = *to_add[i];
  1847             auto &source = *to_add[i + 1];
  1848             for (
size_type j = 0; j < source.size(); ++j) gmm::add(source[j], target[j]);
  1852         for (
auto it = begin(to_add); it < end(to_add);){
  1853           if (next(it) < end(to_add)) it = to_add.erase(next(it));
  1859   void model::brick_call(
size_type ib, build_version version,
  1862     const brick_description &brick = bricks[ib];
  1863     bool cplx = is_complex() && brick.pbr->is_complex();
  1865     brick_init(ib, version, rhs_ind);
  1869       brick.pbr->complex_pre_assembly_in_serial(*
this, ib, brick.vlist,
  1870                                                 brick.dlist, brick.mims,
  1872                                                 brick.cveclist[rhs_ind],
  1873                                                 brick.cveclist_sym[rhs_ind],
  1874                                                 brick.region, version);
  1885         open_mp_is_running_properly check;
  1887         #pragma omp parallel default(shared)  1891             brick.pbr->asm_complex_tangent_terms(*
this, ib, brick.vlist,
  1892                                                  brick.dlist, brick.mims,
  1896                                                  brick.region, version);
  1899         exception.rethrow();
  1901       brick.pbr->complex_post_assembly_in_serial(*
this, ib, brick.vlist,
  1902                                                  brick.dlist, brick.mims,
  1904                                                  brick.cveclist[rhs_ind],
  1905                                                  brick.cveclist_sym[rhs_ind],
  1906                                                  brick.region, version);
  1908       if (brick.is_update_brick) 
  1910         for (
size_type i = 0; i < brick.cmatlist.size(); ++i)
  1912           gmm::clear(brick.cmatlist[i]);
  1915         for (
size_type i = 0; i < brick.cveclist.size(); ++i)
  1916           for (
size_type j = 0; j < brick.cveclist[i].size(); ++j)
  1918             gmm::clear(brick.cveclist[i][j]);
  1921         for (
size_type i = 0; i < brick.cveclist_sym.size(); ++i)
  1922           for (
size_type j = 0; j < brick.cveclist_sym[i].size(); ++j)
  1924             gmm::clear(brick.cveclist_sym[i][j]);
  1930       brick.pbr->real_pre_assembly_in_serial(*
this, ib, brick.vlist,
  1931                                              brick.dlist, brick.mims,
  1933                                              brick.rveclist[rhs_ind],
  1934                                              brick.rveclist_sym[rhs_ind],
  1935                                              brick.region, version);
  1944         open_mp_is_running_properly check;
  1946         #pragma omp parallel default(shared)  1950             brick.pbr->asm_real_tangent_terms(*
this, ib, brick.vlist,
  1951                                               brick.dlist, brick.mims,
  1959         exception.rethrow();
  1961       brick.pbr->real_post_assembly_in_serial(*
this, ib, brick.vlist,
  1962                                               brick.dlist, brick.mims,
  1964                                               brick.rveclist[rhs_ind],
  1965                                               brick.rveclist_sym[rhs_ind],
  1966                                               brick.region, version);
  1968       if (brick.is_update_brick) 
  1970         for (
size_type i = 0; i < brick.rmatlist.size(); ++i)
  1972           gmm::clear(brick.rmatlist[i]);
  1975         for (
size_type i = 0; i < brick.rveclist.size(); ++i)
  1976           for (
size_type j = 0; j < brick.rveclist[i].size(); ++j)
  1978             gmm::clear(brick.rveclist[i][j]);
  1981         for (
size_type i = 0; i < brick.rveclist_sym.size(); ++i)
  1982           for (
size_type j = 0; j < brick.rveclist_sym[i].size(); ++j)
  1984             gmm::clear(brick.rveclist_sym[i][j]);
  1991   void model::set_dispatch_coeff() {
  1992     for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
  1993       brick_description &brick = bricks[ib];
  1994       if (brick.pdispatch)
  1995         brick.pdispatch->set_dispatch_coeff(*
this, ib);
  2001     context_check(); 
if (act_size_to_be_done) actualize_sizes();
  2002     for (VAR_SET::iterator it = variables.begin(); it != variables.end(); ++it)
  2003       it->second.clear_temporaries();
  2005     set_dispatch_coeff();
  2007     for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
  2008       brick_description &brick = bricks[ib];
  2009       bool cplx = is_complex() && brick.pbr->is_complex();
  2010       if (brick.pdispatch) {
  2012           brick.pdispatch->next_complex_iter(*
this, ib, brick.vlist,
  2014                                              brick.cmatlist, brick.cveclist,
  2015                                              brick.cveclist_sym, 
true);
  2017           brick.pdispatch->next_real_iter(*
this, ib, brick.vlist, brick.dlist,
  2018                                              brick.rmatlist, brick.rveclist,
  2019                                              brick.rveclist_sym, 
true);
  2025     context_check(); 
if (act_size_to_be_done) actualize_sizes();
  2026     set_dispatch_coeff();
  2028     for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
  2029       brick_description &brick = bricks[ib];
  2030       bool cplx = is_complex() && brick.pbr->is_complex();
  2031       if (brick.pdispatch) {
  2033           brick.pdispatch->next_complex_iter(*
this, ib, brick.vlist,
  2035                                              brick.cmatlist, brick.cveclist,
  2036                                              brick.cveclist_sym, 
false);
  2038           brick.pdispatch->next_real_iter(*
this, ib, brick.vlist, brick.dlist,
  2039                                           brick.rmatlist, brick.rveclist,
  2040                                           brick.rveclist_sym, 
false);
  2044     for (VAR_SET::iterator it = variables.begin(); it != variables.end();
  2046       for (
size_type i = 1; i < it->second.n_iter; ++i) {
  2048           gmm::copy(it->second.complex_value[i-1],
  2049                     it->second.complex_value[i]);
  2051           gmm::copy(it->second.real_value[i-1],
  2052                     it->second.real_value[i]);
  2053         it->second.v_num_data[i] = act_counter();
  2058   bool model::is_var_newer_than_brick(
const std::string &varname,
  2060     const brick_description &brick = bricks[ib];
  2061     var_description &vd = variables[varname];
  2062     if (niter == 
size_type(-1)) niter = vd.default_iter;
  2063     return (vd.v_num > brick.v_num || vd.v_num_data[niter] > brick.v_num);
  2066   bool model::is_var_mf_newer_than_brick(
const std::string &varname,
  2068     const brick_description &brick = bricks[ib];
  2069     var_description &vd = variables[varname];
  2070     return (vd.v_num > brick.v_num);
  2073   bool model::is_mim_newer_than_brick(
const mesh_im &im,
  2075     const brick_description &brick = bricks[ib];
  2076     return (im.version_number() > brick.v_num);
  2079   void model::define_variable_group(
const std::string &group_name,
  2080                                     const std::vector<std::string> &nl) {
  2081     GMM_ASSERT1(!(variable_exists(group_name)), 
"The name of a group of "  2082                 "variables cannot be the same as a variable name");
  2084     std::set<const mesh *> ms;
  2085     bool is_data_ = 
false;
  2086     for (
size_type i = 0; i < nl.size(); ++i) {
  2088         is_data_ = is_true_data(nl[i]);
  2090         GMM_ASSERT1(is_data_ == is_true_data(nl[i]),
  2091                     "It is not possible to mix variables and data in a group");
  2093       GMM_ASSERT1(variable_exists(nl[i]),
  2094                   "All variables in a group have to exist in the model");
  2095       const mesh_fem *mf = pmesh_fem_of_variable(nl[i]);
  2096       GMM_ASSERT1(mf, 
"Variables in a group should be fem variables");
  2097       GMM_ASSERT1(ms.find(&(mf->
linked_mesh())) == ms.end(),
  2098                   "Two variables in a group cannot share the same mesh");
  2101     variable_groups[group_name] = nl;
  2104   void model::add_assembly_assignments(
const std::string &varname,
  2107     GMM_ASSERT1(order < 3 || order == 
size_type(-1), 
"Bad order value");
  2108     const im_data *imd = pim_data_of_variable(varname);
  2109     GMM_ASSERT1(imd != 0, 
"Only applicable to im_data");
  2110     assignement_desc as;
  2111     as.varname = varname; as.expr = expr; as.region = rg; as.order = order;
  2113     assignments.push_back(as);
  2116   void model::add_temporaries(
const varnamelist &vl,
  2117                               gmm::uint64_type id_num)
 const {
  2118     for (
size_type i = 0; i < vl.size(); ++i) {
  2119       var_description &vd = variables[vl[i]];
  2120       if (vd.n_iter > 1) {
  2121         vd.add_temporary(id_num);
  2126   bool model::temporary_uptodate(
const std::string &varname,
  2127                                  gmm::uint64_type  id_num,
  2129     var_description &vd = variables[varname];
  2131     for (; ind < vd.n_iter + vd.n_temp_iter ; ++ind) {
  2132       if (vd.v_num_var_iter[ind] == id_num) 
break;
  2134     if (ind <  vd.n_iter + vd.n_temp_iter) {
  2135       if (vd.v_num_iter[ind] <= vd.v_num_data[vd.default_iter]) {
  2136         vd.v_num_iter[ind] = act_counter();
  2145   void model::set_default_iter_of_variable(
const std::string &varname,
  2148       var_description &vd = variables[varname];
  2149       GMM_ASSERT1(ind < vd.n_iter + vd.n_temp_iter,
  2150                   "Inexistent iteration " << ind);
  2151       vd.default_iter = ind;
  2155   void model::reset_default_iter_of_variables(
const varnamelist &vl)
 const {
  2156     for (
size_type i = 0; i < vl.size(); ++i)
  2157       variables[vl[i]].default_iter = 0;
  2160   const model_real_sparse_matrix &
  2162     GMM_ASSERT1(bricks[ib].tlist[iterm].is_matrix_term,
  2163                 "Not a matrix term !");
  2164     GMM_ASSERT1(bricks[ib].pbr->is_linear(), 
"Nonlinear term !");
  2165     return bricks[ib].rmatlist[iterm];
  2168   const model_complex_sparse_matrix &
  2170     GMM_ASSERT1(bricks[ib].tlist[iterm].is_matrix_term,
  2171                 "Not a matrix term !");
  2172     GMM_ASSERT1(bricks[ib].pbr->is_linear(), 
"Nonlinear term !");
  2173     return bricks[ib].cmatlist[iterm];
  2177   void model::update_brick(
size_type ib, build_version version)
 const {
  2178     const brick_description &brick = bricks[ib];
  2179     bool cplx = is_complex() && brick.pbr->is_complex();
  2180     bool tobecomputed = brick.terms_to_be_computed
  2181       || brick.pbr->is_to_be_computed_each_time()
  2182       || !(brick.pbr->is_linear());
  2185     if (!tobecomputed ) {
  2186       for (
size_type i = 0; i < brick.vlist.size() && !tobecomputed; ++i) {
  2187         var_description &vd = variables[brick.vlist[i]];
  2188         if (vd.v_num > brick.v_num) tobecomputed = 
true;
  2193     for (
size_type i = 0; i < brick.dlist.size() && !tobecomputed; ++i) {
  2194       var_description &vd = variables[brick.dlist[i]];
  2195       if (vd.v_num > brick.v_num || vd.v_num_data[vd.default_iter] > brick.v_num) {
  2196         tobecomputed = 
true;
  2197         version = build_version(version | BUILD_ON_DATA_CHANGE);
  2202       brick.external_load = scalar_type(0);
  2204       if (!(brick.pdispatch))
  2205         { brick_call(ib, version, 0); }
  2208           brick.pdispatch->asm_complex_tangent_terms
  2209             (*
this, ib, brick.cmatlist, brick.cveclist, brick.cveclist_sym,
  2212           brick.pdispatch->asm_real_tangent_terms
  2213             (*
this, ib, brick.rmatlist, brick.rveclist, brick.rveclist_sym,
  2216       brick.v_num = act_counter();
  2219     if (brick.pbr->is_linear()) brick.terms_to_be_computed = 
false;
  2226     const brick_description &brick = bricks[ib];
  2227     if (brick.pbr->is_linear()) {
  2229       bool cplx = is_complex() && brick.pbr->is_complex();
  2231       for (
size_type j = 0; j < brick.tlist.size(); ++j) {
  2232         const term_description &term = brick.tlist[j];
  2233         bool isg = term.is_global;
  2236         size_type n_iter_1 = n_iter, n_iter_2 = n_iter;
  2238           n_iter_1 = variables[term.var1].default_iter;
  2239           if (term.is_matrix_term)
  2240             n_iter_2 = variables[term.var2].default_iter;
  2245         if (term.is_matrix_term) {
  2248               model_complex_plain_vector V(nbgdof);
  2249               for (VAR_SET::iterator it = variables.begin();
  2250                    it != variables.end(); ++it)
  2251                 if (it->second.is_variable) {
  2253                     ? it->second.default_iter : n_iter;
  2254                   gmm::copy(it->second.complex_value[n_iter_i],
  2255                             gmm::sub_vector(V, it->second.I));
  2259                  gmm::scaled(V,  complex_type(-1)),
  2260                  brick.cveclist[ind_data][j]);
  2264                  gmm::scaled(variables[term.var2].complex_value[n_iter_2],
  2266                  brick.cveclist[ind_data][j]);
  2270               model_real_plain_vector V(nbgdof);
  2271               for (VAR_SET::iterator it = variables.begin();
  2272                    it != variables.end(); ++it)
  2273                 if (it->second.is_variable) {
  2275                     ? it->second.default_iter : n_iter;
  2276                   gmm::copy(it->second.real_value[n_iter_i],
  2277                             gmm::sub_vector(V, it->second.I));
  2280                 (brick.rmatlist[j], gmm::scaled(V,  scalar_type(-1)),
  2281                  brick.rveclist[ind_data][j]);
  2285                  gmm::scaled(variables[term.var2].real_value[n_iter_2],
  2286                              scalar_type(-1)), brick.rveclist[ind_data][j]);
  2289           if (term.is_symmetric && term.var1.compare(term.var2)) {
  2292                 (gmm::conjugated(brick.cmatlist[j]),
  2293                  gmm::scaled(variables[term.var1].complex_value[n_iter_1],
  2295                  brick.cveclist_sym[ind_data][j]);
  2298                 (gmm::transposed(brick.rmatlist[j]),
  2299                  gmm::scaled(variables[term.var1].real_value[n_iter_1],
  2301                  brick.rveclist_sym[ind_data][j]);
  2308   void model::update_affine_dependent_variables() {
  2309     for (VAR_SET::iterator it = variables.begin(); it != variables.end(); ++it)
  2310       if (it->second.is_affine_dependent) {
  2311         VAR_SET::iterator it2 = variables.find(it->second.org_name);
  2312         if (it->second.size() != it2->second.size())
  2313           it->second.set_size();
  2314          if (it->second.is_complex) {
  2315            gmm::add(gmm::scaled(it2->second.complex_value[0],
  2316                                 complex_type(it->second.alpha)),
  2317                     it->second.affine_complex_value,
  2318                     it->second.complex_value[0]);
  2320            gmm::add(gmm::scaled(it2->second.real_value[0], it->second.alpha),
  2321                     it->second.affine_real_value, it->second.real_value[0]);
  2323         it->second.v_num = std::max(it->second.v_num, it2->second.v_num);
  2324         for (
size_type i = 0; i < it->second.n_iter; ++i)
  2326           it->second.v_num_data[i] = std::max(it->second.v_num_data[i],
  2327                                               it2->second.v_num_data[i]);
  2337     const mesh_fem *mf = pmesh_fem_of_variable(varname);
  2338     GMM_ASSERT1(mf, 
"Works only with fem variables.");
  2342     for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
  2343       brick_description &brick = bricks[ib];
  2345       bool detected = 
false;
  2346       for (
size_type i = 0; i <  brick.vlist.size(); ++i)
  2347         if (brick.vlist[i].compare(varname) == 0)
  2348           { detected = 
true; 
break; }
  2350       if (detected && brick.mims.size()) {
  2352         for (
auto &pmim :  brick.mims)
  2355                                                   pmim->linked_mesh()));
  2356         GMM_ASSERT1(ifo >= 0,
  2357                     "The given region is only partially covered by "  2358                     "region of brick \"" << brick.pbr->brick_name()
  2359                     << 
"\". Please subdivise the region");
  2361           std::string expr = brick.pbr->declare_volume_assembly_string
  2362             (*
this, ib, brick.vlist, brick.dlist);
  2364           ga_workspace workspace(*
this);
  2365           size_type order = workspace.add_expression(expr, dummy_mim, region);
  2366           GMM_ASSERT1(order <= 1, 
"Wrong order for a Neumann term");
  2367           expr = workspace.extract_Neumann_term(varname);
  2370               result += 
" + " + workspace.extract_Neumann_term(varname);
  2372               result = workspace.extract_Neumann_term(varname);
  2387 #if GETFEM_PARA_LEVEL > 1  2388     double t_ref = MPI_Wtime();
  2391     context_check(); 
if (act_size_to_be_done) actualize_sizes();
  2393       if (version & BUILD_MATRIX) gmm::clear(cTM);
  2394       if (version & BUILD_RHS) gmm::clear(crhs);
  2397       if (version & BUILD_MATRIX) gmm::clear(rTM);
  2398       if (version & BUILD_RHS) gmm::clear(rrhs);
  2400     clear_dof_constraints();
  2401     generic_expressions.clear();
  2402     update_affine_dependent_variables();
  2404     if (version & BUILD_RHS) approx_external_load_ = scalar_type(0);
  2406     for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
  2408       brick_description &brick = bricks[ib];
  2411       bool auto_disabled_brick = 
true;
  2412       for (
size_type j = 0; j < brick.vlist.size(); ++j) {
  2413         if (!(is_disabled_variable(brick.vlist[j])))
  2414           auto_disabled_brick = 
false;
  2416       if (auto_disabled_brick) 
continue;
  2418       update_brick(ib, version);
  2420       bool cplx = is_complex() && brick.pbr->is_complex();
  2422       scalar_type coeff0 = scalar_type(1);
  2423       if (brick.pdispatch) coeff0 = brick.matrix_coeff;
  2427       for (
size_type j = 0; j < brick.tlist.size(); ++j) {
  2428         term_description &term = brick.tlist[j];
  2429         bool isg = term.is_global, isprevious = 
false;
  2431         scalar_type alpha = coeff0, alpha1 = coeff0, alpha2 = coeff0;
  2432         gmm::sub_interval I1(0,nbgdof), I2(0,nbgdof);
  2433         VAR_SET::iterator it1, it2;
  2435           it1 = variables.find(term.var1);
  2436           GMM_ASSERT1(it1->second.is_variable, 
"Assembly of data not allowed");
  2439         if (term.is_matrix_term && !isg) {
  2440           it2 = variables.find(term.var2);
  2442           if (!(it2->second.is_variable)) {
  2443             std::string vorgname = sup_previous_and_dot_to_varname(term.var2);
  2444             VAR_SET::iterator it3 = variables.find(vorgname);
  2445             GMM_ASSERT1(it3->second.is_variable,
  2446                         "Assembly of data not allowed");
  2450           alpha *= it1->second.alpha * it2->second.alpha;
  2451           alpha1 *= it1->second.alpha;
  2452           alpha2 *= it2->second.alpha;
  2456           if (term.is_matrix_term && (version & BUILD_MATRIX) && !isprevious
  2457               && (isg || (!(it1->second.is_disabled) && !(it2->second.is_disabled)))) {
  2458             gmm::add(gmm::scaled(brick.cmatlist[j], alpha),
  2459                      gmm::sub_matrix(cTM, I1, I2));
  2460             if (term.is_symmetric && I1.first() != I2.first()) {
  2461               gmm::add(gmm::scaled(gmm::transposed(brick.cmatlist[j]), alpha),
  2462                        gmm::sub_matrix(cTM, I2, I1));
  2465           if (version & BUILD_RHS) {
  2466             if (isg || !(it1->second.is_disabled)) {
  2467               if (brick.pdispatch) {
  2468                 for (
size_type k = 0; k < brick.nbrhs; ++k)
  2469                   gmm::add(gmm::scaled(brick.cveclist[k][j],
  2471                            gmm::sub_vector(crhs, I1));
  2474                 gmm::add(gmm::scaled(brick.cveclist[0][j],
  2475                                      complex_type(alpha1)),
  2476                          gmm::sub_vector(crhs, I1));
  2479             if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()) {
  2480               if (it2->second.is_affine_dependent
  2481                   && !(it1->second.is_disabled))
  2482                 gmm::mult_add(brick.cmatlist[j],
  2483                               gmm::scaled(it2->second.affine_complex_value,
  2484                                           complex_type(-alpha1)),
  2485                               gmm::sub_vector(crhs, I1));
  2486               if (term.is_symmetric && I1.first() != I2.first()
  2487                   && it1->second.is_affine_dependent
  2488                   && !(it2->second.is_disabled)) {
  2489                 gmm::mult_add(gmm::conjugated(brick.cmatlist[j]),
  2490                               gmm::scaled(it1->second.affine_complex_value,
  2491                                           complex_type(-alpha2)),
  2492                               gmm::sub_vector(crhs, I2));
  2495             if (term.is_matrix_term && brick.pbr->is_linear()
  2496                 && (!is_linear() || (version & BUILD_WITH_COMPLETE_RHS))) {
  2497               if (!(it1->second.is_disabled))
  2498                 gmm::mult_add(brick.cmatlist[j],
  2499                               gmm::scaled(it2->second.complex_value[0],
  2500                                           complex_type(-alpha1)),
  2501                               gmm::sub_vector(crhs, I1));
  2503             if (term.is_symmetric && I1.first() != I2.first() &&
  2504                 !(it2->second.is_disabled)) {
  2505               if (brick.pdispatch) {
  2506                 for (
size_type k = 0; k < brick.nbrhs; ++k)
  2507                   gmm::add(gmm::scaled(brick.cveclist_sym[k][j],
  2509                            gmm::sub_vector(crhs, I2));
  2511                 gmm::add(gmm::scaled(brick.cveclist_sym[0][j],
  2512                                      complex_type(alpha2)),
  2513                          gmm::sub_vector(crhs, I2));
  2515                if (brick.pbr->is_linear()
  2516                    && (!is_linear() || (version & BUILD_WITH_COMPLETE_RHS))) {
  2517                  gmm::mult_add(gmm::conjugated(brick.cmatlist[j]),
  2518                             gmm::scaled(it1->second.complex_value[0],
  2519                                         complex_type(-alpha2)),
  2520                             gmm::sub_vector(crhs, I2));
  2524         } 
else if (is_complex()) {
  2525           if (term.is_matrix_term && (version & BUILD_MATRIX) && !isprevious
  2526               && (isg || (!(it1->second.is_disabled) && !(it2->second.is_disabled)))) {
  2527             gmm::add(gmm::scaled(brick.rmatlist[j], alpha),
  2528                      gmm::sub_matrix(cTM, I1, I2));
  2529             if (term.is_symmetric && I1.first() != I2.first()) {
  2530               gmm::add(gmm::scaled(gmm::transposed(brick.rmatlist[j]), alpha),
  2531                        gmm::sub_matrix(cTM, I2, I1));
  2534           if (version & BUILD_RHS) {
  2535             if (isg || !(it1->second.is_disabled)) {
  2536               if (brick.pdispatch) {
  2537                 for (
size_type k = 0; k < brick.nbrhs; ++k)
  2538                   gmm::add(gmm::scaled(brick.rveclist[k][j],
  2540                            gmm::sub_vector(crhs, I1));
  2543                 gmm::add(gmm::scaled(brick.rveclist[0][j], alpha1),
  2544                          gmm::sub_vector(crhs, I1));
  2547             if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()) {
  2548               if (it2->second.is_affine_dependent
  2549                   && !(it1->second.is_disabled))
  2550                 gmm::mult_add(brick.rmatlist[j],
  2551                               gmm::scaled(it2->second.affine_complex_value,
  2552                                           complex_type(-alpha1)),
  2553                               gmm::sub_vector(crhs, I1));
  2554               if (term.is_symmetric && I1.first() != I2.first()
  2555                   && it1->second.is_affine_dependent
  2556                   && !(it2->second.is_disabled)) {
  2557                 gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
  2558                               gmm::scaled(it1->second.affine_complex_value,
  2559                                           complex_type(-alpha2)),
  2560                               gmm::sub_vector(crhs, I2));
  2563             if (term.is_matrix_term && brick.pbr->is_linear()
  2564                 && (!is_linear() || (version & BUILD_WITH_COMPLETE_RHS))) {
  2565               if (!(it1->second.is_disabled))
  2566                 gmm::mult_add(brick.rmatlist[j],
  2567                               gmm::scaled(it2->second.complex_value[0],
  2568                                           complex_type(-alpha1)),
  2569                               gmm::sub_vector(crhs, I1));
  2571             if (term.is_symmetric && I1.first() != I2.first() &&
  2572                 !(it2->second.is_disabled)) {
  2573               if (brick.pdispatch) {
  2574                 for (
size_type k = 0; k < brick.nbrhs; ++k)
  2575                   gmm::add(gmm::scaled(brick.rveclist_sym[k][j],
  2577                            gmm::sub_vector(crhs, I2));
  2580                 gmm::add(gmm::scaled(brick.rveclist_sym[0][j], alpha2),
  2581                          gmm::sub_vector(crhs, I2));
  2583               if (brick.pbr->is_linear()
  2584                   && (!is_linear() || (version & BUILD_WITH_COMPLETE_RHS))) {
  2585                 gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
  2586                              gmm::scaled(it1->second.complex_value[0],
  2587                                           complex_type(-alpha2)),
  2588                               gmm::sub_vector(crhs, I2));
  2593           if (term.is_matrix_term && (version & BUILD_MATRIX) && !isprevious
  2594               && (isg || (!(it1->second.is_disabled)
  2595                           && !(it2->second.is_disabled)))) {
  2596             gmm::add(gmm::scaled(brick.rmatlist[j], alpha),
  2597                      gmm::sub_matrix(rTM, I1, I2));
  2598             if (term.is_symmetric && I1.first() != I2.first()) {
  2599               gmm::add(gmm::scaled(gmm::transposed(brick.rmatlist[j]), alpha),
  2600                        gmm::sub_matrix(rTM, I2, I1));
  2603           if (version & BUILD_RHS) {
  2604             if (isg || !(it1->second.is_disabled)) {
  2605               if (brick.pdispatch) {
  2606                 for (
size_type k = 0; k < brick.nbrhs; ++k)
  2607                   gmm::add(gmm::scaled(brick.rveclist[k][j],
  2609                            gmm::sub_vector(rrhs, I1));
  2612                 gmm::add(gmm::scaled(brick.rveclist[0][j], alpha1),
  2613                          gmm::sub_vector(rrhs, I1));
  2616             if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()) {
  2617               if (it2->second.is_affine_dependent
  2618                   && !(it1->second.is_disabled))
  2619                 gmm::mult_add(brick.rmatlist[j],
  2620                               gmm::scaled(it2->second.affine_real_value,
  2622                               gmm::sub_vector(rrhs, I1));
  2623               if (term.is_symmetric && I1.first() != I2.first()
  2624                   && it1->second.is_affine_dependent
  2625                   && !(it2->second.is_disabled)) {
  2626                 gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
  2627                               gmm::scaled(it1->second.affine_real_value,
  2629                               gmm::sub_vector(rrhs, I2));
  2632             if (term.is_matrix_term && brick.pbr->is_linear()
  2633                 && (!is_linear() || (version & BUILD_WITH_COMPLETE_RHS))) {
  2634               if (!(it1->second.is_disabled))
  2635                 gmm::mult_add(brick.rmatlist[j],
  2636                               gmm::scaled(it2->second.real_value[0],
  2638                               gmm::sub_vector(rrhs, I1));
  2640             if (term.is_symmetric && I1.first() != I2.first() &&
  2641                 !(it2->second.is_disabled)) {
  2642               if (brick.pdispatch) {
  2643                 for (
size_type k = 0; k < brick.nbrhs; ++k)
  2644                   gmm::add(gmm::scaled(brick.rveclist_sym[k][j],
  2646                            gmm::sub_vector(rrhs, I2));
  2649                 gmm::add(gmm::scaled(brick.rveclist_sym[0][j], alpha2),
  2650                          gmm::sub_vector(rrhs, I2));
  2652               if (brick.pbr->is_linear()
  2653                   && (!is_linear() || (version & BUILD_WITH_COMPLETE_RHS))) {
  2654                 gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
  2655                               gmm::scaled(it1->second.real_value[0], -alpha2),
  2656                               gmm::sub_vector(rrhs, I2));
  2663       if (brick.pbr->is_linear())
  2664         brick.terms_to_be_computed = 
false;
  2677       if (version & BUILD_RHS) approx_external_load_ += brick.external_load;
  2681     if (generic_expressions.size()) {
  2682       model_real_plain_vector residual;
  2683       if (version & BUILD_RHS) gmm::resize(residual, gmm::vect_size(rrhs));
  2691         open_mp_is_running_properly check;
  2693         #pragma omp parallel default(shared)  2697             if (version & BUILD_RHS)
  2698               GMM_TRACE2(
"Global generic assembly RHS");
  2699             if (version & BUILD_MATRIX)
  2700               GMM_TRACE2(
"Global generic assembly tangent term");
  2702             ga_workspace workspace(*
this);
  2704             for (
const auto &ad : assignments)
  2705               workspace.add_assignment_expression
  2706                 (ad.varname, ad.expr, ad.region, ad.order, ad.before);
  2708             for (
const auto &ge : generic_expressions)
  2709               workspace.add_expression(ge.expr, ge.mim, ge.region);
  2711             if (version & BUILD_RHS) {
  2713                 GMM_ASSERT1(
false, 
"to be done");
  2715                 workspace.set_assembled_vector(residual_distributed);
  2716                 workspace.assembly(1);
  2720             if (version & BUILD_MATRIX) {
  2722                 GMM_ASSERT1(
false, 
"to be done");
  2724                 workspace.set_assembled_matrix(tangent_matrix_distributed);
  2725                 workspace.assembly(2);
  2730         exception.rethrow();
  2733       if (version & BUILD_RHS) gmm::add(gmm::scaled(residual, scalar_type(-1)), rrhs);
  2738     if ((version & BUILD_RHS) || (version & BUILD_MATRIX)) {
  2740         std::vector<size_type> dof_indices;
  2741         std::vector<complex_type> dof_pr_values;
  2742         std::vector<complex_type> dof_go_values;
  2743         for (
const auto &keyval : complex_dof_constraints) {
  2744           const gmm::sub_interval &I = interval_of_variable(keyval.first);
  2745           const model_complex_plain_vector &V = complex_variable(keyval.first);
  2746           for (
const auto &val : keyval.second) {
  2747             dof_indices.push_back(val.first + I.first());
  2748             dof_go_values.push_back(val.second);
  2749             dof_pr_values.push_back(V[val.first]);
  2753         if (dof_indices.size()) {
  2754           gmm::sub_index SI(dof_indices);
  2755           gmm::sub_interval II(0, nb_dof());
  2757           if (version & BUILD_RHS) {
  2758             if (MPI_IS_MASTER())
  2759               approx_external_load_ += gmm::vect_norm1(dof_go_values);
  2761               if (is_symmetric_) {
  2762                 scalar_type valnorm = gmm::vect_norm2(dof_go_values);
  2763                 if (valnorm > scalar_type(0)) {
  2764                   GMM_ASSERT1(version & BUILD_MATRIX, 
"Rhs only for a "  2765                               "symmetric linear problem with dof "  2766                               "constraint not allowed");
  2767                   model_complex_plain_vector vv(gmm::vect_size(crhs));
  2768                   gmm::mult(gmm::sub_matrix(cTM, II, SI), dof_go_values, vv);
  2770                   gmm::add(gmm::scaled(vv, scalar_type(-1)), crhs);
  2773               gmm::copy(dof_go_values, gmm::sub_vector(crhs, SI));
  2775               gmm::add(dof_go_values,
  2776                        gmm::scaled(dof_pr_values, complex_type(-1)),
  2777                        gmm::sub_vector(crhs, SI));
  2780           if (version & BUILD_MATRIX) {
  2781             gmm::clear(gmm::sub_matrix(cTM, SI, II));
  2782             if (is_symmetric_) gmm::clear(gmm::sub_matrix(cTM, II, SI));
  2784             if (MPI_IS_MASTER()) {
  2785               for (
size_type i = 0; i < dof_indices.size(); ++i)
  2786                 cTM(dof_indices[i], dof_indices[i]) = complex_type(1);
  2791         std::vector<size_type> dof_indices;
  2792         std::vector<scalar_type> dof_pr_values;
  2793         std::vector<scalar_type> dof_go_values;
  2794         for (
const auto &keyval : real_dof_constraints) {
  2795           const gmm::sub_interval &I = interval_of_variable(keyval.first);
  2796           const model_real_plain_vector &V = real_variable(keyval.first);
  2797           for (
const auto &val : keyval.second) {
  2798             dof_indices.push_back(val.first + I.first());
  2799             dof_go_values.push_back(val.second);
  2800             dof_pr_values.push_back(V[val.first]);
  2804         #if GETFEM_PARA_LEVEL > 1  2805         GMM_ASSERT1(MPI_IS_MASTER() || (dof_indices.size() == 0),
  2806                     "Sorry, for the moment, the dof constraints have to be "  2807                     "added on the master process only");
  2808         size_type dof_indices_size = dof_indices.size();
  2809         MPI_BCAST0_SCALAR(dof_indices_size);
  2810         dof_indices.resize(dof_indices_size);
  2811         MPI_BCAST0_VECTOR(dof_indices);
  2812         dof_pr_values.resize(dof_indices_size);
  2813         MPI_BCAST0_VECTOR(dof_pr_values);
  2814         dof_go_values.resize(dof_indices_size);
  2815         MPI_BCAST0_VECTOR(dof_go_values);
  2818         if (dof_indices.size()) {
  2819           gmm::sub_index SI(dof_indices);
  2820           gmm::sub_interval II(0, nb_dof());
  2822           if (version & BUILD_RHS) {
  2823             if (MPI_IS_MASTER())
  2824               approx_external_load_ += gmm::vect_norm1(dof_go_values);
  2826               if (is_symmetric_) {
  2827                 scalar_type valnorm = gmm::vect_norm2(dof_go_values);
  2828                 if (valnorm > scalar_type(0)) {
  2829                   GMM_ASSERT1(version & BUILD_MATRIX, 
"Rhs only for a "  2830                               "symmetric linear problem with dof "  2831                               "constraint not allowed");
  2832                   model_real_plain_vector vv(gmm::vect_size(rrhs));
  2833                   gmm::mult(gmm::sub_matrix(rTM, II, SI), dof_go_values, vv);
  2835                   gmm::add(gmm::scaled(vv, scalar_type(-1)), rrhs);
  2838               gmm::copy(dof_go_values, gmm::sub_vector(rrhs, SI));
  2840               gmm::add(dof_go_values,
  2841                        gmm::scaled(dof_pr_values, scalar_type(-1)),
  2842                        gmm::sub_vector(rrhs, SI));
  2845           if (version & BUILD_MATRIX) {
  2846             gmm::clear(gmm::sub_matrix(rTM, SI, II));
  2847             if (is_symmetric_) gmm::clear(gmm::sub_matrix(rTM, II, SI));
  2849             if (MPI_IS_MASTER()) {
  2850               for (
size_type i = 0; i < dof_indices.size(); ++i)
  2851                 rTM(dof_indices[i], dof_indices[i]) = scalar_type(1);
  2858     if (version & BUILD_RHS) {
  2859       approx_external_load_ = MPI_SUM_SCALAR(approx_external_load_);
  2863     #if GETFEM_PARA_LEVEL > 1  2865     if (MPI_IS_MASTER()) cout << 
"Assembly time " << MPI_Wtime()-t_ref << endl;
  2874     return it->second.associated_mf();
  2880     return it->second.passociated_mf();
  2884   model::qdims_of_variable(
const std::string &name)
 const {
  2886     const mesh_fem *mf = it->second.passociated_mf();
  2887     const im_data *imd = it->second.pim_data;
  2890       bgeot::multi_index mi = mf->get_qdims();
  2891       if (n > 1 || it->second.qdims.size() > 1) {
  2893         if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
  2894         for (; i < it->second.qdims.size(); ++i)
  2895           mi.push_back(it->second.qdims[i]);
  2899       bgeot::multi_index mi = imd->tensor_size();
  2902                   "Invalid mesh im data vector");
  2903       if (n > 1 || it->second.qdims.size() > 1) {
  2905         if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
  2906         for (; i < it->second.qdims.size(); ++i)
  2907           mi.push_back(it->second.qdims[i]);
  2911     return it->second.qdims;
  2914   size_type model::qdim_of_variable(
const std::string &name)
 const {
  2916     const mesh_fem *mf = it->second.passociated_mf();
  2917     const im_data *imd = it->second.pim_data;
  2922       return imd->tensor_size().total_size() * n;
  2928   const gmm::sub_interval &
  2929   model::interval_of_variable(
const std::string &name)
 const {
  2931     if (act_size_to_be_done) actualize_sizes();
  2932     VAR_SET::const_iterator it = find_variable(name);
  2933     return it->second.I;
  2936   const model_real_plain_vector &
  2939     else return real_variable(name, 
size_type(-1));
  2942   const model_real_plain_vector &
  2944     GMM_ASSERT1(!complex_version, 
"This model is a complex one");
  2945     GMM_ASSERT1(!
is_old(name), 
"Please don't use Old_ prefix in combination with"  2946                                " variable version");
  2948     auto it = variables.find(name);
  2949     GMM_ASSERT1(it!=variables.end(), 
"Undefined variable " << name);
  2950     if (act_size_to_be_done && it->second.is_fem_dofs) {
  2951       if (it->second.filter != VDESCRFILTER_NO)
  2954         it->second.set_size();
  2956     if (niter == 
size_type(-1)) niter = it->second.default_iter;
  2957     GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
  2958                 "Invalid iteration number " << niter << 
" for " << name);
  2959     return it->second.real_value[niter];
  2962   const model_complex_plain_vector &
  2965     else return complex_variable(name, 
size_type(-1));
  2968   const model_complex_plain_vector &
  2970     GMM_ASSERT1(complex_version, 
"This model is a real one");
  2971     GMM_ASSERT1(!
is_old(name), 
"Please don't use Old_ prefix in combination with"  2972                                " variable version");
  2974     auto it = variables.find(name);
  2975     GMM_ASSERT1(it!=variables.end(), 
"Undefined variable " << name);
  2976     if (act_size_to_be_done && it->second.is_fem_dofs) {
  2977       if (it->second.filter != VDESCRFILTER_NO)
  2980         it->second.set_size();
  2982     if (niter == 
size_type(-1)) niter = it->second.default_iter;
  2983     GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter  > niter,
  2984                 "Invalid iteration number "  2985                 << niter << 
" for " << name);
  2986     return it->second.complex_value[niter];
  2989   model_real_plain_vector &
  2992     else return set_real_variable(name, 
size_type(-1));
  2996   model_real_plain_vector &
  2998     GMM_ASSERT1(!complex_version, 
"This model is a complex one");
  2999     GMM_ASSERT1(!
is_old(name), 
"Please don't use Old_ prefix in combination with"  3000                                " variable version");
  3002     auto it = variables.find(name);
  3003     GMM_ASSERT1(it!=variables.end(), 
"Undefined variable " << name);
  3004     if (act_size_to_be_done && it->second.is_fem_dofs) {
  3005       if (it->second.filter != VDESCRFILTER_NO)
  3008         it->second.set_size();
  3010     if (niter == 
size_type(-1)) niter = it->second.default_iter;
  3011     it->second.v_num_data[niter] = act_counter();
  3012     GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
  3013                 "Invalid iteration number "  3014                 << niter << 
" for " << name);
  3015     return it->second.real_value[niter];
  3018 model_complex_plain_vector &
  3021     else return set_complex_variable(name, 
size_type(-1));
  3024   model_complex_plain_vector &
  3026     GMM_ASSERT1(complex_version, 
"This model is a real one");
  3027     GMM_ASSERT1(!
is_old(name), 
"Please don't use Old_ prefix in combination with"  3028                                " variable version");
  3030     auto it = variables.find(name);
  3031     GMM_ASSERT1(it!=variables.end(), 
"Undefined variable " << name);
  3032     if (act_size_to_be_done && it->second.is_fem_dofs) {
  3033       if (it->second.filter != VDESCRFILTER_NO)
  3036         it->second.set_size();
  3038     if (niter == 
size_type(-1)) niter = it->second.default_iter;
  3039     it->second.v_num_data[niter] = act_counter();
  3040     GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
  3041                 "Invalid iteration number "  3042                 << niter << 
" for " << name);
  3043     return it->second.complex_value[niter];
  3046   model_real_plain_vector &
  3047   model::set_real_constant_part(
const std::string &name)
 const {
  3048     GMM_ASSERT1(!complex_version, 
"This model is a complex one");
  3050     VAR_SET::iterator it = variables.find(name);
  3051     GMM_ASSERT1(it != variables.end(), 
"Undefined variable " << name);
  3052     GMM_ASSERT1(it->second.is_affine_dependent,
  3053                 "Only for affine dependent variables");
  3054     if (act_size_to_be_done && it->second.is_fem_dofs) {
  3055       if (it->second.filter != VDESCRFILTER_NO)
  3058         it->second.set_size();
  3060     for (
auto &v_num : it->second.v_num_data) v_num = act_counter();
  3061     return it->second.affine_real_value;
  3064   model_complex_plain_vector &
  3065   model::set_complex_constant_part(
const std::string &name)
 const {
  3066     GMM_ASSERT1(complex_version, 
"This model is a real one");
  3068     VAR_SET::iterator it = variables.find(name);
  3069     GMM_ASSERT1(it!=variables.end(), 
"Undefined variable " << name);
  3070     if (act_size_to_be_done && it->second.is_fem_dofs) {
  3071       if (it->second.filter != VDESCRFILTER_NO)
  3074         it->second.set_size();
  3076     for (
auto &v_num : it->second.v_num_data) v_num = act_counter();
  3077     return it->second.affine_complex_value;
  3082     const brick_description &brick = bricks[ind_brick];
  3083     update_brick(ind_brick, model::BUILD_ALL);
  3085     brick.pbr->check_stiffness_matrix_and_rhs(*
this, ind_brick, brick.tlist,
  3086                       brick.vlist, brick.dlist, brick.mims, brick.rmatlist,
  3087                       brick.rveclist[0], brick.rveclist_sym[0], brick.region);
  3090   void model::clear() {
  3092     active_bricks.clear();
  3093     valid_bricks.clear();
  3094     real_dof_constraints.clear();
  3095     complex_dof_constraints.clear();
  3097     rTM = model_real_sparse_matrix();
  3098     cTM = model_complex_sparse_matrix();
  3099     rrhs = model_real_plain_vector();
  3100     crhs = model_complex_plain_vector();
  3105   void virtual_brick::full_asm_real_tangent_terms_(
const model &md, 
size_type ind_brick,
  3106     const model::varnamelist &term_list,
  3107     const model::varnamelist &var_list,
  3108     const model::mimlist &mim_list,
  3109     model::real_matlist &rmatlist,
  3110     model::real_veclist &rveclist,
  3111     model::real_veclist &rveclist_sym,
  3112     size_type region, build_version version)
 const  3114     real_pre_assembly_in_serial(md, ind_brick, term_list, var_list, mim_list, rmatlist,
  3115       rveclist, rveclist_sym, region, version);
  3116     asm_real_tangent_terms(md, ind_brick, term_list, var_list, mim_list, rmatlist,
  3117       rveclist, rveclist_sym, region, version);
  3118     real_post_assembly_in_serial(md, ind_brick, term_list, var_list, mim_list, rmatlist,
  3119       rveclist, rveclist_sym, region, version);
  3124    const model::termlist& tlist,
  3125    const model::varnamelist &vl,
  3126    const model::varnamelist &dl,
  3127    const model::mimlist &mims,
  3128    model::real_matlist &matl,
  3129    model::real_veclist &rvc1,
  3130    model::real_veclist &rvc2,
  3132    const scalar_type TINY) 
const  3134     std::cout<<
"******Verifying stiffnesses of *******"<<std::endl;
  3135     std::cout<<
"*** "<<brick_name()<<std::endl;
  3138     std::map<std::string,size_type> rhs_index;
  3139     for(
size_type iterm=0;iterm<matl.size();iterm++)
  3140       if (tlist[iterm].var1==tlist[iterm].var2) rhs_index[tlist[iterm].var1]=iterm;
  3142     if (rhs_index.size()==0){
  3143       GMM_WARNING0(
"*** cannot verify stiffness for this brick***");
  3146     full_asm_real_tangent_terms_(md, s, vl, dl, mims, matl, rvc1, rvc2,
  3147                            rg, model::BUILD_MATRIX);
  3148     for(
size_type iterm=0;iterm<matl.size();iterm++)
  3151       std::cout<<std::endl;
  3152       std::cout<<
"    Stiffness["<<tlist[iterm].var1
  3153                <<
","<<tlist[iterm].var2<<
"]:"<<std::endl;
  3156           std::cout<<
"    "<<tlist[iterm].var1<<
" has zero size. Skipping this term"<<std::endl;
  3161           std::cout<<
"    "<<tlist[iterm].var2<<
" has zero size. Skipping this term"<<std::endl;
  3165       model_real_sparse_matrix SM(matl[iterm]);
  3166       gmm::fill(rvc1[rhs_index[tlist[iterm].var1]], 0.0);
  3167       full_asm_real_tangent_terms_(md, s, vl, dl, mims, matl, rvc1, rvc2,
  3168                              rg, model::BUILD_RHS);
  3169       if (gmm::mat_euclidean_norm(matl[iterm])<1e-12){
  3170         std::cout<<
"    The assembled matrix is nearly zero, skipping."<<std::endl;
  3173       model_real_plain_vector RHS0(rvc1[rhs_index[tlist[iterm].var1]]);
  3176       model_real_sparse_matrix fdSM(matl[iterm].nrows(), matl[iterm].ncols());
  3178       model_real_plain_vector& RHS1 = rvc1[rhs_index[tlist[iterm].var1]];
  3180       scalar_type relative_tiny = gmm::vect_norminf(RHS1)*TINY;
  3181       if (relative_tiny < TINY) relative_tiny = TINY;
  3183       for (
size_type j = 0; j < matl[iterm].ncols(); j++){
  3184         U[j] += relative_tiny;
  3185         gmm::fill(RHS1, 0.0);
  3186         full_asm_real_tangent_terms_(md, s, vl, dl, mims, matl, rvc1, rvc2,
  3187           rg, model::BUILD_RHS);
  3188         for (
size_type i = 0; i<matl[iterm].nrows(); i++)
  3189           fdSM(i, j) = (RHS0[i] - RHS1[i]) / relative_tiny;
  3190         U[j] -= relative_tiny;
  3193       model_real_sparse_matrix diffSM(matl[iterm].nrows(),matl[iterm].ncols());
  3194       gmm::add(SM,gmm::scaled(fdSM,-1.0),diffSM);
  3195       scalar_type norm_error_euc
  3196         = gmm::mat_euclidean_norm(diffSM)/gmm::mat_euclidean_norm(SM)*100;
  3197       scalar_type norm_error_1
  3198         = gmm::mat_norm1(diffSM)/gmm::mat_norm1(SM)*100;
  3199       scalar_type norm_error_max
  3200         = gmm::mat_maxnorm(diffSM)/gmm::mat_maxnorm(SM)*100;
  3203       scalar_type nsym_norm_error_euc=0.0;
  3204       scalar_type nsym_norm_error_1=0.0;
  3205       scalar_type nsym_norm_error_max=0.0;
  3206       if (tlist[iterm].var1==tlist[iterm].var2){
  3207         model_real_sparse_matrix diffSMtransposed(matl[iterm].nrows(),matl[iterm].ncols());
  3208         gmm::add(gmm::transposed(fdSM),gmm::scaled(fdSM,-1.0),diffSMtransposed);
  3210           = gmm::mat_euclidean_norm(diffSMtransposed)/gmm::mat_euclidean_norm(fdSM)*100;
  3212           = gmm::mat_norm1(diffSMtransposed)/gmm::mat_norm1(fdSM)*100;
  3214           = gmm::mat_maxnorm(diffSMtransposed)/gmm::mat_maxnorm(fdSM)*100;
  3218       if(rvc1[0].size()<8){
  3219         std::cout << 
"RHS Stiffness Matrix: \n";
  3220         std::cout << 
"------------------------\n";
  3221         for(
size_type i=0; i < rvc1[iterm].size(); ++i){
  3223           for(
size_type j=0; j < rvc1[iterm].size(); ++j){
  3224             std::cout << fdSM(i,j) << 
"  ";
  3228         std::cout << 
"Analytical Stiffness Matrix: \n";
  3229         std::cout << 
"------------------------\n";
  3230         for(
size_type i=0; i < rvc1[iterm].size(); ++i){
  3232           for(
size_type j=0; j < rvc1[iterm].size(); ++j){
  3233             std::cout << matl[iterm](i,j) << 
"  ";
  3237         std::cout << 
"Vector U: \n";
  3238         std::cout << 
"------------------------\n";
  3239         for(
size_type i=0; i < rvc1[iterm].size(); ++i){
  3246         << 
"\n\nfinite diff test error_norm_eucl: " << norm_error_euc << 
"%\n"  3247         << 
"finite diff test error_norm1: " << norm_error_1 << 
"%\n"  3248         << 
"finite diff test error_max_norm: " << norm_error_max << 
"%\n\n\n";
  3250       if (tlist[iterm].var1==tlist[iterm].var2){
  3252           << 
"Nonsymmetrical test error_norm_eucl: "<< nsym_norm_error_euc<< 
"%\n"  3253           << 
"Nonsymmetrical test error_norm1: " << nsym_norm_error_1 << 
"%\n"  3254           << 
"Nonsymmetrical test error_max_norm: " << nsym_norm_error_max << 
"%"  3274   struct gen_source_term_assembly_brick : 
public virtual_brick {
  3276     std::string expr, directvarname, directdataname;
  3277     model::varnamelist vl_test1;
  3280                                 const model::varnamelist &,
  3281                                 const model::varnamelist &,
  3282                                 const model::mimlist &mims,
  3283                                 model::real_matlist &,
  3284                                 model::real_veclist &vecl,
  3285                                 model::real_veclist &,
  3287                                 build_version)
 const override {
  3288       GMM_ASSERT1(vecl.size() ==  vl_test1.size()
  3289                   + ((directdataname.size() == 0) ? 0 : 1), 
"Wrong number "  3290                   "of terms for Generic source term assembly brick ");
  3291       GMM_ASSERT1(mims.size() == 1, 
"Generic source term assembly brick "  3292                   "needs one and only one mesh_im");
  3293       GMM_TRACE2(
"Generic source term assembly");
  3295       gmm::clear(vecl[0]);
  3299         ga_workspace workspace(md, 
true);
  3300         GMM_TRACE2(name << 
": generic source term assembly");
  3301         workspace.add_expression(expr, *(mims[0]), region);
  3302         model::varnamelist vlmd; md.variable_list(vlmd);
  3303         for (
size_type i = 0; i < vlmd.size(); ++i)
  3304           if (md.is_disabled_variable(vlmd[i]))
  3305             nbgdof = std::max(nbgdof,
  3306                               workspace.interval_of_variable(vlmd[i]).last());
  3307         GMM_TRACE2(name << 
": generic matrix assembly");
  3308         model_real_plain_vector V(nbgdof);
  3309         workspace.set_assembled_vector(V);
  3310         workspace.assembly(1);
  3311         for (
size_type i = 0; i < vl_test1.size(); ++i) {
  3312           gmm::copy(gmm::sub_vector
  3313                     (V, workspace.interval_of_variable(vl_test1[i])), vecl[i]);
  3317       if (directvarname.size()) {
  3323                                       const model::varnamelist &,
  3324                                       const model::varnamelist &,
  3325                                       const model::mimlist &,
  3326                                       model::real_matlist &,
  3327                                       model::real_veclist &vecl,
  3328                                       model::real_veclist &,
  3330                                       build_version)
 const override {
  3331       scalar_type el = scalar_type(0);
  3332       for (
size_type i=0; i < vecl.size(); ++i) el += gmm::vect_norm1(vecl[i]);
  3333       md.add_external_load(ib, el);
  3336     virtual std::string declare_volume_assembly_string
  3338      const model::varnamelist &)
 const {
  3339       return std::string();
  3342     gen_source_term_assembly_brick(
const std::string &expr_,
  3343                                    std::string brickname,
  3344                                    const model::varnamelist &vl_test1_,
  3345                                    const std::string &directvarname_,
  3346                                    const std::string &directdataname_)
  3347       : vl_test1(vl_test1_) {
  3348       if (brickname.size() == 0)
  3349         brickname = 
"Generic source term assembly brick";
  3351       set_flags(brickname, 
true ,
  3355       directvarname = directvarname_; directdataname = directdataname_;
  3360   static bool check_compatibility_vl_test(
model &md,
const model::varnamelist vl_test) {
  3361     model::varnamelist org;
  3362     for (
size_type i = 0; i < vl_test.size(); ++i) {
  3363       if (md.is_affine_dependent_variable(vl_test[i]))
  3364         org.push_back(md.org_variable(vl_test[i]));
  3366     for (
size_type i = 0; i < vl_test.size(); ++i)
  3367       for (
size_type j = 0; j < org.size(); ++j)
  3368         if (vl_test[i].compare(org[j]) == 0) 
return false;
  3374    std::string brickname, std::string directvarname,
  3375    const std::string &directdataname, 
bool return_if_nonlin) {
  3377     ga_workspace workspace(md);
  3378     size_type order = workspace.add_expression(expr, mim, region);
  3379     GMM_ASSERT1(order <= 1, 
"Wrong order for a source term");
  3380     model::varnamelist vl, vl_test1, vl_test2, dl;
  3381     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 1);
  3382     if (!is_lin && return_if_nonlin) 
return size_type(-1);
  3383     GMM_ASSERT1(is_lin, 
"Nonlinear term");
  3384     GMM_ASSERT1(check_compatibility_vl_test(md, vl_test1),
  3385                 "This brick do not support the assembly on both an affine "  3386                 "dependent variable and its original variable. "  3387                 "Split the brick.");
  3389     if (directdataname.size()) {
  3390       vl.push_back(directvarname);
  3391       dl.push_back(directdataname);
  3392     } 
else directvarname = 
"";
  3394     pbrick pbr = std::make_shared<gen_source_term_assembly_brick>
  3395       (expr, brickname, vl_test1, directvarname, directdataname);
  3398     for (
size_type i = 0; i < vl_test1.size(); ++i)
  3399       tl.push_back(model::term_description(vl_test1[i]));
  3400     if (directdataname.size())
  3401       tl.push_back(model::term_description(directvarname));
  3403     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  3416     model::varnamelist vl_test1, vl_test2;
  3418     virtual void asm_real_tangent_terms(
const model &md, 
size_type ib,
  3419                                         const model::varnamelist &,
  3420                                         const model::varnamelist &dl,
  3421                                         const model::mimlist &mims,
  3422                                         model::real_matlist &matl,
  3423                                         model::real_veclist &,
  3424                                         model::real_veclist &,
  3426                                         build_version version)
 const {
  3427       GMM_ASSERT1(matl.size() == vl_test1.size(),
  3428                   "Wrong number of terms for Generic linear assembly brick");
  3429       GMM_ASSERT1(mims.size() == 1,
  3430                   "Generic linear assembly brick needs one and only one "  3432       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
  3433       for (
size_type i = 0; i < dl.size(); ++i)
  3434         recompute_matrix = recompute_matrix ||
  3435           md.is_var_newer_than_brick(dl[i], ib);
  3437       if (recompute_matrix) {
  3439         ga_workspace workspace(md, 
true);
  3440         workspace.add_expression(expr, *(mims[0]), region);
  3441         model::varnamelist vlmd; md.variable_list(vlmd);
  3442         for (
size_type i = 0; i < vlmd.size(); ++i)
  3443           if (md.is_disabled_variable(vlmd[i]))
  3444             nbgdof = std::max(nbgdof,
  3445                               workspace.interval_of_variable(vlmd[i]).last());
  3446         GMM_TRACE2(name << 
": generic matrix assembly");
  3447         model_real_sparse_matrix R(nbgdof, nbgdof);
  3448         workspace.set_assembled_matrix(R);
  3449         workspace.assembly(2);
  3450         for (
size_type i = 0; i < vl_test1.size(); ++i) {
  3451           scalar_type alpha = scalar_type(1)
  3452             / ( workspace.factor_of_variable(vl_test1[i]) *
  3453                 workspace.factor_of_variable(vl_test2[i]));
  3454           gmm::copy(gmm::scaled(gmm::sub_matrix
  3455                     (R, workspace.interval_of_variable(vl_test1[i]),
  3456                      workspace.interval_of_variable(vl_test2[i])), alpha),
  3462     virtual std::string declare_volume_assembly_string
  3464      const model::varnamelist &)
 const {
  3465       return is_lower_dim ? std::string() : expr;
  3468     gen_linear_assembly_brick(
const std::string &expr_, 
const mesh_im &mim,
  3470                               bool is_coer, std::string brickname,
  3471                               const model::varnamelist &vl_test1_,
  3472                               const model::varnamelist &vl_test2_)
  3473       : vl_test1(vl_test1_), vl_test2(vl_test2_) {
  3474       if (brickname.size() == 0) brickname = 
"Generic linear assembly brick";
  3476       is_lower_dim = mim.is_lower_dimensional();
  3477       set_flags(brickname, 
true ,
  3484   static bool check_compatibility_vl_test(
model &md,
  3485                                           const model::varnamelist vl_test1,
  3486                                           const model::varnamelist vl_test2) {
  3487     for (
size_type i = 0; i < vl_test1.size(); ++i)
  3488       for (
size_type j = 0; j < vl_test1.size(); ++j) {
  3489         bool is1 = md.is_affine_dependent_variable(vl_test1[i]);
  3490         bool is2 = md.is_affine_dependent_variable(vl_test2[i]);
  3492           const std::string &org1
  3493             = is1 ? md.org_variable(vl_test1[i]) : vl_test1[i];
  3494           const std::string &org2
  3495             = is2 ? md.org_variable(vl_test2[i]) : vl_test2[i];
  3496           bool is1_bis = md.is_affine_dependent_variable(vl_test1[j]);
  3497           bool is2_bis = md.is_affine_dependent_variable(vl_test2[j]);
  3498           const std::string &org1_bis = is1_bis ? md.org_variable(vl_test1[j])
  3500           const std::string &org2_bis = is2_bis ? md.org_variable(vl_test2[j])
  3502           if (org1.compare(org1_bis) == 0 && org2.compare(org2_bis))
  3511    bool is_sym, 
bool is_coercive, std::string brickname,
  3512    bool return_if_nonlin) {
  3514     ga_workspace workspace(md, 
true);
  3515     size_type order = workspace.add_expression(expr, mim, region);
  3516     model::varnamelist vl, vl_test1, vl_test2, dl;
  3517     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 2);
  3519     if (!is_lin && return_if_nonlin) 
return size_type(-1);
  3520     GMM_ASSERT1(is_lin, 
"Nonlinear term");
  3521     if (order == 0) { is_coercive = is_sym = 
true; }
  3523     std::string const_expr= workspace.extract_constant_term(mim.
linked_mesh());
  3524     if (const_expr.size()) {
  3525       add_source_term_generic_assembly_brick
  3526         (md, mim, const_expr, region, brickname+
" (source term)");
  3531     GMM_ASSERT1(check_compatibility_vl_test(md, vl_test1, vl_test2),
  3532                 "This brick do not support the assembly on both an affine "  3533                 "dependent variable and its original variable. "  3534                 "Split the brick.");
  3536     if (vl_test1.size()) {
  3537       pbrick pbr = std::make_shared<gen_linear_assembly_brick>
  3538         (expr, mim, is_sym, is_coercive, brickname, vl_test1, vl_test2);
  3540       for (
size_type i = 0; i < vl_test1.size(); ++i)
  3541         tl.push_back(model::term_description(vl_test1[i], vl_test2[i], 
false));
  3543       return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  3555   struct gen_nonlinear_assembly_brick : 
public virtual_brick {
  3560     virtual void real_post_assembly_in_serial(
const model &md, 
size_type ,
  3561                                               const model::varnamelist &,
  3562                                               const model::varnamelist &,
  3563                                               const model::mimlist &mims,
  3564                                               model::real_matlist &,
  3565                                               model::real_veclist &,
  3566                                               model::real_veclist &,
  3568                                               build_version)
 const {
  3569       GMM_ASSERT1(mims.size() == 1,
  3570                   "Generic linear assembly brick needs one and only one "  3572       md.add_generic_expression(expr, *(mims[0]), region);
  3575     virtual std::string declare_volume_assembly_string
  3577      const model::varnamelist &)
 const {
  3582     gen_nonlinear_assembly_brick(
const std::string &expr_, 
const mesh_im &mim,
  3584                                  bool is_coer, std::string brickname = 
"") {
  3585       if (brickname.size() == 0) brickname = 
"Generic linear assembly brick";
  3587       is_lower_dim = mim.is_lower_dimensional();
  3588       set_flags(brickname, 
false ,
  3597    bool is_sym, 
bool is_coercive, std::string brickname) {
  3599     ga_workspace workspace(md);
  3600     size_type order = workspace.add_expression(expr, mim, region);
  3601     GMM_ASSERT1(order < 2, 
"Order two test functions (Test2) are not allowed"  3602                 " in assembly string for nonlinear terms");
  3603     model::varnamelist vl, vl_test1, vl_test2, ddl, dl;
  3604     workspace.used_variables(vl, vl_test1, vl_test2, ddl, order);
  3605     for (
size_type i = 0; i < ddl.size(); ++i)
  3607       else vl.push_back(ddl[i]);
  3608     if (order == 0) { is_coercive = is_sym = 
true; }
  3609     pbrick pbr = std::make_shared<gen_nonlinear_assembly_brick>
  3610       (expr, mim, is_sym, is_coercive, brickname);
  3614     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  3627                                         const model::varnamelist &vl,
  3628                                         const model::varnamelist &dl,
  3629                                         const model::mimlist &mims,
  3630                                         model::real_matlist &matl,
  3631                                         model::real_veclist &,
  3632                                         model::real_veclist &,
  3634                                         build_version)
 const {
  3635       GMM_ASSERT1(matl.size() == 1,
  3636                   "Generic elliptic brick has one and only one term");
  3637       GMM_ASSERT1(mims.size() == 1,
  3638                   "Generic elliptic brick need one and only one mesh_im");
  3639       GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
  3640                   "Wrong number of variables for generic elliptic brick");
  3643       const mesh &m = mf_u.linked_mesh();
  3644       size_type N = m.dim(), Q = mf_u.get_qdim(), s = 1;
  3645       const mesh_im &mim = *mims[0];
  3646       const model_real_plain_vector *A = 0;
  3649       m.intersect_with_mpi_region(rg);
  3650       if (dl.size() > 0) {
  3653         s = gmm::vect_size(*A);
  3657       gmm::clear(matl[0]);
  3658       GMM_TRACE2(
"Generic elliptic term assembly");
  3663               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3666               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3671               (matl[0], mim, mf_u, rg);
  3674               (matl[0], mim, mf_u, rg);
  3675           if (A) gmm::scale(matl[0], (*A)[0]);
  3677       } 
else if (s == N*N) {
  3681               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3684               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3688               (matl[0], mim, mf_u, *A, rg);
  3691               (matl[0], mim, mf_u, *A, rg);
  3693       } 
else if (s == N*N*Q*Q) {
  3696             (matl[0], mim, mf_u, *mf_a, *A, rg);
  3699             (matl[0], mim, mf_u, *A, rg);
  3701         GMM_ASSERT1(
false, 
"Bad format generic elliptic brick coefficient");
  3705     virtual void real_post_assembly_in_serial(
const model &md, 
size_type,
  3706                                               const model::varnamelist &,
  3707                                               const model::varnamelist &dl,
  3708                                               const model::mimlist &,
  3709                                               model::real_matlist &,
  3710                                               model::real_veclist &,
  3711                                               model::real_veclist &,
  3713                                               build_version)
 const  3715       const model_real_plain_vector *A = 0;
  3724     virtual void complex_post_assembly_in_serial(
const model &md, 
size_type,
  3725                                               const model::varnamelist &,
  3726                                               const model::varnamelist &dl,
  3727                                               const model::mimlist &,
  3728                                               model::complex_matlist &,
  3729                                               model::complex_veclist &,
  3730                                               model::complex_veclist &,
  3732                                               build_version)
 const  3734       const model_real_plain_vector *A = 0;
  3743     virtual scalar_type asm_complex_tangent_terms(
const model &md, 
size_type,
  3744                                                   const model::varnamelist &vl,
  3745                                                   const model::varnamelist &,
  3746                                                   const model::mimlist &,
  3747                                                   model::complex_matlist &matl,
  3748                                                   model::complex_veclist &,
  3749                                                   model::complex_veclist &,
  3752       return gmm::abs(gmm::vect_hp(matl[0], U, U)) / scalar_type(2);
  3756     virtual void asm_complex_tangent_terms(
const model &md, 
size_type,
  3757                                            const model::varnamelist &vl,
  3758                                            const model::varnamelist &dl,
  3759                                            const model::mimlist &mims,
  3760                                            model::complex_matlist &matl,
  3761                                            model::complex_veclist &,
  3762                                            model::complex_veclist &,
  3764                                            build_version)
 const {
  3765       GMM_ASSERT1(matl.size() == 1,
  3766                   "Generic elliptic brick has one and only one term");
  3767       GMM_ASSERT1(mims.size() == 1,
  3768                   "Generic elliptic brick need one and only one mesh_im");
  3769       GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
  3770                   "Wrong number of variables for generic elliptic brick");
  3773       const mesh &m = mf_u.linked_mesh();
  3774       size_type N = m.dim(), Q = mf_u.get_qdim(), s = 1;
  3775       const mesh_im &mim = *mims[0];
  3776       const model_real_plain_vector *A = 0;
  3779       m.intersect_with_mpi_region(rg);
  3782       if (dl.size() > 0) {
  3785         s = gmm::vect_size(*A);
  3789       gmm::clear(matl[0]);
  3790       GMM_TRACE2(
"Generic elliptic term assembly");
  3795               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3798               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3803               (gmm::real_part(matl[0]), mim, mf_u, rg);
  3806               (gmm::real_part(matl[0]), mim, mf_u, rg);
  3807           if (A) gmm::scale(matl[0], (*A)[0]);
  3809       } 
else if (s == N*N) {
  3813               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3816               (matl[0], mim, mf_u, *mf_a, *A, rg);
  3820               (matl[0], mim, mf_u, *A, rg);
  3823               (matl[0], mim, mf_u, *A, rg);
  3825       } 
else if (s == N*N*Q*Q) {
  3828             (matl[0], mim, mf_u, *mf_a, *A, rg);
  3831             (matl[0], mim, mf_u, *A, rg);
  3834                     "Bad format generic elliptic brick coefficient");
  3837     generic_elliptic_brick() {
  3838       set_flags(
"Generic elliptic", 
true ,
  3846                                 const std::string &varname,
  3849       pbrick pbr = std::make_shared<generic_elliptic_brick>();
  3851       tl.push_back(model::term_description(varname, varname, 
true));
  3852       return md.
add_brick(pbr, model::varnamelist(1, varname),
  3853                           model::varnamelist(), tl, model::mimlist(1, &mim),
  3856       std::string test_varname
  3857         = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  3862         expr = 
"Grad_"+varname+
".Grad_"+test_varname;
  3864         expr = 
"Grad_"+varname+
":Grad_"+test_varname;
  3866                              "Laplacian", 
false);
  3871                                        const std::string &varname,
  3872                                        const std::string &dataname,
  3875       pbrick pbr = std::make_shared<generic_elliptic_brick>();
  3877       tl.push_back(model::term_description(varname, varname, 
true));
  3878       return md.
add_brick(pbr, model::varnamelist(1, varname),
  3879                           model::varnamelist(1, dataname), tl,
  3880                           model::mimlist(1, &mim), region);
  3882       std::string test_varname
  3883         = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  3896         if (qdim_data != 1) {
  3897           GMM_ASSERT1(qdim_data == gmm::sqr(dim),
  3898                       "Wrong data size for generic elliptic brick");
  3899           expr = 
"((Reshape("+dataname+
",meshdim,meshdim))*Grad_"+varname+
").Grad_"  3902           expr = 
"(("+dataname+
")*Grad_"+varname+
").Grad_"+test_varname;
  3905         if (qdim_data != 1) {
  3906           if (qdim_data == gmm::sqr(dim))
  3907             expr = 
"((Reshape("+dataname+
",meshdim,meshdim))*Grad_"+varname+
"):Grad_"  3909           else if (qdim_data == gmm::sqr(gmm::sqr(dim)))
  3910             expr = 
"((Reshape("+dataname+
",meshdim,meshdim,meshdim,meshdim))*Grad_"  3911               +varname+
"):Grad_"+test_varname;
  3912           else GMM_ASSERT1(
false, 
"Wrong data size for generic elliptic brick");
  3914           expr = 
"(("+dataname+
")*Grad_"+varname+
"):Grad_"+test_varname;
  3918         (md, mim, expr, region, 
true, 
true, 
"Generic elliptic", 
true);
  3921                                 "Generic elliptic (nonlinear)");
  3936                                         const model::varnamelist &vl,
  3937                                         const model::varnamelist &dl,
  3938                                         const model::mimlist &mims,
  3939                                         model::real_matlist &,
  3940                                         model::real_veclist &vecl,
  3941                                         model::real_veclist &,
  3943                                         build_version)
 const override {
  3944       GMM_ASSERT1(vecl.size() == 1,
  3945                   "Source term brick has one and only one term");
  3946       GMM_ASSERT1(mims.size() == 1,
  3947                   "Source term brick need one and only one mesh_im");
  3948       GMM_ASSERT1(vl.size() == 1 && dl.size() > 0 && dl.size() <= 2,
  3949                   "Wrong number of variables for source term brick");
  3952       const mesh_im &mim = *mims[0];
  3961       GMM_ASSERT1(mf_u.get_qdim() == s,
  3962                   dl[0] << 
": bad format of source term data. "  3963                   "Detected dimension is " << s << 
" should be "  3966       GMM_TRACE2(
"Source term assembly");
  3972       if (dl.size() > 1) gmm::add(md.
real_variable(dl[1]), vecl[0]);
  3976                                       const model::varnamelist &,
  3977                                       const model::varnamelist &,
  3978                                       const model::mimlist &,
  3979                                       model::real_matlist &,
  3980                                       model::real_veclist &vecl,
  3981                                       model::real_veclist &,
  3983                                       build_version)
 const override  3985       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  3990                                    const model::varnamelist &vl,
  3991                                    const model::varnamelist &dl,
  3992                                    const model::mimlist &mims,
  3993                                    model::complex_matlist &,
  3994                                    model::complex_veclist &vecl,
  3995                                    model::complex_veclist &,
  3997                                    build_version)
 const override {
  3998       GMM_ASSERT1(vecl.size() == 1,
  3999                   "Source term brick has one and only one term");
  4000       GMM_ASSERT1(mims.size() == 1,
  4001                   "Source term brick need one and only one mesh_im");
  4002       GMM_ASSERT1(vl.size() == 1 && dl.size() > 0 && dl.size() <= 2,
  4003                   "Wrong number of variables for source term brick");
  4006       const mesh_im &mim = *mims[0];
  4015       GMM_ASSERT1(mf_u.get_qdim() == s, 
"Bad format of source term data");
  4017       GMM_TRACE2(
"Source term assembly");
  4026     void complex_post_assembly_in_serial(
const model &md,
  4028                                          const model::varnamelist &,
  4029                                          const model::varnamelist &,
  4030                                          const model::mimlist &,
  4031                                          model::complex_matlist &,
  4032                                          model::complex_veclist &vecl,
  4033                                          model::complex_veclist &,
  4034                                          size_type, build_version)
 const override  4036       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  4041     source_term_brick() {
  4042       set_flags(
"Source term", 
true ,
  4052                                   const std::string &varname,
  4053                                   const std::string &dataexpr,
  4055                                   const std::string &directdataname) {
  4057       pbrick pbr = std::make_shared<source_term_brick>();
  4059       tl.push_back(model::term_description(varname));
  4060       model::varnamelist vdata(1, dataexpr);
  4061       if (directdataname.size()) vdata.push_back(directdataname);
  4062       return md.
add_brick(pbr, model::varnamelist(1, varname),
  4063                           vdata, tl, model::mimlist(1, &mim), region);
  4065       std::string test_varname
  4066         = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  4071         expr = 
"("+dataexpr+
")*"+test_varname;
  4073         expr = 
"("+dataexpr+
")."+test_varname;
  4074       size_type ib = add_source_term_generic_assembly_brick
  4075         (md, mim, expr, region, 
"Source term", varname, directdataname, 
true);
  4078                                 "Source term (nonlinear)");
  4079         if (directdataname.size())
  4080           add_source_term_generic_assembly_brick
  4081             (md, mim, 
"", region, 
"Source term", varname, directdataname);
  4096                                 const model::varnamelist &vl,
  4097                                 const model::varnamelist &dl,
  4098                                 const model::mimlist &mims,
  4099                                 model::real_matlist &,
  4100                                 model::real_veclist &vecl,
  4101                                 model::real_veclist &,
  4103                                 build_version)
 const override {
  4104       GMM_ASSERT1(vecl.size() == 1,
  4105                   "Source term brick has one and only one term");
  4106       GMM_ASSERT1(mims.size() == 1,
  4107                   "Source term brick need one and only one mesh_im");
  4108       GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
  4109                   "Wrong number of variables for source term brick");
  4112       const mesh_im &mim = *mims[0];
  4118       size_type s = gmm::vect_size(A), N = mf_u.linked_mesh().dim();
  4121       GMM_ASSERT1(mf_u.get_qdim()*N == s,
  4122                   dl[0] << 
": bad format of normal source term data. "  4123                   "Detected dimension is " << s << 
" should be "  4126       GMM_TRACE2(
"source term assembly");
  4134                                       const model::varnamelist &,
  4135                                       const model::varnamelist &,
  4136                                       const model::mimlist &,
  4137                                       model::real_matlist &,
  4138                                       model::real_veclist &vecl,
  4139                                       model::real_veclist &,
  4141                                       build_version)
 const override {
  4142       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  4146     virtual void asm_complex_tangent_terms(
const model &md, 
size_type ,
  4147                                            const model::varnamelist &vl,
  4148                                            const model::varnamelist &dl,
  4149                                            const model::mimlist &mims,
  4150                                            model::complex_matlist &,
  4151                                            model::complex_veclist &vecl,
  4152                                            model::complex_veclist &,
  4154                                            build_version)
 const {
  4155       GMM_ASSERT1(vecl.size() == 1,
  4156                   "Source term brick has one and only one term");
  4157       GMM_ASSERT1(mims.size() == 1,
  4158                   "Source term brick need one and only one mesh_im");
  4159       GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
  4160                   "Wrong number of variables for source term brick");
  4163       const mesh_im &mim = *mims[0];
  4169       size_type s = gmm::vect_size(A), N = mf_u.linked_mesh().dim();
  4172       GMM_ASSERT1(s == mf_u.get_qdim()*N, 
"Bad format of source term data");
  4174       GMM_TRACE2(
"source term assembly");
  4181     void complex_post_assembly_in_serial(
const model &md, 
size_type ib,
  4182                                          const model::varnamelist &,
  4183                                          const model::varnamelist &,
  4184                                          const model::mimlist &,
  4185                                          model::complex_matlist &,
  4186                                          model::complex_veclist &vecl,
  4187                                          model::complex_veclist &,
  4189                                          build_version)
 const override {
  4190       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  4193     normal_source_term_brick() {
  4194       set_flags(
"Normal source term", 
true ,
  4204                                          const std::string &varname,
  4205                                          const std::string &dataexpr,
  4208       pbrick pbr = std::make_shared<normal_source_term_brick>();
  4210       tl.push_back(model::term_description(varname));
  4211       model::varnamelist vdata(1, dataexpr);
  4212       return md.
add_brick(pbr, model::varnamelist(1, varname),
  4213                           vdata, tl, model::mimlist(1, &mim), region);
  4215       std::string test_varname
  4216         = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  4221         expr = 
"(("+dataexpr+
").Normal)*"+test_varname;
  4223         expr = 
"(Reshape("+dataexpr+
",qdim("+varname
  4224           + 
"),meshdim)*Normal)."+test_varname;
  4225       return add_source_term_generic_assembly_brick
  4226         (md, mim, expr, region, 
"Source term");
  4242     bool normal_component; 
  4249     virtual void asm_real_tangent_terms(
const model &md, 
size_type ib,
  4250                                         const model::varnamelist &vl,
  4251                                         const model::varnamelist &dl,
  4252                                         const model::mimlist &mims,
  4253                                         model::real_matlist &matl,
  4254                                         model::real_veclist &vecl,
  4255                                         model::real_veclist &,
  4257                                         build_version version)
 const {
  4258       GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  4259                   "Dirichlet condition brick has one and only one term");
  4260       GMM_ASSERT1(mims.size() == 1,
  4261                   "Dirichlet condition brick need one and only one mesh_im");
  4262       GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 3,
  4263                   "Wrong number of variables for Dirichlet condition brick");
  4265       model_real_sparse_matrix& rB = rB_th;
  4266       model_real_plain_vector&  rV = rV_th;
  4268       bool penalized = (vl.size() == 1);
  4270       const mesh_fem &mf_mult = penalized ? (mf_mult_ ? *mf_mult_ : mf_u)
  4272       const mesh_im &mim = *mims[0];
  4273       const model_real_plain_vector *A = 0, *COEFF = 0, *H = 0;
  4274       const mesh_fem *mf_data = 0, *mf_H = 0;
  4275       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
  4276         || (penalized && md.is_var_newer_than_brick(dl[0], ib));
  4280         GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
  4281                     "Data for coefficient should be a scalar");
  4284       size_type s = 0, ind = (penalized ? 1 : 0);
  4285       if (dl.size() > ind) {
  4288         s = gmm::vect_size(*A);
  4291         GMM_ASSERT1(s == ss, dl[ind] << 
": bad format of "  4292                     "Dirichlet data. Detected dimension is " << s
  4293                     << 
" should be " << ss);
  4296       if (dl.size() > ind + 1) {
  4297         GMM_ASSERT1(H_version,
  4298                     "Wrong number of data for Dirichlet condition brick");
  4301         s = gmm::vect_size(*A);
  4303           s = s * mf_H->get_qdim() / mf_H->nb_dof();
  4304           GMM_ASSERT1(mf_H->get_qdim() == 1,  
"Implemented only for mf_H "  4305                       "a scalar finite element method");
  4307         GMM_ASSERT1(s = gmm::sqr(mf_u.
get_qdim()),
  4308                     dl[ind+1] << 
": bad format of Dirichlet data. "  4309                     "Detected dimension is " << s << 
" should be "  4316       if (recompute_matrix) {
  4317         model_real_sparse_matrix *B = &(matl[0]);
  4318         if (penalized && (&mf_mult != &mf_u)) {
  4323           gmm::clear(matl[0]);
  4325         GMM_TRACE2(
"Mass term assembly for Dirichlet condition");
  4326         if (H_version || normal_component) {
  4327           ga_workspace workspace;
  4328           gmm::sub_interval Imult(0, mf_mult.
nb_dof()), Iu(0, mf_u.
nb_dof());
  4329           base_vector u(mf_u.
nb_dof());
  4330           base_vector mult(mf_mult.
nb_dof());
  4331           workspace.add_fem_variable(
"u", mf_u, Iu, u);
  4332           workspace.add_fem_variable(
"mult", mf_mult, Imult, mult);
  4333           auto expression = std::string{};
  4335             if (mf_H) workspace.add_fem_constant(
"A", *mf_H, *H);
  4336             else workspace.add_fixed_size_constant(
"A", *H);
  4337             expression = (mf_u.
get_qdim() == 1) ?
  4338                           "Test_mult . (A . Test2_u)"  4340                           "Test_mult. (Reshape(A, qdim(u), qdim(u)) . Test2_u)";
  4341           } 
else if (normal_component) {
  4342             expression = 
"Test_mult . (Test2_u . Normal)";
  4344           workspace.add_expression(expression, mim, rg);
  4345           workspace.set_assembled_matrix(*B);
  4346           workspace.assembly(2);
  4351         if (penalized && (&mf_mult != &mf_u)) {
  4352           GMM_ASSERT1(MPI_IS_MASTER(), 
"Sorry, the penalized option "  4353                       "filtered by a multiplier space is not parallelized");
  4354           gmm::mult(gmm::transposed(rB), rB, matl[0]);
  4355           gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
  4356         } 
else if (penalized) {
  4357           gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
  4361       if (dl.size() > ind) {
  4362         GMM_TRACE2(
"Source term assembly for Dirichlet condition");
  4364         if (penalized && (&mf_mult != &mf_u)) {
  4365           gmm::resize(rV, mf_mult.
nb_dof());
  4378         if (penalized && (&mf_mult != &mf_u))  {
  4379           gmm::mult(gmm::transposed(rB), rV, vecl[0]);
  4380           gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
  4381           rV = model_real_plain_vector();
  4382         } 
else if (penalized)
  4383           gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
  4389                                       const model::varnamelist &,
  4390                                       const model::varnamelist &,
  4391                                       const model::mimlist &,
  4392                                       model::real_matlist &,
  4393                                       model::real_veclist &vecl,
  4394                                       model::real_veclist &,
  4396                                       build_version)
 const override {
  4397       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  4400     virtual void asm_complex_tangent_terms(
const model &md, 
size_type ib,
  4401                                            const model::varnamelist &vl,
  4402                                            const model::varnamelist &dl,
  4403                                            const model::mimlist &mims,
  4404                                            model::complex_matlist &matl,
  4405                                            model::complex_veclist &vecl,
  4406                                            model::complex_veclist &,
  4408                                            build_version version)
 const {
  4409       GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  4410                   "Dirichlet condition brick has one and only one term");
  4411       GMM_ASSERT1(mims.size() == 1,
  4412                   "Dirichlet condition brick need one and only one mesh_im");
  4413       GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 3,
  4414                   "Wrong number of variables for Dirichlet condition brick");
  4416       model_complex_sparse_matrix& cB = cB_th;
  4417       model_complex_plain_vector&  cV = cV_th;
  4419       bool penalized = (vl.size() == 1);
  4421       const mesh_fem &mf_mult = penalized ? (mf_mult_ ? *mf_mult_ : mf_u)
  4423       const mesh_im &mim = *mims[0];
  4424       const model_complex_plain_vector *A = 0, *COEFF = 0, *H = 0;
  4425       const mesh_fem *mf_data = 0, *mf_H = 0;
  4426       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
  4427         || (penalized && md.is_var_newer_than_brick(dl[0], ib));
  4431         GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
  4432                     "Data for coefficient should be a scalar");
  4435       size_type s = 0, ind = (penalized ? 1 : 0);
  4436       if (dl.size() > ind) {
  4439         s = gmm::vect_size(*A);
  4443                     dl[ind] << 
": bad format of Dirichlet data. "  4444                     "Detected dimension is " << ss << 
" should be "  4448       if (dl.size() > ind + 1) {
  4449         GMM_ASSERT1(H_version,
  4450                     "Wrong number of data for Dirichlet condition brick");
  4453         s = gmm::vect_size(*A);
  4455           s = s * mf_H->get_qdim() / mf_H->nb_dof();
  4456           GMM_ASSERT1(mf_H->get_qdim() == 1,  
"Implemented only for mf_H "  4457                       "a scalar finite element method");
  4459         GMM_ASSERT1(s = gmm::sqr(mf_u.
get_qdim()),
  4460                     dl[ind+1] << 
": bad format of Dirichlet data. "  4461                     "Detected dimension is " << s << 
" should be "  4468       if (recompute_matrix) {
  4469         model_complex_sparse_matrix *B = &(matl[0]);
  4470         if (penalized && (&mf_mult != &mf_u)) {
  4475           gmm::clear(matl[0]);
  4477         GMM_TRACE2(
"Mass term assembly for Dirichlet condition");
  4480             asm_real_or_complex_1_param_mat(*B, mim, mf_mult, mf_H, *H, rg,
  4481                                             "(A*Test_u).Test2_u");
  4483             asm_real_or_complex_1_param_mat(*B, mim, mf_mult, mf_H, *H, rg,
  4484                             "(Reshape(A,qdim(u),qdim(u))*Test2_u).Test_u");
  4500         else if (normal_component) {
  4501           ga_workspace workspace;
  4502           gmm::sub_interval Imult(0, mf_mult.
nb_dof()), Iu(0, mf_u.
nb_dof());
  4504           workspace.add_fem_variable(
"mult", mf_mult, Imult, mult);
  4505           workspace.add_fem_variable(
"u", mf_u, Iu, u);
  4506           workspace.add_expression(
"Test_mult.(Test2_u.Normal)", mim, rg);
  4507           model_real_sparse_matrix BB(mf_mult.
nb_dof(), mf_u.
nb_dof());
  4508           workspace.set_assembled_matrix(BB);
  4509           workspace.assembly(2);
  4525         if (penalized && (&mf_mult != &mf_u)) {
  4526           gmm::mult(gmm::transposed(cB), cB, matl[0]);
  4527           gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
  4528         } 
else if (penalized) {
  4529           gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
  4533       if (dl.size() > ind) {
  4534         GMM_TRACE2(
"Source term assembly for Dirichlet condition");
  4536         if (penalized && (&mf_mult != &mf_u)) {
  4537           gmm::resize(cV, mf_mult.
nb_dof());
  4550         if (penalized && (&mf_mult != &mf_u))  {
  4551           gmm::mult(gmm::transposed(cB), cV, vecl[0]);
  4552           gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
  4553           cV = model_complex_plain_vector();
  4554         } 
else if (penalized)
  4555           gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
  4559     void complex_post_assembly_in_serial(
const model &md, 
size_type ib,
  4560                                          const model::varnamelist &,
  4561                                          const model::varnamelist &,
  4562                                          const model::mimlist &,
  4563                                          model::complex_matlist &,
  4564                                          model::complex_veclist &vecl,
  4565                                          model::complex_veclist &,
  4567                                          build_version)
 const override {
  4568       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  4572     virtual std::string declare_volume_assembly_string
  4574      const model::varnamelist &)
 const {
  4575       return std::string();
  4578     Dirichlet_condition_brick(
bool penalized, 
bool H_version_,
  4579                               bool normal_component_,
  4581       mf_mult_ = mf_mult__;
  4582       H_version = H_version_;
  4583       normal_component = normal_component_;
  4584       GMM_ASSERT1(!(H_version && normal_component), 
"Bad Dirichlet version");
  4585       set_flags(penalized ? 
"Dirichlet with penalization brick"  4586                           : 
"Dirichlet with multipliers brick",
  4596    const std::string &multname, 
size_type region,
  4597    const std::string &dataname) {
  4598     pbrick pbr = std::make_shared<Dirichlet_condition_brick>(
false,
false,
false);
  4600     tl.push_back(model::term_description(multname, varname, 
true));
  4601     model::varnamelist vl(1, varname);
  4602     vl.push_back(multname);
  4603     model::varnamelist dl;
  4604     if (dataname.size()) dl.push_back(dataname);
  4605     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  4611    const std::string &dataname) {
  4612     std::string multname = md.
new_name(
"mult_on_" + varname);
  4615       (md, mim, varname, multname, region, dataname);
  4621    const std::string &dataname) {
  4626       (md, mim, varname, mf_mult, region, dataname);
  4635    scalar_type penalisation_coeff, 
size_type region,
  4636    const std::string &dataname, 
const mesh_fem *mf_mult) {
  4637     std::string coeffname = md.
new_name(
"penalization_on_" + varname);
  4643     pbrick pbr = std::make_shared<Dirichlet_condition_brick>
  4644       (
true, 
false, 
false, mf_mult);
  4646     tl.push_back(model::term_description(varname, varname, 
true));
  4647     model::varnamelist vl(1, varname);
  4648     model::varnamelist dl(1, coeffname);
  4649     if (dataname.size()) dl.push_back(dataname);
  4650     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  4655    const std::string &multname, 
size_type region,
  4656    const std::string &dataname) {
  4657     pbrick pbr = std::make_shared<Dirichlet_condition_brick>(
false,
false,
true);
  4659     tl.push_back(model::term_description(multname, varname, 
true));
  4660     model::varnamelist vl(1, varname);
  4661     vl.push_back(multname);
  4662     model::varnamelist dl;
  4663     if (dataname.size()) dl.push_back(dataname);
  4664     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  4670    const std::string &dataname) {
  4671     std::string multname = md.
new_name(
"mult_on_" + varname);
  4674       (md, mim, varname, multname, region, dataname);
  4680    const std::string &dataname) {
  4684       (md, mim, varname, mf_mult, region, dataname);
  4689    scalar_type penalisation_coeff, 
size_type region,
  4690    const std::string &dataname, 
const mesh_fem *mf_mult) {
  4691     std::string coeffname = md.
new_name(
"penalization_on_" + varname);
  4697     pbrick pbr = std::make_shared<Dirichlet_condition_brick>
  4698       (
true, 
false, 
true, mf_mult);
  4700     tl.push_back(model::term_description(varname, varname, 
true));
  4701     model::varnamelist vl(1, varname);
  4702     model::varnamelist dl(1, coeffname);
  4703     if (dataname.size()) dl.push_back(dataname);
  4704     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  4710    const std::string &multname, 
size_type region,
  4711    const std::string &dataname, 
const std::string &Hname) {
  4712     pbrick pbr = std::make_shared<Dirichlet_condition_brick>(
false,
true,
false);
  4714     tl.push_back(model::term_description(multname, varname, 
true));
  4715     model::varnamelist vl(1, varname);
  4716     vl.push_back(multname);
  4717     model::varnamelist dl;
  4718     dl.push_back(dataname);
  4719     dl.push_back(Hname);
  4720     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  4726    const std::string &dataname, 
const std::string &Hname) {
  4727     std::string multname = md.
new_name(
"mult_on_" + varname);
  4730       (md, mim, varname, multname, region, dataname, Hname);
  4736    const std::string &dataname, 
const std::string &Hname) {
  4741       (md, mim, varname, mf_mult, region, dataname, Hname);
  4746    scalar_type penalisation_coeff, 
size_type region,
  4747    const std::string &dataname, 
const std::string &Hname,
  4749     std::string coeffname = md.
new_name(
"penalization_on_" + varname);
  4755     pbrick pbr = std::make_shared<Dirichlet_condition_brick>
  4756       (
true, 
true, 
false, mf_mult);
  4758     tl.push_back(model::term_description(varname, varname, 
true));
  4759     model::varnamelist vl(1, varname);
  4760     model::varnamelist dl(1, coeffname);
  4761     dl.push_back(dataname);
  4762     dl.push_back(Hname);
  4763     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  4767                                  scalar_type penalisation_coeff) {
  4771       GMM_ASSERT1(gmm::vect_size(d)==1,
  4772                   "Wrong coefficient size, may be not a Dirichlet brick "  4773                   "with penalization");
  4774       d[0] = penalisation_coeff;
  4778       GMM_ASSERT1(gmm::vect_size(d)==1,
  4779                   "Wrong coefficient size, may be not a Dirichlet brick "  4780                   "with penalization");
  4781       d[0] = penalisation_coeff;
  4791   struct simplification_Dirichlet_condition_brick : 
public virtual_brick {
  4794                                         const model::varnamelist &vl,
  4795                                         const model::varnamelist &dl,
  4796                                         const model::mimlist &mims,
  4797                                         model::real_matlist &matl,
  4798                                         model::real_veclist &vecl,
  4799                                         model::real_veclist &,
  4801                                         build_version )
 const {
  4802       if (MPI_IS_MASTER()) {
  4804         GMM_ASSERT1(vecl.size() == 0 && matl.size() == 0,
  4805                     "Dirichlet condition brick by simplification has no term");
  4806         GMM_ASSERT1(mims.size() == 0,
  4807                     "Dirichlet condition brick by simplification need no "  4809         GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
  4810                     "Wrong number of variables for Dirichlet condition brick "  4811                     "by simplification");
  4814         const model_real_plain_vector *A = 0;
  4818         if (dl.size() == 1) {
  4823             GMM_ASSERT1(mf_data == &mf_u, 
"Sorry, for this brick, the data has"  4824                         " to be defined on the same f.e.m. as the unknown");
  4826             s = gmm::vect_size(*A);
  4827             GMM_ASSERT1(mf_u.get_qdim() == s, 
": bad format of "  4828                         "Dirichlet data. Detected dimension is " << s
  4829                         << 
" should be " << 
size_type(mf_u.get_qdim()));
  4836         if (mf_u.get_qdim() > 1 || (!mf_data && A)) {
  4837           for (
mr_visitor i(rg, mf_u.linked_mesh()); !i.finished(); ++i) {
  4838             pfem pf = mf_u.fem_of_element(i.cv());
  4840               GMM_ASSERT1(pf->target_dim() == 1,
  4841                           "Intrinsically vectorial fems are not allowed");
  4842               GMM_ASSERT1(mf_data || pf->is_lagrange(), 
"Constant Dirichlet "  4843                           "data allowed for lagrange fems only");
  4848         dal::bit_vector dofs = mf_u.dof_on_region(rg);
  4850         if (A && !mf_data) {
  4851           GMM_ASSERT1(dofs.card() % s == 0, 
"Problem with dof vectorization");
  4854         for (dal::bv_visitor i(dofs); !i.finished(); ++i) {
  4856           if (A) val = (mf_data ? (*A)[i] :  (*A)[i%s]);
  4857           md.add_real_dof_constraint(vl[0], i, val);
  4862     virtual void asm_complex_tangent_terms(
const model &md, 
size_type ,
  4863                                            const model::varnamelist &vl,
  4864                                            const model::varnamelist &dl,
  4865                                            const model::mimlist &mims,
  4866                                            model::complex_matlist &matl,
  4867                                            model::complex_veclist &vecl,
  4868                                            model::complex_veclist &,
  4870                                            build_version )
 const {
  4871       if (MPI_IS_MASTER()) {
  4872         GMM_ASSERT1(vecl.size() == 0 && matl.size() == 0,
  4873                     "Dirichlet condition brick by simplification has no term");
  4874         GMM_ASSERT1(mims.size() == 0,
  4875                     "Dirichlet condition brick by simplification need no "  4877         GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
  4878                     "Wrong number of variables for Dirichlet condition brick "  4879                     "by simplification");
  4882         const model_complex_plain_vector *A = 0;
  4886         if (dl.size() == 1) {
  4891             GMM_ASSERT1(mf_data == &mf_u, 
"Sorry, for this brick, the data has"  4892                         " to be define on the same f.e.m. than the unknown");
  4894             s = gmm::vect_size(*A);
  4895             GMM_ASSERT1(mf_u.get_qdim() == s, 
": bad format of "  4896                         "Dirichlet data. Detected dimension is " << s
  4897                         << 
" should be " << 
size_type(mf_u.get_qdim()));
  4904         if (mf_u.get_qdim() > 1 || (!mf_data && A)) {
  4905           for (
mr_visitor i(rg, mf_u.linked_mesh()); !i.finished(); ++i) {
  4906             pfem pf = mf_u.fem_of_element(i.cv());
  4908               GMM_ASSERT1(pf->target_dim() == 1,
  4909                           "Intrinsically vectorial fems are not allowed");
  4910               GMM_ASSERT1(mf_data || pf->is_lagrange(), 
"Constant Dirichlet "  4911                           "data allowed for lagrange fems only");
  4916         dal::bit_vector dofs = mf_u.dof_on_region(rg);
  4918         if (A && !mf_data) {
  4919           GMM_ASSERT1(dofs.card() % s == 0, 
"Problem with dof vectorization");
  4922         for (dal::bv_visitor i(dofs); !i.finished(); ++i) {
  4923           complex_type val(0);
  4924           if (A) val = (mf_data ? (*A)[i] :  (*A)[i%s]);
  4925           md.add_complex_dof_constraint(vl[0], i, val);
  4931     virtual std::string declare_volume_assembly_string
  4933      const model::varnamelist &)
 const {
  4934       return std::string();
  4937     simplification_Dirichlet_condition_brick() {
  4938       set_flags(
"Dirichlet with simplification brick",
  4948    size_type region, 
const std::string &dataname) {
  4949     pbrick pbr = std::make_shared<simplification_Dirichlet_condition_brick>();
  4951     model::varnamelist vl(1, varname);
  4952     model::varnamelist dl;
  4953     if (dataname.size()) dl.push_back(dataname);
  4954     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(), region);
  4965    const std::string &Neumannterm,
  4966    const std::string &datagamma0, 
size_type region, scalar_type theta_,
  4967    const std::string &datag) {
  4969     std::string theta = std::to_string(theta_);
  4970     ga_workspace workspace(md, 
true);
  4971     size_type order = workspace.add_expression(Neumannterm, mim, region, 1);
  4972     GMM_ASSERT1(order == 0, 
"Wrong expression of the Neumann term");
  4973     model::varnamelist vl, vl_test1, vl_test2, dl;
  4974     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 1);
  4976     std::string condition = 
"("+varname + (datag.size() ? 
"-("+datag+
"))":
")");
  4977     std::string gamma = 
"(("+datagamma0+
")*element_size)";
  4978     std::string r = 
"(1/"+gamma+
")";
  4979     std::string expr = 
"("+r+
"*"+condition+
"-("+Neumannterm+
")).Test_"+varname;
  4980     if (theta_ != scalar_type(0)) {
  4981       std::string derivative_Neumann = workspace.extract_order1_term(varname);
  4982       if (derivative_Neumann.size())
  4983         expr+=
"-"+theta+
"*"+condition+
".("+derivative_Neumann+
")";
  4991                              "Dirichlet condition with Nitsche's method");
  4994                                 "Dirichlet condition with Nitsche's method");
  5000    const std::string &Neumannterm,
  5001    const std::string &datagamma0, 
size_type region, scalar_type theta_,
  5002    const std::string &datag) {
  5003     std::string theta = std::to_string(theta_);
  5004     ga_workspace workspace(md, 
true);
  5005     size_type order = workspace.add_expression(Neumannterm, mim, region, 1);
  5006     GMM_ASSERT1(order == 0, 
"Wrong expression of the Neumann term");
  5007     model::varnamelist vl, vl_test1, vl_test2, dl;
  5008     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 1);
  5010     std::string condition = 
"("+varname+
".Normal"  5011       + (datag.size() ? 
"-("+datag+
"))":
")");
  5012     std::string gamma = 
"(("+datagamma0+
")*element_size)";
  5013     std::string r = 
"(1/"+gamma+
")";
  5014     std::string expr = 
"("+r+
"*"+condition+
"-Normal.("+Neumannterm
  5015       +
"))*(Normal.Test_"+varname+
")";
  5016     if (theta_ != scalar_type(0)) {
  5017       std::string derivative_Neumann = workspace.extract_order1_term(varname);
  5018       if (derivative_Neumann.size())
  5019         expr+=
"-"+theta+
"*"+condition+
"*Normal.("  5020           +derivative_Neumann+
")";
  5024                              "Dirichlet condition with Nitsche's method");
  5027                                 "Dirichlet condition with Nitsche's method");
  5033    const std::string &Neumannterm,
  5034    const std::string &datagamma0, 
size_type region, scalar_type theta_,
  5035    const std::string &datag, 
const std::string &dataH) {
  5036     std::string theta = std::to_string(theta_);
  5037     ga_workspace workspace(md, 
true);
  5038     size_type order = workspace.add_expression(Neumannterm, mim, region, 1);
  5039     GMM_ASSERT1(order == 0, 
"Wrong expression of the Neumann term");
  5040     model::varnamelist vl, vl_test1, vl_test2, dl;
  5041     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 1);
  5043     std::string condition = 
"(("+dataH+
")*"+varname
  5044       + (datag.size() ? 
"-("+datag+
"))":
")");
  5045     std::string gamma = 
"(("+datagamma0+
")*element_size)";
  5046     std::string r = 
"(1/"+gamma+
")";
  5047     std::string expr = 
"("+r+
"*"+condition+
"-("+dataH+
")*("+Neumannterm
  5048       +
"))*(("+dataH+
")*Test_"+varname+
")";
  5049     if (theta_ != scalar_type(0)) {
  5050       std::string derivative_Neumann = workspace.extract_order1_term(varname);
  5051       if (derivative_Neumann.size())
  5052         expr+=
"-"+theta+
"*"+condition+
"*(("+dataH+
")*("  5053           +derivative_Neumann+
"))";
  5057                              "Dirichlet condition with Nitsche's method");
  5060                                 "Dirichlet condition with Nitsche's method");
  5074     mutable gmm::row_matrix<model_real_sparse_vector> rB;
  5075     mutable gmm::row_matrix<model_complex_sparse_vector> cB;
  5077     virtual void  real_pre_assembly_in_serial(
const model &md, 
size_type ib,
  5078                                         const model::varnamelist &vl,
  5079                                         const model::varnamelist &dl,
  5080                                         const model::mimlist &mims,
  5081                                         model::real_matlist &matl,
  5082                                         model::real_veclist &vecl,
  5083                                         model::real_veclist &,
  5085                                         build_version version)
 const {
  5086       if (MPI_IS_MASTER()) {
  5088         GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5089                     "Pointwize constraints brick has only one term");
  5090         GMM_ASSERT1(mims.size() == 0,
  5091                     "Pointwize constraints brick does not need a mesh_im");
  5092         GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2,
  5093                   "Wrong number of variables for pointwize constraints brick");
  5094         bool penalized = (vl.size() == 1);
  5098         GMM_ASSERT1(dl.size() == dlsize || dl.size() == dlsize+1,
  5099                     "Wrong number of data for pointwize constraints brick");
  5102         const model_real_plain_vector *COEFF = 0;
  5106           GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
  5107                       "Data for coefficient should be a scalar");
  5110         const model_real_plain_vector &PT = md.
real_variable(dl[ind_pt]);
  5111         size_type nb_co = gmm::vect_size(PT) / N;
  5113         dim_type ind_unitv = dim_type((Q > 1) ? ind_pt+1 : 0);
  5114         const model_real_plain_vector &unitv =md.
real_variable(dl[ind_unitv]);
  5115         GMM_ASSERT1((!ind_unitv || gmm::vect_size(unitv) == nb_co * Q),
  5116                     "Wrong size for vector of unit vectors");
  5118         dim_type ind_rhs = dim_type((Q > 1) ? ind_pt+2 : ind_pt+1);
  5119         if (dl.size() < 
size_type(ind_rhs + 1)) ind_rhs = 0;
  5120         const model_real_plain_vector &rhs =  md.
real_variable(dl[ind_rhs]);
  5121         GMM_ASSERT1((!ind_rhs || gmm::vect_size(rhs) == nb_co),
  5122                     "Wrong size for vector of rhs");
  5124         bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
  5125           || (penalized && (md.is_var_newer_than_brick(dl[ind_pt], ib)
  5126                             || md.is_var_newer_than_brick(dl[ind_unitv], ib)
  5127                             || md.is_var_newer_than_brick(dl[ind_rhs], ib)));
  5129         if (recompute_matrix) {
  5130           gmm::row_matrix<model_real_sparse_vector> BB(nb_co*Q, mf_u.
nb_dof());
  5131           gmm::clear(rB); gmm::resize(rB, nb_co, mf_u.
nb_dof());
  5133           dal::bit_vector dof_untouched;
  5137             gmm::copy(gmm::sub_vector(PT, gmm::sub_interval(i*N, N)), pt);
  5140           gmm::row_matrix<model_real_sparse_vector> &BBB = ((Q > 1) ? BB : rB);
  5141           model_real_plain_vector vv;
  5142           interpolation(mf_u, mti, vv, vv, BBB,  1, 1, &dof_untouched);
  5143           GMM_ASSERT1(dof_untouched.card() == 0,
  5144                       "Pointwize constraints : some of the points are outside "  5145                       "the mesh: " << dof_untouched);
  5150                 gmm::add(gmm::scaled(gmm::mat_row(BB, i*Q+q), unitv[i*Q+q]),
  5151                          gmm::mat_row(rB, i));
  5154           gmm::mult(gmm::transposed(rB), rB, matl[0]);
  5155           gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
  5157             gmm::copy(rB, matl[0]);
  5162             gmm::mult(gmm::transposed(rB), rhs, vecl[0]);
  5163             gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
  5165           else gmm::copy(rhs, vecl[0]);
  5167         else gmm::clear(vecl[0]);
  5171     virtual void complex_pre_assembly_in_serial(
const model &md, 
size_type ib,
  5172                                            const model::varnamelist &vl,
  5173                                            const model::varnamelist &dl,
  5174                                            const model::mimlist &mims,
  5175                                            model::complex_matlist &matl,
  5176                                            model::complex_veclist &vecl,
  5177                                            model::complex_veclist &,
  5179                                            build_version version)
 const {
  5180       if (MPI_IS_MASTER()) {
  5181         GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5182                     "Pointwize constraints brick only one term");
  5183         GMM_ASSERT1(mims.size() == 0,
  5184                     "Pointwize constraints brick does not need a mesh_im");
  5185         GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2,
  5186                   "Wrong number of variables for pointwize constraints brick");
  5187         bool penalized = (vl.size() == 1);
  5191         GMM_ASSERT1(dl.size() == dlsize || dl.size() == dlsize+1,
  5192                     "Wrong number of data for pointwize constraints brick");
  5195         const model_complex_plain_vector *COEFF = 0;
  5199           GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
  5200                       "Data for coefficient should be a scalar");
  5204         size_type nb_co = gmm::vect_size(PT) / N;
  5206         dim_type ind_unitv = dim_type((Q > 1) ? ind_pt+1 : 0);
  5207         const model_complex_plain_vector &unitv
  5209         GMM_ASSERT1((!ind_unitv || gmm::vect_size(unitv) == nb_co * Q),
  5210                     "Wrong size for vector of unit vectors");
  5212         dim_type ind_rhs = dim_type((Q > 1) ? ind_pt+2 : ind_pt+1);
  5213         if (dl.size() < 
size_type(ind_rhs + 1)) ind_rhs = 0;
  5214         const model_complex_plain_vector &rhs
  5216         GMM_ASSERT1((!ind_rhs || gmm::vect_size(rhs) == nb_co),
  5217                     "Wrong size for vector of rhs");
  5219         bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
  5220           || (penalized && (md.is_var_newer_than_brick(dl[ind_pt], ib)
  5221                             || md.is_var_newer_than_brick(dl[ind_unitv], ib)
  5222                             || md.is_var_newer_than_brick(dl[ind_rhs], ib)));
  5224         if (recompute_matrix) {
  5225           gmm::row_matrix<model_complex_sparse_vector>
  5226             BB(nb_co*Q,mf_u.
nb_dof());
  5227           gmm::clear(cB); gmm::resize(cB, nb_co, mf_u.
nb_dof());
  5228           dal::bit_vector dof_untouched;
  5232             gmm::copy(gmm::real_part
  5233                       (gmm::sub_vector(PT, gmm::sub_interval(i*N, N))), pt);
  5236           gmm::row_matrix<model_complex_sparse_vector> &BBB = ((Q > 1) ? BB :cB);
  5237           model_complex_plain_vector vv;
  5238           interpolation(mf_u, mti, vv, vv, BBB,  1, 1, &dof_untouched);
  5239           GMM_ASSERT1(dof_untouched.card() == 0,
  5240                       "Pointwize constraints : some of the points are outside "  5241                       "the mesh: " << dof_untouched);
  5246                 gmm::add(gmm::scaled(gmm::mat_row(BB, i*Q+q), unitv[i*Q+q]),
  5247                          gmm::mat_row(cB, i));
  5251             gmm::mult(gmm::transposed(cB), cB, matl[0]);
  5252             gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
  5254             gmm::copy(cB, matl[0]);
  5260             gmm::mult(gmm::transposed(cB), rhs, vecl[0]);
  5261             gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
  5263           else gmm::copy(rhs, vecl[0]);
  5265         else gmm::clear(vecl[0]);
  5269     virtual std::string declare_volume_assembly_string
  5271      const model::varnamelist &)
 const {
  5272       return std::string();
  5275     pointwise_constraints_brick(
bool penalized) {
  5276       set_flags(penalized ? 
"Pointwise cosntraints with penalization brick"  5277                           : 
"Pointwise cosntraints with multipliers brick",
  5288    scalar_type penalisation_coeff, 
const std::string &dataname_pt,
  5289    const std::string &dataname_unitv, 
const std::string &dataname_val) {
  5290     std::string coeffname = md.
new_name(
"penalization_on_" + varname);
  5296     pbrick pbr = std::make_shared<pointwise_constraints_brick>(
true);
  5298     tl.push_back(model::term_description(varname, varname, 
true));
  5299     model::varnamelist vl(1, varname);
  5300     model::varnamelist dl(1, coeffname);
  5301     dl.push_back(dataname_pt);
  5303     if (mf_u.
get_qdim() > 1) dl.push_back(dataname_unitv);
  5304     if (dataname_val.size() > 0) dl.push_back(dataname_val);
  5310    const std::string &multname, 
const std::string &dataname_pt,
  5311    const std::string &dataname_unitv, 
const std::string &dataname_val) {
  5312     pbrick pbr = std::make_shared<pointwise_constraints_brick>(
false);
  5314     tl.push_back(model::term_description(multname, varname, 
true));
  5315     model::varnamelist vl(1, varname);
  5316     vl.push_back(multname);
  5317     model::varnamelist dl(1, dataname_pt);
  5319     if (mf_u.
get_qdim() > 1) dl.push_back(dataname_unitv);
  5320     if (dataname_val.size() > 0) dl.push_back(dataname_val);
  5325   (
model &md, 
const std::string &varname, 
const std::string &dataname_pt,
  5326    const std::string &dataname_unitv, 
const std::string &dataname_val) {
  5327     std::string multname = md.
new_name(
"mult_on_" + varname);
  5335       (md, varname, multname, dataname_pt, dataname_unitv, dataname_val);
  5348                                         const model::varnamelist &vl,
  5349                                         const model::varnamelist &dl,
  5350                                         const model::mimlist &mims,
  5351                                         model::real_matlist &matl,
  5352                                         model::real_veclist &,
  5353                                         model::real_veclist &,
  5355                                         build_version)
 const {
  5356       GMM_ASSERT1(matl.size() == 1,
  5357                   "Helmholtz brick has one and only one term");
  5358       GMM_ASSERT1(mims.size() == 1,
  5359                   "Helmholtz brick need one and only one mesh_im");
  5360       GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
  5361                   "Wrong number of variables for Helmholtz brick");
  5364       const mesh &m = mf_u.linked_mesh();
  5366       GMM_ASSERT1(Q == 1, 
"Helmholtz brick is only for scalar field, sorry.");
  5367       const mesh_im &mim = *mims[0];
  5370       m.intersect_with_mpi_region(rg);
  5371       const model_real_plain_vector *A = &(md.
real_variable(dl[0]));
  5373       s = gmm::vect_size(*A);
  5377         GMM_TRACE2(
"Stiffness matrix assembly for Helmholtz problem");
  5378         gmm::clear(matl[0]);
  5379         model_real_plain_vector A2(gmm::vect_size(*A));
  5380         for (
size_type i=0; i < gmm::vect_size(*A); ++i) 
  5381           A2[i] = gmm::sqr((*A)[i]); 
  5387         GMM_ASSERT1(
false, 
"Bad format Helmholtz brick coefficient");
  5390     virtual void asm_complex_tangent_terms(
const model &md, 
size_type,
  5391                                            const model::varnamelist &vl,
  5392                                            const model::varnamelist &dl,
  5393                                            const model::mimlist &mims,
  5394                                            model::complex_matlist &matl,
  5395                                            model::complex_veclist &,
  5396                                            model::complex_veclist &,
  5398                                            build_version)
 const {
  5399       GMM_ASSERT1(matl.size() == 1,
  5400                   "Helmholtz brick has one and only one term");
  5401       GMM_ASSERT1(mims.size() == 1,
  5402                   "Helmholtz brick need one and only one mesh_im");
  5403       GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
  5404                   "Wrong number of variables for Helmholtz brick");
  5407       const mesh &m = mf_u.linked_mesh();
  5409       GMM_ASSERT1(Q == 1, 
"Helmholtz brick is only for scalar field, sorry.");
  5410       const mesh_im &mim = *mims[0];
  5413       m.intersect_with_mpi_region(rg);
  5416       s = gmm::vect_size(*A);
  5420         GMM_TRACE2(
"Stiffness matrix assembly for Helmholtz problem");
  5421         gmm::clear(matl[0]);
  5422         model_complex_plain_vector A2(gmm::vect_size(*A));
  5423         for (
size_type i=0; i < gmm::vect_size(*A); ++i) 
  5424           A2[i] = gmm::sqr((*A)[i]); 
  5430         GMM_ASSERT1(
false, 
"Bad format Helmholtz brick coefficient");
  5434       set_flags(
"Helmholtz", 
true ,
  5442                                 const std::string &varname,
  5443                                 const std::string &dataexpr,
  5446       pbrick pbr = std::make_shared<Helmholtz_brick>();
  5448       tl.push_back(model::term_description(varname, varname, 
true));
  5449       return md.
add_brick(pbr, model::varnamelist(1, varname),
  5450                           model::varnamelist(1, dataexpr), tl,
  5451                           model::mimlist(1, &mim), region);
  5453       std::string test_varname
  5454         = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  5455       std::string expr = 
"Grad_"+varname+
".Grad_"+test_varname
  5456         +
" + sqr("+dataexpr+
")*"+varname+
"*"+test_varname;
  5462                                  "Helmholtz (nonlinear)");
  5478                                         const model::varnamelist &vl,
  5479                                         const model::varnamelist &dl,
  5480                                         const model::mimlist &mims,
  5481                                         model::real_matlist &matl,
  5482                                         model::real_veclist &,
  5483                                         model::real_veclist &,
  5485                                         build_version)
 const {
  5486       GMM_ASSERT1(matl.size() == 1,
  5487                   "Fourier-Robin brick has one and only one term");
  5488       GMM_ASSERT1(mims.size() == 1,
  5489                   "Fourier-Robin brick need one and only one mesh_im");
  5490       GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
  5491                   "Wrong number of variables for Fourier-Robin brick");
  5494       const mesh &m = mf_u.linked_mesh();
  5496       const mesh_im &mim = *mims[0];
  5499       m.intersect_with_mpi_region(rg);
  5500       const model_real_plain_vector *A = &(md.
real_variable(dl[0]));
  5502       s = gmm::vect_size(*A);
  5504       GMM_ASSERT1(s == Q*Q,
  5505                   "Bad format Fourier-Robin brick coefficient");
  5507       GMM_TRACE2(
"Fourier-Robin term assembly");
  5508       gmm::clear(matl[0]);
  5512         asm_homogeneous_qu_term(matl[0], mim, mf_u, *A, rg);
  5515     virtual void asm_complex_tangent_terms(
const model &md, 
size_type,
  5516                                            const model::varnamelist &vl,
  5517                                            const model::varnamelist &dl,
  5518                                            const model::mimlist &mims,
  5519                                            model::complex_matlist &matl,
  5520                                            model::complex_veclist &,
  5521                                            model::complex_veclist &,
  5523                                            build_version)
 const {
  5524       GMM_ASSERT1(matl.size() == 1,
  5525                   "Fourier-Robin brick has one and only one term");
  5526       GMM_ASSERT1(mims.size() == 1,
  5527                   "Fourier-Robin brick need one and only one mesh_im");
  5528       GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
  5529                   "Wrong number of variables for Fourier-Robin brick");
  5532       const mesh &m = mf_u.linked_mesh();
  5534       const mesh_im &mim = *mims[0];
  5537       m.intersect_with_mpi_region(rg);
  5540       s = gmm::vect_size(*A);
  5542       GMM_ASSERT1(s == Q*Q,
  5543                   "Bad format Fourier-Robin brick coefficient");
  5545       GMM_TRACE2(
"Fourier-Robin term assembly");
  5546       gmm::clear(matl[0]);
  5550         asm_homogeneous_qu_term(matl[0], mim, mf_u, *A, rg);
  5553     Fourier_Robin_brick() {
  5554       set_flags(
"Fourier Robin condition", 
true ,
  5563                                     const std::string &varname,
  5564                                     const std::string &dataexpr,
  5567       pbrick pbr = std::make_shared<Fourier_Robin_brick>();
  5569       tl.push_back(model::term_description(varname, varname, 
true));
  5570       return md.
add_brick(pbr, model::varnamelist(1, varname),
  5571                           model::varnamelist(1, dataexpr), tl,
  5572                           model::mimlist(1, &mim), region);
  5574       std::string test_varname
  5575         = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  5576       std::string expr = 
"(("+dataexpr+
")*"+varname+
")."+test_varname;
  5578                                      "Fourier-Robin", 
true);
  5581                                 "Fourier-Robin (nonlinear)");
  5594     model_real_sparse_matrix rB;
  5595     model_complex_sparse_matrix cB;
  5596     model_real_plain_vector rL;
  5597     model_complex_plain_vector cL;
  5601   struct constraint_brick : 
public have_private_data_brick {
  5603     virtual void real_pre_assembly_in_serial(
const model &md, 
size_type,
  5604                                              const model::varnamelist &vl,
  5605                                              const model::varnamelist &dl,
  5606                                              const model::mimlist &mims,
  5607                                              model::real_matlist &matl,
  5608                                              model::real_veclist &vecl,
  5609                                              model::real_veclist &,
  5611       if (MPI_IS_MASTER()) {
  5613         GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5614                     "Constraint brick has one and only one term");
  5615         GMM_ASSERT1(mims.size() == 0,
  5616                     "Constraint brick need no mesh_im");
  5617         GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 1,
  5618                     "Wrong number of variables for constraint brick");
  5620         bool penalized = (vl.size() == 1);
  5621         const model_real_plain_vector *COEFF = 0;
  5623         bool has_data = (nameL.compare(
"") != 0);
  5625           GMM_ASSERT1(nameL.compare(dl.back()) == 0 &&
  5628         const model_real_plain_vector &
  5633           GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
  5634                       "Data for coefficient should be a scalar");
  5636           gmm::mult(gmm::transposed(rB),
  5637                     gmm::scaled(rrL, gmm::abs((*COEFF)[0])), vecl[0]);
  5638           gmm::mult(gmm::transposed(rB),
  5639                     gmm::scaled(rB, gmm::abs((*COEFF)[0])), matl[0]);
  5641           gmm::copy(rrL, vecl[0]);
  5642           gmm::copy(rB, matl[0]);
  5647     virtual void complex_pre_assembly_in_serial(
const model &md, 
size_type,
  5648                                                 const model::varnamelist &vl,
  5649                                                 const model::varnamelist &dl,
  5650                                                 const model::mimlist &mims,
  5651                                                 model::complex_matlist &matl,
  5652                                                 model::complex_veclist &vecl,
  5653                                                 model::complex_veclist &,
  5655                                                 build_version)
 const {
  5656       if (MPI_IS_MASTER()) {
  5658         GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5659                     "Constraint brick has one and only one term");
  5660         GMM_ASSERT1(mims.size() == 0,
  5661                     "Constraint brick need no mesh_im");
  5662         GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 1,
  5663                     "Wrong number of variables for constraint brick");
  5665         bool penalized = (vl.size() == 1);
  5666         const model_complex_plain_vector *COEFF = 0;
  5668         bool has_data = (nameL.compare(
"") != 0);
  5670           GMM_ASSERT1(nameL.compare(dl.back()) == 0 &&
  5673         const model_complex_plain_vector &
  5678           GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
  5679                       "Data for coefficient should be a scalar");
  5681           gmm::mult(gmm::transposed(cB),
  5682                     gmm::scaled(ccL, gmm::abs((*COEFF)[0])), vecl[0]);
  5683           gmm::mult(gmm::transposed(cB),
  5684                     gmm::scaled(cB, gmm::abs((*COEFF)[0])), matl[0]);
  5686           gmm::copy(ccL, vecl[0]);
  5687           gmm::copy(cB, matl[0]);
  5692     virtual std::string declare_volume_assembly_string
  5694      const model::varnamelist &)
 const {
  5695       return std::string();
  5698     constraint_brick(
bool penalized) {
  5699       set_flags(penalized ? 
"Constraint with penalization brick"  5700                           : 
"Constraint with multipliers brick",
  5709   model_real_sparse_matrix &set_private_data_brick_real_matrix
  5711     pbrick pbr = md.brick_pointer(indbrick);
  5713     have_private_data_brick *p = 
dynamic_cast<have_private_data_brick *
>  5715     GMM_ASSERT1(p, 
"Wrong type of brick");
  5719   model_real_plain_vector &set_private_data_brick_real_rhs
  5721     pbrick pbr = md.brick_pointer(indbrick);
  5723     have_private_data_brick *p = 
dynamic_cast<have_private_data_brick *
>  5725     GMM_ASSERT1(p, 
"Wrong type of brick");
  5726     if (p->nameL.compare(
"") != 0) GMM_WARNING1(
"Rhs already set by data name");
  5730   model_complex_sparse_matrix &set_private_data_brick_complex_matrix
  5732     pbrick pbr = md.brick_pointer(indbrick);
  5734     have_private_data_brick *p = 
dynamic_cast<have_private_data_brick *
>  5736     GMM_ASSERT1(p, 
"Wrong type of brick");
  5740   model_complex_plain_vector &set_private_data_brick_complex_rhs
  5742     pbrick pbr = md.brick_pointer(indbrick);
  5744     have_private_data_brick *p = 
dynamic_cast<have_private_data_brick *
>  5746     GMM_ASSERT1(p, 
"Wrong type of brick");
  5747     if (p->nameL.compare(
"") != 0) GMM_WARNING1(
"Rhs already set by data name");
  5751   void set_private_data_rhs
  5753     pbrick pbr = md.brick_pointer(indbrick);
  5755     have_private_data_brick *p = 
dynamic_cast<have_private_data_brick *
>  5757     GMM_ASSERT1(p, 
"Wrong type of brick");
  5758     if (p->nameL.compare(varname) != 0) {
  5759       model::varnamelist dl = md.datanamelist_of_brick(indbrick);
  5760       if (p->nameL.compare(
"") == 0) dl.push_back(varname);
  5761       else dl.back() = varname;
  5767   size_type add_constraint_with_penalization
  5768   (
model &md, 
const std::string &varname, scalar_type penalisation_coeff) {
  5769     std::string coeffname = md.
new_name(
"penalization_on_" + varname);
  5775     pbrick pbr = std::make_shared<constraint_brick>(
true);
  5777     tl.push_back(model::term_description(varname, varname, 
true));
  5778     model::varnamelist vl(1, varname);
  5779     model::varnamelist dl(1, coeffname);
  5783   size_type add_constraint_with_multipliers
  5784   (
model &md, 
const std::string &varname, 
const std::string &multname) {
  5785     pbrick pbr = std::make_shared<constraint_brick>(
false);
  5787     tl.push_back(model::term_description(multname, varname, 
true));
  5788     model::varnamelist vl(1, varname);
  5789     vl.push_back(multname);
  5790     model::varnamelist dl;
  5801   struct explicit_matrix_brick : 
public have_private_data_brick {
  5803     virtual void real_pre_assembly_in_serial(
const model &, 
size_type,
  5804                                         const model::varnamelist &vl,
  5805                                         const model::varnamelist &dl,
  5806                                         const model::mimlist &mims,
  5807                                         model::real_matlist &matl,
  5808                                         model::real_veclist &vecl,
  5809                                         model::real_veclist &,
  5811       GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5812                   "Explicit matrix has one and only one term");
  5813       GMM_ASSERT1(mims.size() == 0, 
"Explicit matrix need no mesh_im");
  5814       GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() == 0,
  5815                   "Wrong number of variables for explicit matrix brick");
  5816       gmm::copy(rB, matl[0]);
  5819     virtual void complex_pre_assembly_in_serial(
const model &, 
size_type,
  5820                                            const model::varnamelist &vl,
  5821                                            const model::varnamelist &dl,
  5822                                            const model::mimlist &mims,
  5823                                            model::complex_matlist &matl,
  5824                                            model::complex_veclist &vecl,
  5825                                            model::complex_veclist &,
  5827                                            build_version)
 const {
  5828       GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5829                   "Explicit matrix has one and only one term");
  5830       GMM_ASSERT1(mims.size() == 0, 
"Explicit matrix need no mesh_im");
  5831       GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() == 0,
  5832                   "Wrong number of variables for explicit matrix brick");
  5833       gmm::copy(cB, matl[0]);
  5836     virtual std::string declare_volume_assembly_string
  5838      const model::varnamelist &)
 const {
  5839       return std::string();
  5842     explicit_matrix_brick(
bool symmetric_, 
bool coercive_) {
  5843       set_flags(
"Explicit matrix brick",
  5845                 symmetric_ , coercive_ ,
  5852   (
model &md, 
const std::string &varname1, 
const std::string &varname2,
  5853    bool issymmetric, 
bool iscoercive) {
  5854     pbrick pbr = std::make_shared<explicit_matrix_brick>(issymmetric,
  5857     tl.push_back(model::term_description(varname1, varname2, issymmetric));
  5858     model::varnamelist vl(1, varname1);
  5859     vl.push_back(varname2);
  5860     model::varnamelist dl;
  5870   struct explicit_rhs_brick : 
public have_private_data_brick {
  5872     virtual void real_pre_assembly_in_serial(
const model &, 
size_type,
  5873                                         const model::varnamelist &vl,
  5874                                         const model::varnamelist &dl,
  5875                                         const model::mimlist &mims,
  5876                                         model::real_matlist &matl,
  5877                                         model::real_veclist &vecl,
  5878                                         model::real_veclist &,
  5880       if (MPI_IS_MASTER()) {
  5881         GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5882                     "Explicit rhs has one and only one term");
  5883         GMM_ASSERT1(mims.size() == 0, 
"Explicit rhs need no mesh_im");
  5884         GMM_ASSERT1(vl.size() == 1 && dl.size() == 0,
  5885                     "Wrong number of variables for explicit rhs brick");
  5886         gmm::copy(rL, vecl[0]);
  5890     virtual void complex_pre_assembly_in_serial(
const model &, 
size_type,
  5891                                            const model::varnamelist &vl,
  5892                                            const model::varnamelist &dl,
  5893                                            const model::mimlist &mims,
  5894                                            model::complex_matlist &matl,
  5895                                            model::complex_veclist &vecl,
  5896                                            model::complex_veclist &,
  5898                                            build_version)
 const {
  5899       if (MPI_IS_MASTER()) {
  5900         GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
  5901                     "Explicit rhs has one and only one term");
  5902         GMM_ASSERT1(mims.size() == 0, 
"Explicit rhs need no mesh_im");
  5903         GMM_ASSERT1(vl.size() == 1 && dl.size() == 0,
  5904                     "Wrong number of variables for explicit rhs brick");
  5905         gmm::copy(cL, vecl[0]);
  5910     virtual std::string declare_volume_assembly_string
  5912      const model::varnamelist &)
 const {
  5913       return std::string();
  5916     explicit_rhs_brick() {
  5917       set_flags(
"Explicit rhs brick",
  5927   (
model &md, 
const std::string &varname) {
  5928     pbrick pbr = std::make_shared<explicit_rhs_brick>();
  5930     tl.push_back(model::term_description(varname));
  5931     model::varnamelist vl(1, varname);
  5932     model::varnamelist dl;
  5943   struct iso_lin_elasticity_new_brick : 
public virtual_brick {
  5945     std::string expr, dataname3;
  5948                                 const model::varnamelist &vl,
  5949                                 const model::varnamelist &dl,
  5950                                 const model::mimlist &mims,
  5951                                 model::real_matlist &matl,
  5952                                 model::real_veclist &vecl,
  5953                                 model::real_veclist &,
  5955                                 build_version version)
 const override {
  5956       GMM_ASSERT1(vl.size() == 1, 
"Linearized isotropic elasticity brick "  5957                   "has one and only one variable");
  5958       GMM_ASSERT1(matl.size() == 1, 
"Linearized isotropic elasticity brick "  5959                   "has one and only one term");
  5960       GMM_ASSERT1(mims.size() == 1, 
"Linearized isotropic elasticity brick "  5961                   "needs one and only one mesh_im");
  5963       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
  5964       for (
size_type i = 0; i < dl.size(); ++i) {
  5965         recompute_matrix = recompute_matrix ||
  5966           md.is_var_newer_than_brick(dl[i], ib);
  5969       if (recompute_matrix) {
  5971         ga_workspace workspace(md, 
true);
  5972         workspace.add_expression(expr, *(mims[0]), region);
  5973         GMM_TRACE2(name << 
": generic matrix assembly");
  5974         model::varnamelist vlmd; md.variable_list(vlmd);
  5975         for (
size_type i = 0; i < vlmd.size(); ++i)
  5976           if (md.is_disabled_variable(vlmd[i]))
  5977             nbgdof = std::max(nbgdof,
  5978                               workspace.interval_of_variable(vlmd[i]).last());
  5979         model_real_sparse_matrix R(nbgdof, nbgdof);
  5980         workspace.set_assembled_matrix(R);
  5981         workspace.assembly(2);
  5982         scalar_type alpha = scalar_type(1)
  5983           / (workspace.factor_of_variable(vl[0]));
  5984         gmm::sub_interval I = workspace.interval_of_variable(vl[0]);
  5985         gmm::copy(gmm::scaled(gmm::sub_matrix(R, I, I), alpha),
  5989       if  (dataname3.size()) { 
  5993         gmm::clear(vecl[0]);
  6002                                       const model::varnamelist &,
  6003                                       const model::varnamelist &,
  6004                                       const model::mimlist &,
  6005                                       model::real_matlist &,
  6006                                       model::real_veclist &vecl,
  6007                                       model::real_veclist &,
  6009                                       build_version)
 const override {
  6010       md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
  6014     virtual std::string declare_volume_assembly_string
  6016      const model::varnamelist &)
 const {
  6020     iso_lin_elasticity_new_brick(
const std::string &expr_,
  6021                                  const std::string &dataname3_) {
  6022       expr = expr_; dataname3 = dataname3_;
  6023       set_flags(
"Linearized isotropic elasticity", 
true ,
  6033    const std::string &dataexpr1, 
const std::string &dataexpr2,
  6034    size_type region, 
const std::string &dataname3) {
  6035     std::string test_varname
  6036       = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  6038     std::string expr1 = 
"((("+dataexpr1+
")*(Div_"+varname+
"-Div_"+dataname3
  6039       +
"))*Id(meshdim)+(2*("+dataexpr2+
"))*(Sym(Grad_"+varname
  6040       +
")-Sym(Grad_"+dataname3+
"))):Grad_" +test_varname;
  6041     std::string expr2 = 
"(Div_"+varname+
"*(("+dataexpr1+
")*Id(meshdim))"  6042       +
"+(2*("+dataexpr2+
"))*Sym(Grad_"+varname+
")):Grad_"+test_varname;
  6044     ga_workspace workspace(md, 
true);
  6045     workspace.add_expression(expr2, mim, region);
  6046     model::varnamelist vl, vl_test1, vl_test2, dl;
  6047     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 2);
  6050       pbrick pbr = std::make_shared<iso_lin_elasticity_new_brick>
  6053       tl.push_back(model::term_description(varname,
  6054                            sup_previous_and_dot_to_varname(varname), 
true));
  6055       if (dataname3.size()) dl.push_back(dataname3);
  6056       return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  6058       return add_nonlinear_generic_assembly_brick
  6059         (md, mim, dataname3.size() ? expr1 : expr2, region, 
false, 
false,
  6060          "Linearized isotropic elasticity (with nonlinear dependance)");
  6066    const std::string &data_E, 
const std::string &data_nu,
  6068     std::string test_varname
  6069       = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  6071     std::string mu = 
"(("+data_E+
")/(2*(1+("+data_nu+
"))))";
  6072     std::string lambda = 
"(("+data_E+
")*("+data_nu+
")/((1+("+data_nu+
"))*(1-2*("  6074     std::string expr = lambda+
"*Div_"+varname+
"*Div_"+test_varname
  6075       + 
"+"+mu+
"*(Grad_"+varname+
"+Grad_"+varname+
"'):Grad_"+test_varname;
  6077     ga_workspace workspace(md, 
true);
  6078     workspace.add_expression(expr, mim, region);
  6079     model::varnamelist vl, vl_test1, vl_test2, dl;
  6080     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 2);
  6084                              "Linearized isotropic elasticity");
  6087         (md, mim, expr, region, 
false, 
false,
  6088          "Linearized isotropic elasticity (with nonlinear dependance)");
  6094    const std::string &data_E, 
const std::string &data_nu,
  6096     std::string test_varname
  6097       = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  6100     GMM_ASSERT1(mfu, 
"The variable should be a fem variable");
  6103     std::string mu = 
"(("+data_E+
")/(2*(1+("+data_nu+
"))))";
  6104     std::string lambda =  
"(("+data_E+
")*("+data_nu+
")/((1+("+data_nu+
"))*(1-2*("  6107       lambda = 
"(("+data_E+
")*("+data_nu+
")/((1-sqr("+data_nu+
"))))";
  6108     std::string expr = lambda+
"*Div_"+varname+
"*Div_"+test_varname
  6109       + 
"+"+mu+
"*(Grad_"+varname+
"+Grad_"+varname+
"'):Grad_"+test_varname;
  6111     ga_workspace workspace(md, 
true);
  6112     workspace.add_expression(expr, mim, region);
  6113     model::varnamelist vl, vl_test1, vl_test2, dl;
  6114     bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 2);
  6118                              "Linearized isotropic elasticity");
  6121         (md, mim, expr, region, 
false, 
false,
  6122          "Linearized isotropic elasticity (with nonlinear dependance)");
  6127   void compute_isotropic_linearized_Von_Mises_or_Tresca
  6128   (
model &md, 
const std::string &varname, 
const std::string &data_lambda,
  6129    const std::string &data_mu, 
const mesh_fem &mf_vm,
  6130    model_real_plain_vector &VM, 
bool tresca) {
  6135       const model_real_plain_vector *lambda=&(md.
real_variable(data_lambda));
  6137       const model_real_plain_vector *mu = &(md.
real_variable(data_mu));
  6140       if (mf_lambda) sl = sl * mf_lambda->
get_qdim() / mf_lambda->
nb_dof();
  6144       GMM_ASSERT1(sl == 1 && sm == 1, 
"Bad format for Lame coefficients");
  6145       GMM_ASSERT1(mf_lambda == mf_mu,
  6146                   "The two Lame coefficients should be described on the same "  6147                   "finite element method.");
  6152                                                   *mf_lambda, *lambda,
  6157         model_real_plain_vector LAMBDA(mf_lambda->
nb_dof(), (*lambda)[0]);
  6158         model_real_plain_vector MU(mf_lambda->
nb_dof(), (*mu)[0]);
  6169       std::string sigma_d=
"("+data_mu+
")*(Grad_"+varname+
"+Grad_"+varname+
"')";
  6170       std::string expr = 
"sqrt(3/2)*Norm(Deviator("+sigma_d+
"))";
  6171       ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM);
  6177   (
model &md, 
const std::string &varname, 
const std::string &data_E,
  6178    const std::string &data_nu, 
const mesh_fem &mf_vm,
  6179    model_real_plain_vector &VM) {
  6183     std::string mu = 
"(("+data_E+
")/(2*(1+("+data_nu+
"))))";
  6186     std::string sigma_d = mu+
"*(Grad_"+varname+
"+Grad_"+varname+
"')";
  6187     std::string expr = 
"sqrt(3/2)*Norm(Deviator("+sigma_d+
"))";
  6188     ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM);
  6192   (
model &md, 
const std::string &varname, 
const std::string &data_E,
  6193    const std::string &data_nu, 
const mesh_fem &mf_vm,
  6194    model_real_plain_vector &VM) {
  6203     std::string mu = 
"(("+data_E+
")/(2*(1+("+data_nu+
"))))";
  6206     std::string sigma_d = mu+
"*(Grad_"+varname+
"+Grad_"+varname+
"')";
  6207     std::string expr = 
"sqrt(3/2)*Norm(Deviator("+sigma_d+
"))";
  6208     ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM);
  6218   struct linear_incompressibility_brick : 
public virtual_brick {
  6221                                         const model::varnamelist &vl,
  6222                                         const model::varnamelist &dl,
  6223                                         const model::mimlist &mims,
  6224                                         model::real_matlist &matl,
  6225                                         model::real_veclist &,
  6226                                         model::real_veclist &,
  6228                                         build_version)
 const {
  6230       GMM_ASSERT1((matl.size() == 1 && dl.size() == 0)
  6231                   || (matl.size() == 2 && dl.size() == 1),
  6232                   "Wrong term and/or data number for Linear incompressibility "  6234       GMM_ASSERT1(mims.size() == 1, 
"Linear incompressibility brick need one "  6235                   "and only one mesh_im");
  6236       GMM_ASSERT1(vl.size() == 2, 
"Wrong number of variables for linear "  6237                   "incompressibility brick");
  6239       bool penalized = (dl.size() == 1);
  6242       const mesh_im &mim = *mims[0];
  6243       const model_real_plain_vector *COEFF = 0;
  6251         GMM_ASSERT1(s == 1, 
"Bad format for the penalization parameter");
  6257       GMM_TRACE2(
"Stokes term assembly");
  6258       gmm::clear(matl[0]);
  6262         gmm::clear(matl[1]);
  6265           gmm::scale(matl[1], scalar_type(-1));
  6269           gmm::scale(matl[1], -(*COEFF)[0]);
  6276     virtual void real_post_assembly_in_serial(
const model &, 
size_type,
  6277                                               const model::varnamelist &,
  6278                                               const model::varnamelist &,
  6279                                               const model::mimlist &,
  6280                                               model::real_matlist &,
  6281                                               model::real_veclist &,
  6282                                               model::real_veclist &,
  6284                                               build_version)
 const  6288     linear_incompressibility_brick() {
  6289       set_flags(
"Linear incompressibility brick",
  6299    const std::string &multname, 
size_type region,
  6300    const std::string &dataexpr) {
  6302     pbrick pbr = std::make_shared<linear_incompressibility_brick>();
  6304     tl.push_back(model::term_description(multname, varname, 
true));
  6305     model::varnamelist vl(1, varname);
  6306     vl.push_back(multname);
  6307     model::varnamelist dl;
  6308     if (dataname.size()) {
  6309       dl.push_back(dataexpr);
  6310       tl.push_back(model::term_description(multname, multname, 
true));
  6312     return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
  6314     std::string test_varname
  6315       = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  6316     std::string test_multname
  6317       = 
"Test_" + sup_previous_and_dot_to_varname(multname);
  6319     if (dataexpr.size())
  6320       expr = 
"-"+multname+
"*Div_"+test_varname + 
"-"+test_multname
  6321         +
"*Div_"+varname+
"+(("+dataexpr+
")*"+multname+
")*"+test_multname;
  6323       expr = 
"-"+multname+
"*Div_"+test_varname + 
"-"+test_multname
  6326                                    "Linear incompressibility", 
true);
  6329         (md, mim, expr, region, 
false, 
false,
  6330          "Linear incompressibility (with nonlinear dependance)");
  6346                                         const model::varnamelist &vl,
  6347                                         const model::varnamelist &dl,
  6348                                         const model::mimlist &mims,
  6349                                         model::real_matlist &matl,
  6350                                         model::real_veclist &,
  6351                                         model::real_veclist &,
  6353                                         build_version)
 const {
  6354       GMM_ASSERT1(matl.size() == 1,
  6355                   "Mass brick has one and only one term");
  6356       GMM_ASSERT1(mims.size() == 1,
  6357                   "Mass brick need one and only one mesh_im");
  6358       GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
  6359                   "Wrong number of variables for mass brick");
  6362       const mesh &m = mf_u.linked_mesh();
  6363       const mesh_im &mim = *mims[0];
  6365       m.intersect_with_mpi_region(rg);
  6368       const model_real_plain_vector *rho = 0;
  6375         GMM_ASSERT1(sl == 1, 
"Bad format of mass brick coefficient");
  6378       GMM_TRACE2(
"Mass matrix assembly");
  6379       gmm::clear(matl[0]);
  6380       if (dl.size() && mf_rho) {
  6384         if (dl.size()) gmm::scale(matl[0], (*rho)[0]);
  6388     virtual void asm_complex_tangent_terms(
const model &md, 
size_type,
  6389                                            const model::varnamelist &vl,
  6390                                            const model::varnamelist &dl,
  6391                                            const model::mimlist &mims,
  6392                                            model::complex_matlist &matl,
  6393                                            model::complex_veclist &,
  6394                                            model::complex_veclist &,
  6396                                            build_version)
 const {
  6397       GMM_ASSERT1(matl.size() == 1,
  6398                   "Mass brick has one and only one term");
  6399       GMM_ASSERT1(mims.size() == 1,
  6400                   "Mass brick need one and only one mesh_im");
  6401       GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
  6402                   "Wrong number of variables for mass brick");
  6405       const mesh &m = mf_u.linked_mesh();
  6406       const mesh_im &mim = *mims[0];
  6408       m.intersect_with_mpi_region(rg);
  6411       const model_complex_plain_vector *rho = 0;
  6418         GMM_ASSERT1(sl == 1, 
"Bad format of mass brick coefficient");
  6421       GMM_TRACE2(
"Mass matrix assembly");
  6422       gmm::clear(matl[0]);
  6423       if (dl.size() && mf_rho) {
  6427         if (dl.size()) gmm::scale(matl[0], (*rho)[0]);
  6431     virtual std::string declare_volume_assembly_string
  6433      const model::varnamelist &)
 const {
  6434       return std::string();
  6438       set_flags(
"Mass brick", 
true ,
  6448    const std::string &dataexpr_rho,  
size_type region) {
  6450       pbrick pbr = std::make_shared<mass_brick>();
  6452       tl.push_back(model::term_description(varname, varname, 
true));
  6453       model::varnamelist dl;
  6454       if (dataexpr_rho.size())
  6455         dl.push_back(dataexpr_rho);
  6456       return md.
add_brick(pbr, model::varnamelist(1, varname), dl, tl,
  6457                           model::mimlist(1, &mim), region);
  6459       std::string test_varname
  6460          = 
"Test_" + sup_previous_and_dot_to_varname(varname);
  6462       if (dataexpr_rho.size())
  6463         expr =
"(("+dataexpr_rho+
")*"+varname+
")."+test_varname;
  6465         expr = varname+
"."+test_varname;
  6467                                      "Mass matrix", 
true);
  6470                                 "Mass matrix (nonlinear)");
  6491     virtual void asm_real_tangent_terms(
const model &md, 
size_type ib,
  6492                                         const model::varnamelist &vl,
  6493                                         const model::varnamelist &dl,
  6494                                         const model::mimlist &mims,
  6495                                         model::real_matlist &matl,
  6496                                         model::real_veclist &vecl,
  6497                                         model::real_veclist &,
  6499                                         build_version version)
 const {
  6500       GMM_ASSERT1(matl.size() == 1,
  6501                   "Basic d/dt brick has one and only one term");
  6502       GMM_ASSERT1(mims.size() == 1,
  6503                   "Basic d/dt brick need one and only one mesh_im");
  6504       GMM_ASSERT1(vl.size() == 1 && dl.size() >= 2 && dl.size() <= 3,
  6505                   "Wrong number of variables for basic d/dt brick");
  6509       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
  6510         || (md.is_var_newer_than_brick(dl[1], ib));
  6512         recompute_matrix = recompute_matrix ||
  6513           md.is_var_newer_than_brick(dl[2], ib);
  6516       if (recompute_matrix) {
  6519         const mesh_im &mim = *mims[0];
  6521         m.intersect_with_mpi_region(rg);
  6523         const model_real_plain_vector &dt = md.
real_variable(dl[1]);
  6524         GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for time step");
  6527         const model_real_plain_vector *rho = 0;
  6529         if (dl.size() > 2) {
  6534           GMM_ASSERT1(sl == 1, 
"Bad format for density");
  6537         GMM_TRACE2(
"Mass matrix assembly for d_on_dt brick");
  6538         if (dl.size() > 2 && mf_rho) {
  6539           gmm::clear(matl[0]);
  6541           gmm::scale(matl[0], scalar_type(1) / dt[0]);
  6543           gmm::clear(matl[0]);
  6545           if (dl.size() > 2) gmm::scale(matl[0], (*rho)[0] / dt[0]);
  6546           else gmm::scale(matl[0], scalar_type(1) / dt[0]);
  6552     virtual void asm_complex_tangent_terms(
const model &md, 
size_type ib,
  6553                                            const model::varnamelist &vl,
  6554                                            const model::varnamelist &dl,
  6555                                            const model::mimlist &mims,
  6556                                            model::complex_matlist &matl,
  6557                                            model::complex_veclist &vecl,
  6558                                            model::complex_veclist &,
  6560                                            build_version version)
 const {
  6561       GMM_ASSERT1(matl.size() == 1,
  6562                   "Basic d/dt brick has one and only one term");
  6563       GMM_ASSERT1(mims.size() == 1,
  6564                   "Basic d/dt brick need one and only one mesh_im");
  6565       GMM_ASSERT1(vl.size() == 1 && dl.size() >= 2 && dl.size() <= 3,
  6566                   "Wrong number of variables for basic d/dt brick");
  6570       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
  6571         || (md.is_var_newer_than_brick(dl[1], ib));
  6573         recompute_matrix = recompute_matrix ||
  6574           md.is_var_newer_than_brick(dl[2], ib);
  6576       if (recompute_matrix) {
  6579         const mesh_im &mim = *mims[0];
  6582         m.intersect_with_mpi_region(rg);
  6585         GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for time step");
  6588         const model_complex_plain_vector *rho = 0;
  6590         if (dl.size() > 2) {
  6595           GMM_ASSERT1(sl == 1, 
"Bad format for density");
  6598         GMM_TRACE2(
"Mass matrix assembly for d_on_dt brick");
  6599         if (dl.size() > 2 && mf_rho) {
  6600           gmm::clear(matl[0]);
  6602           gmm::scale(matl[0], scalar_type(1) / dt[0]);
  6604           gmm::clear(matl[0]);
  6606           if (dl.size() > 2) gmm::scale(matl[0], (*rho)[0] / dt[0]);
  6607           else gmm::scale(matl[0], scalar_type(1) / dt[0]);
  6613     virtual std::string declare_volume_assembly_string
  6615      const model::varnamelist &)
 const {
  6616       return std::string();
  6619     basic_d_on_dt_brick() {
  6620       set_flags(
"Basic d/dt brick", 
true ,
  6630    const std::string &dataname_dt, 
const std::string &dataname_rho,
  6632     pbrick pbr = std::make_shared<basic_d_on_dt_brick>();
  6634     tl.push_back(model::term_description(varname, varname, 
true));
  6635     model::varnamelist dl(1, varname);
  6636     dl.push_back(dataname_dt);
  6637     if (dataname_rho.size())
  6638       dl.push_back(dataname_rho);
  6639     return md.
add_brick(pbr, model::varnamelist(1, varname), dl, tl,
  6640                         model::mimlist(1, &mim), region);
  6653     mutable scalar_type old_alphadt2;
  6655     virtual void asm_real_tangent_terms(
const model &md, 
size_type ib,
  6656                                         const model::varnamelist &vl,
  6657                                         const model::varnamelist &dl,
  6658                                         const model::mimlist &mims,
  6659                                         model::real_matlist &matl,
  6660                                         model::real_veclist &vecl,
  6661                                         model::real_veclist &,
  6663                                         build_version version)
 const {
  6664       GMM_ASSERT1(matl.size() == 1,
  6665                   "Basic d2/dt2 brick has one and only one term");
  6666       GMM_ASSERT1(mims.size() == 1,
  6667                   "Basic d2/dt2 brick need one and only one mesh_im");
  6668       GMM_ASSERT1(vl.size() == 1 && dl.size() >= 4 && dl.size() <= 5,
  6669                   "Wrong number of variables for basic d2/dt2 brick");
  6671       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
  6673       recompute_matrix = recompute_matrix || md.is_var_newer_than_brick(dl[2], ib);
  6674       if (dl.size() > 4) recompute_matrix || md.is_var_newer_than_brick(dl[4], ib);
  6676       const model_real_plain_vector &dt = md.
real_variable(dl[2]);
  6677       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for time step");
  6678       const model_real_plain_vector &alpha = md.
real_variable(dl[3]);
  6679       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for parameter alpha");
  6680       scalar_type alphadt2 = gmm::sqr(dt[0]) * alpha[0];
  6682       if (!recompute_matrix && alphadt2 != old_alphadt2)
  6683         gmm::scale(matl[0], old_alphadt2/alphadt2);
  6684       old_alphadt2 = alphadt2;
  6686       if (recompute_matrix) {
  6689         const mesh_im &mim = *mims[0];
  6691         m.intersect_with_mpi_region(rg);
  6694         const model_real_plain_vector *rho = 0;
  6696         if (dl.size() > 4) {
  6701           GMM_ASSERT1(sl == 1, 
"Bad format for density");
  6704         GMM_TRACE2(
"Mass matrix assembly for d2_on_dt2 brick");
  6705         if (dl.size() > 4 && mf_rho) {
  6706           gmm::clear(matl[0]);
  6708           gmm::scale(matl[0], scalar_type(1) / alphadt2);
  6710           gmm::clear(matl[0]);
  6712           if (dl.size() > 4) gmm::scale(matl[0], (*rho)[0] / alphadt2);
  6713           else gmm::scale(matl[0], scalar_type(1) / alphadt2);
  6717       gmm::mult_add(matl[0], gmm::scaled(md.
real_variable(dl[1], 1), dt[0]),
  6721     virtual void asm_complex_tangent_terms(
const model &md, 
size_type ib,
  6722                                            const model::varnamelist &vl,
  6723                                            const model::varnamelist &dl,
  6724                                            const model::mimlist &mims,
  6725                                            model::complex_matlist &matl,
  6726                                            model::complex_veclist &vecl,
  6727                                            model::complex_veclist &,
  6729                                            build_version version)
 const {
  6730       GMM_ASSERT1(matl.size() == 1,
  6731                   "Basic d2/dt2 brick has one and only one term");
  6732       GMM_ASSERT1(mims.size() == 1,
  6733                   "Basic d2/dt2 brick need one and only one mesh_im");
  6734       GMM_ASSERT1(vl.size() == 1 && dl.size() >= 4 && dl.size() <= 5,
  6735                   "Wrong number of variables for basic d2/dt2 brick");
  6737       bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
  6739       recompute_matrix = recompute_matrix || md.is_var_newer_than_brick(dl[2], ib);
  6740       if (dl.size() > 4) recompute_matrix || md.is_var_newer_than_brick(dl[4], ib);
  6744       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for time step");
  6746       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for parameter alpha");
  6747       scalar_type alphadt2 = gmm::real(gmm::sqr(dt[0]) * alpha[0]);
  6749       if (!recompute_matrix && alphadt2 != old_alphadt2)
  6750         gmm::scale(matl[0], old_alphadt2/alphadt2);
  6751       old_alphadt2 = alphadt2;
  6753       if (recompute_matrix) {
  6756         const mesh_im &mim = *mims[0];
  6758         m.intersect_with_mpi_region(rg);
  6761         const model_complex_plain_vector *rho = 0;
  6763         if (dl.size() > 4) {
  6768           GMM_ASSERT1(sl == 1, 
"Bad format for density");
  6771         GMM_TRACE2(
"Mass matrix assembly for d2_on_dt2 brick");
  6772         if (dl.size() > 4 && mf_rho) {
  6773           gmm::clear(matl[0]);
  6775           gmm::scale(matl[0], scalar_type(1) / alphadt2);
  6777           gmm::clear(matl[0]);
  6779           if (dl.size() > 4) gmm::scale(matl[0], (*rho)[0] / alphadt2);
  6780           else gmm::scale(matl[0], scalar_type(1) / alphadt2);
  6788     virtual std::string declare_volume_assembly_string
  6790      const model::varnamelist &)
 const {
  6791       return std::string();
  6794     basic_d2_on_dt2_brick() {
  6795       set_flags(
"Basic d2/dt2 brick", 
true ,
  6805    const std::string &datanameV,
  6806    const std::string &dataname_dt,
  6807    const std::string &dataname_alpha,
  6808    const std::string &dataname_rho,
  6810     pbrick pbr = std::make_shared<basic_d2_on_dt2_brick>();
  6812     tl.push_back(model::term_description(varnameU, varnameU, 
true));
  6813     model::varnamelist dl(1, varnameU);
  6814     dl.push_back(datanameV);
  6815     dl.push_back(dataname_dt);
  6816     dl.push_back(dataname_alpha);
  6817     if (dataname_rho.size())
  6818       dl.push_back(dataname_rho);
  6819     return md.
add_brick(pbr, model::varnamelist(1, varnameU), dl, tl,
  6820                         model::mimlist(1, &mim), region);
  6839     void theta_method_dispatcher::set_dispatch_coeff(
const model &md, 
size_type ib)
 const {
  6846       md.matrix_coeff_of_brick(ib) = theta;
  6848       md.rhs_coeffs_of_brick(ib)[0] = theta;
  6850       md.rhs_coeffs_of_brick(ib)[1] = (scalar_type(1) - theta);
  6854     void theta_method_dispatcher::next_real_iter
  6856      const model::varnamelist &dl, model::real_matlist &matl,
  6857      std::vector<model::real_veclist> &vectl,
  6858      std::vector<model::real_veclist> &vectl_sym, 
bool first_iter)
 const {
  6859       next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
  6862     void theta_method_dispatcher::next_complex_iter
  6864      const model::varnamelist &dl,
  6865      model::complex_matlist &matl,
  6866      std::vector<model::complex_veclist> &vectl,
  6867      std::vector<model::complex_veclist> &vectl_sym,
  6868      bool first_iter)
 const {
  6869       next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
  6872     void theta_method_dispatcher::asm_real_tangent_terms
  6874      std::vector<model::real_veclist> &,
  6875      std::vector<model::real_veclist> &,
  6876      build_version version)
 const  6877     { md.brick_call(ib, version, 0); }
  6879     void theta_method_dispatcher::asm_complex_tangent_terms
  6881      std::vector<model::complex_veclist> &,
  6882      std::vector<model::complex_veclist> &,
  6883      build_version version)
 const  6884     { md.brick_call(ib, version, 0); }
  6886     theta_method_dispatcher::theta_method_dispatcher(
const std::string &THETA)
  6888       param_names.push_back(THETA);
  6892   (
model &md, dal::bit_vector ibricks, 
const std::string &THETA) {
  6893     pdispatcher pdispatch = std::make_shared<theta_method_dispatcher>(THETA);
  6894     for (dal::bv_visitor i(ibricks); !i.finished(); ++i)
  6899   (
model &md, 
const std::string &U, 
const std::string &V,
  6900    const std::string &pdt, 
const std::string &ptheta) {
  6906       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for time step");
  6908       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for parameter theta");
  6911                             scalar_type(1) - scalar_type(1) / theta[0]),
  6914                            scalar_type(1) / (theta[0]*dt[0])),
  6917                            -scalar_type(1) / (theta[0]*dt[0])),
  6921       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for time step");
  6922       const model_real_plain_vector &theta = md.
real_variable(ptheta);
  6923       GMM_ASSERT1(gmm::vect_size(dt) == 1, 
"Bad format for parameter theta");
  6926                             scalar_type(1) - scalar_type(1) / theta[0]),
  6929                            scalar_type(1) / (theta[0]*dt[0])),
  6932                            -scalar_type(1) / (theta[0]*dt[0])),
  6945    const std::string &pdt, 
const std::string &ptwobeta,
  6946    const std::string &pgamma) {
  6956       if (twobeta != gamma) {
  6958         md.set_dispatch_coeff();  
  6962       md.
assembly(model::BUILD_COMPLETE_RHS);
  6965       model_complex_plain_vector W(nbdof), RHS(nbdof);
  6966       gmm::copy(gmm::sub_vector(md.
complex_rhs(), md.interval_of_variable(U)),
  6971       gmm::cg(md.linear_complex_matrix_term(id2dt2b, 0),
  6972               W, RHS, gmm::identity_matrix(), iter);
  6973       GMM_ASSERT1(iter.converged(), 
"Velocity not well computed");
  6975                gmm::scaled(W, complex_type(1)/(twobeta*dt)),
  6979       if (twobeta != gamma) {
  6981         md.set_dispatch_coeff();  
  6985       GMM_ASSERT1(
false, 
"to be done");
  6994       if (twobeta != gamma) {
  6996         md.set_dispatch_coeff();  
  7000       md.
assembly(model::BUILD_COMPLETE_RHS);
  7003       model_real_plain_vector W(nbdof), RHS(nbdof);
  7004       gmm::copy(gmm::sub_vector(md.
real_rhs(), md.interval_of_variable(U)),
  7009       gmm::cg(md.linear_real_matrix_term(id2dt2b, 0),
  7010               W, RHS, gmm::identity_matrix(), iter);
  7011       GMM_ASSERT1(iter.converged(), 
"Velocity not well computed");
  7013                gmm::scaled(W, scalar_type(1)/(twobeta*dt)),
  7017       if (twobeta != gamma) {
  7019         md.set_dispatch_coeff();  
  7036     gmm::uint64_type id_num;
  7040     typedef model::build_version build_version;
  7043       md.matrix_coeff_of_brick(ib) = scalar_type(1)/scalar_type(2);
  7044       md.rhs_coeffs_of_brick(ib)[0] = scalar_type(1);
  7045       md.rhs_coeffs_of_brick(ib)[1] = scalar_type(1)/scalar_type(2);
  7048     template <
typename MATLIST, 
typename VECTLIST>
  7050                           const model::varnamelist &vl,
  7051                           const model::varnamelist &dl,
  7053                           VECTLIST &vectl, VECTLIST &vectl_sym,
  7054                           bool first_iter)
 const {
  7056       pbrick pbr = md.brick_pointer(ib);
  7060         if (!(pbr->is_linear()))
  7061           md.add_temporaries(vl, id_num); 
  7062         md.add_temporaries(dl, id_num); 
  7063         for (
auto &&v : vectl[1]) gmm::clear(v);
  7064         for (
auto &&v : vectl_sym[1]) gmm::clear(v);
  7067       if (pbr->is_linear()) { 
  7070         if (first_iter) md.update_brick(ib, model::BUILD_RHS);
  7071         for (
auto &&v : vectl[1]) gmm::clear(v);
  7072         for (
auto &&v : vectl_sym[1]) gmm::clear(v);
  7073         md.linear_brick_add_to_rhs(ib, 1, 0);
  7079      const model::varnamelist &dl, model::real_matlist &matl,
  7080      std::vector<model::real_veclist> &vectl,
  7081      std::vector<model::real_veclist> &vectl_sym, 
bool first_iter)
 const {
  7082       next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
  7085     void next_complex_iter
  7087      const model::varnamelist &dl,
  7088      model::complex_matlist &matl,
  7089      std::vector<model::complex_veclist> &vectl,
  7090      std::vector<model::complex_veclist> &vectl_sym,
  7091      bool first_iter)
 const {
  7092       next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
  7095     void asm_real_tangent_terms
  7097      std::vector<model::real_veclist> &vectl,
  7098      std::vector<model::real_veclist> &vectl_sym,
  7099      build_version version)
 const {
  7101       scalar_type half = scalar_type(1)/scalar_type(2);
  7102       pbrick pbr = md.brick_pointer(ib);
  7105       const model::varnamelist &vl = md.varnamelist_of_brick(ib);
  7106       const model::varnamelist &dl = md.datanamelist_of_brick(ib);
  7108       if (!(pbr->is_linear())) { 
  7109         for (
size_type i = 0; i < vl.size(); ++i) {
  7110           bool is_uptodate = md.temporary_uptodate(vl[i], id_num, ind);
  7111           if (!is_uptodate && ind != 
size_type(-1))
  7115           md.set_default_iter_of_variable(vl[i], ind);
  7120       for (
size_type i = 0; i < dl.size(); ++i) {
  7121         bool is_uptodate = md.temporary_uptodate(dl[i], id_num, ind);
  7122         if (!is_uptodate && ind != 
size_type(-1)) {
  7127         md.set_default_iter_of_variable(dl[i], ind);
  7131       md.brick_call(ib, version, 0);
  7132       if (pbr->is_linear()) { 
  7134         for (
auto &&v : vectl[1]) gmm::clear(v);
  7135         for (
auto &&v : vectl_sym[1]) gmm::clear(v);
  7136         md.linear_brick_add_to_rhs(ib, 1, 1);
  7139       md.reset_default_iter_of_variables(dl);
  7140       if (!(pbr->is_linear()))
  7141         md.reset_default_iter_of_variables(vl);
  7144     virtual void asm_complex_tangent_terms
  7146      std::vector<model::complex_veclist> &vectl,
  7147      std::vector<model::complex_veclist> &vectl_sym,
  7148      build_version version)
 const {
  7150       scalar_type half = scalar_type(1)/scalar_type(2);
  7151       pbrick pbr = md.brick_pointer(ib);
  7154       const model::varnamelist &vl = md.varnamelist_of_brick(ib);
  7155       const model::varnamelist &dl = md.datanamelist_of_brick(ib);
  7157       if (!(pbr->is_linear())) { 
  7158         for (
size_type i = 0; i < vl.size(); ++i) {
  7159           bool is_uptodate = md.temporary_uptodate(vl[i], id_num, ind);
  7160           if (!is_uptodate && ind != 
size_type(-1))
  7164           md.set_default_iter_of_variable(vl[i], ind);
  7169       for (
size_type i = 0; i < dl.size(); ++i) {
  7170         bool is_uptodate = md.temporary_uptodate(dl[i], id_num, ind);
  7171         if (!is_uptodate && ind != 
size_type(-1)) {
  7176         md.set_default_iter_of_variable(dl[i], ind);
  7180       md.brick_call(ib, version, 0);
  7181       if (pbr->is_linear()) { 
  7183         for (
auto &&v : vectl[1]) gmm::clear(v);
  7184         for (
auto &&v : vectl_sym[1]) gmm::clear(v);
  7185         md.linear_brick_add_to_rhs(ib, 1, 1);
  7188       md.reset_default_iter_of_variables(dl);
  7189       if (!(pbr->is_linear()))
  7190         md.reset_default_iter_of_variables(vl);
  7194     { id_num = act_counter(); }
  7199     pdispatcher pdispatch = std::make_shared<midpoint_dispatcher>();
  7200     for (dal::bv_visitor i(ibricks); !i.finished(); ++i)
 multi-threaded distribution of a single vector or a matrix. 
const model_real_plain_vector & real_rhs() const 
Gives the access to the right hand side of the tangent linear system. 
void add_fixed_size_data(const std::string &name, size_type size, size_type niter=1)
Add a fixed size data to the model. 
const APIDECL std::string & mult_varname_Dirichlet(model &md, size_type ind_brick)
When ind_brick is the index of a Dirichlet brick with multiplier on the model md, the function return...
virtual size_type nb_dof() const 
Return the total number of degrees of freedom. 
structure used to hold a set of convexes and/or convex faces. 
void asm_stiffness_matrix_for_homogeneous_scalar_elliptic_componentwise(MAT &M, const mesh_im &mim, const mesh_fem &mf, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
The same but with a constant matrix. 
const model_complex_plain_vector & complex_rhs() const 
Gives access to the right hand side of the tangent linear system. 
size_type nb_dof() const 
Total number of degrees of freedom in the model. 
size_type APIDECL add_normal_Dirichlet_condition_with_multipliers(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname, size_type region, const std::string &dataname=std::string())
Add a Dirichlet condition to the normal component of the vector (or tensor) valued variable varname a...
size_type APIDECL add_generalized_Dirichlet_condition_with_Nitsche_method(model &md, const mesh_im &mim, const std::string &varname, const std::string &Neumannterm, const std::string &datagamma0, size_type region, scalar_type theta, const std::string &datag, const std::string &dataH)
Add a Dirichlet condition on the variable varname and the mesh region region. 
void asm_stiffness_matrix_for_scalar_elliptic(MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
assembly of , where  is a (symmetric positive definite) NxN matrix. 
void asm_stokes_B(const MAT &B, const mesh_im &mim, const mesh_fem &mf_u, const mesh_fem &mf_p, const mesh_region &rg=mesh_region::all_convexes())
Build the mixed pressure term . 
void change_mims_of_brick(size_type ib, const mimlist &ml)
Change the mim list of a brick. 
const auto PREFIX_OLD
A prefix to refer to the previous version of a variable. 
void disable_brick(size_type ib)
Disable a brick. 
void APIDECL add_midpoint_dispatcher(model &md, dal::bit_vector ibricks)
Add a midpoint time dispatcher to a list of bricks. 
size_type APIDECL add_normal_Dirichlet_condition_with_Nitsche_method(model &md, const mesh_im &mim, const std::string &varname, const std::string &Neumannterm, const std::string &datagamma0, size_type region, scalar_type theta=scalar_type(0), const std::string &datag=std::string())
Add a Dirichlet condition on the normal component of the variable varname and the mesh region region...
void disable_variable(const std::string &name)
Disable a variable (and its attached mutlipliers). 
size_type APIDECL add_pointwise_constraints_with_given_multipliers(model &md, const std::string &varname, const std::string &multname, const std::string &dataname_pt, const std::string &dataname_unitv=std::string(), const std::string &dataname_val=std::string())
Add some pointwise constraints on the variable varname using a given multiplier multname. 
void add_macro(const std::string &name, const std::string &expr)
Add a macro definition for the high generic assembly langage. 
void check_brick_stiffness_rhs(size_type ind_brick) const 
check consistency of RHS and Stiffness matrix for brick with 
size_type APIDECL add_isotropic_linearized_elasticity_brick_pstress(model &md, const mesh_im &mim, const std::string &varname, const std::string &data_E, const std::string &data_nu, size_type region)
Linear elasticity brick (  ). 
void listvar(std::ostream &ost) const 
List the model variables and constant. 
void change_variables_of_brick(size_type ib, const varnamelist &vl)
Change the variable list of a brick. 
The Iteration object calculates whether the solution has reached the desired accuracy, or whether the maximum number of iterations has been reached. 
void asm_homogeneous_Helmholtz(MAT &M, const mesh_im &mim, const mesh_fem &mf_u, const VECT &K_squared, const mesh_region &rg=mesh_region::all_convexes())
assembly of the term , for the helmholtz equation ( , with ). 
void asm_stiffness_matrix_for_laplacian_componentwise(MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
The same as getfem::asm_stiffness_matrix_for_laplacian , but on each component of mf when mf has a qd...
void listbricks(std::ostream &ost, size_type base_id=0) const 
List the model bricks. 
void asm_mass_matrix(const MAT &M, const mesh_im &mim, const mesh_fem &mf1, const mesh_region &rg=mesh_region::all_convexes())
generic mass matrix assembly (on the whole mesh or on the specified convex set or boundary) ...
void asm_stiffness_matrix_for_homogeneous_laplacian_componentwise(const MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_region &rg=mesh_region::all_convexes())
assembly of . 
const std::string & varname_of_brick(size_type ind_brick, size_type ind_var)
Gives the name of the variable of index ind_var of the brick of index ind_brick. 
size_type APIDECL add_source_term_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region=size_type(-1), const std::string &directdataname=std::string())
Add a source term on the variable varname. 
size_type APIDECL add_isotropic_linearized_elasticity_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataname_lambda, const std::string &dataname_mu, size_type region=size_type(-1), const std::string &dataname_preconstraint=std::string())
Linear elasticity brick (  ). 
size_type APIDECL add_mass_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr_rho=std::string(), size_type region=size_type(-1))
Mass brick (  ). 
void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target, const VECTU &U, VECTV &V, int extrapolation=0, double EPS=1E-10, mesh_region rg_source=mesh_region::all_convexes(), mesh_region rg_target=mesh_region::all_convexes())
interpolation/extrapolation of (mf_source, U) on mf_target. 
void asm_stiffness_matrix_for_homogeneous_vector_elliptic(MAT &M, const mesh_im &mim, const mesh_fem &mf, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
Assembly of , where  is a NxNxQxQ (symmetric positive definite) constant tensor. 
int region_is_faces_of(const getfem::mesh &m1, const mesh_region &rg2, const getfem::mesh &m2) const 
Test if the region is a boundary of a list of faces of elements of region rg. 
size_type APIDECL add_Helmholtz_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region=size_type(-1))
Add a Helmoltz brick to the model. 
computation of the condition number of dense matrices. 
Describe a mesh (collection of convexes (elements) and points). 
pinterpolate_transformation interpolate_transformation_neighbour_instance()
Create a new instance of a transformation corresponding to the interpolation on the neighbour element...
void asm_source_term(const VECT1 &B, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT2 &F, const mesh_region &rg=mesh_region::all_convexes())
source term (for both volumic sources and boundary (Neumann) sources). 
void enable_variable(const std::string &name)
Enable a variable (and its attached mutlipliers). 
void APIDECL velocity_update_for_Newmark_scheme(model &md, size_type id2dt2b, const std::string &U, const std::string &V, const std::string &pdt, const std::string &ptwobeta, const std::string &pgamma)
Function which udpate the velocity $v^{n+1}$ after the computation of the displacement $u^{n+1}$ and ...
bool is_old(const std::string &name)
Does the variable have Old_ prefix. 
Describe an integration method linked to a mesh. 
void add_affine_dependent_variable(const std::string &name, const std::string &org_name, scalar_type alpha=scalar_type(1))
Add a "virtual" variable be an affine depedent variable with respect to another variable. 
size_type APIDECL add_pointwise_constraints_with_penalization(model &md, const std::string &varname, scalar_type penalisation_coeff, const std::string &dataname_pt, const std::string &dataname_unitv=std::string(), const std::string &dataname_val=std::string())
Add some pointwise constraints on the variable varname thanks to a penalization. 
virtual void next_iter()
For transient problems. 
void asm_stiffness_matrix_for_homogeneous_scalar_elliptic(MAT &M, const mesh_im &mim, const mesh_fem &mf, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
The same but with a constant matrix. 
void asm_stiffness_matrix_for_homogeneous_laplacian(const MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_region &rg=mesh_region::all_convexes())
assembly of . 
The time integration scheme object provides the necessary methods for the model object to apply a tim...
size_type APIDECL add_linear_incompressibility(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname_pressure, size_type region=size_type(-1), const std::string &dataexpr_penal_coeff=std::string())
Mixed linear incompressibility condition brick. 
takes a list (more often it's a std::vector) of matrices or vectors, creates an empty copy on each th...
const mesh_fem & mesh_fem_of_variable(const std::string &name) const 
Gives the access to the mesh_fem of a variable if any. 
``Model'' variables store the variables, the data and the description of a model. ...
void change_terms_of_brick(size_type ib, const termlist &terms)
Change the term list of a brick. 
size_type APIDECL add_Dirichlet_condition_with_Nitsche_method(model &md, const mesh_im &mim, const std::string &varname, const std::string &Neumannterm, const std::string &datagamma0, size_type region, scalar_type theta=scalar_type(0), const std::string &datag=std::string())
Add a Dirichlet condition on the variable varname and the mesh region region. 
void asm_homogeneous_source_term(const VECT1 &B, const mesh_im &mim, const mesh_fem &mf, const VECT2 &F, const mesh_region &rg=mesh_region::all_convexes())
source term (for both volumic sources and boundary (Neumann) sources). 
size_t size_type
used as the common size type in the library 
void change_update_flag_of_brick(size_type ib, bool flag)
Change the update flag of a brick. 
void add_initialized_matrix_data(const std::string &name, const base_matrix &M)
Add a fixed size data (assumed to be a matrix) to the model and initialized with M. 
Model representation in Getfem. 
void asm_stiffness_matrix_for_scalar_elliptic_componentwise(MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
The same but on each component of mf when mf has a qdim > 1. 
size_type add_brick(pbrick pbr, const varnamelist &varnames, const varnamelist &datanames, const termlist &terms, const mimlist &mims, size_type region)
Add a brick to the model. 
Interpolation of fields from a mesh_fem onto another. 
virtual dim_type get_qdim() const 
Return the Q dimension. 
size_type APIDECL add_isotropic_linearized_elasticity_brick_pstrain(model &md, const mesh_im &mim, const std::string &varname, const std::string &data_E, const std::string &data_nu, size_type region)
Linear elasticity brick (  ). 
void add_multiplier(const std::string &name, const mesh_fem &mf, const std::string &primal_name, size_type niter=1)
Add a particular variable linked to a fem being a multiplier with respect to a primal variable...
this is the above solutions for linux, but it still needs to be tested. 
bool is_complex() const 
Boolean which says if the model deals with real or complex unknowns and data. 
The time dispatcher object modify the result of a brick in order to apply a time integration scheme...
size_type APIDECL add_Dirichlet_condition_with_simplification(model &md, const std::string &varname, size_type region, const std::string &dataname=std::string())
Add a (simple) Dirichlet condition on the variable varname and the mesh region region. 
"iterator" class for regions. 
size_type APIDECL add_generalized_Dirichlet_condition_with_multipliers(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname, size_type region, const std::string &dataname, const std::string &Hname)
Add a generalized Dirichlet condition on the variable varname and the mesh region region...
void del_macro(const std::string &name)
Delete a previously defined macro definition. 
void delete_variable(const std::string &varname)
Delete a variable or data of the model. 
bool is_data(const std::string &name) const 
Says if a name corresponds to a declared data or disabled variable. 
std::string Neumann_term(const std::string &varname, size_type region)
Gives the assembly string corresponding to the Neumann term of the fem variable varname on region...
A langage for generic assembly of pde boundary value problems. 
virtual void first_iter()
For transient problems. 
void add_filtered_fem_variable(const std::string &name, const mesh_fem &mf, size_type region, size_type niter=1)
Add a variable linked to a fem with the dof filtered with respect to a mesh region. 
GEneric Tool for Finite Element Methods. 
size_type APIDECL add_basic_d2_on_dt2_brick(model &md, const mesh_im &mim, const std::string &varnameU, const std::string &datanameV, const std::string &dataname_dt, const std::string &dataname_alpha, const std::string &dataname_rho=std::string(), size_type region=size_type(-1))
Basic d2/dt2 brick (  ). 
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description 
Describe a finite element method linked to a mesh. 
size_type APIDECL add_Laplacian_brick(model &md, const mesh_im &mim, const std::string &varname, size_type region=size_type(-1))
Add a Laplacian term on the variable varname (in fact with a minus : :math:-\text{div}(\nabla u))...
size_type nb_filtered_index() const 
Total numbers of filtered index (integration points) 
model_real_plain_vector & set_real_variable(const std::string &name, size_type niter) const 
Gives the write access to the vector value of a variable. 
Conjugate gradient iterative solver. 
void APIDECL add_theta_method_dispatcher(model &md, dal::bit_vector ibricks, const std::string &THETA)
Add a theta-method time dispatcher to a list of bricks. 
size_type APIDECL add_normal_Dirichlet_condition_with_penalization(model &md, const mesh_im &mim, const std::string &varname, scalar_type penalization_coeff, size_type region, const std::string &dataname=std::string(), const mesh_fem *mf_mult=0)
Add a Dirichlet condition to the normal component of the vector (or tensor) valued variable varname a...
void APIDECL velocity_update_for_order_two_theta_method(model &md, const std::string &U, const std::string &V, const std::string &pdt, const std::string &ptheta)
Function which udpate the velocity $v^{n+1}$ after the computation of the displacement $u^{n+1}$ and ...
The virtual brick has to be derived to describe real model bricks. 
void asm_normal_source_term(VECT1 &B, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT2 &F, const mesh_region &rg)
Normal source term (for boundary (Neumann) condition). 
void asm_homogeneous_normal_source_term(VECT1 &B, const mesh_im &mim, const mesh_fem &mf, const VECT2 &F, const mesh_region &rg)
Homogeneous normal source term (for boundary (Neumann) condition). 
void APIDECL compute_isotropic_linearized_Von_Mises_pstrain(model &md, const std::string &varname, const std::string &data_E, const std::string &data_nu, const mesh_fem &mf_vm, model_real_plain_vector &VM)
Compute the Von-Mises stress of a displacement field for isotropic linearized elasticity in 3D or in ...
Extract a basis of the range of a (large sparse) matrix from the columns of this matrix. 
void resize_fixed_size_variable(const std::string &name, size_type size)
Resize a fixed size variable (or data) of the model. 
size_type APIDECL add_generalized_Dirichlet_condition_with_penalization(model &md, const mesh_im &mim, const std::string &varname, scalar_type penalization_coeff, size_type region, const std::string &dataname, const std::string &Hname, const mesh_fem *mf_mult=0)
Add a Dirichlet condition on the variable varname and the mesh region region. 
size_type APIDECL add_pointwise_constraints_with_multipliers(model &md, const std::string &varname, const std::string &dataname_pt, const std::string &dataname_unitv=std::string(), const std::string &dataname_val=std::string())
Add some pointwise constraints on the variable varname using multiplier. 
void run(Function f, Parameters...params)
Run function f in parallel part to capture it's exceptions. 
void add_mim_to_brick(size_type ib, const mesh_im &mim)
Add an integration method to a brick. 
void touch_brick(size_type ib)
Force the re-computation of a brick for the next assembly. 
bool variable_exists(const std::string &name) const 
Says if a name corresponds to a declared variable. 
void add_fem_data(const std::string &name, const mesh_fem &mf, dim_type qdim=1, size_type niter=1)
Add a data being the dofs of a finite element method to the model. 
void asm_stiffness_matrix_for_vector_elliptic(MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
Assembly of , where  is a NxNxQxQ (symmetric positive definite) tensor defined on mf_data...
void enable_brick(size_type ib)
Enable a brick. 
size_type APIDECL add_normal_source_term_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region)
Add a source term on the variable varname on a boundary region. 
size_type APIDECL add_basic_d_on_dt_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataname_dt, const std::string &dataname_rho=std::string(), size_type region=size_type(-1))
Basic d/dt brick (  ). 
void add_im_data(const std::string &name, const im_data &im_data, size_type niter=1)
Add data, defined at integration points. 
size_type APIDECL add_source_term(model &md, const mesh_im &mim, const std::string &expr, size_type region=size_type(-1), std::string brickname="", std::string directvarname=std::string(), const std::string &directdataname=std::string(), bool return_if_nonlin=false)
Add a source term given by the assembly string expr which will be assembled in region region and with...
std::string new_name(const std::string &name)
Gives a non already existing variable name begining by name. 
void asm_stiffness_matrix_for_laplacian(MAT &M, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
assembly of  , where  is scalar. 
void add_fem_variable(const std::string &name, const mesh_fem &mf, size_type niter=1)
Add a variable being the dofs of a finite element method to the model. 
const mesh & linked_mesh() const 
Return a reference to the underlying mesh. 
const mesh & linked_mesh() const 
Give a reference to the linked mesh of type mesh. 
Allows to re-throw exceptions, generated in OpemMP parallel section. 
const mesh_fem * pmesh_fem_of_variable(const std::string &name) const 
Gives a pointer to the mesh_fem of a variable if any. 
const model_real_plain_vector & real_variable(const std::string &name, size_type niter) const 
Gives the access to the vector value of a variable. 
void APIDECL compute_isotropic_linearized_Von_Mises_pstress(model &md, const std::string &varname, const std::string &data_E, const std::string &data_nu, const mesh_fem &mf_vm, model_real_plain_vector &VM)
Compute the Von-Mises stress of a displacement field for isotropic linearized elasticity in 3D or in ...
bool is_true_data(const std::string &name) const 
Says if a name corresponds to a declared data. 
size_type APIDECL add_linear_term(model &md, const mesh_im &mim, const std::string &expr, size_type region=size_type(-1), bool is_sym=false, bool is_coercive=false, std::string brickname="", bool return_if_nonlin=false)
Add a matrix term given by the assembly string expr which will be assembled in region region and with...
model_complex_plain_vector & set_complex_variable(const std::string &name, size_type niter) const 
Gives the write access to the vector value of a variable. 
void delete_brick(size_type ib)
Delete the brick of index ib from the model. 
std::string no_old_prefix_name(const std::string &name)
Strip the variable name from prefix Old_ if it has one. 
void asm_Helmholtz(MAT &M, const mesh_im &mim, const mesh_fem &mf_u, const mesh_fem &mf_data, const VECT &K_squared, const mesh_region &rg=mesh_region::all_convexes())
assembly of the term , for the helmholtz equation ( , with ). 
im_data provides indexing to the integration points of a mesh im object. 
const std::string & dataname_of_brick(size_type ind_brick, size_type ind_data)
Gives the name of the data of index ind_data of the brick of index ind_brick. 
const mesh_region region(size_type id) const 
Return the region of index 'id'. 
void add_time_dispatcher(size_type ibrick, pdispatcher pdispatch)
Add a time dispacther to a brick. 
size_type APIDECL add_nonlinear_term(model &md, const mesh_im &mim, const std::string &expr, size_type region=size_type(-1), bool is_sym=false, bool is_coercive=false, std::string brickname="")
Add a nonlinear term given by the assembly string expr which will be assembled in region region and w...
size_type APIDECL add_Fourier_Robin_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region)
Add a Fourier-Robin brick to the model. 
size_type APIDECL add_Dirichlet_condition_with_penalization(model &md, const mesh_im &mim, const std::string &varname, scalar_type penalization_coeff, size_type region, const std::string &dataname=std::string(), const mesh_fem *mf_mult=0)
Add a Dirichlet condition on the variable varname and the mesh region region. 
void add_initialized_tensor_data(const std::string &name, const base_tensor &t)
Add a fixed size data (assumed to be a tensor) to the model and initialized with t. 
void interpolation_von_mises_or_tresca(const getfem::mesh_fem &mf_u, const getfem::mesh_fem &mf_vm, const VEC1 &U, VEC2 &VM, const getfem::mesh_fem &mf_lambda, const VEC3 &lambda, const getfem::mesh_fem &mf_mu, const VEC3 &mu, bool tresca)
Compute the Von-Mises stress of a field (valid for linearized elasticity in 2D and 3D) ...
Compute the gradient of a field on a getfem::mesh_fem. 
Miscelleanous assembly routines for common terms. Use the low-level generic assembly. Prefer the high-level one. 
void add_fixed_size_variable(const std::string &name, size_type size, size_type niter=1)
Add a fixed size variable to the model assumed to be a vector. 
void check_stiffness_matrix_and_rhs(const model &, size_type, const model::termlist &tlist, const model::varnamelist &, const model::varnamelist &, const model::mimlist &, model::real_matlist &, model::real_veclist &, model::real_veclist &, size_type rg, const scalar_type delta=1e-8) const 
check consistency of stiffness matrix and rhs 
std::shared_ptr< const virtual_brick > pbrick
type of pointer on a brick 
size_type nb_tensor_elem() const 
sum of tensor elements, M(3,3) will have 3*3=9 elements 
size_type APIDECL add_generic_elliptic_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region=size_type(-1))
Add an elliptic term on the variable varname. 
const mesh_fem & classical_mesh_fem(const mesh &mesh, dim_type degree, dim_type qdim=1, bool complete=false)
Gives the descriptor of a classical finite element method of degree K on mesh. 
void asm_mass_matrix_param(const MAT &M, const mesh_im &mim, const mesh_fem &mf1, const mesh_fem &mf2, const mesh_fem &mf_data, const VECT &A, const mesh_region &rg=mesh_region::all_convexes())
generic mass matrix assembly with an additional parameter (on the whole mesh or on the specified boun...
void asm_qu_term(MAT &M, const mesh_im &mim, const mesh_fem &mf_u, const mesh_fem &mf_d, const VECT &Q, const mesh_region &rg)
assembly of  
size_type APIDECL add_Dirichlet_condition_with_multipliers(model &md, const mesh_im &mim, const std::string &varname, const std::string &multname, size_type region, const std::string &dataname=std::string())
Add a Dirichlet condition on the variable varname and the mesh region region. 
const model_complex_plain_vector & complex_variable(const std::string &name, size_type niter) const 
Gives the access to the vector value of a variable. 
void change_data_of_brick(size_type ib, const varnamelist &vl)
Change the data list of a brick. 
virtual void assembly(build_version version)
Assembly of the tangent system taking into account the terms from all bricks. 
void APIDECL change_penalization_coeff(model &md, size_type ind_brick, scalar_type penalisation_coeff)
Change the penalization coefficient of a Dirichlet condition with penalization brick.