GetFEM  5.4.1
getfem_models.cc
1 /*===========================================================================
2 
3  Copyright (C) 2009-2020 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 #include <iomanip>
23 #include "gmm/gmm_range_basis.h"
24 #include "gmm/gmm_solver_cg.h"
26 #include "getfem/getfem_models.h"
33 
34 
35 namespace getfem {
36 
37  model::model(bool comp_version) {
38  init(); complex_version = comp_version;
39  is_linear_ = is_symmetric_ = is_coercive_ = true;
40  leading_dim = 0;
41  time_integration = 0; init_step = false; time_step = scalar_type(1);
45  ("neighbor_element", interpolate_transformation_neighbor_instance());
46 
47  ga_tree tree1;
48  pstring s1 = std::make_shared<std::string>("Hess_u");
49  tree1.add_name(s1->c_str(), 6, 0, s1);
50  tree1.root->name = "u";
51  tree1.root->op_type = GA_NAME;
52  tree1.root->node_type = GA_NODE_MACRO_PARAM;
53  tree1.root->nbc1 = 0;
54  tree1.root->nbc2 = ga_parse_prefix_operator(*s1);
55  tree1.root->nbc3 = ga_parse_prefix_test(*s1);
56  ga_macro gam1("Hess", tree1, 1);
57  macro_dict.add_macro(gam1);
58 
59  ga_tree tree2;
60  pstring s2 = std::make_shared<std::string>("Div_u");
61  tree2.add_name(s2->c_str(), 5, 0, s2);
62  tree2.root->name = "u";
63  tree2.root->op_type = GA_NAME;
64  tree2.root->node_type = GA_NODE_MACRO_PARAM;
65  tree2.root->nbc1 = 0;
66  tree2.root->nbc2 = ga_parse_prefix_operator(*s2);
67  tree2.root->nbc3 = ga_parse_prefix_test(*s2);
68  ga_macro gam2("Div", tree2, 1);
69  macro_dict.add_macro(gam2);
70  }
71 
72  void model::var_description::set_size() {
73  clear_temporaries();
74  v_num_var_iter.resize(n_iter);
75  v_num_iter.resize(n_iter);
76  size_type s = is_fem_dofs ? passociated_mf()->nb_dof()
77  : (imd ? imd->nb_filtered_index()
78  * imd->nb_tensor_elem()
79  : 1);
80  s *= qdim();
81  for (size_type i = 0; i < n_iter; ++i)
82  if (is_complex)
83  complex_value[i].resize(s);
84  else
85  real_value[i].resize(s);
86  if (is_affine_dependent) {
87  if (is_complex)
88  affine_complex_value.resize(s);
89  else
90  affine_real_value.resize(s);
91  }
92  }
93 
94  size_type model::var_description::add_temporary(gmm::uint64_type id_num) {
95  size_type nit = n_iter;
96  for (; nit < n_iter + n_temp_iter ; ++nit)
97  if (v_num_var_iter[nit] == id_num) break;
98  if (nit >= n_iter + n_temp_iter) {
99  ++n_temp_iter;
100  v_num_var_iter.resize(nit+1);
101  v_num_var_iter[nit] = id_num;
102  v_num_iter.resize(nit+1);
103  v_num_iter[nit] = 0;
104  if (is_complex) {
105  size_type s = complex_value[0].size();
106  complex_value.resize(n_iter + n_temp_iter);
107  complex_value[nit].resize(s);
108  } else {
109  size_type s = real_value[0].size();
110  real_value.resize(n_iter + n_temp_iter);
111  real_value[nit].resize(s);
112  }
113  }
114  return nit;
115  }
116 
117  void model::var_description::clear_temporaries() {
118  n_temp_iter = 0;
119  default_iter = 0;
120  if (is_complex)
121  complex_value.resize(n_iter);
122  else
123  real_value.resize(n_iter);
124  }
125 
126  bool model::check_name_validity(const std::string &name, bool assert) const {
127 
128  if (variables.count(name) != 0) {
129  GMM_ASSERT1(!assert, "Variable " << name << " already exists");
130  return false;
131  } else if (variable_groups.count(name) != 0) {
132  GMM_ASSERT1(!assert,
133  name << " corresponds to an already existing group of "
134  "variables name");
135  return false;
136  } else if (macro_exists(name)) {
137  GMM_ASSERT1(!assert,
138  name << " corresponds to an already existing macro");
139  return false;
140  } else if (name.compare("X") == 0) {
141  GMM_ASSERT1(!assert, "X is a reserved keyword of the generic "
142  "assembly language");
143  return false;
144  }
145 
146  int ga_valid = ga_check_name_validity(name);
147  if (ga_valid == 1) {
148  GMM_ASSERT1(!assert, "Invalid variable name, corresponds to an "
149  "operator or function name of the generic assembly language");
150  return false;
151  } else if (ga_valid == 2) {
152  GMM_ASSERT1(!assert, "Invalid variable name having a reserved "
153  "prefix used by the generic assembly language");
154  return false;
155  } else if (ga_valid == 3) {
156  std::string org_name = sup_previous_and_dot_to_varname(name);
157  if (org_name.size() < name.size() &&
158  variables.find(org_name) != variables.end()) {
159  GMM_ASSERT1(!assert,
160  "Dot and Previous are reserved prefix used for time "
161  "integration schemes");
162  return false;
163  }
164  }
165 
166  bool valid = !name.empty() && isalpha(name[0]);
167  if (valid)
168  for (size_type i = 1; i < name.size(); ++i)
169  if (!(isalnum(name[i]) || name[i] == '_')) valid = false;
170  GMM_ASSERT1(!assert || valid,
171  "Illegal variable name : \"" << name << "\"");
172  return valid;
173  }
174 
175  std::string model::new_name(const std::string &name) {
176  std::string res_name = name;
177  bool valid = check_name_validity(res_name, false);
178  for (size_type i = 2; !valid && i < 50; ++i) {
179  std::stringstream m;
180  m << name << '_' << i;
181  res_name = m.str();
182  valid = check_name_validity(res_name, false);
183  }
184  for (size_type i = 2; !valid && i < 1000; ++i) {
185  std::stringstream m;
186  m << "new_" << name << '_' << i;
187  res_name = m.str();
188  valid = check_name_validity(res_name, false);
189  }
190  GMM_ASSERT1(valid, "Illegal variable name: " << name);
191  return res_name;
192  }
193 
194 
195  model::VAR_SET::const_iterator
196  model::find_variable(const std::string &name) const {
197  VAR_SET::const_iterator it = variables.find(name);
198  GMM_ASSERT1(it != variables.end(), "Undefined variable " << name);
199  return it;
200  }
201 
202  const model::var_description &
203  model::variable_description(const std::string &name) const {
204  return find_variable(name)->second;
205  }
206 
207  std::string sup_previous_and_dot_to_varname(std::string v) {
208  if (!(v.compare(0, 8, "Previous")) && (v[8] == '_' || v[9] == '_')) {
209  v = v.substr((v[8] == '_') ? 9 : 10);
210  }
211  if (!(v.compare(0, 3, "Dot")) && (v[3] == '_' || v[4] == '_')) {
212  v = v.substr((v[3] == '_') ? 4 : 5);
213  }
214  if (is_old(v)) v = no_old_prefix_name(v);
215  return v;
216  }
217 
218  bool is_old(const std::string &name){
219  return name.substr(0, PREFIX_OLD_LENGTH) == PREFIX_OLD;
220  }
221 
222  std::string no_old_prefix_name(const std::string &name){
223  return is_old(name) ? name.substr(PREFIX_OLD_LENGTH) : name;
224  }
225 
226  bool model::is_disabled_variable(const std::string &name) const {
227  if (is_old(name)) return false;
228  VAR_SET::const_iterator it = find_variable(name);
229  if (!(it->second.is_variable)) return false;
230  if (it->second.is_affine_dependent)
231  it = variables.find(it->second.org_name);
232  return it->second.is_disabled;
233  }
234 
235  bool model::is_data(const std::string &name) const {
236  if (is_old(name)) return true;
237  VAR_SET::const_iterator it = find_variable(name);
238  if (it->second.is_affine_dependent)
239  it = variables.find(it->second.org_name);
240  return !(it->second.is_variable) || it->second.is_disabled;
241  }
242 
243  bool model::is_true_data(const std::string &name) const {
244  return is_old(name) || !(variable_description(name).is_variable);
245  }
246 
247  bool model::is_internal_variable(const std::string &name) const {
248  if (is_old(name)) return false;
249  const auto &var_descr = variable_description(name);
250  return var_descr.is_internal && !var_descr.is_disabled;
251  }
252 
253  bool model::is_affine_dependent_variable(const std::string &name) const {
254  return !(is_old(name)) && variable_description(name).is_affine_dependent;
255  }
256 
257  const std::string &
258  model::org_variable(const std::string &name) const {
259  GMM_ASSERT1(is_affine_dependent_variable(name),
260  "For affine dependent variables only");
261  return variable_description(name).org_name;
262  }
263 
264  const scalar_type &
265  model::factor_of_variable(const std::string &name) const {
266  return variable_description(name).alpha;
267  }
268 
269  void model::set_factor_of_variable(const std::string &name, scalar_type a) {
270  VAR_SET::iterator it = variables.find(name);
271  GMM_ASSERT1(it != variables.end(), "Undefined variable " << name);
272  if (it->second.alpha != a) {
273  it->second.alpha = a;
274  for (auto &v_num : it->second.v_num_data) v_num = act_counter();
275  }
276  }
277 
278  bool model::is_im_data(const std::string &name) const {
279  return variable_description(no_old_prefix_name(name)).imd != 0;
280  }
281 
282  const im_data *
283  model::pim_data_of_variable(const std::string &name) const {
284  return variable_description(no_old_prefix_name(name)).imd;
285  }
286 
287  const gmm::uint64_type &
288  model::version_number_of_data_variable(const std::string &name,
289  size_type niter) const {
290  VAR_SET::const_iterator it = find_variable(name);
291  if (niter == size_type(-1)) niter = it->second.default_iter;
292  return it->second.v_num_data[niter];
293  }
294 
295  size_type model::nb_dof(bool with_internal) const {
296  context_check();
297  if (act_size_to_be_done) actualize_sizes();
298  if (complex_version)
299  return gmm::vect_size(crhs);
300  else if (with_internal && gmm::vect_size(full_rrhs))
301  return gmm::vect_size(full_rrhs);
302  else
303  return gmm::vect_size(rrhs);
304  }
305 
306  void model::resize_global_system() const {
307 
308  size_type full_size = 0;
309  for (auto &&v : variables)
310  if (v.second.is_variable) {
311  if (v.second.is_disabled)
312  v.second.I = gmm::sub_interval(0,0);
313  else if (!v.second.is_affine_dependent && !v.second.is_internal) {
314  v.second.I = gmm::sub_interval(full_size, v.second.size());
315  full_size += v.second.size();
316  }
317  }
318  size_type primary_size = full_size;
319 
320  for (auto &&v : variables)
321  if (v.second.is_internal && !v.second.is_disabled) { // is_internal_variable()
322  v.second.I = gmm::sub_interval(full_size, v.second.size());
323  full_size += v.second.size();
324  }
325 
326  for (auto &&v : variables)
327  if (v.second.is_affine_dependent) {
328  v.second.I = variables.find(v.second.org_name)->second.I;
329  v.second.set_size();
330  }
331 
332  if (complex_version) {
333  gmm::resize(cTM, primary_size, primary_size);
334  gmm::resize(crhs, primary_size);
335  }
336  else {
337  gmm::resize(rTM, primary_size, primary_size);
338  gmm::resize(rrhs, primary_size);
339  }
340 
341  if (full_size > primary_size) {
342  GMM_ASSERT1(has_internal_variables(), "Internal error");
343  gmm::resize(internal_rTM, full_size-primary_size, primary_size);
344  gmm::resize(full_rrhs, full_size);
345  gmm::resize(internal_sol, full_size-primary_size);
346  } else {
347  GMM_ASSERT1(!(has_internal_variables()), "Internal error");
348  gmm::resize(internal_rTM, 0, 0);
349  full_rrhs.clear();
350  }
351 
352  for (dal::bv_visitor ib(valid_bricks); !ib.finished(); ++ib)
353  for (const term_description &term : bricks[ib].tlist)
354  if (term.is_global) {
355  bricks[ib].terms_to_be_computed = true;
356  break;
357  }
358  }
359 
360  void model::actualize_sizes() const {
361  // cout << "begin act size" << endl;
362  bool actualized = false;
363  getfem::local_guard lock = locks_.get_lock();
364  if (actualized) return; // If multiple threads are calling the method
365 
366  act_size_to_be_done = false;
367 
368  std::map<std::string, std::vector<std::string> > multipliers;
369  std::set<std::string> tobedone;
370 
371 // #if GETFEM_PARA_LEVEL > 1
372 // int rk; MPI_Comm_rank(MPI_COMM_WORLD, &rk);
373 // double t_ref = MPI_Wtime();
374 // cout << "Actualize size called from thread " << rk << endl;
375 // #endif
376 
377 
378  // In case of change in fems or mims, linear terms have to be recomputed
379  // We could select which brick is to be recomputed if we would be able
380  // to know which fem or mim is changed
381  // -> already taken into account in update_brick()
382  // for (dal::bv_visitor ib(valid_bricks); !ib.finished(); ++ib)
383  // bricks[ib].terms_to_be_computed = true;
384 
385  for (auto &&v : variables) {
386  const std::string &vname = v.first;
387  var_description &vdescr = v.second;
388  if (vdescr.is_fem_dofs && !vdescr.is_affine_dependent) {
389  if ((vdescr.filter & VDESCRFILTER_CTERM)
390  || (vdescr.filter & VDESCRFILTER_INFSUP)) {
391  VAR_SET::iterator vfilt = variables.find(vdescr.filter_var);
392  GMM_ASSERT1(vfilt != variables.end(), "The primal variable of the"
393  " multiplier does not exist : " << vdescr.filter_var);
394  GMM_ASSERT1(vfilt->second.is_fem_dofs, "The primal variable of "
395  "the multiplier is not a fem variable");
396  multipliers[vdescr.filter_var].push_back(vname);
397  if (vdescr.v_num < vdescr.mf->version_number() ||
398  vdescr.v_num < vfilt->second.mf->version_number()) {
399  tobedone.insert(vdescr.filter_var);
400  }
401  }
402  switch (vdescr.filter) {
403  case VDESCRFILTER_NO:
404  if (vdescr.v_num < vdescr.mf->version_number()) {
405  vdescr.set_size();
406  vdescr.v_num = act_counter();
407  }
408  break;
409  case VDESCRFILTER_REGION:
410  if (vdescr.v_num < vdescr.mf->version_number()) {
411  dal::bit_vector
412  dor = vdescr.mf->dof_on_region(vdescr.filter_region);
413  vdescr.partial_mf->adapt(dor);
414  vdescr.set_size();
415  vdescr.v_num = act_counter();
416  }
417  break;
418  default : break;
419  }
420  }
421 
422  if (vdescr.imd != 0
423  && vdescr.v_num < vdescr.imd->version_number()) {
424  vdescr.set_size();
425  vdescr.v_num = act_counter();
426  }
427  }
428 
429  for (auto &&v : variables) {
430  var_description &vdescr = v.second;
431  if (vdescr.is_fem_dofs && !(vdescr.is_affine_dependent) &&
432  ((vdescr.filter & VDESCRFILTER_CTERM)
433  || (vdescr.filter & VDESCRFILTER_INFSUP))) {
434  if (tobedone.count(vdescr.filter_var)) {
435  // This step forces the recomputation of corresponding bricks.
436  // A test to check if a modification is really necessary could
437  // be done first ... (difficult to coordinate with other
438  // multipliers)
439  dal::bit_vector alldof; alldof.add(0, vdescr.mf->nb_dof());
440  vdescr.partial_mf->adapt(alldof);
441  vdescr.set_size();
442  vdescr.v_num = act_counter();
443  }
444  }
445  }
446 
447  resize_global_system();
448 
449  for (const std::string &vname : tobedone) {
450 // #if GETFEM_PARA_LEVEL > 1
451 // double tt_ref = MPI_Wtime();
452 // if (!rk) cout << "compute size of multipliers for " << vname
453 // << endl;
454 // #endif
455 
456  const std::vector<std::string> &mults = multipliers[vname];
457  const var_description &vdescr = variable_description(vname);
458 
459  gmm::col_matrix< gmm::rsvector<scalar_type> > MGLOB;
460  if (mults.size() > 1) {
461  size_type s = 0;
462  for (const std::string &mult : mults)
463  s += variable_description(mult).mf->nb_dof();
464  gmm::resize(MGLOB, vdescr.mf->nb_dof(), s);
465  }
466  size_type s = 0;
467  std::set<size_type> glob_columns;
468  for (const std::string &multname : mults) {
469  var_description &multdescr = variables.find(multname)->second;
470 
471  // Obtaining the coupling matrix between the multipier and
472  // the primal variable. A search is done on all the terms of the
473  // model. Only the corresponding linear terms are added.
474  // If no linear term is available, a mass matrix is used.
475  gmm::col_matrix< gmm::rsvector<scalar_type> >
476  MM(vdescr.associated_mf().nb_dof(), multdescr.mf->nb_dof());
477  bool termadded = false;
478 
479  if (multdescr.filter & VDESCRFILTER_CTERM) {
480 
481  for (dal::bv_visitor ib(valid_bricks); !ib.finished(); ++ib) {
482  const brick_description &brick = bricks[ib];
483  bool bupd = false;
484  bool cplx = is_complex() && brick.pbr->is_complex();
485 
486  if (brick.tlist.size() == 0) {
487  bool varc = false, multc = false;
488  for (const std::string &var : brick.vlist) {
489  if (multname.compare(var) == 0) multc = true;
490  if (vname.compare(var) == 0) varc = true;
491  }
492  if (multc && varc) {
493  GMM_ASSERT1(!cplx, "Sorry, not taken into account");
494  generic_expressions.clear();
495  brick.terms_to_be_computed = true;
496  update_brick(ib, BUILD_MATRIX);
497  if (generic_expressions.size()) {
498  GMM_TRACE2("Generic assembly for actualize sizes");
499  {
500  gmm::clear(rTM);
501  accumulated_distro<decltype(rTM)> distro_rTM(rTM);
503  ga_workspace workspace(*this);
504  for (const auto &ge : generic_expressions)
505  workspace.add_expression(ge.expr, ge.mim, ge.region,
506  2, ge.secondary_domain);
507  workspace.set_assembled_matrix(distro_rTM);
508  workspace.assembly(2);
509  );
510  } //accumulated_distro scope
511  gmm::add(gmm::sub_matrix(rTM, vdescr.I, multdescr.I), MM);
512  gmm::add(gmm::transposed
513  (gmm::sub_matrix(rTM, multdescr.I, vdescr.I)), MM);
514  bupd = false;
515  }
516  }
517  }
518 
519  for (size_type j = 0; j < brick.tlist.size(); ++j) {
520  const term_description &term = brick.tlist[j];
521 
522  if (term.is_matrix_term) {
523  if (term.is_global) {
524  bool varc = false, multc = false;
525  for (const std::string var : brick.vlist) {
526  if (multname.compare(var) == 0) multc = true;
527  if (vname.compare(var) == 0) varc = true;
528  }
529  if (multc && varc) {
530  GMM_ASSERT1(!cplx, "Sorry, not taken into account");
531  generic_expressions.clear();
532  if (!bupd) {
533  brick.terms_to_be_computed = true;
534  update_brick(ib, BUILD_MATRIX);
535  bupd = true;
536  }
537  gmm::add(gmm::sub_matrix(brick.rmatlist[j],
538  multdescr.I, vdescr.I),
539  MM);
540  gmm::add(gmm::transposed(gmm::sub_matrix
541  (brick.rmatlist[j],
542  vdescr.I, multdescr.I)),
543  MM);
544  termadded = true;
545  }
546  } else if (multname.compare(term.var1) == 0 &&
547  vname.compare(term.var2) == 0) {
548  if (!bupd) {
549  brick.terms_to_be_computed = true;
550  update_brick(ib, BUILD_MATRIX);
551  bupd = true;
552  }
553  if (cplx)
554  gmm::add(gmm::transposed(gmm::real_part(brick.cmatlist[j])),
555  MM);
556  else
557  gmm::add(gmm::transposed(brick.rmatlist[j]), MM);
558  termadded = true;
559 
560  } else if (multname.compare(term.var2) == 0 &&
561  vname.compare(term.var1) == 0) {
562  if (!bupd) {
563  brick.terms_to_be_computed = true;
564  update_brick(ib, BUILD_MATRIX);
565  bupd = true;
566  }
567  if (cplx)
568  gmm::add(gmm::real_part(brick.cmatlist[j]), MM);
569  else
570  gmm::add(brick.rmatlist[j], MM);
571  termadded = true;
572  }
573  }
574  }
575  }
576 
577  if (!termadded)
578  GMM_WARNING1("No term found to filter multiplier " << multname
579  << ". Variable is cancelled");
580  } else if (multdescr.filter & VDESCRFILTER_INFSUP) {
581  mesh_region rg(multdescr.filter_region);
582  multdescr.filter_mim->linked_mesh().intersect_with_mpi_region(rg);
583  asm_mass_matrix(MM, *(multdescr.filter_mim), vdescr.associated_mf(),
584  *(multdescr.mf), rg);
585  }
586 
587  MPI_SUM_SPARSE_MATRIX(MM);
588 
589  //
590  // filtering
591  //
592  std::set<size_type> columns;
593  gmm::range_basis(MM, columns);
594  if (columns.size() == 0)
595  GMM_WARNING1("Empty basis found for multiplier " << multname);
596 
597  if (mults.size() > 1) {
598  gmm::copy(MM, gmm::sub_matrix
599  (MGLOB,
600  gmm::sub_interval(0, vdescr.associated_mf().nb_dof()),
601  gmm::sub_interval(s, multdescr.mf->nb_dof())));
602  for (const size_type &icol : columns)
603  glob_columns.insert(s + icol);
604  s += multdescr.mf->nb_dof();
605  } else {
606  dal::bit_vector kept;
607  for (const size_type &icol : columns)
608  kept.add(icol);
609  if (multdescr.filter & VDESCRFILTER_REGION)
610  kept &= multdescr.mf->dof_on_region(multdescr.filter_region);
611  multdescr.partial_mf->adapt(kept);
612  multdescr.set_size();
613  multdescr.v_num = act_counter();
614  }
615  }
616 
617 // #if GETFEM_PARA_LEVEL > 1
618 // if (!rk) cout << "Range basis for multipliers for " << vname << " time : " << MPI_Wtime()-tt_ref << endl;
619 // #endif
620 
621  if (mults.size() > 1) {
622  gmm::range_basis(MGLOB, glob_columns, 1E-12, gmm::col_major(), true);
623 
624 // #if GETFEM_PARA_LEVEL > 1
625 // if (!rk) cout << "Producing partial mf for multipliers for " << vname << " time : " << MPI_Wtime()-tt_ref << endl;
626 // #endif
627 
628  s = 0;
629  for (const std::string &multname : mults) {
630  var_description &multdescr = variables.find(multname)->second;
631  dal::bit_vector kept;
632  size_type nbdof = multdescr.mf->nb_dof();
633  for (const size_type &icol : glob_columns)
634  if (icol >= s && icol < s + nbdof) kept.add(icol-s);
635  if (multdescr.filter & VDESCRFILTER_REGION)
636  kept &= multdescr.mf->dof_on_region(multdescr.filter_region);
637  multdescr.partial_mf->adapt(kept);
638  multdescr.set_size();
639  multdescr.v_num = act_counter();
640  s += multdescr.mf->nb_dof();
641  }
642  }
643 // #if GETFEM_PARA_LEVEL > 1
644 // if (!rk) cout << "End compute size of multipliers for " << vname << " time : " << MPI_Wtime()-tt_ref << endl;
645 // #endif
646  }
647 
648  resize_global_system();
649  actualized = true;
650 // #if GETFEM_PARA_LEVEL > 1
651 // cout << "Actualize sizes time from thread " << rk << " : " << MPI_Wtime()-t_ref << endl;
652 
653 // #endif
654 
655  // cout << "end act size" << endl;
656  }
657 
658 
659  void model::listvar(std::ostream &ost) const {
660  if (variables.size() == 0)
661  ost << "Model with no variable nor data" << endl;
662  else {
663  ost << "List of model variables and data:" << endl;
664  for (const auto &v : variables) {
665  const var_description &vdescr = v.second;
666  if (vdescr.is_variable) ost << "Variable ";
667  else ost << "Data ";
668  ost << std::setw(30) << std::left << v.first;
669  if (vdescr.n_iter == 1)
670  ost << " 1 copy ";
671  else
672  ost << std::setw(2) << std::right << vdescr.n_iter << " copies ";
673  if (vdescr.is_fem_dofs) ost << "fem dependant ";
674  else ost << "constant size ";
675  size_type si = vdescr.size();
676  ost << std::setw(8) << std::right << si;
677  if (is_complex()) ost << " complex";
678  ost << " double" << ((si > 1) ? "s." : ".");
679  if (vdescr.is_variable &&
680  is_disabled_variable(v.first)) ost << "\t (disabled)";
681  else ost << "\t ";
682  if (vdescr.imd != 0) ost << "\t (is im_data)";
683  if (vdescr.is_affine_dependent) ost << "\t (is affine dependent)";
684  ost << endl;
685  }
686  for (const auto &vargroup : variable_groups) {
687  ost << "Variable group " << std::setw(30) << std::left
688  << vargroup.first;
689  if (vargroup.second.size()) {
690  bool first(true);
691  for (const std::string vname : vargroup.second) {
692  if (!first) ost << ","; else first = false;
693  ost << " " << vname;
694  }
695  ost << endl;
696  } else ost << " empty" << endl;
697  }
698  }
699  }
700 
701  void model::listresiduals(std::ostream &ost) const {
702  context_check(); if (act_size_to_be_done) actualize_sizes();
703  if (variables.size() == 0)
704  ost << "Model with no variable nor data" << endl;
705  else {
706  bool firstvar(true);
707  for (const auto &v : variables) {
708  if (v.second.is_variable) {
709  const model_real_plain_vector &rhs = v.second.is_internal
710  ? full_rrhs : rrhs;
711  const gmm::sub_interval &II = interval_of_variable(v.first);
712  scalar_type res = gmm::vect_norm2(gmm::sub_vector(rhs, II));
713  if (!firstvar) cout << ", ";
714  ost << "res_" << v.first << "= " << std::setw(11) << res;
715  firstvar = false;
716  }
717  }
718  ost << endl;
719  }
720  }
721 
722  void model::add_fixed_size_variable(const std::string &name, size_type size,
723  size_type niter) {
724  bgeot::multi_index sizes(1);
725  sizes[0] = size;
726  add_fixed_size_variable(name, sizes, niter);
727  }
728 
729  void model::add_fixed_size_variable(const std::string &name,
730  const bgeot::multi_index &sizes,
731  size_type niter) {
732  check_name_validity(name);
733  variables.emplace(name, var_description(true, is_complex(), 0, 0, niter));
734  variables[name].qdims = sizes;
735  act_size_to_be_done = true;
736  variables[name].set_size();
737  GMM_ASSERT1(variables[name].qdim(),
738  "Variables of null size are not allowed");
739  }
740 
741  void model::resize_fixed_size_variable(const std::string &name,
742  size_type size) {
743  bgeot::multi_index sizes(1);
744  sizes[0] = size;
745  resize_fixed_size_variable(name, sizes);
746  }
747 
748  void model::resize_fixed_size_variable(const std::string &name,
749  const bgeot::multi_index &sizes) {
750  GMM_ASSERT1(!(variables[name].is_fem_dofs),
751  "Cannot explicitly resize a fem variable or data");
752  GMM_ASSERT1(variables[name].imd == 0,
753  "Cannot explicitly resize an im data");
754  variables[name].qdims = sizes;
755  variables[name].set_size();
756  }
757 
758  void model::add_fixed_size_data(const std::string &name, size_type size,
759  size_type niter) {
760  bgeot::multi_index sizes(1);
761  sizes[0] = size;
762  add_fixed_size_data(name, sizes, niter);
763  }
764 
765  void model::add_fixed_size_data(const std::string &name,
766  const bgeot::multi_index &sizes,
767  size_type niter) {
768  check_name_validity(name);
769  variables.emplace(name, var_description(false, is_complex(), 0, 0, niter));
770  variables[name].qdims = sizes;
771  GMM_ASSERT1(variables[name].qdim(), "Data of null size are not allowed");
772  variables[name].set_size();
773  }
774 
775  void model::add_initialized_matrix_data(const std::string &name,
776  const base_matrix &M) {
777  add_fixed_size_data(name, bgeot::multi_index(gmm::mat_nrows(M),
778  gmm::mat_ncols(M)));
779  GMM_ASSERT1(!(is_complex()), "Sorry, complex version to be done");
780  gmm::copy(M.as_vector(), set_real_variable(name));
781  }
782 
783  void model::add_initialized_matrix_data(const std::string &name,
784  const base_complex_matrix &M) {
785  add_fixed_size_data(name, bgeot::multi_index(gmm::mat_nrows(M),
786  gmm::mat_ncols(M)));
787  GMM_ASSERT1(!(is_complex()), "Sorry, complex version to be done");
788  gmm::copy(M.as_vector(), set_complex_variable(name));
789  }
790 
791  void model::add_initialized_tensor_data(const std::string &name,
792  const base_tensor &t) {
793  add_fixed_size_data(name, t.sizes(), 1);
794  GMM_ASSERT1(!(is_complex()), "Sorry, complex version to be done");
795  gmm::copy(t.as_vector(), set_real_variable(name));
796  }
797 
798  void model::add_initialized_tensor_data(const std::string &name,
799  const base_complex_tensor &t) {
800  add_fixed_size_data(name, t.sizes(), 1);
801  GMM_ASSERT1(!(is_complex()), "Sorry, complex version to be done");
802  gmm::copy(t.as_vector(), set_complex_variable(name));
803  }
804 
805  void model::add_im_variable(const std::string &name, const im_data &imd,
806  size_type niter) {
807  check_name_validity(name);
808  variables.emplace(name,
809  var_description(true, is_complex(), 0, &imd, niter));
810  variables[name].set_size();
811  add_dependency(imd);
812  act_size_to_be_done = true;
813  }
814 
815  void model::add_internal_im_variable(const std::string &name,
816  const im_data &imd) {
817  add_im_variable(name, imd);
818  variables[name].is_internal = true;
819  }
820 
821  void model::add_im_data(const std::string &name, const im_data &imd,
822  size_type niter) {
823  check_name_validity(name);
824  variables.emplace(name,
825  var_description(false, is_complex(), 0, &imd, niter));
826  variables[name].set_size();
827  add_dependency(imd);
828  }
829 
830  void model::add_fem_variable(const std::string &name, const mesh_fem &mf,
831  size_type niter) {
832  check_name_validity(name);
833  variables.emplace(name, var_description(true, is_complex(), &mf, 0, niter,
834  VDESCRFILTER_NO));
835  variables[name].set_size();
836  add_dependency(mf);
837  act_size_to_be_done = true;
838  leading_dim = std::max(leading_dim, mf.linked_mesh().dim());
839  }
840 
841  void model::add_filtered_fem_variable(const std::string &name,
842  const mesh_fem &mf,
843  size_type region, size_type niter) {
844  check_name_validity(name);
845  variables.emplace(name, var_description(true, is_complex(), &mf, 0, niter,
846  VDESCRFILTER_REGION, region));
847  variables[name].set_size();
848  act_size_to_be_done = true;
849  add_dependency(mf);
850  }
851 
852  void model::add_affine_dependent_variable(const std::string &name,
853  const std::string &org_name,
854  scalar_type alpha) {
855  check_name_validity(name);
856  VAR_SET::const_iterator it = find_variable(org_name);
857  GMM_ASSERT1(it->second.is_variable && !(it->second.is_affine_dependent),
858  "The original variable should be a variable");
859  variables.emplace(name, variables[org_name]);
860  variables[name].is_affine_dependent = true;
861  variables[name].org_name = org_name;
862  variables[name].alpha = alpha;
863  variables[name].set_size();
864  }
865 
866  void model::add_fem_data(const std::string &name, const mesh_fem &mf,
867  dim_type qdim, size_type niter) {
868  bgeot::multi_index sizes(1);
869  sizes[0] = qdim;
870  add_fem_data(name, mf, sizes, niter);
871  }
872 
873  void model::add_fem_data(const std::string &name, const mesh_fem &mf,
874  const bgeot::multi_index &sizes, size_type niter) {
875  check_name_validity(name);
876  variables.emplace(name, var_description(false, is_complex(), &mf, 0, niter,
877  VDESCRFILTER_NO));
878  variables[name].qdims = sizes;
879  GMM_ASSERT1(variables[name].qdim(), "Data of null size are not allowed");
880  variables[name].set_size();
881  add_dependency(mf);
882  }
883 
884  void model::add_multiplier(const std::string &name, const mesh_fem &mf,
885  const std::string &primal_name,
886  size_type niter) {
887  check_name_validity(name);
888  variables.emplace(name, var_description(true, is_complex(), &mf, 0, niter,
889  VDESCRFILTER_CTERM, size_type(-1),
890  primal_name));
891  variables[name].set_size();
892  act_size_to_be_done = true;
893  add_dependency(mf);
894  }
895 
896  void model::add_multiplier(const std::string &name, const mesh_fem &mf,
897  size_type region, const std::string &primal_name,
898  size_type niter) {
899  check_name_validity(name);
900  variables.emplace(name, var_description(true, is_complex(), &mf, 0, niter,
901  VDESCRFILTER_REGION_CTERM, region,
902  primal_name));
903  variables[name].set_size();
904  act_size_to_be_done = true;
905  add_dependency(mf);
906  }
907 
908  void model::add_multiplier(const std::string &name, const mesh_fem &mf,
909  const std::string &primal_name,
910  const mesh_im &mim,
911  size_type region, size_type niter) {
912  check_name_validity(name);
913  variables.emplace(name, var_description(true, is_complex(), &mf, 0, niter,
914  VDESCRFILTER_INFSUP, region,
915  primal_name, &mim));
916  variables[name].set_size();
917  act_size_to_be_done = true;
918  add_dependency(mf);
919  add_dependency(mim);
920  }
921 
922  void model::disable_variable(const std::string &name) {
923  enable_variable(name, false);
924  }
925 
926  void model::enable_variable(const std::string &name, bool enabled) {
927  VAR_SET::iterator it = variables.find(name);
928  GMM_ASSERT1(it != variables.end(), "Undefined variable " << name);
929  it->second.is_disabled = !enabled;
930  for (auto &&v : variables) {
931  if (((v.second.filter & VDESCRFILTER_INFSUP) ||
932  (v.second.filter & VDESCRFILTER_CTERM))
933  && name.compare(v.second.filter_var) == 0) {
934  v.second.is_disabled = !enabled;
935  }
936  if (v.second.is_variable && v.second.is_affine_dependent
937  && name.compare(v.second.org_name) == 0)
938  v.second.is_disabled = !enabled;
939  }
940  if (!act_size_to_be_done) resize_global_system();
941  }
942 
943  bool model::variable_exists(const std::string &name) const {
944  return variables.count(no_old_prefix_name(name)) > 0;
945  }
946 
947  void model::add_macro(const std::string &name, const std::string &expr) {
948  check_name_validity(name.substr(0, name.find("(")));
949  macro_dict.add_macro(name, expr);
950  }
951 
952  void model::del_macro(const std::string &name)
953  { macro_dict.del_macro(name); }
954 
956  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
957  valid_bricks.del(ib);
958  active_bricks.del(ib);
959 
960  for (size_type i = 0; i < bricks[ib].mims.size(); ++i) {
961  const mesh_im *mim = bricks[ib].mims[i];
962  bool found = false;
963  for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
964  for (size_type j = 0; j < bricks[ibb].mims.size(); ++j)
965  if (bricks[ibb].mims[j] == mim) found = true;
966  }
967  for (const auto &v : variables) {
968  if (v.second.is_fem_dofs &&
969  (v.second.filter & VDESCRFILTER_INFSUP) &&
970  mim == v.second.filter_mim) found = true;
971  }
972  if (!found) sup_dependency(*mim);
973  }
974 
975  is_linear_ = is_symmetric_ = is_coercive_ = true;
976  for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
977  is_linear_ = is_linear_ && bricks[ibb].pbr->is_linear();
978  is_symmetric_ = is_symmetric_ && bricks[ibb].pbr->is_symmetric();
979  is_coercive_ = is_coercive_ && bricks[ibb].pbr->is_coercive();
980  }
981  bricks[ib] = brick_description();
982  }
983 
984  void model::delete_variable(const std::string &varname) {
985  for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
986  for (const auto &vname : bricks[ibb].vlist)
987  GMM_ASSERT1(varname.compare(vname),
988  "Cannot delete a variable which is still used by a brick");
989  for (const auto &dname : bricks[ibb].dlist)
990  GMM_ASSERT1(varname.compare(dname),
991  "Cannot delete a data which is still used by a brick");
992  }
993 
994  VAR_SET::const_iterator it = find_variable(varname);
995 
996  if (it->second.is_fem_dofs) {
997  const mesh_fem *mf = it->second.mf;
998  bool found = false;
999  for(VAR_SET::iterator it2 = variables.begin();
1000  it2 != variables.end(); ++it2) {
1001  if (it != it2 && it2->second.is_fem_dofs && mf == it2->second.mf)
1002  found = true;
1003  }
1004  if (!found) sup_dependency(*mf);
1005 
1006  if (it->second.filter & VDESCRFILTER_INFSUP) {
1007  const mesh_im *mim = it->second.filter_mim;
1008  found = false;
1009  for (dal::bv_visitor ibb(valid_bricks); !ibb.finished(); ++ibb) {
1010  for (size_type j = 0; j < bricks[ibb].mims.size(); ++j)
1011  if (bricks[ibb].mims[j] == mim) found = true;
1012  }
1013  for (VAR_SET::iterator it2 = variables.begin();
1014  it2 != variables.end(); ++it2) {
1015  if (it != it2 && it2->second.is_fem_dofs &&
1016  (it2->second.filter & VDESCRFILTER_INFSUP) &&
1017  mim == it2->second.filter_mim) found = true;
1018  }
1019  if (!found) sup_dependency(*mim);
1020  }
1021  }
1022 
1023  if (it->second.imd != 0) sup_dependency(*(it->second.imd));
1024 
1025  variables.erase(varname);
1026  act_size_to_be_done = true;
1027  }
1028 
1029  size_type model::add_brick(pbrick pbr, const varnamelist &varnames,
1030  const varnamelist &datanames,
1031  const termlist &terms,
1032  const mimlist &mims, size_type region) {
1033  size_type ib = valid_bricks.first_false();
1034 
1035  for (size_type i = 0; i < terms.size(); ++i)
1036  if (terms[i].is_global && terms[i].is_matrix_term && pbr->is_linear())
1037  GMM_ASSERT1(false, "Global linear matrix terms are not allowed");
1038 
1039  if (ib == bricks.size())
1040  bricks.push_back(brick_description(pbr, varnames, datanames, terms,
1041  mims, region));
1042  else
1043  bricks[ib] = brick_description(pbr, varnames, datanames, terms,
1044  mims, region);
1045  active_bricks.add(ib);
1046  valid_bricks.add(ib);
1047 
1048  // The brick itself already reacts to a mesh_im change in update_brick()
1049  // for (size_type i = 0; i < bricks[ib].mims.size(); ++i)
1050  // add_dependency(*(bricks[ib].mims[i]));
1051 
1052  GMM_ASSERT1(pbr->is_real() || is_complex(),
1053  "Impossible to add a complex brick to a real model");
1054  if (is_complex() && pbr->is_complex()) {
1055  bricks[ib].cmatlist.resize(terms.size());
1056  bricks[ib].cveclist[0].resize(terms.size());
1057  bricks[ib].cveclist_sym[0].resize(terms.size());
1058  } else {
1059  bricks[ib].rmatlist.resize(terms.size());
1060  bricks[ib].rveclist[0].resize(terms.size());
1061  bricks[ib].rveclist_sym[0].resize(terms.size());
1062  }
1063  is_linear_ = is_linear_ && pbr->is_linear();
1064  is_symmetric_ = is_symmetric_ && pbr->is_symmetric();
1065  is_coercive_ = is_coercive_ && pbr->is_coercive();
1066 
1067  for (const auto &vname : varnames)
1068  GMM_ASSERT1(variables.count(vname),
1069  "Undefined model variable " << vname);
1070  // cout << "dl == " << datanames << endl;
1071  for (const auto &dname : datanames)
1072  GMM_ASSERT1(variables.count(dname),
1073  "Undefined model data or variable " << dname);
1074 
1075  return ib;
1076  }
1077 
1079  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
1080  touch_brick(ib);
1081  bricks[ib].mims.push_back(&mim);
1082  add_dependency(mim);
1083  }
1084 
1085  void model::change_terms_of_brick(size_type ib, const termlist &terms) {
1086  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
1087  touch_brick(ib);
1088  bricks[ib].tlist = terms;
1089  if (is_complex() && bricks[ib].pbr->is_complex()) {
1090  bricks.back().cmatlist.resize(terms.size());
1091  bricks.back().cveclist[0].resize(terms.size());
1092  bricks.back().cveclist_sym[0].resize(terms.size());
1093  } else {
1094  bricks.back().rmatlist.resize(terms.size());
1095  bricks.back().rveclist[0].resize(terms.size());
1096  bricks.back().rveclist_sym[0].resize(terms.size());
1097  }
1098  }
1099 
1100  void model::change_variables_of_brick(size_type ib, const varnamelist &vl) {
1101  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
1102  touch_brick(ib);
1103  bricks[ib].vlist = vl;
1104  for (const auto &v : vl)
1105  GMM_ASSERT1(variables.count(v), "Undefined model variable " << v);
1106  }
1107 
1108  void model::change_data_of_brick(size_type ib, const varnamelist &dl) {
1109  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
1110  touch_brick(ib);
1111  bricks[ib].dlist = dl;
1112  for (const auto &v : dl)
1113  GMM_ASSERT1(variables.count(v), "Undefined model variable " << v);
1114  }
1115 
1116  void model::change_mims_of_brick(size_type ib, const mimlist &ml) {
1117  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
1118  touch_brick(ib);
1119  bricks[ib].mims = ml;
1120  for (const auto &mim : ml) add_dependency(*mim);
1121  }
1122 
1124  GMM_ASSERT1(valid_bricks[ib], "Inexistent brick");
1125  touch_brick(ib);
1126  bricks[ib].is_update_brick = flag;
1127  }
1128 
1129  void model::set_time(scalar_type t, bool to_init) {
1130  static const std::string varname("t");
1131  VAR_SET::iterator it = variables.find(varname);
1132  if (it == variables.end()) {
1133  add_fixed_size_data(varname, 1);
1134  } else {
1135  GMM_ASSERT1(it->second.size() == 1, "Time data should be of size 1");
1136  }
1137  if (it == variables.end() || to_init) {
1138  if (is_complex())
1139  set_complex_variable(varname)[0] = complex_type(t);
1140  else
1141  set_real_variable(varname)[0] = t;
1142  }
1143  }
1144 
1145  scalar_type model::get_time() {
1146  static const std::string varname("t");
1147  set_time(scalar_type(0), false);
1148  if (is_complex())
1149  return gmm::real(complex_variable(varname)[0]);
1150  else
1151  return real_variable(varname)[0];
1152  }
1153 
1154  void model::call_init_affine_dependent_variables(int version) {
1155  for (VAR_SET::iterator it = variables.begin();
1156  it != variables.end(); ++it) {
1157  var_description &vdescr = it->second;
1158  if (vdescr.is_variable && vdescr.ptsc) {
1159  if (version == 2)
1160  vdescr.ptsc->init_affine_dependent_variables_precomputation(*this);
1161  else
1162  vdescr.ptsc->init_affine_dependent_variables(*this);
1163  }
1164  }
1165  }
1166 
1167  void model::shift_variables_for_time_integration() {
1168  for (VAR_SET::iterator it = variables.begin();
1169  it != variables.end(); ++it)
1170  if (it->second.is_variable && it->second.ptsc)
1171  it->second.ptsc->shift_variables(*this);
1172  }
1173 
1174  void model::add_time_integration_scheme(const std::string &varname,
1175  ptime_scheme ptsc) {
1176  VAR_SET::iterator it = variables.find(varname);
1177  GMM_ASSERT1(it != variables.end(), "Undefined variable " << varname);
1178  GMM_ASSERT1(it->second.is_variable && !(it->second.is_affine_dependent),
1179  "Cannot apply an integration scheme to " << varname);
1180  it->second.ptsc = ptsc;
1181 // if (!first_step)
1182 // GMM_WARNING2("When you apply a scheme to new variable or change the "
1183 // "scheme of a variable after the first time step, "
1184 // "the precomputation of time derivative will not be "
1185 // "executed. Caution: You have to care by yourself of "
1186 // "the compatbility of the operation");
1187  time_integration = 1;
1188  }
1189 
1190  void model::copy_init_time_derivative() {
1191 
1192  for (VAR_SET::iterator it = variables.begin();
1193  it != variables.end(); ++it)
1194  if (it->second.is_variable && it->second.ptsc) {
1195 
1196  std::string name_v, name_previous_v;
1197  it->second.ptsc->time_derivative_to_be_initialized(name_v,
1198  name_previous_v);
1199 
1200  if (name_v.size()) {
1201  if (is_complex()) {
1202  model_complex_plain_vector v0 = complex_variable(name_v);
1203  gmm::copy(v0, set_complex_variable(name_previous_v));
1204  } else {
1205  const model_real_plain_vector &v0 = real_variable(name_v);
1206  gmm::copy(v0, set_real_variable(name_previous_v));
1207  }
1208  }
1209  }
1210  }
1211 
1212  // ----------------------------------------------------------------------
1213  //
1214  // Theta-method scheme for first order problems
1215  //
1216  // ----------------------------------------------------------------------
1217 
1218  class APIDECL first_order_theta_method_scheme
1219  : public virtual_time_scheme {
1220 
1221  std::string U, U0, V, V0;
1222  scalar_type theta;
1223 
1224  public:
1225  // V = (U-U0)/(theta*dt) - ((1-theta)/theta)*V0
1226  virtual void init_affine_dependent_variables(model &md) const {
1227  scalar_type dt = md.get_time_step();
1228  scalar_type a = scalar_type(1)/(theta*dt);
1229  scalar_type b = (scalar_type(1)-theta)/theta;
1230  md.set_factor_of_variable(V, a);
1231  if (md.is_complex()) {
1232  gmm::add(gmm::scaled(md.complex_variable(U0), -complex_type(a)),
1233  gmm::scaled(md.complex_variable(V0), -complex_type(b)),
1234  md.set_complex_constant_part(V));
1235 
1236  } else {
1237  gmm::add(gmm::scaled(md.real_variable(U0), -a),
1238  gmm::scaled(md.real_variable(V0), -b),
1239  md.set_real_constant_part(V));
1240  }
1241  }
1242 
1243  // V = (U-U0)/dt (backward Euler for precomputation)
1244  virtual void init_affine_dependent_variables_precomputation(model &md)
1245  const {
1246  scalar_type dt = md.get_time_step();
1247  md.set_factor_of_variable(V, scalar_type(1)/dt);
1248  if (md.is_complex()) {
1249  gmm::copy(gmm::scaled(md.complex_variable(U0), -complex_type(1)/dt),
1250  md.set_complex_constant_part(V));
1251 
1252  } else {
1253  gmm::copy(gmm::scaled(md.real_variable(U0), -scalar_type(1)/dt),
1254  md.set_real_constant_part(V));
1255  }
1256  }
1257 
1258  virtual void time_derivative_to_be_initialized
1259  (std::string &name_v, std::string &name_previous_v) const
1260  { if (theta != scalar_type(1)) { name_v = V; name_previous_v = V0; } }
1261 
1262  virtual void shift_variables(model &md) const {
1263  if (md.is_complex()) {
1264  gmm::copy(md.complex_variable(U), md.set_complex_variable(U0));
1265  gmm::copy(md.complex_variable(V), md.set_complex_variable(V0));
1266  } else {
1267  gmm::copy(md.real_variable(U), md.set_real_variable(U0));
1268  gmm::copy(md.real_variable(V), md.set_real_variable(V0));
1269  }
1270  }
1271 
1272 
1273  first_order_theta_method_scheme(model &md, std::string varname,
1274  scalar_type th) {
1275  U = varname;
1276  U0 = "Previous_" + U;
1277  V = "Dot_" + U;
1278  V0 = "Previous_Dot_" + U;
1279  theta = th;
1280  GMM_ASSERT1(theta > scalar_type(0) && theta <= scalar_type(1),
1281  "Invalid value of theta parameter for the theta-method");
1282 
1283  if (!(md.variable_exists(V)))
1284  md.add_affine_dependent_variable(V, U);
1285  const mesh_fem *mf = md.pmesh_fem_of_variable(U);
1286  size_type s = md.is_complex() ? gmm::vect_size(md.complex_variable(U))
1287  : gmm::vect_size(md.real_variable(U));
1288 
1289  if (mf) {
1290  if (!(md.variable_exists(U0))) md.add_fem_data(U0, *mf);
1291  if (!(md.variable_exists(V0))) md.add_fem_data(V0, *mf);
1292  } else {
1293  if (!(md.variable_exists(U0))) md.add_fixed_size_data(U0, s);
1294  if (!(md.variable_exists(V0))) md.add_fixed_size_data(V0, s);
1295  }
1296  }
1297 
1298 
1299  };
1300 
1301  void add_theta_method_for_first_order(model &md, const std::string &varname,
1302  scalar_type theta) {
1303  ptime_scheme ptsc
1304  = std::make_shared<first_order_theta_method_scheme>(md, varname,theta);
1305  md.add_time_integration_scheme(varname, ptsc);
1306  }
1307 
1308  // ----------------------------------------------------------------------
1309  //
1310  // Theta-method for second order problems
1311  //
1312  // ----------------------------------------------------------------------
1313 
1314  class APIDECL second_order_theta_method_scheme
1315  : public virtual_time_scheme {
1316 
1317  std::string U, U0, V, V0, A, A0;
1318  scalar_type theta;
1319 
1320  public:
1321  // V = (U-U0)/(theta*dt) - dt*(1-theta)*V0
1322  // A = (U-U0)/(theta^2*dt^2) - V0/(theta^2*dt) - dt*(1-theta)*A0
1323  virtual void init_affine_dependent_variables(model &md) const {
1324  scalar_type dt = md.get_time_step();
1325  md.set_factor_of_variable(V, scalar_type(1)/(theta*dt));
1326  md.set_factor_of_variable(A, scalar_type(1)/(theta*theta*dt*dt));
1327  if (md.is_complex()) {
1328  gmm::add(gmm::scaled(md.complex_variable(U0),
1329  -complex_type(1)/(theta*dt)),
1330  gmm::scaled(md.complex_variable(V0),
1331  -(complex_type(1)-complex_type(theta))/theta),
1332  md.set_complex_constant_part(V));
1333  gmm::add(gmm::scaled(md.complex_variable(U0),
1334  -complex_type(1)/(theta*theta*dt*dt)),
1335  gmm::scaled(md.complex_variable(A0),
1336  -(complex_type(1)-complex_type(theta))/theta),
1337  md.set_complex_constant_part(A));
1338  gmm::add(gmm::scaled(md.complex_variable(V0),
1339  -complex_type(1)/(theta*theta*dt)),
1340  md.set_complex_constant_part(A));
1341 
1342 
1343  } else {
1344  gmm::add(gmm::scaled(md.real_variable(U0),
1345  -scalar_type(1)/(theta*dt)),
1346  gmm::scaled(md.real_variable(V0),
1347  -(scalar_type(1)-theta)/theta),
1348  md.set_real_constant_part(V));
1349  gmm::add(gmm::scaled(md.real_variable(U0),
1350  -scalar_type(1)/(theta*theta*dt*dt)),
1351  gmm::scaled(md.real_variable(A0),
1352  -(scalar_type(1)-theta)/theta),
1353  md.set_real_constant_part(A));
1354  gmm::add(gmm::scaled(md.real_variable(V0),
1355  -scalar_type(1)/(theta*theta*dt)),
1356  md.set_real_constant_part(A));
1357 
1358  }
1359  }
1360 
1361  // V = (U-U0)/dt (backward Euler for precomputation)
1362  // A = (U-U0)/(dt^2) - V0/dt
1363  virtual void init_affine_dependent_variables_precomputation(model &md)
1364  const {
1365  scalar_type dt = md.get_time_step();
1366  md.set_factor_of_variable(V, scalar_type(1)/dt);
1367  md.set_factor_of_variable(A, scalar_type(1)/(dt*dt));
1368  if (md.is_complex()) {
1369  gmm::copy(gmm::scaled(md.complex_variable(U0),
1370  -complex_type(1)/dt),
1371  md.set_complex_constant_part(V));
1372  gmm::add(gmm::scaled(md.complex_variable(U0),
1373  -complex_type(1)/(dt*dt)),
1374  gmm::scaled(md.complex_variable(V0),
1375  -complex_type(1)/dt),
1376  md.set_complex_constant_part(A));
1377  } else {
1378  gmm::copy(gmm::scaled(md.real_variable(U0),
1379  -scalar_type(1)/dt),
1380  md.set_real_constant_part(V));
1381  gmm::add(gmm::scaled(md.real_variable(U0),
1382  -scalar_type(1)/(dt*dt)),
1383  gmm::scaled(md.real_variable(V0),
1384  -scalar_type(1)/dt),
1385  md.set_real_constant_part(A));
1386  }
1387  }
1388 
1389  virtual void time_derivative_to_be_initialized
1390  (std::string &name_v, std::string &name_previous_v) const
1391  { if (theta != scalar_type(1)) { name_v = A; name_previous_v = A0; } }
1392 
1393  virtual void shift_variables(model &md) const {
1394  if (md.is_complex()) {
1395  gmm::copy(md.complex_variable(U), md.set_complex_variable(U0));
1396  gmm::copy(md.complex_variable(V), md.set_complex_variable(V0));
1397  gmm::copy(md.complex_variable(A), md.set_complex_variable(A0));
1398  } else {
1399  gmm::copy(md.real_variable(U), md.set_real_variable(U0));
1400  gmm::copy(md.real_variable(V), md.set_real_variable(V0));
1401  gmm::copy(md.real_variable(A), md.set_real_variable(A0));
1402  }
1403  }
1404 
1405 
1406  second_order_theta_method_scheme(model &md, std::string varname,
1407  scalar_type th) {
1408  U = varname;
1409  U0 = "Previous_" + U;
1410  V = "Dot_" + U;
1411  V0 = "Previous_Dot_" + U;
1412  A = "Dot2_" + U;
1413  A0 = "Previous_Dot2_" + U;
1414  theta = th;
1415  GMM_ASSERT1(theta > scalar_type(0) && theta <= scalar_type(1),
1416  "Invalid value of theta parameter for the theta-method");
1417 
1418  if (!(md.variable_exists(V)))
1419  md.add_affine_dependent_variable(V, U);
1420  if (!(md.variable_exists(A)))
1421  md.add_affine_dependent_variable(A, U);
1422 
1423  const mesh_fem *mf = md.pmesh_fem_of_variable(U);
1424  size_type s = md.is_complex() ? gmm::vect_size(md.complex_variable(U))
1425  : gmm::vect_size(md.real_variable(U));
1426 
1427  if (mf) {
1428  if (!(md.variable_exists(U0))) md.add_fem_data(U0, *mf);
1429  if (!(md.variable_exists(V0))) md.add_fem_data(V0, *mf);
1430  if (!(md.variable_exists(A0))) md.add_fem_data(A0, *mf);
1431  } else {
1432  if (!(md.variable_exists(U0))) md.add_fixed_size_data(U0, s);
1433  if (!(md.variable_exists(V0))) md.add_fixed_size_data(V0, s);
1434  if (!(md.variable_exists(A0))) md.add_fixed_size_data(A0, s);
1435  }
1436  }
1437 
1438 
1439  };
1440 
1441  void add_theta_method_for_second_order(model &md, const std::string &varname,
1442  scalar_type theta) {
1443  ptime_scheme ptsc = std::make_shared<second_order_theta_method_scheme>
1444  (md,varname,theta);
1445  md.add_time_integration_scheme(varname, ptsc);
1446  }
1447 
1448 
1449  // ----------------------------------------------------------------------
1450  //
1451  // Newmark method for second order problems
1452  //
1453  // ----------------------------------------------------------------------
1454 
1455  class APIDECL Newmark_scheme
1456  : public virtual_time_scheme {
1457 
1458  std::string U, U0, V, V0, A, A0;
1459  scalar_type beta, gamma;
1460 
1461  public:
1462  // V = (U-U0)/(theta*dt) - dt*(1-theta)*V0
1463  // A = (U-U0)/(theta^2*dt^2) - V0/(theta^2*dt) - dt*(1-theta)*A0
1464  virtual void init_affine_dependent_variables(model &md) const {
1465  scalar_type dt = md.get_time_step();
1466  scalar_type a0 = scalar_type(1)/(beta*dt*dt), a1 = dt*a0;
1467  scalar_type a2 = (scalar_type(1) - scalar_type(2)*beta)
1468  / (scalar_type(2)*beta);
1469  scalar_type b0 = gamma/(beta*dt), b1 = (beta-gamma)/beta;
1470  scalar_type b2 = dt*(scalar_type(1)-gamma/(scalar_type(2)*beta));
1471 
1472  md.set_factor_of_variable(V, b0);
1473  md.set_factor_of_variable(A, a0);
1474  if (md.is_complex()) {
1475  gmm::add(gmm::scaled(md.complex_variable(U0), -complex_type(b0)),
1476  gmm::scaled(md.complex_variable(V0), complex_type(b1)),
1477  md.set_complex_constant_part(V));
1478  gmm::add(gmm::scaled(md.complex_variable(A0), complex_type(b2)),
1479  md.set_complex_constant_part(V));
1480  gmm::add(gmm::scaled(md.complex_variable(U0), -complex_type(a0)),
1481  gmm::scaled(md.complex_variable(V0), -complex_type(a1)),
1482  md.set_complex_constant_part(A));
1483  gmm::add(gmm::scaled(md.complex_variable(A0), -complex_type(a2)),
1484  md.set_complex_constant_part(A));
1485  } else {
1486  gmm::add(gmm::scaled(md.real_variable(U0), -b0),
1487  gmm::scaled(md.real_variable(V0), b1),
1488  md.set_real_constant_part(V));
1489  gmm::add(gmm::scaled(md.real_variable(A0), b2),
1490  md.set_real_constant_part(V));
1491  gmm::add(gmm::scaled(md.real_variable(U0), -a0),
1492  gmm::scaled(md.real_variable(V0), -a1),
1493  md.set_real_constant_part(A));
1494  gmm::add(gmm::scaled(md.real_variable(A0), -a2),
1495  md.set_real_constant_part(A));
1496 
1497  }
1498  }
1499 
1500  // V = (U-U0)/dt (backward Euler for precomputation)
1501  // A = (U-U0)/(dt^2) - V0/dt
1502  virtual void init_affine_dependent_variables_precomputation(model &md)
1503  const {
1504  scalar_type dt = md.get_time_step();
1505  md.set_factor_of_variable(V, scalar_type(1)/dt);
1506  md.set_factor_of_variable(A, scalar_type(1)/(dt*dt));
1507  if (md.is_complex()) {
1508  gmm::copy(gmm::scaled(md.complex_variable(U0),
1509  -complex_type(1)/dt),
1510  md.set_complex_constant_part(V));
1511  gmm::add(gmm::scaled(md.complex_variable(U0),
1512  -complex_type(1)/(dt*dt)),
1513  gmm::scaled(md.complex_variable(V0),
1514  -complex_type(1)/dt),
1515  md.set_complex_constant_part(A));
1516  } else {
1517  gmm::copy(gmm::scaled(md.real_variable(U0),
1518  -scalar_type(1)/dt),
1519  md.set_real_constant_part(V));
1520  gmm::add(gmm::scaled(md.real_variable(U0),
1521  -scalar_type(1)/(dt*dt)),
1522  gmm::scaled(md.real_variable(V0),
1523  -scalar_type(1)/dt),
1524  md.set_real_constant_part(A));
1525  }
1526  }
1527 
1528  virtual void time_derivative_to_be_initialized
1529  (std::string &name_v, std::string &name_previous_v) const {
1530  if (beta != scalar_type(0.5) || gamma != scalar_type(1))
1531  { name_v = A; name_previous_v = A0; }
1532  }
1533 
1534  virtual void shift_variables(model &md) const {
1535  if (md.is_complex()) {
1536  gmm::copy(md.complex_variable(U), md.set_complex_variable(U0));
1537  gmm::copy(md.complex_variable(V), md.set_complex_variable(V0));
1538  gmm::copy(md.complex_variable(A), md.set_complex_variable(A0));
1539  } else {
1540  gmm::copy(md.real_variable(U), md.set_real_variable(U0));
1541  gmm::copy(md.real_variable(V), md.set_real_variable(V0));
1542  gmm::copy(md.real_variable(A), md.set_real_variable(A0));
1543  }
1544  }
1545 
1546 
1547  Newmark_scheme(model &md, std::string varname,
1548  scalar_type be, scalar_type ga) {
1549  U = varname;
1550  U0 = "Previous_" + U;
1551  V = "Dot_" + U;
1552  V0 = "Previous_Dot_" + U;
1553  A = "Dot2_" + U;
1554  A0 = "Previous_Dot2_" + U;
1555  beta = be; gamma = ga;
1556  GMM_ASSERT1(beta > scalar_type(0) && beta <= scalar_type(1)
1557  && gamma >= scalar_type(0.5) && gamma <= scalar_type(1),
1558  "Invalid parameter values for the Newmark scheme");
1559 
1560  if (!(md.variable_exists(V)))
1561  md.add_affine_dependent_variable(V, U);
1562  if (!(md.variable_exists(A)))
1563  md.add_affine_dependent_variable(A, U);
1564 
1565  const mesh_fem *mf = md.pmesh_fem_of_variable(U);
1566  size_type s = md.is_complex() ? gmm::vect_size(md.complex_variable(U))
1567  : gmm::vect_size(md.real_variable(U));
1568 
1569  if (mf) {
1570  if (!(md.variable_exists(U0))) md.add_fem_data(U0, *mf);
1571  if (!(md.variable_exists(V0))) md.add_fem_data(V0, *mf);
1572  if (!(md.variable_exists(A0))) md.add_fem_data(A0, *mf);
1573  } else {
1574  if (!(md.variable_exists(U0))) md.add_fixed_size_data(U0, s);
1575  if (!(md.variable_exists(V0))) md.add_fixed_size_data(V0, s);
1576  if (!(md.variable_exists(A0))) md.add_fixed_size_data(A0, s);
1577  }
1578  }
1579 
1580 
1581  };
1582 
1583  void add_Newmark_scheme(model &md, const std::string &varname,
1584  scalar_type beta, scalar_type gamma) {
1585  ptime_scheme ptsc = std::make_shared<Newmark_scheme>
1586  (md, varname, beta, gamma);
1587  md.add_time_integration_scheme(varname, ptsc);
1588  }
1589 
1590  // ----------------------------------------------------------------------
1591  //
1592  // Houbolt method
1593  //
1594  // ----------------------------------------------------------------------
1595 
1596  class APIDECL Houbolt_scheme
1597  : public virtual_time_scheme {
1598 
1599  std::string U, U01, U02, U03, V, A;
1600 
1601  public:
1602  // V = 1/(6*dt)*(11*U-18*U01+9*U02-2*U03)
1603  // A = 1/(dt**2)*(2*U-5*U01+4*U02-U03)
1604  virtual void init_affine_dependent_variables(model &md) const {
1605  scalar_type dt = md.get_time_step();
1606  scalar_type a0 = scalar_type(2)/(dt*dt);
1607  scalar_type a1 = scalar_type(5)/(dt*dt);
1608  scalar_type a2 = scalar_type(4)/(dt*dt);
1609  scalar_type a3 = scalar_type(1)/(dt*dt);
1610  scalar_type b0 = scalar_type(11)/(scalar_type(6)*dt);
1611  scalar_type b1 = scalar_type(18)/(scalar_type(6)*dt);
1612  scalar_type b2 = scalar_type(9)/(scalar_type(6)*dt);
1613  scalar_type b3 = scalar_type(2)/(scalar_type(6)*dt);
1614 
1615  md.set_factor_of_variable(V, b0);
1616  md.set_factor_of_variable(A, a0);
1617  if (md.is_complex()) {
1618  gmm::add(gmm::scaled(md.complex_variable(U01), -complex_type(b1)),
1619  gmm::scaled(md.complex_variable(U02), complex_type(b2)),
1620  md.set_complex_constant_part(V));
1621  gmm::add(gmm::scaled(md.complex_variable(U03), -complex_type(b3)),
1622  md.set_complex_constant_part(V));
1623  gmm::add(gmm::scaled(md.complex_variable(U01), -complex_type(a1)),
1624  gmm::scaled(md.complex_variable(U02), complex_type(a2)),
1625  md.set_complex_constant_part(A));
1626  gmm::add(gmm::scaled(md.complex_variable(U03), -complex_type(a3)),
1627  md.set_complex_constant_part(A));
1628  } else {
1629  gmm::add(gmm::scaled(md.real_variable(U01), -b1),
1630  gmm::scaled(md.real_variable(U02), b2),
1631  md.set_real_constant_part(V));
1632  gmm::add(gmm::scaled(md.real_variable(U03), -b3),
1633  md.set_real_constant_part(V));
1634  gmm::add(gmm::scaled(md.real_variable(U01), -a1),
1635  gmm::scaled(md.real_variable(U02), a2),
1636  md.set_real_constant_part(A));
1637  gmm::add(gmm::scaled(md.real_variable(U03), -a3),
1638  md.set_real_constant_part(A));
1639  }
1640  }
1641 
1642  virtual void init_affine_dependent_variables_precomputation(model &md)
1643  const {
1644  (void) md;
1645  }
1646 
1647  virtual void time_derivative_to_be_initialized
1648  (std::string &name_v, std::string &name_previous_v) const {
1649  (void) name_v;
1650  (void) name_previous_v;
1651  }
1652 
1653  virtual void shift_variables(model &md) const {
1654  if (md.is_complex()) {
1655  gmm::copy(md.complex_variable(U02), md.set_complex_variable(U03));
1656  gmm::copy(md.complex_variable(U01), md.set_complex_variable(U02));
1657  gmm::copy(md.complex_variable(U), md.set_complex_variable(U01));
1658  } else {
1659  gmm::copy(md.real_variable(U02), md.set_real_variable(U03));
1660  gmm::copy(md.real_variable(U01), md.set_real_variable(U02));
1661  gmm::copy(md.real_variable(U), md.set_real_variable(U01));
1662  }
1663  }
1664 
1665 
1666  Houbolt_scheme(model &md, std::string varname) {
1667  U = varname;
1668  U01 = "Previous_" + U;
1669  U02 = "Previous2_" + U;
1670  U03 = "Previous3_" + U;
1671  V = "Dot_" + U;
1672  A = "Dot2_" + U;
1673 
1674  if (!(md.variable_exists(V)))
1675  md.add_affine_dependent_variable(V, U);
1676  if (!(md.variable_exists(A)))
1677  md.add_affine_dependent_variable(A, U);
1678 
1679  const mesh_fem *mf = md.pmesh_fem_of_variable(U);
1680  size_type s = md.is_complex() ? gmm::vect_size(md.complex_variable(U))
1681  : gmm::vect_size(md.real_variable(U));
1682 
1683  if (mf) {
1684  if (!(md.variable_exists(U01))) md.add_fem_data(U01, *mf);
1685  if (!(md.variable_exists(U02))) md.add_fem_data(U02, *mf);
1686  if (!(md.variable_exists(U03))) md.add_fem_data(U03, *mf);
1687  } else {
1688  if (!(md.variable_exists(U01))) md.add_fixed_size_data(U01, s);
1689  if (!(md.variable_exists(U02))) md.add_fixed_size_data(U02, s);
1690  if (!(md.variable_exists(U03))) md.add_fixed_size_data(U03, s);
1691  }
1692 
1693  }
1694 
1695  };
1696 
1697  void add_Houbolt_scheme(model &md, const std::string &varname) {
1698  ptime_scheme ptsc = std::make_shared<Houbolt_scheme>
1699  (md, varname);
1700  md.add_time_integration_scheme(varname, ptsc);
1701  }
1702 
1703 
1704 
1705 
1706 
1707 
1708 
1709 
1710 
1711  void model::add_time_dispatcher(size_type ibrick, pdispatcher pdispatch) {
1712  GMM_ASSERT1(valid_bricks[ibrick], "Inexistent brick");
1713  pbrick pbr = bricks[ibrick].pbr;
1714 
1715  bricks[ibrick].pdispatch = pdispatch;
1716 
1717  size_type nbrhs = bricks[ibrick].nbrhs
1718  = std::max(size_type(1), pdispatch->nbrhs());
1719 
1720  gmm::resize(bricks[ibrick].coeffs, nbrhs);
1721 
1722  if (is_complex() && pbr->is_complex()) {
1723  bricks[ibrick].cveclist.resize(nbrhs);
1724  bricks[ibrick].cveclist_sym.resize(nbrhs);
1725  for (size_type k = 1; k < nbrhs; ++k) {
1726  bricks[ibrick].cveclist[k] = bricks[ibrick].cveclist[0];
1727  bricks[ibrick].cveclist_sym[k] = bricks[ibrick].cveclist_sym[0];
1728  }
1729  } else {
1730  bricks[ibrick].rveclist.resize(nbrhs);
1731  bricks[ibrick].rveclist_sym.resize(nbrhs);
1732  for (size_type k = 1; k < nbrhs; ++k) {
1733  bricks[ibrick].rveclist[k] = bricks[ibrick].rveclist[0];
1734  bricks[ibrick].rveclist_sym[k] = bricks[ibrick].rveclist_sym[0];
1735  }
1736  }
1737  }
1738 
1739  const std::string &model::varname_of_brick(size_type ind_brick,
1740  size_type ind_var) {
1741  GMM_ASSERT1(valid_bricks[ind_brick], "Inexistent brick");
1742  GMM_ASSERT1(ind_var < bricks[ind_brick].vlist.size(),
1743  "Inexistent brick variable");
1744  return bricks[ind_brick].vlist[ind_var];
1745  }
1746 
1747  const std::string &model::dataname_of_brick(size_type ind_brick,
1748  size_type ind_data) {
1749  GMM_ASSERT1(valid_bricks[ind_brick], "Inexistent brick");
1750  GMM_ASSERT1(ind_data < bricks[ind_brick].dlist.size(),
1751  "Inexistent brick data");
1752  return bricks[ind_brick].dlist[ind_data];
1753  }
1754 
1755  void model::listbricks(std::ostream &ost, size_type base_id) const {
1756  if (valid_bricks.card() == 0)
1757  ost << "Model with no bricks" << endl;
1758  else {
1759  ost << "List of model bricks:" << endl;
1760  for (dal::bv_visitor i(valid_bricks); !i.finished(); ++i) {
1761  ost << "Brick " << std::setw(3) << std::right << i + base_id
1762  << " " << std::setw(20) << std::right
1763  << bricks[i].pbr->brick_name();
1764  if (!(active_bricks[i])) ost << " (deactivated)";
1765  if (bricks[i].pdispatch) ost << " (dispatched)";
1766  ost << endl << " concerned variables: " << bricks[i].vlist[0];
1767  for (size_type j = 1; j < bricks[i].vlist.size(); ++j)
1768  ost << ", " << bricks[i].vlist[j];
1769  ost << "." << endl;
1770  ost << " brick with " << bricks[i].tlist.size() << " term";
1771  if (bricks[i].tlist.size() > 1) ost << "s";
1772  ost << endl;
1773  // + lister les termes
1774  }
1775  }
1776  }
1777 
1778  // before call to asm_real_tangent_terms or asm_complex_tangent_terms
1779  // from the assembly procedure or a time dispatcher
1780  void model::brick_init(size_type ib, build_version version,
1781  size_type rhs_ind) const {
1782  const brick_description &brick = bricks[ib];
1783  bool cplx = is_complex() && brick.pbr->is_complex();
1784 
1785  // Initialization of vector and matrices.
1786  for (size_type j = 0; j < brick.tlist.size(); ++j) {
1787  const term_description &term = brick.tlist[j];
1788  bool isg = term.is_global;
1789  size_type nbgdof = is_complex() ?
1790  gmm::vect_size(crhs) : gmm::vect_size(rrhs);
1791  size_type nbd1 = isg ? nbgdof : variables[term.var1].size();
1792  size_type nbd2 = isg ? nbgdof : (term.is_matrix_term ?
1793  variables[term.var2].size() : 0);
1794  if (term.is_matrix_term &&
1795  (brick.pbr->is_linear() || (version | BUILD_MATRIX))) {
1796  if (version | BUILD_ON_DATA_CHANGE) {
1797  if (cplx)
1798  gmm::resize(brick.cmatlist[j], nbd1, nbd2);
1799  else
1800  gmm::resize(brick.rmatlist[j], nbd1, nbd2);
1801  } else {
1802  if (cplx)
1803  brick.cmatlist[j] = model_complex_sparse_matrix(nbd1, nbd2);
1804  else
1805  brick.rmatlist[j] = model_real_sparse_matrix(nbd1, nbd2);
1806  }
1807  }
1808  if (brick.pbr->is_linear() || (version | BUILD_RHS)) {
1809  for (size_type k = 0; k < brick.nbrhs; ++k) {
1810  if (cplx) {
1811  if (k == rhs_ind) gmm::clear(brick.cveclist[k][j]);
1812  gmm::resize(brick.cveclist[k][j], nbd1);
1813  if (term.is_symmetric && term.var1.compare(term.var2)) {
1814  if (k == rhs_ind) gmm::clear(brick.cveclist_sym[k][j]);
1815  gmm::resize(brick.cveclist_sym[k][j], nbd2);
1816  }
1817  } else {
1818  if (k == rhs_ind) gmm::clear(brick.rveclist[k][j]);
1819  gmm::resize(brick.rveclist[k][j], nbd1);
1820  if (term.is_symmetric && term.var1.compare(term.var2)) {
1821  if (k == rhs_ind) gmm::clear(brick.rveclist_sym[k][j]);
1822  gmm::resize(brick.rveclist_sym[k][j], nbd2);
1823  }
1824  }
1825  }
1826  }
1827  }
1828  }
1829 
1830  void model::post_to_variables_step(){}
1831 
1832  void model::brick_call(size_type ib, build_version version,
1833  size_type rhs_ind) const
1834  {
1835  const brick_description &brick = bricks[ib];
1836  bool cplx = is_complex() && brick.pbr->is_complex();
1837 
1838  brick_init(ib, version, rhs_ind);
1839 
1840  if (cplx)
1841  {
1842  brick.pbr->complex_pre_assembly_in_serial(*this, ib, brick.vlist,
1843  brick.dlist, brick.mims,
1844  brick.cmatlist,
1845  brick.cveclist[rhs_ind],
1846  brick.cveclist_sym[rhs_ind],
1847  brick.region, version);
1848 
1849  /*distributing the resulting vectors and matrices for individual threads.*/
1850  { //brackets are needed because accumulated_distro has constructor/destructor
1851  //semantics (as in RAII)
1852  accumulated_distro<complex_matlist> cmatlist(brick.cmatlist);
1853  accumulated_distro<complex_veclist> cveclist(brick.cveclist[rhs_ind]);
1854  accumulated_distro<complex_veclist> cveclist_sym(brick.cveclist_sym[rhs_ind]);
1855 
1856  /*running the assembly in parallel*/
1858  brick.pbr->asm_complex_tangent_terms(*this, ib, brick.vlist,
1859  brick.dlist, brick.mims,
1860  cmatlist,
1861  cveclist,
1862  cveclist_sym,
1863  brick.region, version);
1864  )
1865  }
1866  brick.pbr->complex_post_assembly_in_serial(*this, ib, brick.vlist,
1867  brick.dlist, brick.mims,
1868  brick.cmatlist,
1869  brick.cveclist[rhs_ind],
1870  brick.cveclist_sym[rhs_ind],
1871  brick.region, version);
1872 
1873  if (brick.is_update_brick) //contributions of pure update bricks must be deleted
1874  {
1875  for (auto &&mat : brick.cmatlist)
1876  gmm::clear(mat);
1877 
1878  for (auto &&vecs : brick.cveclist)
1879  for (auto &&vec : vecs)
1880  gmm::clear(vec);
1881 
1882  for (auto &&vecs : brick.cveclist_sym)
1883  for (auto &&vec : vecs)
1884  gmm::clear(vec);
1885  }
1886  }
1887  else //not cplx
1888  {
1889  brick.pbr->real_pre_assembly_in_serial(*this, ib, brick.vlist,
1890  brick.dlist, brick.mims,
1891  brick.rmatlist,
1892  brick.rveclist[rhs_ind],
1893  brick.rveclist_sym[rhs_ind],
1894  brick.region, version);
1895  {
1896  /*distributing the resulting vectors and matrices for individual threads.*/
1897  accumulated_distro<real_matlist> rmatlist(brick.rmatlist);
1898  accumulated_distro<real_veclist> rveclist(brick.rveclist[rhs_ind]);
1899  accumulated_distro<real_veclist> rveclist_sym(brick.rveclist_sym[rhs_ind]);
1900 
1901  /*running the assembly in parallel*/
1903  brick.pbr->asm_real_tangent_terms(*this, ib, brick.vlist,
1904  brick.dlist, brick.mims,
1905  rmatlist,
1906  rveclist,
1907  rveclist_sym,
1908  brick.region,
1909  version);
1910  );
1911  }
1912  brick.pbr->real_post_assembly_in_serial(*this, ib, brick.vlist,
1913  brick.dlist, brick.mims,
1914  brick.rmatlist,
1915  brick.rveclist[rhs_ind],
1916  brick.rveclist_sym[rhs_ind],
1917  brick.region, version);
1918 
1919  if (brick.is_update_brick) //contributions of pure update bricks must be deleted
1920  {
1921  for (auto &&mat : brick.rmatlist)
1922  gmm::clear(mat);
1923 
1924  for (auto &&vecs : brick.rveclist)
1925  for (auto &&vec : vecs)
1926  gmm::clear(vec);
1927 
1928  for (auto &&vecs : brick.rveclist_sym)
1929  for (auto &&vec : vecs)
1930  gmm::clear(vec);
1931  }
1932  }
1933  }
1934 
1935 
1936  void model::set_dispatch_coeff() {
1937  for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
1938  brick_description &brick = bricks[ib];
1939  if (brick.pdispatch)
1940  brick.pdispatch->set_dispatch_coeff(*this, ib);
1941 
1942  }
1943  }
1944 
1946  context_check(); if (act_size_to_be_done) actualize_sizes();
1947  for (auto && v : variables) v.second.clear_temporaries();
1948 
1949  set_dispatch_coeff();
1950 
1951  for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
1952  brick_description &brick = bricks[ib];
1953  if (brick.pdispatch) {
1954  if (is_complex() && brick.pbr->is_complex())
1955  brick.pdispatch->next_complex_iter(*this, ib, brick.vlist,
1956  brick.dlist,
1957  brick.cmatlist, brick.cveclist,
1958  brick.cveclist_sym, true);
1959  else
1960  brick.pdispatch->next_real_iter(*this, ib, brick.vlist, brick.dlist,
1961  brick.rmatlist, brick.rveclist,
1962  brick.rveclist_sym, true);
1963  }
1964  }
1965  }
1966 
1968  context_check(); if (act_size_to_be_done) actualize_sizes();
1969  set_dispatch_coeff();
1970 
1971  for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
1972  brick_description &brick = bricks[ib];
1973  if (brick.pdispatch) {
1974  if (is_complex() && brick.pbr->is_complex())
1975  brick.pdispatch->next_complex_iter(*this, ib, brick.vlist,
1976  brick.dlist,
1977  brick.cmatlist, brick.cveclist,
1978  brick.cveclist_sym, false);
1979  else
1980  brick.pdispatch->next_real_iter(*this, ib, brick.vlist, brick.dlist,
1981  brick.rmatlist, brick.rveclist,
1982  brick.rveclist_sym, false);
1983  }
1984  }
1985 
1986  for (auto &&v : variables)
1987  for (size_type i = 1; i < v.second.n_iter; ++i) {
1988  if (is_complex())
1989  gmm::copy(v.second.complex_value[i-1], v.second.complex_value[i]);
1990  else
1991  gmm::copy(v.second.real_value[i-1], v.second.real_value[i]);
1992  v.second.v_num_data[i] = act_counter();
1993  }
1994  }
1995 
1996  bool model::is_var_newer_than_brick(const std::string &varname,
1997  size_type ib, size_type niter) const {
1998  const brick_description &brick = bricks[ib];
1999  var_description &vd = variables[varname];
2000  if (niter == size_type(-1)) niter = vd.default_iter;
2001  return (vd.v_num > brick.v_num || vd.v_num_data[niter] > brick.v_num);
2002  }
2003 
2004  bool model::is_var_mf_newer_than_brick(const std::string &varname,
2005  size_type ib) const {
2006  const brick_description &brick = bricks[ib];
2007  var_description &vd = variables[varname];
2008  return (vd.v_num > brick.v_num);
2009  }
2010 
2011  bool model::is_mim_newer_than_brick(const mesh_im &im,
2012  size_type ib) const {
2013  const brick_description &brick = bricks[ib];
2014  return (im.version_number() > brick.v_num);
2015  }
2016 
2017  void model::define_variable_group(const std::string &group_name,
2018  const std::vector<std::string> &nl) {
2019  GMM_ASSERT1(!(variable_exists(group_name)), "The name of a group of "
2020  "variables cannot be the same as a variable name");
2021 
2022  std::set<const mesh *> ms;
2023  bool is_data_ = false;
2024  for (size_type i = 0; i < nl.size(); ++i) {
2025  if (i == 0)
2026  is_data_ = is_true_data(nl[i]);
2027  else {
2028  GMM_ASSERT1(is_data_ == is_true_data(nl[i]),
2029  "It is not possible to mix variables and data in a group");
2030  }
2031  GMM_ASSERT1(variable_exists(nl[i]),
2032  "All variables in a group have to exist in the model");
2033  const mesh_fem *mf = pmesh_fem_of_variable(nl[i]);
2034  GMM_ASSERT1(mf, "Variables in a group should be fem variables");
2035  GMM_ASSERT1(ms.find(&(mf->linked_mesh())) == ms.end(),
2036  "Two variables in a group cannot share the same mesh");
2037  ms.insert(&(mf->linked_mesh()));
2038  }
2039  variable_groups[group_name] = nl;
2040  }
2041 
2042  void model::add_assembly_assignments(const std::string &varname,
2043  const std::string &expr, size_type rg,
2044  size_type order, bool before) {
2045  GMM_ASSERT1(order < 3 || order == size_type(-1), "Bad order value");
2046  const im_data *imd = pim_data_of_variable(varname);
2047  GMM_ASSERT1(imd != 0, "Only applicable to im_data");
2048  assignement_desc as;
2049  as.varname = varname; as.expr = expr; as.region = rg; as.order = order;
2050  as.before = before;
2051  assignments.push_back(as);
2052  }
2053 
2054  void model::add_temporaries(const varnamelist &vl,
2055  gmm::uint64_type id_num) const {
2056  for (size_type i = 0; i < vl.size(); ++i) {
2057  var_description &vd = variables[vl[i]];
2058  if (vd.n_iter > 1) {
2059  vd.add_temporary(id_num);
2060  }
2061  }
2062  }
2063 
2064  bool model::temporary_uptodate(const std::string &varname,
2065  gmm::uint64_type id_num,
2066  size_type &ind) const {
2067  var_description &vd = variables[varname];
2068  ind = vd.n_iter;
2069  for (; ind < vd.n_iter + vd.n_temp_iter ; ++ind) {
2070  if (vd.v_num_var_iter[ind] == id_num) break;
2071  }
2072  if (ind < vd.n_iter + vd.n_temp_iter) {
2073  if (vd.v_num_iter[ind] <= vd.v_num_data[vd.default_iter]) {
2074  vd.v_num_iter[ind] = act_counter();
2075  return false;
2076  }
2077  return true;
2078  }
2079  ind = size_type(-1);
2080  return true;
2081  }
2082 
2083  void model::set_default_iter_of_variable(const std::string &varname,
2084  size_type ind) const {
2085  if (ind != size_type(-1)) {
2086  var_description &vd = variables[varname];
2087  GMM_ASSERT1(ind < vd.n_iter + vd.n_temp_iter,
2088  "Inexistent iteration " << ind);
2089  vd.default_iter = ind;
2090  }
2091  }
2092 
2093  void model::reset_default_iter_of_variables(const varnamelist &vl) const {
2094  for (size_type i = 0; i < vl.size(); ++i)
2095  variables[vl[i]].default_iter = 0;
2096  }
2097 
2098  const model_real_sparse_matrix &
2099  model::linear_real_matrix_term(size_type ib, size_type iterm) {
2100  GMM_ASSERT1(bricks[ib].tlist[iterm].is_matrix_term,
2101  "Not a matrix term !");
2102  GMM_ASSERT1(bricks[ib].pbr->is_linear(), "Nonlinear term !");
2103  return bricks[ib].rmatlist[iterm];
2104  }
2105 
2106  const model_complex_sparse_matrix &
2107  model::linear_complex_matrix_term(size_type ib, size_type iterm) {
2108  GMM_ASSERT1(bricks[ib].tlist[iterm].is_matrix_term,
2109  "Not a matrix term !");
2110  GMM_ASSERT1(bricks[ib].pbr->is_linear(), "Nonlinear term !");
2111  return bricks[ib].cmatlist[iterm];
2112  }
2113 
2114  // Call the brick to compute the terms
2115  void model::update_brick(size_type ib, build_version version) const {
2116  const brick_description &brick = bricks[ib];
2117  bool cplx = is_complex() && brick.pbr->is_complex();
2118  bool tobecomputed = brick.terms_to_be_computed
2119  || brick.pbr->is_to_be_computed_each_time()
2120  || !(brick.pbr->is_linear());
2121 
2122  // check variable list to test if a mesh_fem has changed.
2123  if (!tobecomputed ) {
2124  for (size_type i = 0; i < brick.vlist.size() && !tobecomputed; ++i) {
2125  var_description &vd = variables[brick.vlist[i]];
2126  if (vd.v_num > brick.v_num) tobecomputed = true;
2127  }
2128  }
2129 
2130  // check data list to test if a vector value of a data has changed.
2131  for (size_type i = 0; i < brick.dlist.size() && !tobecomputed; ++i) {
2132  var_description &vd = variables[brick.dlist[i]];
2133  if (vd.v_num > brick.v_num || vd.v_num_data[vd.default_iter] > brick.v_num) {
2134  tobecomputed = true;
2135  version = build_version(version | BUILD_ON_DATA_CHANGE);
2136  }
2137  }
2138 
2139  // Check if a mesh_im has changed
2140  if (!tobecomputed ) {
2141  for (size_type i = 0; i < brick.mims.size() && !tobecomputed; ++i) {
2142  if (brick.mims[i]->version_number() > brick.v_num) tobecomputed = true;
2143  }
2144  }
2145 
2146  if (tobecomputed) {
2147  brick.external_load = scalar_type(0);
2148 
2149  if (!(brick.pdispatch))
2150  { brick_call(ib, version, 0); }
2151  else {
2152  if (cplx)
2153  brick.pdispatch->asm_complex_tangent_terms
2154  (*this, ib, brick.cmatlist, brick.cveclist, brick.cveclist_sym,
2155  version);
2156  else
2157  brick.pdispatch->asm_real_tangent_terms
2158  (*this, ib, brick.rmatlist, brick.rveclist, brick.rveclist_sym,
2159  version);
2160  }
2161  brick.v_num = act_counter();
2162  }
2163 
2164  if (brick.pbr->is_linear()) brick.terms_to_be_computed = false;
2165  }
2166 
2167  // OBSOLETE (linked to time dispatchers) or to be corrected to take
2168  // into account global matrices
2169  void model::linear_brick_add_to_rhs(size_type ib, size_type ind_data,
2170  size_type n_iter) const {
2171  const brick_description &brick = bricks[ib];
2172  if (brick.pbr->is_linear()) {
2173 
2174  bool cplx = is_complex() && brick.pbr->is_complex();
2175 
2176  for (size_type j = 0; j < brick.tlist.size(); ++j) {
2177  const term_description &term = brick.tlist[j];
2178  bool isg = term.is_global;
2179  size_type nbgdof = nb_dof();
2180 
2181  size_type n_iter_1 = n_iter, n_iter_2 = n_iter;
2182  if (!isg && n_iter == size_type(-1)) {
2183  n_iter_1 = variables[term.var1].default_iter;
2184  if (term.is_matrix_term)
2185  n_iter_2 = variables[term.var2].default_iter;
2186  }
2187 
2188 
2189 
2190  if (term.is_matrix_term) {
2191  if (cplx) {
2192  if (isg) {
2193  model_complex_plain_vector V(nbgdof);
2194  for (VAR_SET::iterator it = variables.begin();
2195  it != variables.end(); ++it)
2196  if (it->second.is_variable) {
2197  size_type n_iter_i = (n_iter == size_type(-1))
2198  ? it->second.default_iter : n_iter;
2199  gmm::copy(it->second.complex_value[n_iter_i],
2200  gmm::sub_vector(V, it->second.I));
2201  }
2203  (brick.cmatlist[j],
2204  gmm::scaled(V, complex_type(-1)),
2205  brick.cveclist[ind_data][j]);
2206  } else
2208  (brick.cmatlist[j],
2209  gmm::scaled(variables[term.var2].complex_value[n_iter_2],
2210  complex_type(-1)),
2211  brick.cveclist[ind_data][j]);
2212  }
2213  else {
2214  if (isg) {
2215  model_real_plain_vector V(nbgdof);
2216  for (VAR_SET::iterator it = variables.begin();
2217  it != variables.end(); ++it)
2218  if (it->second.is_variable) {
2219  size_type n_iter_i = (n_iter == size_type(-1))
2220  ? it->second.default_iter : n_iter;
2221  gmm::copy(it->second.real_value[n_iter_i],
2222  gmm::sub_vector(V, it->second.I));
2223  }
2225  (brick.rmatlist[j], gmm::scaled(V, scalar_type(-1)),
2226  brick.rveclist[ind_data][j]);
2227  } else
2229  (brick.rmatlist[j],
2230  gmm::scaled(variables[term.var2].real_value[n_iter_2],
2231  scalar_type(-1)), brick.rveclist[ind_data][j]);
2232  }
2233 
2234  if (term.is_symmetric && term.var1.compare(term.var2)) {
2235  if (cplx)
2237  (gmm::conjugated(brick.cmatlist[j]),
2238  gmm::scaled(variables[term.var1].complex_value[n_iter_1],
2239  complex_type(-1)),
2240  brick.cveclist_sym[ind_data][j]);
2241  else
2243  (gmm::transposed(brick.rmatlist[j]),
2244  gmm::scaled(variables[term.var1].real_value[n_iter_1],
2245  scalar_type(-1)),
2246  brick.rveclist_sym[ind_data][j]);
2247  }
2248  }
2249  }
2250  }
2251  }
2252 
2253  void model::update_affine_dependent_variables() {
2254  for (VAR_SET::iterator it = variables.begin(); it != variables.end(); ++it)
2255  if (it->second.is_affine_dependent) {
2256  VAR_SET::iterator it2 = variables.find(it->second.org_name);
2257  if (it->second.size() != it2->second.size())
2258  it->second.set_size();
2259  if (it->second.is_complex) {
2260  gmm::add(gmm::scaled(it2->second.complex_value[0],
2261  complex_type(it->second.alpha)),
2262  it->second.affine_complex_value,
2263  it->second.complex_value[0]);
2264  } else {
2265  gmm::add(gmm::scaled(it2->second.real_value[0], it->second.alpha),
2266  it->second.affine_real_value, it->second.real_value[0]);
2267  }
2268  it->second.v_num = std::max(it->second.v_num, it2->second.v_num);
2269  for (size_type i = 0; i < it->second.n_iter; ++i)
2270  {
2271  it->second.v_num_data[i] = std::max(it->second.v_num_data[i],
2272  it2->second.v_num_data[i]);
2273  }
2274  }
2275  }
2276 
2277 
2278 
2279  std::string model::Neumann_term(const std::string &varname,
2280  size_type region) {
2281  std::string result;
2282  const mesh_fem *mf = pmesh_fem_of_variable(varname);
2283  GMM_ASSERT1(mf, "Works only with fem variables.");
2284  mesh &m = const_cast<mesh &>(mf->linked_mesh());
2285  mesh_im dummy_mim(m);
2286 
2287  for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
2288  brick_description &brick = bricks[ib];
2289 
2290  bool detected = false;
2291  for (size_type i = 0; i < brick.vlist.size(); ++i)
2292  if (brick.vlist[i].compare(varname) == 0)
2293  { detected = true; break; }
2294 
2295  if (detected && brick.mims.size()) {
2296  int ifo = -1;
2297  for (auto &pmim : brick.mims)
2298  ifo = std::max(ifo, mf->linked_mesh().region(region)
2299  .region_is_faces_of(m, brick.region,
2300  pmim->linked_mesh()));
2301  GMM_ASSERT1(ifo >= 0,
2302  "The given region is only partially covered by "
2303  "region of brick \"" << brick.pbr->brick_name()
2304  << "\". Please subdivise the region");
2305  if (ifo == 1) {
2306  std::string expr = brick.pbr->declare_volume_assembly_string
2307  (*this, ib, brick.vlist, brick.dlist);
2308 
2309  ga_workspace workspace(*this);
2310  size_type order = workspace.add_expression
2311  (expr, dummy_mim, region);
2312  GMM_ASSERT1(order <= 1, "Wrong order for a Neumann term");
2313  expr = workspace.extract_Neumann_term(varname);
2314  if (expr.size()) {
2315  if (result.size())
2316  result += " + " + workspace.extract_Neumann_term(varname);
2317  else
2318  result = workspace.extract_Neumann_term(varname);
2319  }
2320  }
2321  }
2322  }
2323  return result;
2324  }
2325 
2326 
2327 
2328  void model::assembly(build_version version) {
2329 
2330  GMM_ASSERT1(version != BUILD_ON_DATA_CHANGE,
2331  "Invalid assembly version BUILD_ON_DATA_CHANGE");
2332  GMM_ASSERT1(version != BUILD_WITH_LIN,
2333  "Invalid assembly version BUILD_WITH_LIN");
2334  GMM_ASSERT1(version != BUILD_WITH_INTERNAL,
2335  "Invalid assembly version BUILD_WITH_INTERNAL");
2336 #if GETFEM_PARA_LEVEL > 1
2337  double t_ref = MPI_Wtime();
2338 #endif
2339 
2340  context_check(); if (act_size_to_be_done) actualize_sizes();
2341  if (is_complex()) {
2342  if (version & BUILD_MATRIX) gmm::clear(cTM);
2343  if (version & BUILD_RHS) gmm::clear(crhs);
2344  }
2345  else {
2346  if (version & BUILD_MATRIX) gmm::clear(rTM);
2347  if (version & BUILD_RHS) gmm::clear(rrhs);
2348  }
2349  clear_dof_constraints();
2350  generic_expressions.clear();
2351  update_affine_dependent_variables();
2352 
2353  if (version & BUILD_RHS) approx_external_load_ = scalar_type(0);
2354 
2355  for (dal::bv_visitor ib(active_bricks); !ib.finished(); ++ib) {
2356 
2357  brick_description &brick = bricks[ib];
2358 
2359  // Disables the brick if all its variables are disabled.
2360  bool auto_disabled_brick = true;
2361  for (size_type j = 0; j < brick.vlist.size(); ++j) {
2362  if (!(is_disabled_variable(brick.vlist[j])))
2363  auto_disabled_brick = false;
2364  }
2365  if (auto_disabled_brick) continue;
2366 
2367  update_brick(ib, version);
2368 
2369  bool cplx = is_complex() && brick.pbr->is_complex();
2370 
2371  scalar_type coeff0 = scalar_type(1);
2372  if (brick.pdispatch) coeff0 = brick.matrix_coeff;
2373 
2374  // Assembly of terms
2375 
2376  for (size_type j = 0; j < brick.tlist.size(); ++j) {
2377  term_description &term = brick.tlist[j];
2378  bool isg = term.is_global, isprevious = false;
2379  size_type nbgdof = nb_dof();
2380  scalar_type alpha = coeff0, alpha1 = coeff0, alpha2 = coeff0;
2381  gmm::sub_interval I1(0,nbgdof), I2(0,nbgdof);
2382  var_description *var1=nullptr, *var2=nullptr;
2383  if (!isg) {
2384  VAR_SET::iterator it1 = variables.find(term.var1);
2385  GMM_ASSERT1(it1 != variables.end(), "Internal error");
2386  var1 = &(it1->second);
2387  GMM_ASSERT1(var1->is_variable, "Assembly of data not allowed");
2388  I1 = var1->I;
2389  if (term.is_matrix_term) {
2390  VAR_SET::iterator it2 = variables.find(term.var2);
2391  GMM_ASSERT1(it2 != variables.end(), "Internal error");
2392  var2 = &(it2->second);
2393  I2 = var2->I;
2394  if (!(var2->is_variable)) {
2395  std::string vorgname = sup_previous_and_dot_to_varname(term.var2);
2396  VAR_SET::iterator it3 = variables.find(vorgname);
2397  GMM_ASSERT1(it3->second.is_variable,
2398  "Assembly of data not allowed");
2399  I2 = it3->second.I;
2400  isprevious = true;
2401  }
2402  alpha *= var1->alpha * var2->alpha;
2403  alpha1 *= var1->alpha;
2404  alpha2 *= var2->alpha;
2405  }
2406  }
2407 
2408  if (cplx) { // complex term in complex model
2409  if (term.is_matrix_term && (version & BUILD_MATRIX) && !isprevious
2410  && (isg || (!(var1->is_disabled) && !(var2->is_disabled)))) {
2411  gmm::add(gmm::scaled(brick.cmatlist[j], alpha),
2412  gmm::sub_matrix(cTM, I1, I2));
2413  if (term.is_symmetric && I1.first() != I2.first()) {
2414  gmm::add(gmm::scaled(gmm::transposed(brick.cmatlist[j]), alpha),
2415  gmm::sub_matrix(cTM, I2, I1));
2416  }
2417  }
2418  if (version & BUILD_RHS) {
2419  if (isg || !(var1->is_disabled)) {
2420  if (brick.pdispatch) {
2421  for (size_type k = 0; k < brick.nbrhs; ++k)
2422  gmm::add(gmm::scaled(brick.cveclist[k][j],
2423  brick.coeffs[k]),
2424  gmm::sub_vector(crhs, I1));
2425  }
2426  else {
2427  gmm::add(gmm::scaled(brick.cveclist[0][j],
2428  complex_type(alpha1)),
2429  gmm::sub_vector(crhs, I1));
2430  }
2431  }
2432  if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()) {
2433  if (var2->is_affine_dependent
2434  && !(var1->is_disabled))
2435  gmm::mult_add(brick.cmatlist[j],
2436  gmm::scaled(var2->affine_complex_value,
2437  complex_type(-alpha1)),
2438  gmm::sub_vector(crhs, I1));
2439  if (term.is_symmetric && I1.first() != I2.first()
2440  && var1->is_affine_dependent
2441  && !(var2->is_disabled)) {
2442  gmm::mult_add(gmm::conjugated(brick.cmatlist[j]),
2443  gmm::scaled(var1->affine_complex_value,
2444  complex_type(-alpha2)),
2445  gmm::sub_vector(crhs, I2));
2446  }
2447  }
2448  if (term.is_matrix_term && brick.pbr->is_linear()
2449  && (!is_linear() || (version & BUILD_WITH_LIN))) {
2450  if (!(var1->is_disabled))
2451  gmm::mult_add(brick.cmatlist[j],
2452  gmm::scaled(var2->complex_value[0],
2453  complex_type(-alpha1)),
2454  gmm::sub_vector(crhs, I1));
2455  }
2456  if (term.is_symmetric && I1.first() != I2.first() &&
2457  !(var2->is_disabled)) {
2458  if (brick.pdispatch) {
2459  for (size_type k = 0; k < brick.nbrhs; ++k)
2460  gmm::add(gmm::scaled(brick.cveclist_sym[k][j],
2461  brick.coeffs[k]),
2462  gmm::sub_vector(crhs, I2));
2463  } else {
2464  gmm::add(gmm::scaled(brick.cveclist_sym[0][j],
2465  complex_type(alpha2)),
2466  gmm::sub_vector(crhs, I2));
2467  }
2468  if (brick.pbr->is_linear()
2469  && (!is_linear() || (version & BUILD_WITH_LIN))) {
2470  gmm::mult_add(gmm::conjugated(brick.cmatlist[j]),
2471  gmm::scaled(var1->complex_value[0],
2472  complex_type(-alpha2)),
2473  gmm::sub_vector(crhs, I2));
2474  }
2475  }
2476  }
2477  } else if (is_complex()) { // real term in complex model
2478  if (term.is_matrix_term && (version & BUILD_MATRIX) && !isprevious
2479  && (isg || (!(var1->is_disabled) && !(var2->is_disabled)))) {
2480  gmm::add(gmm::scaled(brick.rmatlist[j], alpha),
2481  gmm::sub_matrix(cTM, I1, I2));
2482  if (term.is_symmetric && I1.first() != I2.first()) {
2483  gmm::add(gmm::scaled(gmm::transposed(brick.rmatlist[j]), alpha),
2484  gmm::sub_matrix(cTM, I2, I1));
2485  }
2486  }
2487  if (version & BUILD_RHS) {
2488  if (isg || !(var1->is_disabled)) {
2489  if (brick.pdispatch) {
2490  for (size_type k = 0; k < brick.nbrhs; ++k)
2491  gmm::add(gmm::scaled(brick.rveclist[k][j],
2492  brick.coeffs[k]),
2493  gmm::sub_vector(crhs, I1));
2494  }
2495  else {
2496  gmm::add(gmm::scaled(brick.rveclist[0][j], alpha1),
2497  gmm::sub_vector(crhs, I1));
2498  }
2499  }
2500  if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()) {
2501  if (var2->is_affine_dependent
2502  && !(var1->is_disabled))
2503  gmm::mult_add(brick.rmatlist[j],
2504  gmm::scaled(var2->affine_complex_value,
2505  complex_type(-alpha1)),
2506  gmm::sub_vector(crhs, I1));
2507  if (term.is_symmetric && I1.first() != I2.first()
2508  && var1->is_affine_dependent
2509  && !(var2->is_disabled)) {
2510  gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
2511  gmm::scaled(var1->affine_complex_value,
2512  complex_type(-alpha2)),
2513  gmm::sub_vector(crhs, I2));
2514  }
2515  }
2516  if (term.is_matrix_term && brick.pbr->is_linear()
2517  && (!is_linear() || (version & BUILD_WITH_LIN))) {
2518  if (!(var1->is_disabled))
2519  gmm::mult_add(brick.rmatlist[j],
2520  gmm::scaled(var2->complex_value[0],
2521  complex_type(-alpha1)),
2522  gmm::sub_vector(crhs, I1));
2523  }
2524  if (term.is_symmetric && I1.first() != I2.first() &&
2525  !(var2->is_disabled)) {
2526  if (brick.pdispatch) {
2527  for (size_type k = 0; k < brick.nbrhs; ++k)
2528  gmm::add(gmm::scaled(brick.rveclist_sym[k][j],
2529  brick.coeffs[k]),
2530  gmm::sub_vector(crhs, I2));
2531  }
2532  else {
2533  gmm::add(gmm::scaled(brick.rveclist_sym[0][j], alpha2),
2534  gmm::sub_vector(crhs, I2));
2535  }
2536  if (brick.pbr->is_linear()
2537  && (!is_linear() || (version & BUILD_WITH_LIN))) {
2538  gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
2539  gmm::scaled(var1->complex_value[0],
2540  complex_type(-alpha2)),
2541  gmm::sub_vector(crhs, I2));
2542  }
2543  }
2544  }
2545  } else { // real term in real model
2546  if (term.is_matrix_term && (version & BUILD_MATRIX) && !isprevious
2547  && (isg || (!(var1->is_disabled)
2548  && !(var2->is_disabled)))) {
2549  gmm::add(gmm::scaled(brick.rmatlist[j], alpha),
2550  gmm::sub_matrix(rTM, I1, I2));
2551  if (term.is_symmetric && I1.first() != I2.first()) {
2552  gmm::add(gmm::scaled(gmm::transposed(brick.rmatlist[j]), alpha),
2553  gmm::sub_matrix(rTM, I2, I1));
2554  }
2555  }
2556  if (version & BUILD_RHS) {
2557  // Contributions to interval I1 of var1
2558  if (isg || !(var1->is_disabled)) {
2559  if (brick.pdispatch) {
2560  for (size_type k = 0; k < brick.nbrhs; ++k)
2561  gmm::add(gmm::scaled(brick.rveclist[k][j],
2562  brick.coeffs[k]),
2563  gmm::sub_vector(rrhs, I1));
2564  }
2565  else
2566  gmm::add(gmm::scaled(brick.rveclist[0][j], alpha1),
2567  gmm::sub_vector(rrhs, I1));
2568  }
2569  if (!(var1->is_disabled)) {
2570  // Contributions from affine dependent variables
2571  if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()
2572  && var2->is_affine_dependent)
2573  gmm::mult_add(brick.rmatlist[j],
2574  gmm::scaled(var2->affine_real_value, -alpha1),
2575  gmm::sub_vector(rrhs, I1));
2576  // Contributions from linear terms
2577  if (term.is_matrix_term && brick.pbr->is_linear()
2578  && (!is_linear() || (version & BUILD_WITH_LIN)))
2579  gmm::mult_add(brick.rmatlist[j],
2580  gmm::scaled(var2->real_value[0], -alpha1),
2581  gmm::sub_vector(rrhs, I1));
2582  }
2583  // Contributions to interval I2 of var2 due to symmetric terms
2584  if (term.is_symmetric && I1.first() != I2.first() &&
2585  !(var2->is_disabled)) {
2586  if (brick.pdispatch) {
2587  for (size_type k = 0; k < brick.nbrhs; ++k)
2588  gmm::add(gmm::scaled(brick.rveclist_sym[k][j],
2589  brick.coeffs[k]),
2590  gmm::sub_vector(rrhs, I2));
2591  }
2592  else
2593  gmm::add(gmm::scaled(brick.rveclist_sym[0][j], alpha2),
2594  gmm::sub_vector(rrhs, I2));
2595  // Contributions from affine dependent variables
2596  if (term.is_matrix_term && brick.pbr->is_linear() && is_linear()
2597  && var1->is_affine_dependent)
2598  gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
2599  gmm::scaled(var1->affine_real_value, -alpha2),
2600  gmm::sub_vector(rrhs, I2));
2601  // Contributions from linear terms
2602  if (brick.pbr->is_linear()
2603  && (!is_linear() || (version & BUILD_WITH_LIN)))
2604  gmm::mult_add(gmm::transposed(brick.rmatlist[j]),
2605  gmm::scaled(var1->real_value[0], -alpha2),
2606  gmm::sub_vector(rrhs, I2));
2607  }
2608  }
2609  }
2610  }
2611 
2612  if (brick.pbr->is_linear())
2613  brick.terms_to_be_computed = false;
2614  // Commented to allow to get the information after assembly. Used in
2615  // some aplications. Should be optional ?
2616 // else
2617 // if (cplx) {
2618 // brick.cmatlist = complex_matlist(brick.tlist.size());
2619 // brick.cveclist[0] = complex_veclist(brick.tlist.size());
2620 // } else {
2621 // brick.rmatlist = real_matlist(brick.tlist.size());
2622 // brick.rveclist[0] = real_veclist(brick.tlist.size());
2623 // }
2624 
2625  if (version & BUILD_RHS) approx_external_load_ += brick.external_load;
2626  }
2627 
2628  if (version & BUILD_RHS && version & BUILD_WITH_INTERNAL) {
2629  GMM_ASSERT1(gmm::vect_size(full_rrhs) > 0 && has_internal_variables(),
2630  "Internal error");
2631  gmm::sub_interval IP(0,gmm::vect_size(rrhs));
2632  gmm::fill(full_rrhs, 0.);
2633  gmm::copy(rrhs, gmm::sub_vector(full_rrhs, IP)); // TICTIC
2634  }
2635 
2636  // Generic expressions
2637  if (generic_expressions.size()) {
2638  GMM_ASSERT1(!is_complex(), "to be done");
2639 
2640  if (version & BUILD_RHS)
2641  GMM_TRACE2("Global generic assembly RHS");
2642  if (version & BUILD_MATRIX)
2643  GMM_TRACE2("Global generic assembly tangent term");
2644 
2645  // auxilliary lambda function
2646  auto add_assignments_and_expressions_to_workspace =
2647  [&](ga_workspace &workspace)
2648  {
2649  for (const auto &ad : assignments)
2650  workspace.add_assignment_expression
2651  (ad.varname, ad.expr, ad.region, ad.order, ad.before);
2652  for (const auto &ge : generic_expressions)
2653  workspace.add_expression(ge.expr, ge.mim, ge.region,
2654  2, ge.secondary_domain);
2655  };
2656 
2657  const bool with_internal = version & BUILD_WITH_INTERNAL
2659  model_real_sparse_matrix intern_mat; // temp for extracting condensation info
2660  model_real_plain_vector res0, // holds the original RHS
2661  res1; // holds the condensed RHS
2662 
2663  size_type full_size = gmm::vect_size(full_rrhs),
2664  primary_size = gmm::vect_size(rrhs);
2665 
2666  if ((version & BUILD_RHS) || (version & BUILD_MATRIX && with_internal))
2667  gmm::resize(res0, with_internal ? full_size : primary_size);
2668  if (version & BUILD_MATRIX && with_internal)
2669  gmm::resize(res1, full_size);
2670 
2671  if (version & BUILD_MATRIX) {
2672  if (with_internal) {
2673  gmm::resize(intern_mat, full_size, primary_size);
2674  gmm::resize(res1, full_size);
2675  }
2676  accumulated_distro<decltype(rTM)> tangent_matrix_distro(rTM);
2677  accumulated_distro<decltype(intern_mat)> intern_mat_distro(intern_mat);
2679 
2680  if (version & BUILD_RHS) { // both BUILD_RHS & BUILD_MATRIX
2682  GETFEM_OMP_PARALLEL( // running the assembly in parallel
2683  ga_workspace workspace(*this);
2684  add_assignments_and_expressions_to_workspace(workspace);
2685  workspace.set_assembled_vector(res0_distro);
2686  workspace.assembly(1, with_internal);
2687  if (with_internal) { // Condensation reads from/writes to rhs
2688  gmm::copy(res0_distro.get(), res1_distro.get());
2689  gmm::add(gmm::scaled(full_rrhs, scalar_type(-1)),
2690  res1_distro.get()); // initial value residual=-rhs (actually only the internal variables residual is needed)
2691  workspace.set_assembled_vector(res1_distro);
2692  workspace.set_internal_coupling_matrix(intern_mat_distro);
2693  }
2694  workspace.set_assembled_matrix(tangent_matrix_distro);
2695  workspace.assembly(2, with_internal);
2696  ) // end GETFEM_OMP_PARALLEL
2697  } // end of res0_distro scope
2698  else { // only BUILD_MATRIX
2699  GETFEM_OMP_PARALLEL( // running the assembly in parallel
2700  ga_workspace workspace(*this);
2701  add_assignments_and_expressions_to_workspace(workspace);
2702  if (with_internal) { // Condensation reads from/writes to rhs
2703  gmm::copy(gmm::scaled(full_rrhs, scalar_type(-1)),
2704  res1_distro.get()); // initial value residual=-rhs (actually only the internal variables residual is needed)
2705  workspace.set_assembled_vector(res1_distro);
2706  workspace.set_internal_coupling_matrix(intern_mat_distro);
2707  }
2708  workspace.set_assembled_matrix(tangent_matrix_distro);
2709  workspace.assembly(2, with_internal);
2710  ) // end GETFEM_OMP_PARALLEL
2711  }
2712  } // end of tangent_matrix_distro, intern_mat_distro, res1_distro scope
2713  else if (version & BUILD_RHS) {
2715  GETFEM_OMP_PARALLEL( // running the assembly in parallel
2716  ga_workspace workspace(*this);
2717  add_assignments_and_expressions_to_workspace(workspace);
2718  workspace.set_assembled_vector(res0_distro);
2719  workspace.assembly(1, with_internal);
2720  ) // end GETFEM_OMP_PARALLEL
2721  } // end of res0_distro scope
2722 
2723  if (version & BUILD_RHS) {
2724  gmm::scale(res0, scalar_type(-1)); // from residual to rhs
2725  if (with_internal) {
2726  gmm::sub_interval IP(0,gmm::vect_size(rrhs));
2727  gmm::add(gmm::sub_vector(res0, IP), rrhs); // TOCTOC
2728  gmm::add(res0, full_rrhs);
2729  } else
2730  gmm::add(res0, rrhs);
2731  }
2732 
2733  if (version & BUILD_MATRIX && with_internal) {
2734  gmm::scale(res1, scalar_type(-1)); // from residual to rhs
2735  gmm::sub_interval IP(0, primary_size),
2736  II(primary_size, full_size-primary_size);
2737  gmm::copy(gmm::sub_matrix(intern_mat, II, IP), internal_rTM); // --> internal_rTM
2738  gmm::add(gmm::sub_vector(res1, IP), rrhs); // --> rrhs
2739  gmm::copy(gmm::sub_vector(res1, II), internal_sol); // --> internal_sol
2740  }
2741  }
2742 
2743  // Post simplification for dof constraints
2744  if ((version & BUILD_RHS) || (version & BUILD_MATRIX)) {
2745  if (is_complex()) {
2746  std::vector<size_type> dof_indices;
2747  std::vector<complex_type> dof_pr_values;
2748  std::vector<complex_type> dof_go_values;
2749  for (const auto &keyval : complex_dof_constraints) {
2750  const gmm::sub_interval &I = interval_of_variable(keyval.first);
2751  const model_complex_plain_vector &V = complex_variable(keyval.first);
2752  for (const auto &val : keyval.second) {
2753  dof_indices.push_back(val.first + I.first());
2754  dof_go_values.push_back(val.second);
2755  dof_pr_values.push_back(V[val.first]);
2756  }
2757  }
2758 
2759  if (dof_indices.size()) {
2760  gmm::sub_index SI(dof_indices);
2761  gmm::sub_interval II(0, nb_dof());
2762 
2763  if (version & BUILD_RHS) {
2764  if (MPI_IS_MASTER())
2765  approx_external_load_ += gmm::vect_norm1(dof_go_values);
2766  if (is_linear_) {
2767  if (is_symmetric_) {
2768  scalar_type valnorm = gmm::vect_norm2(dof_go_values);
2769  if (valnorm > scalar_type(0)) {
2770  GMM_ASSERT1(version & BUILD_MATRIX, "Rhs only for a "
2771  "symmetric linear problem with dof "
2772  "constraint not allowed");
2773  model_complex_plain_vector vv(gmm::vect_size(crhs));
2774  gmm::mult(gmm::sub_matrix(cTM, II, SI), dof_go_values, vv);
2775  MPI_SUM_VECTOR(vv);
2776  gmm::add(gmm::scaled(vv, scalar_type(-1)), crhs);
2777  }
2778  }
2779  gmm::copy(dof_go_values, gmm::sub_vector(crhs, SI));
2780  } else {
2781  gmm::add(dof_go_values,
2782  gmm::scaled(dof_pr_values, complex_type(-1)),
2783  gmm::sub_vector(crhs, SI));
2784  }
2785  }
2786  if (version & BUILD_MATRIX) {
2787  gmm::clear(gmm::sub_matrix(cTM, SI, II));
2788  if (is_symmetric_) gmm::clear(gmm::sub_matrix(cTM, II, SI));
2789 
2790  if (MPI_IS_MASTER()) {
2791  for (size_type i = 0; i < dof_indices.size(); ++i)
2792  cTM(dof_indices[i], dof_indices[i]) = complex_type(1);
2793  }
2794  }
2795  }
2796  } else { // !is_complex()
2797  std::vector<size_type> dof_indices;
2798  std::vector<scalar_type> dof_pr_values;
2799  std::vector<scalar_type> dof_go_values;
2800  for (const auto &keyval : real_dof_constraints) {
2801  const gmm::sub_interval &I = interval_of_variable(keyval.first);
2802  const model_real_plain_vector &V = real_variable(keyval.first);
2803  for (const auto &val : keyval.second) {
2804  dof_indices.push_back(val.first + I.first());
2805  dof_go_values.push_back(val.second);
2806  dof_pr_values.push_back(V[val.first]);
2807  }
2808  }
2809 
2810  #if GETFEM_PARA_LEVEL > 1
2811  GMM_ASSERT1(MPI_IS_MASTER() || (dof_indices.size() == 0),
2812  "Sorry, for the moment, the dof constraints have to be "
2813  "added on the master process only");
2814  size_type dof_indices_size = dof_indices.size();
2815  MPI_BCAST0_SCALAR(dof_indices_size);
2816  dof_indices.resize(dof_indices_size);
2817  MPI_BCAST0_VECTOR(dof_indices);
2818  dof_pr_values.resize(dof_indices_size);
2819  MPI_BCAST0_VECTOR(dof_pr_values);
2820  dof_go_values.resize(dof_indices_size);
2821  MPI_BCAST0_VECTOR(dof_go_values);
2822  #endif
2823 
2824  if (dof_indices.size()) {
2825  gmm::sub_index SI(dof_indices);
2826  gmm::sub_interval II(0, nb_dof());
2827 
2828  if (version & BUILD_RHS) {
2829  if (MPI_IS_MASTER())
2830  approx_external_load_ += gmm::vect_norm1(dof_go_values);
2831  if (is_linear_) {
2832  if (is_symmetric_) {
2833  scalar_type valnorm = gmm::vect_norm2(dof_go_values);
2834  if (valnorm > scalar_type(0)) {
2835  GMM_ASSERT1(version & BUILD_MATRIX, "Rhs only for a "
2836  "symmetric linear problem with dof "
2837  "constraint not allowed");
2838  model_real_plain_vector vv(gmm::vect_size(rrhs));
2839  gmm::mult(gmm::sub_matrix(rTM, II, SI), dof_go_values, vv);
2840  MPI_SUM_VECTOR(vv);
2841  gmm::add(gmm::scaled(vv, scalar_type(-1)), rrhs);
2842  }
2843  }
2844  gmm::copy(dof_go_values, gmm::sub_vector(rrhs, SI));
2845  } else {
2846  gmm::add(dof_go_values,
2847  gmm::scaled(dof_pr_values, scalar_type(-1)),
2848  gmm::sub_vector(rrhs, SI));
2849  }
2850  }
2851  if (version & BUILD_MATRIX) {
2852  gmm::clear(gmm::sub_matrix(rTM, SI, II));
2853  if (is_symmetric_) gmm::clear(gmm::sub_matrix(rTM, II, SI));
2854 
2855  if (MPI_IS_MASTER()) {
2856  for (size_type i = 0; i < dof_indices.size(); ++i)
2857  rTM(dof_indices[i], dof_indices[i]) = scalar_type(1);
2858  }
2859  }
2860  }
2861  }
2862  }
2863 
2864  if (version & BUILD_RHS) {
2865  approx_external_load_ = MPI_SUM_SCALAR(approx_external_load_);
2866  }
2867 
2868  #if GETFEM_PARA_LEVEL > 1
2869  // int rk; MPI_Comm_rank(MPI_COMM_WORLD, &rk);
2870  if (MPI_IS_MASTER()) cout << "Assembly time " << MPI_Wtime()-t_ref << endl;
2871  #endif
2872 
2873  }
2874 
2875 
2876  const mesh_fem &
2877  model::mesh_fem_of_variable(const std::string &name) const {
2878  auto it = find_variable(no_old_prefix_name(name));
2879  return it->second.associated_mf();
2880  }
2881 
2882  const mesh_fem *
2883  model::pmesh_fem_of_variable(const std::string &name) const {
2884  auto it = find_variable(no_old_prefix_name(name));
2885  return it->second.passociated_mf();
2886  }
2887 
2888  bgeot::multi_index
2889  model::qdims_of_variable(const std::string &name) const {
2890  auto it = find_variable(no_old_prefix_name(name));
2891  const mesh_fem *mf = it->second.passociated_mf();
2892  const im_data *imd = it->second.imd;
2893  size_type n = it->second.qdim();
2894  if (mf) {
2895  bgeot::multi_index mi = mf->get_qdims();
2896  if (n > 1 || it->second.qdims.size() > 1) {
2897  size_type i = 0;
2898  if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
2899  for (; i < it->second.qdims.size(); ++i)
2900  mi.push_back(it->second.qdims[i]);
2901  }
2902  return mi;
2903  } else if (imd) {
2904  bgeot::multi_index mi = imd->tensor_size();
2905  size_type q = n / imd->nb_filtered_index();
2906  GMM_ASSERT1(q % imd->nb_tensor_elem() == 0,
2907  "Invalid mesh im data vector");
2908  if (n > 1 || it->second.qdims.size() > 1) {
2909  size_type i = 0;
2910  if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
2911  for (; i < it->second.qdims.size(); ++i)
2912  mi.push_back(it->second.qdims[i]);
2913  }
2914  return mi;
2915  }
2916  return it->second.qdims;
2917  }
2918 
2919  size_type model::qdim_of_variable(const std::string &name) const {
2920  auto it = find_variable(no_old_prefix_name(name));
2921  const mesh_fem *mf = it->second.passociated_mf();
2922  const im_data *imd = it->second.imd;
2923  size_type n = it->second.qdim();
2924  if (mf) {
2925  return mf->get_qdim() * n;
2926  } else if (imd) {
2927  return imd->tensor_size().total_size() * n;
2928  }
2929  return n;
2930  }
2931 
2932 
2933  const gmm::sub_interval &
2934  model::interval_of_variable(const std::string &name) const {
2935  context_check();
2936  if (act_size_to_be_done) actualize_sizes();
2937  VAR_SET::const_iterator it = find_variable(name);
2938  return it->second.I;
2939  }
2940 
2941  const model_real_plain_vector &
2942  model::real_variable(const std::string &name) const {
2943  return is_old(name) ? real_variable(no_old_prefix_name(name), 1)
2944  : real_variable(name, size_type(-1));
2945  }
2946 
2947  const model_real_plain_vector &
2948  model::real_variable(const std::string &name, size_type niter) const {
2949  GMM_ASSERT1(!complex_version, "This model is a complex one");
2950  GMM_ASSERT1(!is_old(name), "Please don't use Old_ prefix in combination "
2951  "with variable version");
2952  context_check();
2953  auto it = variables.find(name);
2954  GMM_ASSERT1(it != variables.end(), "Undefined variable " << name);
2955  if (act_size_to_be_done && it->second.is_fem_dofs) {
2956  if (it->second.filter != VDESCRFILTER_NO)
2957  actualize_sizes();
2958  else
2959  it->second.set_size();
2960  }
2961  if (niter == size_type(-1)) niter = it->second.default_iter;
2962  GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
2963  "Invalid iteration number " << niter << " for " << name);
2964  return it->second.real_value[niter];
2965  }
2966 
2967  const model_complex_plain_vector &
2968  model::complex_variable(const std::string &name) const {
2969  return is_old(name) ? complex_variable(no_old_prefix_name(name), 1)
2970  : complex_variable(name, size_type(-1));
2971  }
2972 
2973  const model_complex_plain_vector &
2974  model::complex_variable(const std::string &name, size_type niter) const {
2975  GMM_ASSERT1(complex_version, "This model is a real one");
2976  GMM_ASSERT1(!is_old(name), "Please don't use Old_ prefix in combination with"
2977  " variable version");
2978  context_check();
2979  auto it = variables.find(name);
2980  GMM_ASSERT1(it!=variables.end(), "Undefined variable " << name);
2981  if (act_size_to_be_done && it->second.is_fem_dofs) {
2982  if (it->second.filter != VDESCRFILTER_NO)
2983  actualize_sizes();
2984  else
2985  it->second.set_size();
2986  }
2987  if (niter == size_type(-1)) niter = it->second.default_iter;
2988  GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
2989  "Invalid iteration number "
2990  << niter << " for " << name);
2991  return it->second.complex_value[niter];
2992  }
2993 
2994  model_real_plain_vector &
2995  model::set_real_variable(const std::string &name) const {
2996  return is_old(name) ? set_real_variable(no_old_prefix_name(name), 1)
2997  : set_real_variable(name, size_type(-1));
2998  }
2999 
3000 
3001  model_real_plain_vector &
3002  model::set_real_variable(const std::string &name, size_type niter) const {
3003  GMM_ASSERT1(!complex_version, "This model is a complex one");
3004  GMM_ASSERT1(!is_old(name), "Please don't use Old_ prefix in combination with"
3005  " variable version");
3006  context_check();
3007  auto it = variables.find(name);
3008  GMM_ASSERT1(it!=variables.end(), "Undefined variable " << name);
3009  if (act_size_to_be_done && it->second.is_fem_dofs) {
3010  if (it->second.filter != VDESCRFILTER_NO)
3011  actualize_sizes();
3012  else
3013  it->second.set_size();
3014  }
3015  if (niter == size_type(-1)) niter = it->second.default_iter;
3016  it->second.v_num_data[niter] = act_counter();
3017  GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
3018  "Invalid iteration number "
3019  << niter << " for " << name);
3020  return it->second.real_value[niter];
3021  }
3022 
3023  model_complex_plain_vector &
3024  model::set_complex_variable(const std::string &name) const {
3025  return is_old(name) ? set_complex_variable(no_old_prefix_name(name), 1)
3026  : set_complex_variable(name, size_type(-1));
3027  }
3028 
3029  model_complex_plain_vector &
3030  model::set_complex_variable(const std::string &name, size_type niter) const {
3031  GMM_ASSERT1(complex_version, "This model is a real one");
3032  GMM_ASSERT1(!is_old(name), "Please don't use Old_ prefix in combination with"
3033  " variable version");
3034  context_check();
3035  auto it = variables.find(name);
3036  GMM_ASSERT1(it!=variables.end(), "Undefined variable " << name);
3037  if (act_size_to_be_done && it->second.is_fem_dofs) {
3038  if (it->second.filter != VDESCRFILTER_NO)
3039  actualize_sizes();
3040  else
3041  it->second.set_size();
3042  }
3043  if (niter == size_type(-1)) niter = it->second.default_iter;
3044  it->second.v_num_data[niter] = act_counter();
3045  GMM_ASSERT1(it->second.n_iter + it->second.n_temp_iter > niter,
3046  "Invalid iteration number "
3047  << niter << " for " << name);
3048  return it->second.complex_value[niter];
3049  }
3050 
3051  model_real_plain_vector &
3052  model::set_real_constant_part(const std::string &name) const {
3053  GMM_ASSERT1(!complex_version, "This model is a complex one");
3054  context_check();
3055  VAR_SET::iterator it = variables.find(name);
3056  GMM_ASSERT1(it != variables.end(), "Undefined variable " << name);
3057  GMM_ASSERT1(it->second.is_affine_dependent,
3058  "Only for affine dependent variables");
3059  if (act_size_to_be_done && it->second.is_fem_dofs) {
3060  if (it->second.filter != VDESCRFILTER_NO)
3061  actualize_sizes();
3062  else
3063  it->second.set_size();
3064  }
3065  for (auto &v_num : it->second.v_num_data) v_num = act_counter();
3066  return it->second.affine_real_value;
3067  }
3068 
3069  model_complex_plain_vector &
3070  model::set_complex_constant_part(const std::string &name) const {
3071  GMM_ASSERT1(complex_version, "This model is a real one");
3072  context_check();
3073  VAR_SET::iterator it = variables.find(name);
3074  GMM_ASSERT1(it!=variables.end(), "Undefined variable " << name);
3075  if (act_size_to_be_done && it->second.is_fem_dofs) {
3076  if (it->second.filter != VDESCRFILTER_NO)
3077  actualize_sizes();
3078  else
3079  it->second.set_size();
3080  }
3081  for (auto &v_num : it->second.v_num_data) v_num = act_counter();
3082  return it->second.affine_complex_value;
3083  }
3084 
3086 
3087  const brick_description &brick = bricks[ind_brick];
3088  update_brick(ind_brick, model::BUILD_ALL);
3089 
3090  brick.pbr->check_stiffness_matrix_and_rhs(*this, ind_brick, brick.tlist,
3091  brick.vlist, brick.dlist, brick.mims, brick.rmatlist,
3092  brick.rveclist[0], brick.rveclist_sym[0], brick.region);
3093  }
3094 
3095  void model::clear() {
3096  variables.clear();
3097  active_bricks.clear();
3098  valid_bricks.clear();
3099  real_dof_constraints.clear();
3100  complex_dof_constraints.clear();
3101  bricks.resize(0);
3102  rTM = model_real_sparse_matrix();
3103  cTM = model_complex_sparse_matrix();
3104  rrhs = model_real_plain_vector();
3105  crhs = model_complex_plain_vector();
3106  }
3107 
3108 
3109 
3110  void virtual_brick::full_asm_real_tangent_terms_(const model &md, size_type ind_brick,
3111  const model::varnamelist &term_list,
3112  const model::varnamelist &var_list,
3113  const model::mimlist &mim_list,
3114  model::real_matlist &rmatlist,
3115  model::real_veclist &rveclist,
3116  model::real_veclist &rveclist_sym,
3117  size_type region, build_version version) const
3118  {
3119  real_pre_assembly_in_serial(md, ind_brick, term_list, var_list, mim_list, rmatlist,
3120  rveclist, rveclist_sym, region, version);
3121  asm_real_tangent_terms(md, ind_brick, term_list, var_list, mim_list, rmatlist,
3122  rveclist, rveclist_sym, region, version);
3123  real_post_assembly_in_serial(md, ind_brick, term_list, var_list, mim_list, rmatlist,
3124  rveclist, rveclist_sym, region, version);
3125  }
3126 
3128  (const model &md, size_type s,
3129  const model::termlist& tlist,
3130  const model::varnamelist &vl,
3131  const model::varnamelist &dl,
3132  const model::mimlist &mims,
3133  model::real_matlist &matl,
3134  model::real_veclist &rvc1,
3135  model::real_veclist &rvc2,
3136  size_type rg,
3137  const scalar_type TINY) const
3138  {
3139  std::cout<<"******Verifying stiffnesses of *******"<<std::endl;
3140  std::cout<<"*** "<<brick_name()<<std::endl;
3141 
3142  //Build the index for the corresponding RHS
3143  std::map<std::string,size_type> rhs_index;
3144  for(size_type iterm=0;iterm<matl.size();iterm++)
3145  if (tlist[iterm].var1==tlist[iterm].var2) rhs_index[tlist[iterm].var1]=iterm;
3146 
3147  if (rhs_index.size()==0){
3148  GMM_WARNING0("*** cannot verify stiffness for this brick***");
3149  return;
3150  }
3151  full_asm_real_tangent_terms_(md, s, vl, dl, mims, matl, rvc1, rvc2,
3152  rg, model::BUILD_MATRIX);
3153  for(size_type iterm=0;iterm<matl.size();iterm++)
3154  {
3155 
3156  std::cout<<std::endl;
3157  std::cout<<" Stiffness["<<tlist[iterm].var1
3158  <<","<<tlist[iterm].var2<<"]:"<<std::endl;
3159  if (md.real_variable(tlist[iterm].var1).size()==0)
3160  {
3161  std::cout<<" "<<tlist[iterm].var1<<" has zero size. Skipping this term"<<std::endl;
3162  continue;
3163  }
3164  if (md.real_variable(tlist[iterm].var2).size()==0)
3165  {
3166  std::cout<<" "<<tlist[iterm].var2<<" has zero size. Skipping this term"<<std::endl;
3167  continue;
3168  }
3169 
3170  model_real_sparse_matrix SM(matl[iterm]);
3171  gmm::fill(rvc1[rhs_index[tlist[iterm].var1]], 0.0);
3172  full_asm_real_tangent_terms_(md, s, vl, dl, mims, matl, rvc1, rvc2,
3173  rg, model::BUILD_RHS);
3174  if (gmm::mat_euclidean_norm(matl[iterm])<1e-12){
3175  std::cout<<" The assembled matrix is nearly zero, skipping."<<std::endl;
3176  continue;
3177  }
3178  model_real_plain_vector RHS0(rvc1[rhs_index[tlist[iterm].var1]]);
3179 
3180  //finite difference stiffness
3181  model_real_sparse_matrix fdSM(matl[iterm].nrows(), matl[iterm].ncols());
3182  model_real_plain_vector&U = md.set_real_variable(tlist[iterm].var2);
3183  model_real_plain_vector& RHS1 = rvc1[rhs_index[tlist[iterm].var1]];
3184 
3185  scalar_type relative_tiny = gmm::vect_norminf(RHS1)*TINY;
3186  if (relative_tiny < TINY) relative_tiny = TINY;
3187 
3188  for (size_type j = 0; j < matl[iterm].ncols(); j++){
3189  U[j] += relative_tiny;
3190  gmm::fill(RHS1, 0.0);
3191  full_asm_real_tangent_terms_(md, s, vl, dl, mims, matl, rvc1, rvc2,
3192  rg, model::BUILD_RHS);
3193  for (size_type i = 0; i<matl[iterm].nrows(); i++)
3194  fdSM(i, j) = (RHS0[i] - RHS1[i]) / relative_tiny;
3195  U[j] -= relative_tiny;
3196  }
3197 
3198  model_real_sparse_matrix diffSM(matl[iterm].nrows(),matl[iterm].ncols());
3199  gmm::add(SM,gmm::scaled(fdSM,-1.0),diffSM);
3200  scalar_type norm_error_euc
3201  = gmm::mat_euclidean_norm(diffSM)/gmm::mat_euclidean_norm(SM)*100;
3202  scalar_type norm_error_1
3203  = gmm::mat_norm1(diffSM)/gmm::mat_norm1(SM)*100;
3204  scalar_type norm_error_max
3205  = gmm::mat_maxnorm(diffSM)/gmm::mat_maxnorm(SM)*100;
3206 
3207  //checking symmetry of diagonal terms
3208  scalar_type nsym_norm_error_euc=0.0;
3209  scalar_type nsym_norm_error_1=0.0;
3210  scalar_type nsym_norm_error_max=0.0;
3211  if (tlist[iterm].var1==tlist[iterm].var2){
3212  model_real_sparse_matrix diffSMtransposed(matl[iterm].nrows(),matl[iterm].ncols());
3213  gmm::add(gmm::transposed(fdSM),gmm::scaled(fdSM,-1.0),diffSMtransposed);
3214  nsym_norm_error_euc
3215  = gmm::mat_euclidean_norm(diffSMtransposed)/gmm::mat_euclidean_norm(fdSM)*100;
3216  nsym_norm_error_1
3217  = gmm::mat_norm1(diffSMtransposed)/gmm::mat_norm1(fdSM)*100;
3218  nsym_norm_error_max
3219  = gmm::mat_maxnorm(diffSMtransposed)/gmm::mat_maxnorm(fdSM)*100;
3220  }
3221 
3222  //print matrix if the size is small
3223  if(rvc1[0].size()<8){
3224  std::cout << "RHS Stiffness Matrix: \n";
3225  std::cout << "------------------------\n";
3226  for(size_type i=0; i < rvc1[iterm].size(); ++i){
3227  std::cout << "[";
3228  for(size_type j=0; j < rvc1[iterm].size(); ++j){
3229  std::cout << fdSM(i,j) << " ";
3230  }
3231  std::cout << "]\n";
3232  }
3233  std::cout << "Analytical Stiffness Matrix: \n";
3234  std::cout << "------------------------\n";
3235  for(size_type i=0; i < rvc1[iterm].size(); ++i){
3236  std::cout << "[";
3237  for(size_type j=0; j < rvc1[iterm].size(); ++j){
3238  std::cout << matl[iterm](i,j) << " ";
3239  }
3240  std::cout << "]\n";
3241  }
3242  std::cout << "Vector U: \n";
3243  std::cout << "------------------------\n";
3244  for(size_type i=0; i < rvc1[iterm].size(); ++i){
3245  std::cout << "[";
3246  std::cout << md.real_variable(tlist[iterm].var2)[i] << " ";
3247  std::cout << "]\n";
3248  }
3249  }
3250  std::cout
3251  << "\n\nfinite diff test error_norm_eucl: " << norm_error_euc << "%\n"
3252  << "finite diff test error_norm1: " << norm_error_1 << "%\n"
3253  << "finite diff test error_max_norm: " << norm_error_max << "%\n\n\n";
3254 
3255  if (tlist[iterm].var1==tlist[iterm].var2){
3256  std::cout
3257  << "Nonsymmetrical test error_norm_eucl: "<< nsym_norm_error_euc<< "%\n"
3258  << "Nonsymmetrical test error_norm1: " << nsym_norm_error_1 << "%\n"
3259  << "Nonsymmetrical test error_max_norm: " << nsym_norm_error_max << "%"
3260  << std::endl;
3261  }
3262  }
3263  }
3264 
3265  // ----------------------------------------------------------------------
3266  //
3267  //
3268  // Standard bricks
3269  //
3270  //
3271  // ----------------------------------------------------------------------
3272 
3273  // ----------------------------------------------------------------------
3274  //
3275  // Generic assembly source term brick
3276  //
3277  // ----------------------------------------------------------------------
3278 
3279  struct gen_source_term_assembly_brick : public virtual_brick {
3280 
3281  std::string expr, directvarname, directdataname;
3282  model::varnamelist vl_test1;
3283  std::string secondary_domain;
3284 
3285  void asm_real_tangent_terms(const model &md, size_type /* ib */,
3286  const model::varnamelist &,
3287  const model::varnamelist &,
3288  const model::mimlist &mims,
3289  model::real_matlist &,
3290  model::real_veclist &vecl,
3291  model::real_veclist &,
3292  size_type region,
3293  build_version) const override {
3294  GMM_ASSERT1(vecl.size() == vl_test1.size()
3295  + ((directdataname.size() == 0) ? 0 : 1), "Wrong number "
3296  "of terms for Generic source term assembly brick ");
3297  GMM_ASSERT1(mims.size() == 1, "Generic source term assembly brick "
3298  "needs one and only one mesh_im");
3299  GMM_TRACE2("Generic source term assembly");
3300 
3301  gmm::clear(vecl[0]);
3302 
3303  if (expr.size()) {
3304  // reenables disabled variables
3305  ga_workspace workspace(md, ga_workspace::inherit::ALL);
3306  GMM_TRACE2(name << ": generic source term assembly");
3307  workspace.add_expression(expr, *(mims[0]), region, 1, secondary_domain);
3308  workspace.assembly(1);
3309  const auto &V=workspace.assembled_vector();
3310  for (size_type i = 0; i < vl_test1.size(); ++i) {
3311  const auto &I=workspace.interval_of_variable(vl_test1[i]);
3312  gmm::copy(gmm::sub_vector(V, I), vecl[i]);
3313  }
3314  }
3315 
3316  if (directvarname.size()) {
3317  gmm::copy(md.real_variable(directdataname), vecl.back());
3318  }
3319  }
3320 
3321  void real_post_assembly_in_serial(const model &md, size_type ib,
3322  const model::varnamelist &/* vl */,
3323  const model::varnamelist &/* dl */,
3324  const model::mimlist &/* mims */,
3325  model::real_matlist &/*matl*/,
3326  model::real_veclist &vecl,
3327  model::real_veclist &,
3328  size_type /*region*/,
3329  build_version) const override {
3330  scalar_type el = scalar_type(0);
3331  for (size_type i=0; i < vecl.size(); ++i) el += gmm::vect_norm1(vecl[i]);
3332  md.add_external_load(ib, el);
3333  }
3334 
3335  virtual std::string declare_volume_assembly_string
3336  (const model &, size_type, const model::varnamelist &,
3337  const model::varnamelist &) const {
3338  return std::string();
3339  }
3340 
3341  gen_source_term_assembly_brick(const std::string &expr_,
3342  std::string brickname,
3343  const model::varnamelist &vl_test1_,
3344  const std::string &directvarname_,
3345  const std::string &directdataname_,
3346  const std::string &secdom)
3347  : vl_test1(vl_test1_), secondary_domain(secdom) {
3348  if (brickname.size() == 0)
3349  brickname = "Generic source term assembly brick";
3350  expr = expr_;
3351  set_flags(brickname, true /* is linear*/,
3352  true /* is symmetric */, true /* is coercive */,
3353  true /* is real */, false /* is complex */,
3354  false /* compute each time */);
3355  directvarname = directvarname_; directdataname = directdataname_;
3356  }
3357 
3358  };
3359 
3360  static bool check_compatibility_vl_test(model &md,
3361  const model::varnamelist vl_test) {
3362  model::varnamelist org;
3363  for (size_type i = 0; i < vl_test.size(); ++i) {
3364  if (md.is_affine_dependent_variable(vl_test[i]))
3365  org.push_back(md.org_variable(vl_test[i]));
3366  }
3367  for (size_type i = 0; i < vl_test.size(); ++i)
3368  for (size_type j = 0; j < org.size(); ++j)
3369  if (vl_test[i].compare(org[j]) == 0) return false;
3370  return true;
3371  }
3372 
3373  size_type add_source_term_
3374  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3375  const std::string &brickname, std::string directvarname,
3376  const std::string &directdataname, bool return_if_nonlin,
3377  const std::string &secondary_domain) {
3378 
3379  ga_workspace workspace(md);
3380  size_type order = workspace.add_expression(expr, mim, region, 1,
3381  secondary_domain);
3382  GMM_ASSERT1(order <= 1, "Wrong order for a source term");
3383  model::varnamelist vl, vl_test1, vl_test2, dl;
3384  bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 1);
3385  if (!is_lin && return_if_nonlin) return size_type(-1);
3386  GMM_ASSERT1(is_lin, "Nonlinear term");
3387  GMM_ASSERT1(check_compatibility_vl_test(md, vl_test1),
3388  "This brick do not support the assembly on both an affine "
3389  "dependent variable and its original variable. "
3390  "Split the brick.");
3391 
3392  if (directdataname.size()) {
3393  vl.push_back(directvarname);
3394  dl.push_back(directdataname);
3395  } else directvarname = "";
3396 
3397  pbrick pbr = std::make_shared<gen_source_term_assembly_brick>
3398  (expr, brickname, vl_test1, directvarname, directdataname,
3399  secondary_domain);
3400  model::termlist tl;
3401 
3402  for (size_type i = 0; i < vl_test1.size(); ++i)
3403  tl.push_back(model::term_description(vl_test1[i]));
3404  if (directdataname.size())
3405  tl.push_back(model::term_description(directvarname));
3406 
3407  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
3408  }
3409 
3411  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3412  const std::string &brickname, const std::string &directvarname,
3413  const std::string &directdataname, bool return_if_nonlin) {
3414  return add_source_term_(md, mim, expr, region, brickname, directvarname,
3415  directdataname, return_if_nonlin, "");
3416  }
3417 
3419  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3420  const std::string &secondary_domain,
3421  const std::string &brickname, const std::string &directvarname,
3422  const std::string &directdataname, bool return_if_nonlin) {
3423  return add_source_term_(md, mim, expr, region, brickname, directvarname,
3424  directdataname, return_if_nonlin, secondary_domain);
3425  }
3426 
3427  // ----------------------------------------------------------------------
3428  //
3429  // Linear generic assembly brick
3430  //
3431  // ----------------------------------------------------------------------
3432 
3433  struct gen_linear_assembly_brick : public virtual_brick {
3434 
3435  std::string expr;
3436  bool is_lower_dim;
3437  model::varnamelist vl_test1, vl_test2;
3438  std::string secondary_domain;
3439 
3440  virtual void asm_real_tangent_terms(const model &md, size_type ib,
3441  const model::varnamelist &/* vl */,
3442  const model::varnamelist &dl,
3443  const model::mimlist &mims,
3444  model::real_matlist &matl,
3445  model::real_veclist &/* vecl */,
3446  model::real_veclist &,
3447  size_type region,
3448  build_version version) const {
3449  GMM_ASSERT1(matl.size() == vl_test1.size(),
3450  "Wrong number of terms for Generic linear assembly brick");
3451  GMM_ASSERT1(mims.size() == 1,
3452  "Generic linear assembly brick needs one and only one "
3453  "mesh_im");
3454  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
3455  for (size_type i = 0; i < dl.size(); ++i)
3456  recompute_matrix = recompute_matrix ||
3457  md.is_var_newer_than_brick(dl[i], ib);
3458 
3459  if (recompute_matrix) {
3460  // reenables disabled variables
3461  ga_workspace workspace(md, ga_workspace::inherit::ALL);
3462  workspace.add_expression(expr, *(mims[0]), region, 2, secondary_domain);
3463  GMM_TRACE2(name << ": generic matrix assembly");
3464  workspace.assembly(2);
3465  const auto &R=workspace.assembled_matrix();
3466  for (size_type i = 0; i < vl_test1.size(); ++i) {
3467  scalar_type alpha = scalar_type(1)
3468  / ( workspace.factor_of_variable(vl_test1[i]) *
3469  workspace.factor_of_variable(vl_test2[i]));
3470  const auto &I1=workspace.interval_of_variable(vl_test1[i]),
3471  &I2=workspace.interval_of_variable(vl_test2[i]);
3472  gmm::copy(gmm::scaled(gmm::sub_matrix(R, I1, I2), alpha),
3473  matl[i]);
3474  }
3475  }
3476  }
3477 
3478  virtual std::string declare_volume_assembly_string
3479  (const model &, size_type, const model::varnamelist &,
3480  const model::varnamelist &) const {
3481  return is_lower_dim ? std::string() : expr;
3482  }
3483 
3484  gen_linear_assembly_brick(const std::string &expr_, const mesh_im &mim,
3485  bool is_sym,
3486  bool is_coer, std::string brickname,
3487  const model::varnamelist &vl_test1_,
3488  const model::varnamelist &vl_test2_,
3489  const std::string &secdom)
3490  : vl_test1(vl_test1_), vl_test2(vl_test2_), secondary_domain(secdom) {
3491  if (brickname.size() == 0) brickname = "Generic linear assembly brick";
3492  expr = expr_;
3493  is_lower_dim = mim.is_lower_dimensional();
3494  set_flags(brickname, true /* is linear*/,
3495  is_sym /* is symmetric */, is_coer /* is coercive */,
3496  true /* is real */, false /* is complex */);
3497  }
3498 
3499  };
3500 
3501  static bool check_compatibility_vl_test(model &md,
3502  const model::varnamelist vl_test1,
3503  const model::varnamelist vl_test2) {
3504  for (size_type i = 0; i < vl_test1.size(); ++i)
3505  for (size_type j = 0; j < vl_test1.size(); ++j) {
3506  bool is1 = md.is_affine_dependent_variable(vl_test1[i]);
3507  bool is2 = md.is_affine_dependent_variable(vl_test2[i]);
3508  if (is1 || is2) {
3509  const std::string &org1
3510  = is1 ? md.org_variable(vl_test1[i]) : vl_test1[i];
3511  const std::string &org2
3512  = is2 ? md.org_variable(vl_test2[i]) : vl_test2[i];
3513  bool is1_bis = md.is_affine_dependent_variable(vl_test1[j]);
3514  bool is2_bis = md.is_affine_dependent_variable(vl_test2[j]);
3515  const std::string &org1_bis = is1_bis ? md.org_variable(vl_test1[j])
3516  : vl_test1[j];
3517  const std::string &org2_bis = is2_bis ? md.org_variable(vl_test2[j])
3518  : vl_test2[j];
3519  if (org1.compare(org1_bis) == 0 && org2.compare(org2_bis))
3520  return false;
3521  }
3522  }
3523  return true;
3524  }
3525 
3526 
3527 
3528  size_type add_linear_term_
3529  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3530  bool is_sym, bool is_coercive, const std::string &brickname,
3531  bool return_if_nonlin, const std::string &secondary_domain) {
3532  // reenables disabled variables
3533  ga_workspace workspace(md, ga_workspace::inherit::ALL);
3534  size_type order = workspace.add_expression(expr, mim, region,
3535  2, secondary_domain);
3536  model::varnamelist vl, vl_test1, vl_test2, dl;
3537  bool is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 2);
3538 
3539  if (!is_lin && return_if_nonlin) return size_type(-1);
3540  GMM_ASSERT1(is_lin, "Nonlinear term");
3541  if (order == 0) { is_coercive = is_sym = true; }
3542 
3543  std::string const_expr= workspace.extract_constant_term(mim.linked_mesh());
3544  if (const_expr.size()) {
3545  add_source_term_
3546  (md, mim, const_expr, region, brickname+" (source term)",
3547  "", "", false, secondary_domain);
3548  }
3549 
3550  // GMM_ASSERT1(order <= 1,
3551  // "This brick does not support a second order term");
3552  GMM_ASSERT1(check_compatibility_vl_test(md, vl_test1, vl_test2),
3553  "This brick do not support the assembly on both an affine "
3554  "dependent variable and its original variable. "
3555  "Split the brick.");
3556 
3557  if (vl_test1.size()) {
3558  pbrick pbr = std::make_shared<gen_linear_assembly_brick>
3559  (expr, mim, is_sym, is_coercive, brickname, vl_test1, vl_test2,
3560  secondary_domain);
3561  model::termlist tl;
3562  for (size_type i = 0; i < vl_test1.size(); ++i)
3563  tl.push_back(model::term_description(vl_test1[i], vl_test2[i], false));
3564 
3565  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
3566  }
3567  return size_type(-1);
3568  }
3569 
3571  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3572  bool is_sym, bool is_coercive, const std::string &brickname,
3573  bool return_if_nonlin) {
3574  return add_linear_term_(md, mim, expr, region, is_sym, is_coercive,
3575  brickname, return_if_nonlin, "");
3576  }
3577 
3579  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3580  const std::string &secondary_domain, bool is_sym, bool is_coercive,
3581  const std::string &brickname, bool return_if_nonlin) {
3582  return add_linear_term_(md, mim, expr, region, is_sym, is_coercive,
3583  brickname, return_if_nonlin, secondary_domain);
3584  }
3585 
3586 
3587  // ----------------------------------------------------------------------
3588  //
3589  // Nonlinear generic assembly brick
3590  //
3591  // ----------------------------------------------------------------------
3592 
3593  struct gen_nonlinear_assembly_brick : public virtual_brick {
3594 
3595  std::string expr;
3596  bool is_lower_dim;
3597  std::string secondary_domain;
3598 
3599  virtual void real_post_assembly_in_serial(const model &md, size_type ,
3600  const model::varnamelist &,
3601  const model::varnamelist &,
3602  const model::mimlist &mims,
3603  model::real_matlist &,
3604  model::real_veclist &,
3605  model::real_veclist &,
3606  size_type region,
3607  build_version) const {
3608  GMM_ASSERT1(mims.size() == 1,
3609  "Generic linear assembly brick needs one and only one "
3610  "mesh_im");
3611  md.add_generic_expression(expr, *(mims[0]), region, secondary_domain);
3612  }
3613 
3614  virtual std::string declare_volume_assembly_string
3615  (const model &, size_type, const model::varnamelist &,
3616  const model::varnamelist &) const {
3617  return expr;
3618  }
3619 
3620 
3621  gen_nonlinear_assembly_brick(const std::string &expr_, const mesh_im &mim,
3622  bool is_sym,
3623  bool is_coer,
3624  std::string brickname,
3625  const std::string &secdom) {
3626  if (brickname.size() == 0) brickname = "Generic linear assembly brick";
3627  expr = expr_;
3628  secondary_domain = secdom;
3629  is_lower_dim = mim.is_lower_dimensional();
3630  set_flags(brickname, false /* is linear*/,
3631  is_sym /* is symmetric */, is_coer /* is coercive */,
3632  true /* is real */, false /* is complex */);
3633  }
3634 
3635  };
3636 
3637  size_type add_nonlinear_term_
3638  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3639  bool is_sym, bool is_coercive, const std::string &brickname,
3640  const std::string &secondary_domain) {
3641 
3642  ga_workspace workspace(md);
3643  size_type order = workspace.add_expression(expr, mim, region, 2,
3644  secondary_domain);
3645  GMM_ASSERT1(order < 2, "Order two test functions (Test2) are not allowed"
3646  " in assembly string for nonlinear terms");
3647  model::varnamelist vl, vl_test1, vl_test2, ddl, dl;
3648  workspace.used_variables(vl, vl_test1, vl_test2, ddl, order);
3649  for (size_type i = 0; i < ddl.size(); ++i)
3650  if (md.is_true_data(ddl[i])) dl.push_back(ddl[i]);
3651  else vl.push_back(ddl[i]);
3652  if (order == 0) { is_coercive = is_sym = true; }
3653  pbrick pbr = std::make_shared<gen_nonlinear_assembly_brick>
3654  (expr, mim, is_sym, is_coercive, brickname, secondary_domain);
3655  model::termlist tl; // No term
3656  // tl.push_back(model::term_description(true, is_sym));
3657  // TODO to be changed.
3658  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
3659  }
3660 
3661 
3663  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3664  bool is_sym, bool is_coercive, const std::string &brickname) {
3665  return add_nonlinear_term_(md, mim, expr, region, is_sym, is_coercive,
3666  brickname, "");
3667  }
3668 
3670  (model &md, const mesh_im &mim, const std::string &expr, size_type region,
3671  const std::string &secondary_domain, bool is_sym, bool is_coercive,
3672  const std::string &brickname) {
3673  return add_nonlinear_term_(md, mim, expr, region, is_sym, is_coercive,
3674  brickname, secondary_domain);
3675  }
3676 
3677 
3678  // ----------------------------------------------------------------------
3679  //
3680  // Generic elliptic brick
3681  //
3682  // ----------------------------------------------------------------------
3683 
3684  // Kept only for the complex version
3685  struct generic_elliptic_brick : public virtual_brick {
3686 
3687  virtual void asm_real_tangent_terms(const model &md, size_type /*ib*/,
3688  const model::varnamelist &vl,
3689  const model::varnamelist &dl,
3690  const model::mimlist &mims,
3691  model::real_matlist &matl,
3692  model::real_veclist &,
3693  model::real_veclist &,
3694  size_type region,
3695  build_version) const {
3696  GMM_ASSERT1(matl.size() == 1,
3697  "Generic elliptic brick has one and only one term");
3698  GMM_ASSERT1(mims.size() == 1,
3699  "Generic elliptic brick need one and only one mesh_im");
3700  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
3701  "Wrong number of variables for generic elliptic brick");
3702 
3703  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
3704  const mesh &m = mf_u.linked_mesh();
3705  size_type N = m.dim(), Q = mf_u.get_qdim(), s = 1;
3706  const mesh_im &mim = *mims[0];
3707  const model_real_plain_vector *A = 0;
3708  const mesh_fem *mf_a = 0;
3709  mesh_region rg(region);
3710  m.intersect_with_mpi_region(rg);
3711  if (dl.size() > 0) {
3712  A = &(md.real_variable(dl[0]));
3713  mf_a = md.pmesh_fem_of_variable(dl[0]);
3714  s = gmm::vect_size(*A);
3715  if (mf_a) s = s * mf_a->get_qdim() / mf_a->nb_dof();
3716  }
3717 
3718  gmm::clear(matl[0]);
3719  GMM_TRACE2("Generic elliptic term assembly");
3720  if (s == 1) {
3721  if (mf_a) {
3722  if (Q > 1)
3724  (matl[0], mim, mf_u, *mf_a, *A, rg);
3725  else
3727  (matl[0], mim, mf_u, *mf_a, *A, rg);
3728 
3729  } else {
3730  if (Q > 1)
3732  (matl[0], mim, mf_u, rg);
3733  else
3735  (matl[0], mim, mf_u, rg);
3736  if (A) gmm::scale(matl[0], (*A)[0]);
3737  }
3738  } else if (s == N*N) {
3739  if (mf_a) {
3740  if (Q > 1)
3742  (matl[0], mim, mf_u, *mf_a, *A, rg);
3743  else
3745  (matl[0], mim, mf_u, *mf_a, *A, rg);
3746  } else {
3747  if (Q > 1)
3749  (matl[0], mim, mf_u, *A, rg);
3750  else
3752  (matl[0], mim, mf_u, *A, rg);
3753  }
3754  } else if (s == N*N*Q*Q) {
3755  if (mf_a)
3757  (matl[0], mim, mf_u, *mf_a, *A, rg);
3758  else
3760  (matl[0], mim, mf_u, *A, rg);
3761  } else
3762  GMM_ASSERT1(false, "Bad format generic elliptic brick coefficient");
3763 
3764  }
3765 
3766  virtual void real_post_assembly_in_serial(const model &md, size_type,
3767  const model::varnamelist &,
3768  const model::varnamelist &dl,
3769  const model::mimlist &/* mims */,
3770  model::real_matlist &/*matl*/,
3771  model::real_veclist &,
3772  model::real_veclist &,
3773  size_type /*region*/,
3774  build_version) const
3775  {
3776  const model_real_plain_vector *A = 0;
3777  const mesh_fem *mf_a = 0;
3778  if (dl.size() > 0)
3779  {
3780  A = &(md.real_variable(dl[0]));
3781  mf_a = md.pmesh_fem_of_variable(dl[0]);
3782  }
3783  }
3784 
3785  virtual void complex_post_assembly_in_serial(const model &md, size_type,
3786  const model::varnamelist &,
3787  const model::varnamelist &dl,
3788  const model::mimlist &/*mims*/,
3789  model::complex_matlist &/*matl*/,
3790  model::complex_veclist &,
3791  model::complex_veclist &,
3792  size_type /* region */,
3793  build_version) const
3794  {
3795  const model_real_plain_vector *A = 0;
3796  const mesh_fem *mf_a = 0;
3797  if (dl.size() > 0)
3798  {
3799  A = &(md.real_variable(dl[0]));
3800  mf_a = md.pmesh_fem_of_variable(dl[0]);
3801  }
3802  }
3803 
3804  virtual scalar_type asm_complex_tangent_terms(const model &md, size_type,
3805  const model::varnamelist &vl,
3806  const model::varnamelist &,
3807  const model::mimlist &,
3808  model::complex_matlist &matl,
3809  model::complex_veclist &,
3810  model::complex_veclist &,
3811  size_type) const {
3812  const model_complex_plain_vector &U = md.complex_variable(vl[0]);
3813  return gmm::abs(gmm::vect_hp(matl[0], U, U)) / scalar_type(2);
3814  }
3815 
3816 
3817  virtual void asm_complex_tangent_terms(const model &md, size_type,
3818  const model::varnamelist &vl,
3819  const model::varnamelist &dl,
3820  const model::mimlist &mims,
3821  model::complex_matlist &matl,
3822  model::complex_veclist &,
3823  model::complex_veclist &,
3824  size_type region,
3825  build_version) const {
3826  GMM_ASSERT1(matl.size() == 1,
3827  "Generic elliptic brick has one and only one term");
3828  GMM_ASSERT1(mims.size() == 1,
3829  "Generic elliptic brick need one and only one mesh_im");
3830  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
3831  "Wrong number of variables for generic elliptic brick");
3832 
3833  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
3834  const mesh &m = mf_u.linked_mesh();
3835  size_type N = m.dim(), Q = mf_u.get_qdim(), s = 1;
3836  const mesh_im &mim = *mims[0];
3837  const model_real_plain_vector *A = 0;
3838  const mesh_fem *mf_a = 0;
3839  mesh_region rg(region);
3840  m.intersect_with_mpi_region(rg);
3841 
3842 
3843  if (dl.size() > 0) {
3844  A = &(md.real_variable(dl[0]));
3845  mf_a = md.pmesh_fem_of_variable(dl[0]);
3846  s = gmm::vect_size(*A);
3847  if (mf_a) s = s * mf_a->get_qdim() / mf_a->nb_dof();
3848  }
3849 
3850  gmm::clear(matl[0]);
3851  GMM_TRACE2("Generic elliptic term assembly");
3852  if (s == 1) {
3853  if (mf_a) {
3854  if (Q > 1)
3856  (matl[0], mim, mf_u, *mf_a, *A, rg);
3857  else
3859  (matl[0], mim, mf_u, *mf_a, *A, rg);
3860 
3861  } else {
3862  if (Q > 1)
3864  (gmm::real_part(matl[0]), mim, mf_u, rg);
3865  else
3867  (gmm::real_part(matl[0]), mim, mf_u, rg);
3868  if (A) gmm::scale(matl[0], (*A)[0]);
3869  }
3870  } else if (s == N*N) {
3871  if (mf_a) {
3872  if (Q > 1)
3874  (matl[0], mim, mf_u, *mf_a, *A, rg);
3875  else
3877  (matl[0], mim, mf_u, *mf_a, *A, rg);
3878  } else {
3879  if (Q > 1)
3881  (matl[0], mim, mf_u, *A, rg);
3882  else
3884  (matl[0], mim, mf_u, *A, rg);
3885  }
3886  } else if (s == N*N*Q*Q) {
3887  if (mf_a)
3889  (matl[0], mim, mf_u, *mf_a, *A, rg);
3890  else
3892  (matl[0], mim, mf_u, *A, rg);
3893  } else
3894  GMM_ASSERT1(false,
3895  "Bad format generic elliptic brick coefficient");
3896  }
3897 
3898  generic_elliptic_brick() {
3899  set_flags("Generic elliptic", true /* is linear*/,
3900  true /* is symmetric */, true /* is coercive */,
3901  true /* is real */, true /* is complex */);
3902  }
3903 
3904  };
3905 
3907  const std::string &varname,
3908  size_type region) {
3909  if (md.is_complex()) {
3910  pbrick pbr = std::make_shared<generic_elliptic_brick>();
3911  model::termlist tl;
3912  tl.push_back(model::term_description(varname, varname, true));
3913  return md.add_brick(pbr, model::varnamelist(1, varname),
3914  model::varnamelist(), tl, model::mimlist(1, &mim),
3915  region);
3916  } else {
3917  std::string test_varname
3918  = "Test_" + sup_previous_and_dot_to_varname(varname);
3919  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
3920  size_type qdim = mf_u.get_qdim();
3921  std::string expr;
3922  if (qdim == 1)
3923  expr = "Grad_"+varname+".Grad_"+test_varname;
3924  else
3925  expr = "Grad_"+varname+":Grad_"+test_varname;
3926  return add_linear_term(md, mim, expr, region, true, true,
3927  "Laplacian", false);
3928  }
3929  }
3930 
3932  const std::string &varname,
3933  const std::string &dataname,
3934  size_type region) {
3935  if (md.is_complex()) {
3936  pbrick pbr = std::make_shared<generic_elliptic_brick>();
3937  model::termlist tl;
3938  tl.push_back(model::term_description(varname, varname, true));
3939  return md.add_brick(pbr, model::varnamelist(1, varname),
3940  model::varnamelist(1, dataname), tl,
3941  model::mimlist(1, &mim), region);
3942  } else {
3943  std::string test_varname
3944  = "Test_" + sup_previous_and_dot_to_varname(varname);
3945  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
3946  size_type dim = mf_u.linked_mesh().dim(), qdim = mf_u.get_qdim(), qdim_data = 1;
3947  std::string expr;
3948 
3949  if (md.variable_exists(dataname)) {
3950  const mesh_fem *mf = md.pmesh_fem_of_variable(dataname);
3951  size_type n = gmm::vect_size(md.real_variable(dataname));
3952  if (mf) qdim_data = mf->get_qdim() * (n / mf->nb_dof());
3953  else qdim_data = n;
3954  }
3955 
3956  if (qdim == 1) {
3957  if (qdim_data != 1) {
3958  GMM_ASSERT1(qdim_data == gmm::sqr(dim),
3959  "Wrong data size for generic elliptic brick");
3960  expr = "((Reshape("+dataname+",meshdim,meshdim))*Grad_"+varname+").Grad_"
3961  + test_varname;
3962  } else {
3963  expr = "(("+dataname+")*Grad_"+varname+").Grad_"+test_varname;
3964  }
3965  } else {
3966  if (qdim_data != 1) {
3967  if (qdim_data == gmm::sqr(dim))
3968  expr = "((Reshape("+dataname+",meshdim,meshdim))*Grad_"+varname+"):Grad_"
3969  +test_varname;
3970  else if (qdim_data == gmm::sqr(gmm::sqr(dim)))
3971  expr = "((Reshape("+dataname+",meshdim,meshdim,meshdim,meshdim))*Grad_"
3972  +varname+"):Grad_"+test_varname;
3973  else GMM_ASSERT1(false, "Wrong data size for generic elliptic brick");
3974  } else {
3975  expr = "(("+dataname+")*Grad_"+varname+"):Grad_"+test_varname;
3976  }
3977  }
3979  (md, mim, expr, region, true, true, "Generic elliptic", true);
3980  if (ib == size_type(-1))
3981  ib = add_nonlinear_term(md, mim, expr, region, false, false,
3982  "Generic elliptic (nonlinear)");
3983  return ib;
3984  }
3985  }
3986 
3987  // ----------------------------------------------------------------------
3988  //
3989  // Source term brick
3990  //
3991  // ----------------------------------------------------------------------
3992 
3993  // Kept only for the complex version
3994  struct source_term_brick : public virtual_brick {
3995 
3996  void asm_real_tangent_terms(const model &md, size_type /*ib*/,
3997  const model::varnamelist &vl,
3998  const model::varnamelist &dl,
3999  const model::mimlist &mims,
4000  model::real_matlist &,
4001  model::real_veclist &vecl,
4002  model::real_veclist &,
4003  size_type region,
4004  build_version) const override {
4005  GMM_ASSERT1(vecl.size() == 1,
4006  "Source term brick has one and only one term");
4007  GMM_ASSERT1(mims.size() == 1,
4008  "Source term brick need one and only one mesh_im");
4009  GMM_ASSERT1(vl.size() == 1 && dl.size() > 0 && dl.size() <= 2,
4010  "Wrong number of variables for source term brick");
4011 
4012  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4013  const mesh_im &mim = *mims[0];
4014  const model_real_plain_vector &A = md.real_variable(dl[0]);
4015  const mesh_fem *mf_data = md.pmesh_fem_of_variable(dl[0]);
4016  mesh_region rg(region);
4017  mim.linked_mesh().intersect_with_mpi_region(rg);
4018 
4019  size_type s = gmm::vect_size(A);
4020  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
4021 
4022  GMM_ASSERT1(mf_u.get_qdim() == s,
4023  dl[0] << ": bad format of source term data. "
4024  "Detected dimension is " << s << " should be "
4025  << size_type(mf_u.get_qdim()));
4026 
4027  GMM_TRACE2("Source term assembly");
4028  if (mf_data)
4029  asm_source_term(vecl[0], mim, mf_u, *mf_data, A, rg);
4030  else
4031  asm_homogeneous_source_term(vecl[0], mim, mf_u, A, rg);
4032 
4033  if (dl.size() > 1) gmm::add(md.real_variable(dl[1]), vecl[0]);
4034  }
4035 
4036  void real_post_assembly_in_serial(const model &md, size_type ib,
4037  const model::varnamelist &/* vl */,
4038  const model::varnamelist &/* dl */,
4039  const model::mimlist &/* mims */,
4040  model::real_matlist &/*matl*/,
4041  model::real_veclist &vecl,
4042  model::real_veclist &,
4043  size_type /*region*/,
4044  build_version) const override
4045  {
4046  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
4047  }
4048 
4049 
4050  void asm_complex_tangent_terms(const model &md, size_type /*ib*/,
4051  const model::varnamelist &vl,
4052  const model::varnamelist &dl,
4053  const model::mimlist &mims,
4054  model::complex_matlist &,
4055  model::complex_veclist &vecl,
4056  model::complex_veclist &,
4057  size_type region,
4058  build_version) const override {
4059  GMM_ASSERT1(vecl.size() == 1,
4060  "Source term brick has one and only one term");
4061  GMM_ASSERT1(mims.size() == 1,
4062  "Source term brick need one and only one mesh_im");
4063  GMM_ASSERT1(vl.size() == 1 && dl.size() > 0 && dl.size() <= 2,
4064  "Wrong number of variables for source term brick");
4065 
4066  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4067  const mesh_im &mim = *mims[0];
4068  const model_complex_plain_vector &A = md.complex_variable(dl[0]);
4069  const mesh_fem *mf_data = md.pmesh_fem_of_variable(dl[0]);
4070  mesh_region rg(region);
4071  mim.linked_mesh().intersect_with_mpi_region(rg);
4072 
4073  size_type s = gmm::vect_size(A);
4074  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
4075 
4076  GMM_ASSERT1(mf_u.get_qdim() == s, "Bad format of source term data");
4077 
4078  GMM_TRACE2("Source term assembly");
4079  if (mf_data)
4080  asm_source_term(vecl[0], mim, mf_u, *mf_data, A, rg);
4081  else
4082  asm_homogeneous_source_term(vecl[0], mim, mf_u, A, rg);
4083 
4084  if (dl.size() > 1) gmm::add(md.complex_variable(dl[1]), vecl[0]);
4085  }
4086 
4087  void complex_post_assembly_in_serial(const model &md,
4088  size_type ib,
4089  const model::varnamelist &,
4090  const model::varnamelist &,
4091  const model::mimlist &,
4092  model::complex_matlist &,
4093  model::complex_veclist &vecl,
4094  model::complex_veclist &,
4095  size_type, build_version) const override
4096  {
4097  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
4098  }
4099 
4100 
4101 
4102  source_term_brick() {
4103  set_flags("Source term", true /* is linear*/,
4104  true /* is symmetric */, true /* is coercive */,
4105  true /* is real */, true /* is complex */,
4106  false /* compute each time */);
4107  }
4108 
4109 
4110  };
4111 
4113  const std::string &varname,
4114  const std::string &dataexpr,
4115  size_type region,
4116  const std::string &directdataname) {
4117  if (md.is_complex()) {
4118  pbrick pbr = std::make_shared<source_term_brick>();
4119  model::termlist tl;
4120  tl.push_back(model::term_description(varname));
4121  model::varnamelist vdata(1, dataexpr);
4122  if (directdataname.size()) vdata.push_back(directdataname);
4123  return md.add_brick(pbr, model::varnamelist(1, varname),
4124  vdata, tl, model::mimlist(1, &mim), region);
4125  } else {
4126  std::string test_varname
4127  = "Test_" + sup_previous_and_dot_to_varname(varname);
4128  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
4129  size_type qdim = mf_u.get_qdim();
4130  std::string expr;
4131  if (qdim == 1)
4132  expr = "("+dataexpr+")*"+test_varname;
4133  else
4134  expr = "("+dataexpr+")."+test_varname;
4135  size_type ib = add_source_term_generic_assembly_brick
4136  (md, mim, expr, region, "Source term", varname, directdataname, true);
4137  if (ib == size_type(-1)) {
4138  ib = add_nonlinear_term(md, mim, "-("+expr+")", region, false, false,
4139  "Source term (nonlinear)");
4140  if (directdataname.size())
4141  add_source_term_generic_assembly_brick
4142  (md, mim, "", region, "Source term", varname, directdataname);
4143  }
4144  return ib;
4145  }
4146  }
4147 
4148  // ----------------------------------------------------------------------
4149  //
4150  // Normal source term brick
4151  //
4152  // ----------------------------------------------------------------------
4153 
4154  struct normal_source_term_brick : public virtual_brick {
4155 
4156  void asm_real_tangent_terms(const model &md, size_type /* ib */,
4157  const model::varnamelist &vl,
4158  const model::varnamelist &dl,
4159  const model::mimlist &mims,
4160  model::real_matlist &,
4161  model::real_veclist &vecl,
4162  model::real_veclist &,
4163  size_type region,
4164  build_version) const override {
4165  GMM_ASSERT1(vecl.size() == 1,
4166  "Source term brick has one and only one term");
4167  GMM_ASSERT1(mims.size() == 1,
4168  "Source term brick need one and only one mesh_im");
4169  GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
4170  "Wrong number of variables for source term brick");
4171 
4172  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4173  const mesh_im &mim = *mims[0];
4174  const model_real_plain_vector &A = md.real_variable(dl[0]);
4175  const mesh_fem *mf_data = md.pmesh_fem_of_variable(dl[0]);
4176  mesh_region rg(region);
4177  mim.linked_mesh().intersect_with_mpi_region(rg);
4178 
4179  size_type s = gmm::vect_size(A), N = mf_u.linked_mesh().dim();
4180  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
4181 
4182  GMM_ASSERT1(mf_u.get_qdim()*N == s,
4183  dl[0] << ": bad format of normal source term data. "
4184  "Detected dimension is " << s << " should be "
4185  << size_type(mf_u.get_qdim()*N));
4186 
4187  GMM_TRACE2("source term assembly");
4188  if (mf_data)
4189  asm_normal_source_term(vecl[0], mim, mf_u, *mf_data, A, rg);
4190  else
4191  asm_homogeneous_normal_source_term(vecl[0], mim, mf_u, A, rg);
4192  }
4193 
4194  void real_post_assembly_in_serial(const model &md, size_type ib,
4195  const model::varnamelist &/* vl */,
4196  const model::varnamelist &/* dl */,
4197  const model::mimlist &/* mims */,
4198  model::real_matlist &/*matl*/,
4199  model::real_veclist &vecl,
4200  model::real_veclist &,
4201  size_type /*region*/,
4202  build_version) const override {
4203  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
4204  }
4205 
4206 
4207  virtual void asm_complex_tangent_terms(const model &md, size_type /* ib */,
4208  const model::varnamelist &vl,
4209  const model::varnamelist &dl,
4210  const model::mimlist &mims,
4211  model::complex_matlist &,
4212  model::complex_veclist &vecl,
4213  model::complex_veclist &,
4214  size_type region,
4215  build_version) const {
4216  GMM_ASSERT1(vecl.size() == 1,
4217  "Source term brick has one and only one term");
4218  GMM_ASSERT1(mims.size() == 1,
4219  "Source term brick need one and only one mesh_im");
4220  GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
4221  "Wrong number of variables for source term brick");
4222 
4223  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4224  const mesh_im &mim = *mims[0];
4225  const model_complex_plain_vector &A = md.complex_variable(dl[0]);
4226  const mesh_fem *mf_data = md.pmesh_fem_of_variable(dl[0]);
4227  mesh_region rg(region);
4228  mim.linked_mesh().intersect_with_mpi_region(rg);
4229 
4230  size_type s = gmm::vect_size(A), N = mf_u.linked_mesh().dim();
4231  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
4232 
4233  GMM_ASSERT1(s == mf_u.get_qdim()*N, "Bad format of source term data");
4234 
4235  GMM_TRACE2("source term assembly");
4236  if (mf_data)
4237  asm_normal_source_term(vecl[0], mim, mf_u, *mf_data, A, rg);
4238  else
4239  asm_homogeneous_normal_source_term(vecl[0], mim, mf_u, A, rg);
4240  }
4241 
4242  void complex_post_assembly_in_serial(const model &md, size_type ib,
4243  const model::varnamelist &/* vl */,
4244  const model::varnamelist &/* dl */,
4245  const model::mimlist &/* mims */,
4246  model::complex_matlist &/*matl*/,
4247  model::complex_veclist &vecl,
4248  model::complex_veclist &,
4249  size_type /*region*/,
4250  build_version) const override {
4251  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
4252  }
4253 
4254  normal_source_term_brick() {
4255  set_flags("Normal source term", true /* is linear*/,
4256  true /* is symmetric */, true /* is coercive */,
4257  true /* is real */, true /* is complex */,
4258  false /* compute each time */);
4259  }
4260 
4261 
4262  };
4263 
4265  const std::string &varname,
4266  const std::string &dataexpr,
4267  size_type region) {
4268  if (md.is_complex()) {
4269  pbrick pbr = std::make_shared<normal_source_term_brick>();
4270  model::termlist tl;
4271  tl.push_back(model::term_description(varname));
4272  model::varnamelist vdata(1, dataexpr);
4273  return md.add_brick(pbr, model::varnamelist(1, varname),
4274  vdata, tl, model::mimlist(1, &mim), region);
4275  } else {
4276  std::string test_varname
4277  = "Test_" + sup_previous_and_dot_to_varname(varname);
4278  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
4279  size_type qdim = mf_u.get_qdim();
4280  std::string expr;
4281  if (qdim == 1)
4282  expr = "(("+dataexpr+").Normal)*"+test_varname;
4283  else
4284  expr = "(Reshape("+dataexpr+",qdim("+varname
4285  + "),meshdim)*Normal)."+test_varname;
4286  return add_source_term_generic_assembly_brick
4287  (md, mim, expr, region, "Source term");
4288  }
4289  }
4290 
4291 
4292  // ----------------------------------------------------------------------
4293  //
4294  // Dirichlet condition brick
4295  //
4296  // ----------------------------------------------------------------------
4297  // Two variables : with multipliers
4298  // One variable : penalization
4299 
4300  struct Dirichlet_condition_brick : public virtual_brick {
4301 
4302  bool H_version; // The version hu = r for vector fields.
4303  bool normal_component; // Dirichlet on normal component for vector field.
4304  const mesh_fem *mf_mult_;
4309 
4310  virtual void asm_real_tangent_terms(const model &md, size_type ib,
4311  const model::varnamelist &vl,
4312  const model::varnamelist &dl,
4313  const model::mimlist &mims,
4314  model::real_matlist &matl,
4315  model::real_veclist &vecl,
4316  model::real_veclist &,
4317  size_type region,
4318  build_version version) const {
4319  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
4320  "Dirichlet condition brick has one and only one term");
4321  GMM_ASSERT1(mims.size() == 1,
4322  "Dirichlet condition brick need one and only one mesh_im");
4323  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 3,
4324  "Wrong number of variables for Dirichlet condition brick");
4325 
4326  model_real_sparse_matrix& rB = rB_th;
4327  model_real_plain_vector& rV = rV_th;
4328 
4329  bool penalized = (vl.size() == 1);
4330  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4331  const mesh_fem &mf_mult = penalized ? (mf_mult_ ? *mf_mult_ : mf_u)
4332  : md.mesh_fem_of_variable(vl[1]);
4333  const mesh_im &mim = *mims[0];
4334  const model_real_plain_vector *A = 0, *COEFF = 0, *H = 0;
4335  const mesh_fem *mf_data = 0, *mf_H = 0;
4336  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
4337  || (penalized && md.is_var_newer_than_brick(dl[0], ib));
4338 
4339  if (penalized) {
4340  COEFF = &(md.real_variable(dl[0]));
4341  GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
4342  "Data for coefficient should be a scalar");
4343  }
4344 
4345  size_type s = 0, ind = (penalized ? 1 : 0);
4346  if (dl.size() > ind) {
4347  A = &(md.real_variable(dl[ind]));
4348  mf_data = md.pmesh_fem_of_variable(dl[ind]);
4349  s = gmm::vect_size(*A);
4350  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
4351  size_type ss = ((normal_component) ? 1 : mf_u.get_qdim());
4352  GMM_ASSERT1(s == ss, dl[ind] << ": bad format of "
4353  "Dirichlet data. Detected dimension is " << s
4354  << " should be " << ss);
4355  }
4356 
4357  if (dl.size() > ind + 1) {
4358  GMM_ASSERT1(H_version,
4359  "Wrong number of data for Dirichlet condition brick");
4360  H = &(md.real_variable(dl[ind+1]));
4361  mf_H = md.pmesh_fem_of_variable(dl[ind+1]);
4362  s = gmm::vect_size(*A);
4363  if (mf_H) {
4364  s = s * mf_H->get_qdim() / mf_H->nb_dof();
4365  GMM_ASSERT1(mf_H->get_qdim() == 1, "Implemented only for mf_H "
4366  "a scalar finite element method");
4367  }
4368  GMM_ASSERT1(s = gmm::sqr(mf_u.get_qdim()),
4369  dl[ind+1] << ": bad format of Dirichlet data. "
4370  "Detected dimension is " << s << " should be "
4371  << size_type(gmm::sqr(mf_u.get_qdim())));
4372  }
4373 
4374  mesh_region rg(region);
4375  mim.linked_mesh().intersect_with_mpi_region(rg);
4376 
4377  if (recompute_matrix) {
4378  model_real_sparse_matrix *B = &(matl[0]);
4379  if (penalized && (&mf_mult != &mf_u)) {
4380  gmm::resize(rB, mf_mult.nb_dof(), mf_u.nb_dof());
4381  gmm::clear(rB);
4382  B = &rB;
4383  } else {
4384  gmm::clear(matl[0]);
4385  }
4386  GMM_TRACE2("Mass term assembly for Dirichlet condition");
4387  if (H_version || normal_component) {
4388  ga_workspace workspace;
4389  gmm::sub_interval Imult(0, mf_mult.nb_dof()), Iu(0, mf_u.nb_dof());
4390  base_vector u(mf_u.nb_dof());
4391  base_vector mult(mf_mult.nb_dof());
4392  workspace.add_fem_variable("u", mf_u, Iu, u);
4393  workspace.add_fem_variable("mult", mf_mult, Imult, mult);
4394  auto expression = std::string{};
4395  if (H_version){
4396  if (mf_H) workspace.add_fem_constant("A", *mf_H, *H);
4397  else workspace.add_fixed_size_constant("A", *H);
4398  expression = (mf_u.get_qdim() == 1) ?
4399  "Test_mult . (A . Test2_u)"
4400  :
4401  "Test_mult. (Reshape(A, qdim(u), qdim(u)) . Test2_u)";
4402  } else if (normal_component) {
4403  expression = "Test_mult . (Test2_u . Normal)";
4404  }
4405  workspace.add_expression(expression, mim, rg);
4406  workspace.set_assembled_matrix(*B);
4407  workspace.assembly(2);
4408  } else {
4409  asm_mass_matrix(*B, mim, mf_mult, mf_u, rg);
4410  }
4411 
4412  if (penalized && (&mf_mult != &mf_u)) {
4413  GMM_ASSERT1(MPI_IS_MASTER(), "Sorry, the penalized option "
4414  "filtered by a multiplier space is not parallelized");
4415  gmm::mult(gmm::transposed(rB), rB, matl[0]);
4416  gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
4417  } else if (penalized) {
4418  gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
4419  }
4420  }
4421 
4422  if (dl.size() > ind) {
4423  GMM_TRACE2("Source term assembly for Dirichlet condition");
4424 
4425  if (penalized && (&mf_mult != &mf_u)) {
4426  gmm::resize(rV, mf_mult.nb_dof());
4427  gmm::clear(rV);
4428  if (mf_data)
4429  asm_source_term(rV, mim, mf_mult, *mf_data, *A, rg);
4430  else
4431  asm_homogeneous_source_term(rV, mim, mf_mult, *A, rg);
4432  } else {
4433  if (mf_data)
4434  asm_source_term(vecl[0], mim, mf_mult, *mf_data, *A, rg);
4435  else
4436  asm_homogeneous_source_term(vecl[0], mim, mf_mult, *A, rg);
4437  }
4438 
4439  if (penalized && (&mf_mult != &mf_u)) {
4440  gmm::mult(gmm::transposed(rB), rV, vecl[0]);
4441  gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
4442  rV = model_real_plain_vector();
4443  } else if (penalized)
4444  gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
4445  }
4446 
4447  }
4448 
4449  void real_post_assembly_in_serial(const model &md, size_type ib,
4450  const model::varnamelist &/* vl */,
4451  const model::varnamelist &/* dl */,
4452  const model::mimlist &/* mims */,
4453  model::real_matlist &/*matl*/,
4454  model::real_veclist &vecl,
4455  model::real_veclist &,
4456  size_type /*region*/,
4457  build_version) const override {
4458  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
4459  }
4460 
4461  virtual void asm_complex_tangent_terms(const model &md, size_type ib,
4462  const model::varnamelist &vl,
4463  const model::varnamelist &dl,
4464  const model::mimlist &mims,
4465  model::complex_matlist &matl,
4466  model::complex_veclist &vecl,
4467  model::complex_veclist &,
4468  size_type region,
4469  build_version version) const {
4470  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
4471  "Dirichlet condition brick has one and only one term");
4472  GMM_ASSERT1(mims.size() == 1,
4473  "Dirichlet condition brick need one and only one mesh_im");
4474  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 3,
4475  "Wrong number of variables for Dirichlet condition brick");
4476 
4477  model_complex_sparse_matrix& cB = cB_th;
4478  model_complex_plain_vector& cV = cV_th;
4479 
4480  bool penalized = (vl.size() == 1);
4481  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4482  const mesh_fem &mf_mult = penalized ? (mf_mult_ ? *mf_mult_ : mf_u)
4483  : md.mesh_fem_of_variable(vl[1]);
4484  const mesh_im &mim = *mims[0];
4485  const model_complex_plain_vector *A = 0, *COEFF = 0, *H = 0;
4486  const mesh_fem *mf_data = 0, *mf_H = 0;
4487  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
4488  || (penalized && md.is_var_newer_than_brick(dl[0], ib));
4489 
4490  if (penalized) {
4491  COEFF = &(md.complex_variable(dl[0]));
4492  GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
4493  "Data for coefficient should be a scalar");
4494  }
4495 
4496  size_type s = 0, ind = (penalized ? 1 : 0);
4497  if (dl.size() > ind) {
4498  A = &(md.complex_variable(dl[ind]));
4499  mf_data = md.pmesh_fem_of_variable(dl[ind]);
4500  s = gmm::vect_size(*A);
4501  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
4502  size_type ss = s * ((normal_component) ? mf_u.linked_mesh().dim() : 1);
4503  GMM_ASSERT1(mf_u.get_qdim() == ss,
4504  dl[ind] << ": bad format of Dirichlet data. "
4505  "Detected dimension is " << ss << " should be "
4506  << size_type(mf_u.get_qdim()));
4507  }
4508 
4509  if (dl.size() > ind + 1) {
4510  GMM_ASSERT1(H_version,
4511  "Wrong number of data for Dirichlet condition brick");
4512  H = &(md.complex_variable(dl[ind+1]));
4513  mf_H = md.pmesh_fem_of_variable(dl[ind+1]);
4514  s = gmm::vect_size(*A);
4515  if (mf_H) {
4516  s = s * mf_H->get_qdim() / mf_H->nb_dof();
4517  GMM_ASSERT1(mf_H->get_qdim() == 1, "Implemented only for mf_H "
4518  "a scalar finite element method");
4519  }
4520  GMM_ASSERT1(s = gmm::sqr(mf_u.get_qdim()),
4521  dl[ind+1] << ": bad format of Dirichlet data. "
4522  "Detected dimension is " << s << " should be "
4523  << size_type(gmm::sqr(mf_u.get_qdim())));
4524  }
4525 
4526  mesh_region rg(region);
4527  mim.linked_mesh().intersect_with_mpi_region(rg);
4528 
4529  if (recompute_matrix) {
4530  model_complex_sparse_matrix *B = &(matl[0]);
4531  if (penalized && (&mf_mult != &mf_u)) {
4532  gmm::resize(cB, mf_mult.nb_dof(), mf_u.nb_dof());
4533  gmm::clear(cB);
4534  B = &cB;
4535  } else {
4536  gmm::clear(matl[0]);
4537  }
4538  GMM_TRACE2("Mass term assembly for Dirichlet condition");
4539  if (H_version) {
4540  if (mf_u.get_qdim() == 1)
4541  asm_real_or_complex_1_param_mat(*B, mim, mf_mult, mf_H, *H, rg,
4542  "(A*Test_u).Test2_u");
4543  else
4544  asm_real_or_complex_1_param_mat(*B, mim, mf_mult, mf_H, *H, rg,
4545  "(Reshape(A,qdim(u),qdim(u))*Test2_u).Test_u");
4546  // if (mf_H)
4547  // asm_real_or_complex_1_param
4548  // (*B, mim, mf_mult, *mf_H, *H, rg, (mf_u.get_qdim() == 1) ?
4549  // "F=data(#2);"
4550  // "M(#1,#3)+=sym(comp(Base(#1).Base(#3).Base(#2))(:,:,i).F(i))"
4551  // : "F=data(qdim(#1),qdim(#1),#2);"
4552  // "M(#1,#3)+=sym(comp(vBase(#1).vBase(#3).Base(#2))(:,i,:,j,k).F(i,j,k));", &mf_u);
4553  // else
4554  // asm_real_or_complex_1_param
4555  // (*B, mim, mf_mult, mf_u, *H, rg, (mf_u.get_qdim() == 1) ?
4556  // "F=data(1);"
4557  // "M(#1,#2)+=sym(comp(Base(#1).Base(#2)).F(1))"
4558  // : "F=data(qdim(#1),qdim(#1));"
4559  // "M(#1,#2)+=sym(comp(vBase(#1).vBase(#2))(:,i,:,j).F(i,j));");
4560  }
4561  else if (normal_component) {
4562  ga_workspace workspace;
4563  gmm::sub_interval Imult(0, mf_mult.nb_dof()), Iu(0, mf_u.nb_dof());
4564  base_vector mult(mf_mult.nb_dof()), u(mf_u.nb_dof());
4565  workspace.add_fem_variable("mult", mf_mult, Imult, mult);
4566  workspace.add_fem_variable("u", mf_u, Iu, u);
4567  workspace.add_expression("Test_mult.(Test2_u.Normal)", mim, rg);
4568  model_real_sparse_matrix BB(mf_mult.nb_dof(), mf_u.nb_dof());
4569  workspace.set_assembled_matrix(BB);
4570  workspace.assembly(2);
4571  gmm::add(BB, *B);
4572 
4573  // generic_assembly assem;
4574  // if (mf_mult.get_qdim() == 1)
4575  // assem.set("M(#2,#1)+=comp(Base(#2).vBase(#1).Normal())(:,:,i,i);");
4576  // else
4577  // assem.set("M(#2,#1)+=comp(vBase(#2).mBase(#1).Normal())(:,i,:,i,j,j);");
4578  // assem.push_mi(mim);
4579  // assem.push_mf(mf_u);
4580  // assem.push_mf(mf_mult);
4581  // assem.push_mat(gmm::real_part(*B));
4582  // assem.assembly(rg);
4583  } else {
4584  asm_mass_matrix(*B, mim, mf_mult, mf_u, rg);
4585  }
4586  if (penalized && (&mf_mult != &mf_u)) {
4587  gmm::mult(gmm::transposed(cB), cB, matl[0]);
4588  gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
4589  } else if (penalized) {
4590  gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
4591  }
4592  }
4593 
4594  if (dl.size() > ind) {
4595  GMM_TRACE2("Source term assembly for Dirichlet condition");
4596 
4597  if (penalized && (&mf_mult != &mf_u)) {
4598  gmm::resize(cV, mf_mult.nb_dof());
4599  gmm::clear(cV);
4600  if (mf_data)
4601  asm_source_term(cV, mim, mf_mult, *mf_data, *A, rg);
4602  else
4603  asm_homogeneous_source_term(cV, mim, mf_mult, *A, rg);
4604  } else {
4605  if (mf_data)
4606  asm_source_term(vecl[0], mim, mf_mult, *mf_data, *A, rg);
4607  else
4608  asm_homogeneous_source_term(vecl[0], mim, mf_mult, *A, rg);
4609  }
4610 
4611  if (penalized && (&mf_mult != &mf_u)) {
4612  gmm::mult(gmm::transposed(cB), cV, vecl[0]);
4613  gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
4614  cV = model_complex_plain_vector();
4615  } else if (penalized)
4616  gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
4617  }
4618  }
4619 
4620  void complex_post_assembly_in_serial(const model &md, size_type ib,
4621  const model::varnamelist &/* vl */,
4622  const model::varnamelist &/* dl */,
4623  const model::mimlist &/* mims */,
4624  model::complex_matlist &/*matl*/,
4625  model::complex_veclist &vecl,
4626  model::complex_veclist &,
4627  size_type /*region*/,
4628  build_version) const override {
4629  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
4630  }
4631 
4632 
4633  virtual std::string declare_volume_assembly_string
4634  (const model &, size_type, const model::varnamelist &,
4635  const model::varnamelist &) const {
4636  return std::string();
4637  }
4638 
4639  Dirichlet_condition_brick(bool penalized, bool H_version_,
4640  bool normal_component_,
4641  const mesh_fem *mf_mult__ = 0) {
4642  mf_mult_ = mf_mult__;
4643  H_version = H_version_;
4644  normal_component = normal_component_;
4645  GMM_ASSERT1(!(H_version && normal_component), "Bad Dirichlet version");
4646  set_flags(penalized ? "Dirichlet with penalization brick"
4647  : "Dirichlet with multipliers brick",
4648  true /* is linear*/,
4649  true /* is symmetric */, penalized /* is coercive */,
4650  true /* is real */, true /* is complex */,
4651  false /* compute each time */);
4652  }
4653  };
4654 
4656  (model &md, const mesh_im &mim, const std::string &varname,
4657  const std::string &multname, size_type region,
4658  const std::string &dataname) {
4659  pbrick pbr = std::make_shared<Dirichlet_condition_brick>(false,false,false);
4660  model::termlist tl;
4661  tl.push_back(model::term_description(multname, varname, true));
4662  model::varnamelist vl(1, varname);
4663  vl.push_back(multname);
4664  model::varnamelist dl;
4665  if (dataname.size()) dl.push_back(dataname);
4666  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
4667  }
4668 
4670  (model &md, const mesh_im &mim, const std::string &varname,
4671  const mesh_fem &mf_mult, size_type region,
4672  const std::string &dataname) {
4673  std::string multname = md.new_name("mult_on_" + varname);
4674  md.add_multiplier(multname, mf_mult, varname);
4676  (md, mim, varname, multname, region, dataname);
4677  }
4678 
4680  (model &md, const mesh_im &mim, const std::string &varname,
4681  dim_type degree, size_type region,
4682  const std::string &dataname) {
4683  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
4684  const mesh_fem &mf_mult = classical_mesh_fem(mf_u.linked_mesh(),
4685  degree, mf_u.get_qdim());
4687  (md, mim, varname, mf_mult, region, dataname);
4688  }
4689 
4690  const std::string &mult_varname_Dirichlet(model &md, size_type ind_brick) {
4691  return md.varname_of_brick(ind_brick, 1);
4692  }
4693 
4695  (model &md, const mesh_im &mim, const std::string &varname,
4696  scalar_type penalisation_coeff, size_type region,
4697  const std::string &dataname, const mesh_fem *mf_mult) {
4698  std::string coeffname = md.new_name("penalization_on_" + varname);
4699  md.add_fixed_size_data(coeffname, 1);
4700  if (md.is_complex())
4701  md.set_complex_variable(coeffname)[0] = penalisation_coeff;
4702  else
4703  md.set_real_variable(coeffname)[0] = penalisation_coeff;
4704  pbrick pbr = std::make_shared<Dirichlet_condition_brick>
4705  (true, false, false, mf_mult);
4706  model::termlist tl;
4707  tl.push_back(model::term_description(varname, varname, true));
4708  model::varnamelist vl(1, varname);
4709  model::varnamelist dl(1, coeffname);
4710  if (dataname.size()) dl.push_back(dataname);
4711  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
4712  }
4713 
4715  (model &md, const mesh_im &mim, const std::string &varname,
4716  const std::string &multname, size_type region,
4717  const std::string &dataname) {
4718  pbrick pbr = std::make_shared<Dirichlet_condition_brick>(false,false,true);
4719  model::termlist tl;
4720  tl.push_back(model::term_description(multname, varname, true));
4721  model::varnamelist vl(1, varname);
4722  vl.push_back(multname);
4723  model::varnamelist dl;
4724  if (dataname.size()) dl.push_back(dataname);
4725  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
4726  }
4727 
4729  (model &md, const mesh_im &mim, const std::string &varname,
4730  const mesh_fem &mf_mult, size_type region,
4731  const std::string &dataname) {
4732  std::string multname = md.new_name("mult_on_" + varname);
4733  md.add_multiplier(multname, mf_mult, varname);
4735  (md, mim, varname, multname, region, dataname);
4736  }
4737 
4739  (model &md, const mesh_im &mim, const std::string &varname,
4740  dim_type degree, size_type region,
4741  const std::string &dataname) {
4742  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
4743  const mesh_fem &mf_mult = classical_mesh_fem(mf_u.linked_mesh(),degree, 1);
4745  (md, mim, varname, mf_mult, region, dataname);
4746  }
4747 
4749  (model &md, const mesh_im &mim, const std::string &varname,
4750  scalar_type penalisation_coeff, size_type region,
4751  const std::string &dataname, const mesh_fem *mf_mult) {
4752  std::string coeffname = md.new_name("penalization_on_" + varname);
4753  md.add_fixed_size_data(coeffname, 1);
4754  if (md.is_complex())
4755  md.set_complex_variable(coeffname)[0] = penalisation_coeff;
4756  else
4757  md.set_real_variable(coeffname)[0] = penalisation_coeff;
4758  pbrick pbr = std::make_shared<Dirichlet_condition_brick>
4759  (true, false, true, mf_mult);
4760  model::termlist tl;
4761  tl.push_back(model::term_description(varname, varname, true));
4762  model::varnamelist vl(1, varname);
4763  model::varnamelist dl(1, coeffname);
4764  if (dataname.size()) dl.push_back(dataname);
4765  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
4766  }
4767 
4768 
4770  (model &md, const mesh_im &mim, const std::string &varname,
4771  const std::string &multname, size_type region,
4772  const std::string &dataname, const std::string &Hname) {
4773  pbrick pbr = std::make_shared<Dirichlet_condition_brick>(false,true,false);
4774  model::termlist tl;
4775  tl.push_back(model::term_description(multname, varname, true));
4776  model::varnamelist vl(1, varname);
4777  vl.push_back(multname);
4778  model::varnamelist dl;
4779  dl.push_back(dataname);
4780  dl.push_back(Hname);
4781  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
4782  }
4783 
4785  (model &md, const mesh_im &mim, const std::string &varname,
4786  const mesh_fem &mf_mult, size_type region,
4787  const std::string &dataname, const std::string &Hname) {
4788  std::string multname = md.new_name("mult_on_" + varname);
4789  md.add_multiplier(multname, mf_mult, varname);
4791  (md, mim, varname, multname, region, dataname, Hname);
4792  }
4793 
4795  (model &md, const mesh_im &mim, const std::string &varname,
4796  dim_type degree, size_type region,
4797  const std::string &dataname, const std::string &Hname) {
4798  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
4799  const mesh_fem &mf_mult = classical_mesh_fem(mf_u.linked_mesh(),
4800  degree, mf_u.get_qdim());
4802  (md, mim, varname, mf_mult, region, dataname, Hname);
4803  }
4804 
4806  (model &md, const mesh_im &mim, const std::string &varname,
4807  scalar_type penalisation_coeff, size_type region,
4808  const std::string &dataname, const std::string &Hname,
4809  const mesh_fem *mf_mult) {
4810  std::string coeffname = md.new_name("penalization_on_" + varname);
4811  md.add_fixed_size_data(coeffname, 1);
4812  if (md.is_complex())
4813  md.set_complex_variable(coeffname)[0] = penalisation_coeff;
4814  else
4815  md.set_real_variable(coeffname)[0] = penalisation_coeff;
4816  pbrick pbr = std::make_shared<Dirichlet_condition_brick>
4817  (true, true, false, mf_mult);
4818  model::termlist tl;
4819  tl.push_back(model::term_description(varname, varname, true));
4820  model::varnamelist vl(1, varname);
4821  model::varnamelist dl(1, coeffname);
4822  dl.push_back(dataname);
4823  dl.push_back(Hname);
4824  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
4825  }
4826 
4828  scalar_type penalisation_coeff) {
4829  const std::string &coeffname = md.dataname_of_brick(ind_brick, 0);
4830  if (!md.is_complex()) {
4831  model_real_plain_vector &d = md.set_real_variable(coeffname);
4832  GMM_ASSERT1(gmm::vect_size(d)==1,
4833  "Wrong coefficient size, may be not a Dirichlet brick "
4834  "with penalization");
4835  d[0] = penalisation_coeff;
4836  }
4837  else {
4838  model_complex_plain_vector &d = md.set_complex_variable(coeffname);
4839  GMM_ASSERT1(gmm::vect_size(d)==1,
4840  "Wrong coefficient size, may be not a Dirichlet brick "
4841  "with penalization");
4842  d[0] = penalisation_coeff;
4843  }
4844  }
4845 
4846  // ----------------------------------------------------------------------
4847  //
4848  // Dirichlet condition brick with simplification
4849  //
4850  // ----------------------------------------------------------------------
4851 
4852  struct simplification_Dirichlet_condition_brick : public virtual_brick {
4853 
4854  virtual void asm_real_tangent_terms(const model &md, size_type /*ib*/,
4855  const model::varnamelist &vl,
4856  const model::varnamelist &dl,
4857  const model::mimlist &mims,
4858  model::real_matlist &matl,
4859  model::real_veclist &vecl,
4860  model::real_veclist &,
4861  size_type region,
4862  build_version /*version*/) const {
4863  if (MPI_IS_MASTER()) {
4864 
4865  GMM_ASSERT1(vecl.size() == 0 && matl.size() == 0,
4866  "Dirichlet condition brick by simplification has no term");
4867  GMM_ASSERT1(mims.size() == 0,
4868  "Dirichlet condition brick by simplification need no "
4869  "mesh_im");
4870  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
4871  "Wrong number of variables for Dirichlet condition brick "
4872  "by simplification");
4873 
4874  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4875  const model_real_plain_vector *A = 0;
4876  const mesh_fem *mf_data = 0;
4877  size_type s = 0;
4878 
4879  if (dl.size() == 1) {
4880  A = &(md.real_variable(dl[0]));
4881  mf_data = md.pmesh_fem_of_variable(dl[0]);
4882 
4883  if (mf_data) {
4884  GMM_ASSERT1(mf_data == &mf_u, "Sorry, for this brick, the data has"
4885  " to be defined on the same f.e.m. as the unknown");
4886  } else {
4887  s = gmm::vect_size(*A);
4888  GMM_ASSERT1(mf_u.get_qdim() == s, ": bad format of "
4889  "Dirichlet data. Detected dimension is " << s
4890  << " should be " << size_type(mf_u.get_qdim()));
4891  }
4892  }
4893 
4894  mesh_region rg(region);
4895  // mf_u.linked_mesh().intersect_with_mpi_region(rg); // Not distributed
4896 
4897  if (mf_u.get_qdim() > 1 || (!mf_data && A)) {
4898  for (mr_visitor i(rg, mf_u.linked_mesh()); !i.finished(); ++i) {
4899  pfem pf = mf_u.fem_of_element(i.cv());
4900  if (pf) {
4901  GMM_ASSERT1(pf->target_dim() == 1,
4902  "Intrinsically vectorial fems are not allowed");
4903  GMM_ASSERT1(mf_data || pf->is_lagrange(), "Constant Dirichlet "
4904  "data allowed for lagrange fems only");
4905  }
4906  }
4907  }
4908 
4909  dal::bit_vector dofs = mf_u.dof_on_region(rg);
4910 
4911  if (A && !mf_data) {
4912  GMM_ASSERT1(dofs.card() % s == 0, "Problem with dof vectorization");
4913  }
4914 
4915  for (dal::bv_visitor i(dofs); !i.finished(); ++i) {
4916  scalar_type val(0);
4917  if (A) val = (mf_data ? (*A)[i] : (*A)[i%s]);
4918  md.add_real_dof_constraint(vl[0], i, val);
4919  }
4920  }
4921  }
4922 
4923  virtual void asm_complex_tangent_terms(const model &md, size_type /*ib*/,
4924  const model::varnamelist &vl,
4925  const model::varnamelist &dl,
4926  const model::mimlist &mims,
4927  model::complex_matlist &matl,
4928  model::complex_veclist &vecl,
4929  model::complex_veclist &,
4930  size_type region,
4931  build_version /*version*/) const {
4932  if (MPI_IS_MASTER()) {
4933  GMM_ASSERT1(vecl.size() == 0 && matl.size() == 0,
4934  "Dirichlet condition brick by simplification has no term");
4935  GMM_ASSERT1(mims.size() == 0,
4936  "Dirichlet condition brick by simplification need no "
4937  "mesh_im");
4938  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
4939  "Wrong number of variables for Dirichlet condition brick "
4940  "by simplification");
4941 
4942  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
4943  const model_complex_plain_vector *A = 0;
4944  const mesh_fem *mf_data = 0;
4945  size_type s = 0;
4946 
4947  if (dl.size() == 1) {
4948  A = &(md.complex_variable(dl[0]));
4949  mf_data = md.pmesh_fem_of_variable(dl[0]);
4950 
4951  if (mf_data) {
4952  GMM_ASSERT1(mf_data == &mf_u, "Sorry, for this brick, the data has"
4953  " to be define on the same f.e.m. than the unknown");
4954  } else {
4955  s = gmm::vect_size(*A);
4956  GMM_ASSERT1(mf_u.get_qdim() == s, ": bad format of "
4957  "Dirichlet data. Detected dimension is " << s
4958  << " should be " << size_type(mf_u.get_qdim()));
4959  }
4960  }
4961 
4962  mesh_region rg(region);
4963  // mf_u.linked_mesh().intersect_with_mpi_region(rg); // Not distributed
4964 
4965  if (mf_u.get_qdim() > 1 || (!mf_data && A)) {
4966  for (mr_visitor i(rg, mf_u.linked_mesh()); !i.finished(); ++i) {
4967  pfem pf = mf_u.fem_of_element(i.cv());
4968  if (pf) {
4969  GMM_ASSERT1(pf->target_dim() == 1,
4970  "Intrinsically vectorial fems are not allowed");
4971  GMM_ASSERT1(mf_data || pf->is_lagrange(), "Constant Dirichlet "
4972  "data allowed for lagrange fems only");
4973  }
4974  }
4975  }
4976 
4977  dal::bit_vector dofs = mf_u.dof_on_region(rg);
4978 
4979  if (A && !mf_data) {
4980  GMM_ASSERT1(dofs.card() % s == 0, "Problem with dof vectorization");
4981  }
4982 
4983  for (dal::bv_visitor i(dofs); !i.finished(); ++i) {
4984  complex_type val(0);
4985  if (A) val = (mf_data ? (*A)[i] : (*A)[i%s]);
4986  md.add_complex_dof_constraint(vl[0], i, val);
4987  }
4988  }
4989  }
4990 
4991 
4992  virtual std::string declare_volume_assembly_string
4993  (const model &, size_type, const model::varnamelist &,
4994  const model::varnamelist &) const {
4995  return std::string();
4996  }
4997 
4998  simplification_Dirichlet_condition_brick() {
4999  set_flags("Dirichlet with simplification brick",
5000  true /* is linear*/,
5001  true /* is symmetric */, true /* is coercive */,
5002  true /* is real */, true /* is complex */,
5003  true /* compute each time */);
5004  }
5005  };
5006 
5008  (model &md, const std::string &varname,
5009  size_type region, const std::string &dataname) {
5010  pbrick pbr = std::make_shared<simplification_Dirichlet_condition_brick>();
5011  model::termlist tl;
5012  model::varnamelist vl(1, varname);
5013  model::varnamelist dl;
5014  if (dataname.size()) dl.push_back(dataname);
5015  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), region);
5016  }
5017 
5018  // ----------------------------------------------------------------------
5019  //
5020  // Dirichlet condition brick with Nitsche's method
5021  //
5022  // ----------------------------------------------------------------------
5023 
5025  (model &md, const mesh_im &mim, const std::string &varname,
5026  const std::string &Neumannterm,
5027  const std::string &datagamma0, size_type region, scalar_type theta_,
5028  const std::string &datag) {
5029  std::string theta = std::to_string(theta_);
5030  // reenables disabled variables
5031  ga_workspace workspace(md, ga_workspace::inherit::ALL);
5032  size_type order = workspace.add_expression(Neumannterm, mim, region, 1);
5033  GMM_ASSERT1(order == 0, "Wrong expression of the Neumann term");
5034  bool is_lin = workspace.is_linear(1);
5035 
5036  std::string condition = "("+varname + (datag.size() ? "-("+datag+"))":")");
5037  std::string gamma = "(("+datagamma0+")*element_size)";
5038  std::string r = "(1/"+gamma+")";
5039  std::string expr = "("+r+"*"+condition+"-("+Neumannterm+")).Test_"+varname;
5040  if (theta_ != scalar_type(0)) {
5041  std::string derivative_Neumann = workspace.extract_order1_term(varname);
5042  if (derivative_Neumann.size())
5043  expr+="-"+theta+"*"+condition+".("+derivative_Neumann+")";
5044  }
5045 
5046  // cout << "Nitsche expression : " << expr << endl;
5047  // cout << "is_lin : " << int(is_lin) << endl;
5048 
5049  if (is_lin) {
5050  return add_linear_term(md, mim, expr, region, false, false,
5051  "Dirichlet condition with Nitsche's method");
5052  } else {
5053  return add_nonlinear_term(md, mim, expr, region, false, false,
5054  "Dirichlet condition with Nitsche's method");
5055  }
5056  }
5057 
5059  (model &md, const mesh_im &mim, const std::string &varname,
5060  const std::string &Neumannterm,
5061  const std::string &datagamma0, size_type region, scalar_type theta_,
5062  const std::string &datag) {
5063  std::string theta = std::to_string(theta_);
5064  // reenables disabled variables
5065  ga_workspace workspace(md, ga_workspace::inherit::ALL);
5066  size_type order = workspace.add_expression(Neumannterm, mim, region, 1);
5067  GMM_ASSERT1(order == 0, "Wrong expression of the Neumann term");
5068  bool is_lin = workspace.is_linear(1);
5069 
5070  std::string condition = "("+varname+".Normal"
5071  + (datag.size() ? "-("+datag+"))":")");
5072  std::string gamma = "(("+datagamma0+")*element_size)";
5073  std::string r = "(1/"+gamma+")";
5074  std::string expr = "("+r+"*"+condition+"-Normal.("+Neumannterm
5075  +"))*(Normal.Test_"+varname+")";
5076  if (theta_ != scalar_type(0)) {
5077  std::string derivative_Neumann = workspace.extract_order1_term(varname);
5078  if (derivative_Neumann.size())
5079  expr+="-"+theta+"*"+condition+"*Normal.("
5080  +derivative_Neumann+")";
5081  }
5082  if (is_lin) {
5083  return add_linear_term(md, mim, expr, region, false, false,
5084  "Dirichlet condition with Nitsche's method");
5085  } else {
5086  return add_nonlinear_term(md, mim, expr, region, false, false,
5087  "Dirichlet condition with Nitsche's method");
5088  }
5089  }
5090 
5092  (model &md, const mesh_im &mim, const std::string &varname,
5093  const std::string &Neumannterm,
5094  const std::string &datagamma0, size_type region, scalar_type theta_,
5095  const std::string &datag, const std::string &dataH) {
5096  std::string theta = std::to_string(theta_);
5097  // reenables disabled variables
5098  ga_workspace workspace(md, ga_workspace::inherit::ALL);
5099  size_type order = workspace.add_expression(Neumannterm, mim, region, 1);
5100  GMM_ASSERT1(order == 0, "Wrong expression of the Neumann term");
5101  bool is_lin = workspace.is_linear(1);
5102 
5103  std::string condition = "(("+dataH+")*"+varname
5104  + (datag.size() ? "-("+datag+"))":")");
5105  std::string gamma = "(("+datagamma0+")*element_size)";
5106  std::string r = "(1/"+gamma+")";
5107  std::string expr = "("+r+"*"+condition+"-("+dataH+")*("+Neumannterm
5108  +"))*(("+dataH+")*Test_"+varname+")";
5109  if (theta_ != scalar_type(0)) {
5110  std::string derivative_Neumann = workspace.extract_order1_term(varname);
5111  if (derivative_Neumann.size())
5112  expr+="-"+theta+"*"+condition+"*(("+dataH+")*("
5113  +derivative_Neumann+"))";
5114  }
5115  if (is_lin) {
5116  return add_linear_term(md, mim, expr, region, false, false,
5117  "Dirichlet condition with Nitsche's method");
5118  } else {
5119  return add_nonlinear_term(md, mim, expr, region, false, false,
5120  "Dirichlet condition with Nitsche's method");
5121  }
5122  }
5123 
5124  // ----------------------------------------------------------------------
5125  //
5126  // Pointwise constraints brick
5127  //
5128  // ----------------------------------------------------------------------
5129  // Two variables : with multipliers
5130  // One variable : penalization
5131 
5132  struct pointwise_constraints_brick : public virtual_brick {
5133 
5134  mutable gmm::row_matrix<model_real_sparse_vector> rB;
5135  mutable gmm::row_matrix<model_complex_sparse_vector> cB;
5136 
5137  virtual void real_pre_assembly_in_serial(const model &md, size_type ib,
5138  const model::varnamelist &vl,
5139  const model::varnamelist &dl,
5140  const model::mimlist &mims,
5141  model::real_matlist &matl,
5142  model::real_veclist &vecl,
5143  model::real_veclist &/*rvecl*/,
5144  size_type,
5145  build_version version) const {
5146  if (MPI_IS_MASTER()) {
5147 
5148  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5149  "Pointwize constraints brick has only one term");
5150  GMM_ASSERT1(mims.size() == 0,
5151  "Pointwize constraints brick does not need a mesh_im");
5152  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2,
5153  "Wrong number of variables for pointwize constraints brick");
5154  bool penalized = (vl.size() == 1);
5155  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
5156  dim_type N = mf_u.linked_mesh().dim(), Q = mf_u.get_qdim(), ind_pt = 0;
5157  size_type dlsize = size_type((penalized ? 1 : 0) + 1 + (Q > 1 ? 1 : 0));
5158  GMM_ASSERT1(dl.size() == dlsize || dl.size() == dlsize+1,
5159  "Wrong number of data for pointwize constraints brick");
5160 
5161 
5162  const model_real_plain_vector *COEFF = 0;
5163  if (penalized) {
5164  COEFF = &(md.real_variable(dl[0]));
5165  ind_pt = 1;
5166  GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
5167  "Data for coefficient should be a scalar");
5168  }
5169 
5170  const model_real_plain_vector &PT = md.real_variable(dl[ind_pt]);
5171  size_type nb_co = gmm::vect_size(PT) / N;
5172 
5173  dim_type ind_unitv = dim_type((Q > 1) ? ind_pt+1 : 0);
5174  const model_real_plain_vector &unitv =md.real_variable(dl[ind_unitv]);
5175  GMM_ASSERT1((!ind_unitv || gmm::vect_size(unitv) == nb_co * Q),
5176  "Wrong size for vector of unit vectors");
5177 
5178  dim_type ind_rhs = dim_type((Q > 1) ? ind_pt+2 : ind_pt+1);
5179  if (dl.size() < size_type(ind_rhs + 1)) ind_rhs = 0;
5180  const model_real_plain_vector &rhs = md.real_variable(dl[ind_rhs]);
5181  GMM_ASSERT1((!ind_rhs || gmm::vect_size(rhs) == nb_co),
5182  "Wrong size for vector of rhs");
5183 
5184  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
5185  || (penalized && (md.is_var_newer_than_brick(dl[ind_pt], ib)
5186  || md.is_var_newer_than_brick(dl[ind_unitv], ib)
5187  || md.is_var_newer_than_brick(dl[ind_rhs], ib)));
5188 
5189  if (recompute_matrix) {
5190  gmm::row_matrix<model_real_sparse_vector> BB(nb_co*Q, mf_u.nb_dof());
5191  gmm::clear(rB); gmm::resize(rB, nb_co, mf_u.nb_dof());
5192 
5193  dal::bit_vector dof_untouched;
5194  getfem::mesh_trans_inv mti(mf_u.linked_mesh());
5195  base_node pt(N);
5196  for (size_type i = 0; i < nb_co; ++i) {
5197  gmm::copy(gmm::sub_vector(PT, gmm::sub_interval(i*N, N)), pt);
5198  mti.add_point(pt);
5199  }
5200  gmm::row_matrix<model_real_sparse_vector> &BBB = ((Q > 1) ? BB : rB);
5201  model_real_plain_vector vv;
5202  interpolation(mf_u, mti, vv, vv, BBB, 1, 1, &dof_untouched);
5203  GMM_ASSERT1(dof_untouched.card() == 0,
5204  "Pointwize constraints : some of the points are outside "
5205  "the mesh: " << dof_untouched);
5206 
5207  if (Q > 1) {
5208  for (size_type i = 0; i < nb_co; ++i)
5209  for (size_type q = 0; q < Q; ++q)
5210  gmm::add(gmm::scaled(gmm::mat_row(BB, i*Q+q), unitv[i*Q+q]),
5211  gmm::mat_row(rB, i));
5212  }
5213  if (penalized) {
5214  gmm::mult(gmm::transposed(rB), rB, matl[0]);
5215  gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
5216  } else
5217  gmm::copy(rB, matl[0]);
5218  }
5219 
5220  if (ind_rhs) {
5221  if (penalized) {
5222  gmm::mult(gmm::transposed(rB), rhs, vecl[0]);
5223  gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
5224  }
5225  else gmm::copy(rhs, vecl[0]);
5226  }
5227  else gmm::clear(vecl[0]);
5228  }
5229  }
5230 
5231  virtual void complex_pre_assembly_in_serial(const model &md, size_type ib,
5232  const model::varnamelist &vl,
5233  const model::varnamelist &dl,
5234  const model::mimlist &mims,
5235  model::complex_matlist &matl,
5236  model::complex_veclist &vecl,
5237  model::complex_veclist &,
5238  size_type,
5239  build_version version) const {
5240  if (MPI_IS_MASTER()) {
5241  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5242  "Pointwize constraints brick only one term");
5243  GMM_ASSERT1(mims.size() == 0,
5244  "Pointwize constraints brick does not need a mesh_im");
5245  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2,
5246  "Wrong number of variables for pointwize constraints brick");
5247  bool penalized = (vl.size() == 1);
5248  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
5249  dim_type N = mf_u.linked_mesh().dim(), Q = mf_u.get_qdim(), ind_pt = 0;
5250  size_type dlsize = size_type((penalized ? 1 : 0) + 1 + (Q > 1 ? 1 :0));
5251  GMM_ASSERT1(dl.size() == dlsize || dl.size() == dlsize+1,
5252  "Wrong number of data for pointwize constraints brick");
5253 
5254 
5255  const model_complex_plain_vector *COEFF = 0;
5256  if (penalized) {
5257  COEFF = &(md.complex_variable(dl[0]));
5258  ind_pt = 1;
5259  GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
5260  "Data for coefficient should be a scalar");
5261  }
5262 
5263  const model_complex_plain_vector &PT = md.complex_variable(dl[ind_pt]);
5264  size_type nb_co = gmm::vect_size(PT) / N;
5265 
5266  dim_type ind_unitv = dim_type((Q > 1) ? ind_pt+1 : 0);
5267  const model_complex_plain_vector &unitv
5268  = md.complex_variable(dl[ind_unitv]);
5269  GMM_ASSERT1((!ind_unitv || gmm::vect_size(unitv) == nb_co * Q),
5270  "Wrong size for vector of unit vectors");
5271 
5272  dim_type ind_rhs = dim_type((Q > 1) ? ind_pt+2 : ind_pt+1);
5273  if (dl.size() < size_type(ind_rhs + 1)) ind_rhs = 0;
5274  const model_complex_plain_vector &rhs
5275  = md.complex_variable(dl[ind_rhs]);
5276  GMM_ASSERT1((!ind_rhs || gmm::vect_size(rhs) == nb_co),
5277  "Wrong size for vector of rhs");
5278 
5279  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
5280  || (penalized && (md.is_var_newer_than_brick(dl[ind_pt], ib)
5281  || md.is_var_newer_than_brick(dl[ind_unitv], ib)
5282  || md.is_var_newer_than_brick(dl[ind_rhs], ib)));
5283 
5284  if (recompute_matrix) {
5285  gmm::row_matrix<model_complex_sparse_vector>
5286  BB(nb_co*Q,mf_u.nb_dof());
5287  gmm::clear(cB); gmm::resize(cB, nb_co, mf_u.nb_dof());
5288  dal::bit_vector dof_untouched;
5289  getfem::mesh_trans_inv mti(mf_u.linked_mesh());
5290  base_node pt(N);
5291  for (size_type i = 0; i < nb_co; ++i) {
5292  gmm::copy(gmm::real_part
5293  (gmm::sub_vector(PT, gmm::sub_interval(i*N, N))), pt);
5294  mti.add_point(pt);
5295  }
5296  gmm::row_matrix<model_complex_sparse_vector> &BBB = ((Q > 1) ? BB :cB);
5297  model_complex_plain_vector vv;
5298  interpolation(mf_u, mti, vv, vv, BBB, 1, 1, &dof_untouched);
5299  GMM_ASSERT1(dof_untouched.card() == 0,
5300  "Pointwize constraints : some of the points are outside "
5301  "the mesh: " << dof_untouched);
5302 
5303  if (Q > 1) {
5304  for (size_type i = 0; i < nb_co; ++i)
5305  for (size_type q = 0; q < Q; ++q)
5306  gmm::add(gmm::scaled(gmm::mat_row(BB, i*Q+q), unitv[i*Q+q]),
5307  gmm::mat_row(cB, i));
5308  }
5309 
5310  if (penalized) {
5311  gmm::mult(gmm::transposed(cB), cB, matl[0]);
5312  gmm::scale(matl[0], gmm::abs((*COEFF)[0]));
5313  } else
5314  gmm::copy(cB, matl[0]);
5315  }
5316 
5317 
5318  if (ind_rhs) {
5319  if (penalized) {
5320  gmm::mult(gmm::transposed(cB), rhs, vecl[0]);
5321  gmm::scale(vecl[0], gmm::abs((*COEFF)[0]));
5322  }
5323  else gmm::copy(rhs, vecl[0]);
5324  }
5325  else gmm::clear(vecl[0]);
5326  }
5327  }
5328 
5329  virtual std::string declare_volume_assembly_string
5330  (const model &, size_type, const model::varnamelist &,
5331  const model::varnamelist &) const {
5332  return std::string();
5333  }
5334 
5335  pointwise_constraints_brick(bool penalized) {
5336  set_flags(penalized ? "Pointwise cosntraints with penalization brick"
5337  : "Pointwise cosntraints with multipliers brick",
5338  true /* is linear*/,
5339  true /* is symmetric */, penalized /* is coercive */,
5340  true /* is real */, true /* is complex */,
5341  false /* compute each time */);
5342  }
5343  };
5344 
5345 
5347  (model &md, const std::string &varname,
5348  scalar_type penalisation_coeff, const std::string &dataname_pt,
5349  const std::string &dataname_unitv, const std::string &dataname_val) {
5350  std::string coeffname = md.new_name("penalization_on_" + varname);
5351  md.add_fixed_size_data(coeffname, 1);
5352  if (md.is_complex())
5353  md.set_complex_variable(coeffname)[0] = penalisation_coeff;
5354  else
5355  md.set_real_variable(coeffname)[0] = penalisation_coeff;
5356  pbrick pbr = std::make_shared<pointwise_constraints_brick>(true);
5357  model::termlist tl;
5358  tl.push_back(model::term_description(varname, varname, true));
5359  model::varnamelist vl(1, varname);
5360  model::varnamelist dl(1, coeffname);
5361  dl.push_back(dataname_pt);
5362  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
5363  if (mf_u.get_qdim() > 1) dl.push_back(dataname_unitv);
5364  if (dataname_val.size() > 0) dl.push_back(dataname_val);
5365  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), size_type(-1));
5366  }
5367 
5369  (model &md, const std::string &varname,
5370  const std::string &multname, const std::string &dataname_pt,
5371  const std::string &dataname_unitv, const std::string &dataname_val) {
5372  pbrick pbr = std::make_shared<pointwise_constraints_brick>(false);
5373  model::termlist tl;
5374  tl.push_back(model::term_description(multname, varname, true));
5375  model::varnamelist vl(1, varname);
5376  vl.push_back(multname);
5377  model::varnamelist dl(1, dataname_pt);
5378  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
5379  if (mf_u.get_qdim() > 1) dl.push_back(dataname_unitv);
5380  if (dataname_val.size() > 0) dl.push_back(dataname_val);
5381  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), size_type(-1));
5382  }
5383 
5385  (model &md, const std::string &varname, const std::string &dataname_pt,
5386  const std::string &dataname_unitv, const std::string &dataname_val) {
5387  std::string multname = md.new_name("mult_on_" + varname);
5388  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
5389  size_type nb_co =
5390  ((md.is_complex()) ? gmm::vect_size(md.complex_variable(dataname_pt))
5391  : gmm::vect_size(md.real_variable(dataname_pt)))
5392  / mf_u.linked_mesh().dim();
5393  md.add_fixed_size_variable(multname, nb_co);
5395  (md, varname, multname, dataname_pt, dataname_unitv, dataname_val);
5396  }
5397 
5398 
5399  // ----------------------------------------------------------------------
5400  //
5401  // Helmholtz brick
5402  //
5403  // ----------------------------------------------------------------------
5404 
5405  struct Helmholtz_brick : public virtual_brick {
5406 
5407  virtual void asm_real_tangent_terms(const model &md, size_type,
5408  const model::varnamelist &vl,
5409  const model::varnamelist &dl,
5410  const model::mimlist &mims,
5411  model::real_matlist &matl,
5412  model::real_veclist &,
5413  model::real_veclist &,
5414  size_type region,
5415  build_version) const {
5416  GMM_ASSERT1(matl.size() == 1,
5417  "Helmholtz brick has one and only one term");
5418  GMM_ASSERT1(mims.size() == 1,
5419  "Helmholtz brick need one and only one mesh_im");
5420  GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
5421  "Wrong number of variables for Helmholtz brick");
5422 
5423  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
5424  const mesh &m = mf_u.linked_mesh();
5425  size_type Q = mf_u.get_qdim(), s = 1;
5426  GMM_ASSERT1(Q == 1, "Helmholtz brick is only for scalar field, sorry.");
5427  const mesh_im &mim = *mims[0];
5428  const mesh_fem *mf_a = 0;
5429  mesh_region rg(region);
5430  m.intersect_with_mpi_region(rg);
5431  const model_real_plain_vector *A = &(md.real_variable(dl[0]));
5432  mf_a = md.pmesh_fem_of_variable(dl[0]);
5433  s = gmm::vect_size(*A);
5434  if (mf_a) s = s * mf_a->get_qdim() / mf_a->nb_dof();
5435 
5436  if (s == 1) {
5437  GMM_TRACE2("Stiffness matrix assembly for Helmholtz problem");
5438  gmm::clear(matl[0]);
5439  model_real_plain_vector A2(gmm::vect_size(*A));
5440  for (size_type i=0; i < gmm::vect_size(*A); ++i) // Not valid for
5441  A2[i] = gmm::sqr((*A)[i]); // non lagrangian fem ...
5442  if (mf_a)
5443  asm_Helmholtz(matl[0], mim, mf_u, *mf_a, A2, rg);
5444  else
5445  asm_homogeneous_Helmholtz(matl[0], mim, mf_u, A2, rg);
5446  } else
5447  GMM_ASSERT1(false, "Bad format Helmholtz brick coefficient");
5448  }
5449 
5450  virtual void asm_complex_tangent_terms(const model &md, size_type,
5451  const model::varnamelist &vl,
5452  const model::varnamelist &dl,
5453  const model::mimlist &mims,
5454  model::complex_matlist &matl,
5455  model::complex_veclist &,
5456  model::complex_veclist &,
5457  size_type region,
5458  build_version) const {
5459  GMM_ASSERT1(matl.size() == 1,
5460  "Helmholtz brick has one and only one term");
5461  GMM_ASSERT1(mims.size() == 1,
5462  "Helmholtz brick need one and only one mesh_im");
5463  GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
5464  "Wrong number of variables for Helmholtz brick");
5465 
5466  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
5467  const mesh &m = mf_u.linked_mesh();
5468  size_type Q = mf_u.get_qdim(), s = 1;
5469  GMM_ASSERT1(Q == 1, "Helmholtz brick is only for scalar field, sorry.");
5470  const mesh_im &mim = *mims[0];
5471  const mesh_fem *mf_a = 0;
5472  mesh_region rg(region);
5473  m.intersect_with_mpi_region(rg);
5474  const model_complex_plain_vector *A = &(md.complex_variable(dl[0]));
5475  mf_a = md.pmesh_fem_of_variable(dl[0]);
5476  s = gmm::vect_size(*A);
5477  if (mf_a) s = s * mf_a->get_qdim() / mf_a->nb_dof();
5478 
5479  if (s == 1) {
5480  GMM_TRACE2("Stiffness matrix assembly for Helmholtz problem");
5481  gmm::clear(matl[0]);
5482  model_complex_plain_vector A2(gmm::vect_size(*A));
5483  for (size_type i=0; i < gmm::vect_size(*A); ++i) // Not valid for
5484  A2[i] = gmm::sqr((*A)[i]); // non lagrangian fem ...
5485  if (mf_a)
5486  asm_Helmholtz(matl[0], mim, mf_u, *mf_a, A2, rg);
5487  else
5488  asm_homogeneous_Helmholtz(matl[0], mim, mf_u, A2, rg);
5489  } else
5490  GMM_ASSERT1(false, "Bad format Helmholtz brick coefficient");
5491  }
5492 
5493  Helmholtz_brick() {
5494  set_flags("Helmholtz", true /* is linear*/,
5495  true /* is symmetric */, true /* is coercive */,
5496  true /* is real */, true /* is complex */);
5497  }
5498 
5499  };
5500 
5502  const std::string &varname,
5503  const std::string &dataexpr,
5504  size_type region) {
5505  if (md.is_complex()) {
5506  pbrick pbr = std::make_shared<Helmholtz_brick>();
5507  model::termlist tl;
5508  tl.push_back(model::term_description(varname, varname, true));
5509  return md.add_brick(pbr, model::varnamelist(1, varname),
5510  model::varnamelist(1, dataexpr), tl,
5511  model::mimlist(1, &mim), region);
5512  } else {
5513  std::string test_varname
5514  = "Test_" + sup_previous_and_dot_to_varname(varname);
5515  std::string expr = "Grad_"+varname+".Grad_"+test_varname
5516  +" + sqr("+dataexpr+")*"+varname+"*"+test_varname;
5517 
5518  size_type ib = add_linear_term(md, mim, expr, region, true, true,
5519  "Helmholtz", true);
5520  if (ib == size_type(-1))
5521  ib = add_nonlinear_term(md, mim, expr, region, false, false,
5522  "Helmholtz (nonlinear)");
5523  return ib;
5524  }
5525  }
5526 
5527 
5528 
5529  // ----------------------------------------------------------------------
5530  //
5531  // Fourier-Robin brick
5532  //
5533  // ----------------------------------------------------------------------
5534 
5535  struct Fourier_Robin_brick : public virtual_brick {
5536 
5537  virtual void asm_real_tangent_terms(const model &md, size_type,
5538  const model::varnamelist &vl,
5539  const model::varnamelist &dl,
5540  const model::mimlist &mims,
5541  model::real_matlist &matl,
5542  model::real_veclist &,
5543  model::real_veclist &,
5544  size_type region,
5545  build_version) const {
5546  GMM_ASSERT1(matl.size() == 1,
5547  "Fourier-Robin brick has one and only one term");
5548  GMM_ASSERT1(mims.size() == 1,
5549  "Fourier-Robin brick need one and only one mesh_im");
5550  GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
5551  "Wrong number of variables for Fourier-Robin brick");
5552 
5553  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
5554  const mesh &m = mf_u.linked_mesh();
5555  size_type Q = mf_u.get_qdim(), s = 1;
5556  const mesh_im &mim = *mims[0];
5557  const mesh_fem *mf_a = 0;
5558  mesh_region rg(region);
5559  m.intersect_with_mpi_region(rg);
5560  const model_real_plain_vector *A = &(md.real_variable(dl[0]));
5561  mf_a = md.pmesh_fem_of_variable(dl[0]);
5562  s = gmm::vect_size(*A);
5563  if (mf_a) s = s * mf_a->get_qdim() / mf_a->nb_dof();
5564  GMM_ASSERT1(s == Q*Q,
5565  "Bad format Fourier-Robin brick coefficient");
5566 
5567  GMM_TRACE2("Fourier-Robin term assembly");
5568  gmm::clear(matl[0]);
5569  if (mf_a)
5570  asm_qu_term(matl[0], mim, mf_u, *mf_a, *A, rg);
5571  else
5572  asm_homogeneous_qu_term(matl[0], mim, mf_u, *A, rg);
5573  }
5574 
5575  virtual void asm_complex_tangent_terms(const model &md, size_type,
5576  const model::varnamelist &vl,
5577  const model::varnamelist &dl,
5578  const model::mimlist &mims,
5579  model::complex_matlist &matl,
5580  model::complex_veclist &,
5581  model::complex_veclist &,
5582  size_type region,
5583  build_version) const {
5584  GMM_ASSERT1(matl.size() == 1,
5585  "Fourier-Robin brick has one and only one term");
5586  GMM_ASSERT1(mims.size() == 1,
5587  "Fourier-Robin brick need one and only one mesh_im");
5588  GMM_ASSERT1(vl.size() == 1 && dl.size() == 1,
5589  "Wrong number of variables for Fourier-Robin brick");
5590 
5591  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
5592  const mesh &m = mf_u.linked_mesh();
5593  size_type Q = mf_u.get_qdim(), s = 1;
5594  const mesh_im &mim = *mims[0];
5595  const mesh_fem *mf_a = 0;
5596  mesh_region rg(region);
5597  m.intersect_with_mpi_region(rg);
5598  const model_complex_plain_vector *A = &(md.complex_variable(dl[0]));
5599  mf_a = md.pmesh_fem_of_variable(dl[0]);
5600  s = gmm::vect_size(*A);
5601  if (mf_a) s = s * mf_a->get_qdim() / mf_a->nb_dof();
5602  GMM_ASSERT1(s == Q*Q,
5603  "Bad format Fourier-Robin brick coefficient");
5604 
5605  GMM_TRACE2("Fourier-Robin term assembly");
5606  gmm::clear(matl[0]);
5607  if (mf_a)
5608  asm_qu_term(matl[0], mim, mf_u, *mf_a, *A, rg);
5609  else
5610  asm_homogeneous_qu_term(matl[0], mim, mf_u, *A, rg);
5611  }
5612 
5613  Fourier_Robin_brick() {
5614  set_flags("Fourier Robin condition", true /* is linear*/,
5615  true /* is symmetric */, true /* is coercive */,
5616  true /* is real */, true /* is complex */,
5617  false /* compute each time */);
5618  }
5619 
5620  };
5621 
5623  const std::string &varname,
5624  const std::string &dataexpr,
5625  size_type region) {
5626  if (md.is_complex()) {
5627  pbrick pbr = std::make_shared<Fourier_Robin_brick>();
5628  model::termlist tl;
5629  tl.push_back(model::term_description(varname, varname, true));
5630  return md.add_brick(pbr, model::varnamelist(1, varname),
5631  model::varnamelist(1, dataexpr), tl,
5632  model::mimlist(1, &mim), region);
5633  } else {
5634  std::string test_varname
5635  = "Test_" + sup_previous_and_dot_to_varname(varname);
5636  std::string expr = "(("+dataexpr+")*"+varname+")."+test_varname;
5637  size_type ib = add_linear_term(md, mim, expr, region, true, true,
5638  "Fourier-Robin", true);
5639  if (ib == size_type(-1))
5640  ib = add_nonlinear_term(md, mim, expr, region, false, false,
5641  "Fourier-Robin (nonlinear)");
5642  return ib;
5643  }
5644  }
5645 
5646  // ----------------------------------------------------------------------
5647  //
5648  // Constraint brick
5649  //
5650  // ----------------------------------------------------------------------
5651 
5652  struct have_private_data_brick : public virtual_brick {
5653 
5654  model_real_sparse_matrix rB;
5655  model_complex_sparse_matrix cB;
5656  model_real_plain_vector rL;
5657  model_complex_plain_vector cL;
5658  std::string nameL;
5659  };
5660 
5661  struct constraint_brick : public have_private_data_brick {
5662 
5663  virtual void real_pre_assembly_in_serial(const model &md, size_type,
5664  const model::varnamelist &vl,
5665  const model::varnamelist &dl,
5666  const model::mimlist &mims,
5667  model::real_matlist &matl,
5668  model::real_veclist &vecl,
5669  model::real_veclist &,
5670  size_type, build_version) const {
5671  if (MPI_IS_MASTER()) {
5672 
5673  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5674  "Constraint brick has one and only one term");
5675  GMM_ASSERT1(mims.size() == 0,
5676  "Constraint brick need no mesh_im");
5677  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 1,
5678  "Wrong number of variables for constraint brick");
5679 
5680  bool penalized = (vl.size() == 1);
5681  const model_real_plain_vector *COEFF = 0;
5682 
5683  bool has_data = (nameL.compare("") != 0);
5684  if (has_data)
5685  GMM_ASSERT1(nameL.compare(dl.back()) == 0 &&
5686  md.variable_exists(nameL) && md.is_data(nameL),
5687  "Internal error");
5688  const model_real_plain_vector &
5689  rrL = has_data ? md.real_variable(nameL) : rL;
5690 
5691  if (penalized) {
5692  COEFF = &(md.real_variable(dl[0]));
5693  GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
5694  "Data for coefficient should be a scalar");
5695 
5696  gmm::mult(gmm::transposed(rB),
5697  gmm::scaled(rrL, gmm::abs((*COEFF)[0])), vecl[0]);
5698  gmm::mult(gmm::transposed(rB),
5699  gmm::scaled(rB, gmm::abs((*COEFF)[0])), matl[0]);
5700  } else {
5701  gmm::copy(rrL, vecl[0]);
5702  gmm::copy(rB, matl[0]);
5703  }
5704  }
5705  }
5706 
5707  virtual void complex_pre_assembly_in_serial(const model &md, size_type,
5708  const model::varnamelist &vl,
5709  const model::varnamelist &dl,
5710  const model::mimlist &mims,
5711  model::complex_matlist &matl,
5712  model::complex_veclist &vecl,
5713  model::complex_veclist &,
5714  size_type,
5715  build_version) const {
5716  if (MPI_IS_MASTER()) {
5717 
5718  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5719  "Constraint brick has one and only one term");
5720  GMM_ASSERT1(mims.size() == 0,
5721  "Constraint brick need no mesh_im");
5722  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() <= 1,
5723  "Wrong number of variables for constraint brick");
5724 
5725  bool penalized = (vl.size() == 1);
5726  const model_complex_plain_vector *COEFF = 0;
5727 
5728  bool has_data = (nameL.compare("") != 0);
5729  if (has_data)
5730  GMM_ASSERT1(nameL.compare(dl.back()) == 0 &&
5731  md.variable_exists(nameL) && md.is_data(nameL),
5732  "Internal error");
5733  const model_complex_plain_vector &
5734  ccL = has_data ? md.complex_variable(nameL) : cL;
5735 
5736  if (penalized) {
5737  COEFF = &(md.complex_variable(dl[0]));
5738  GMM_ASSERT1(gmm::vect_size(*COEFF) == 1,
5739  "Data for coefficient should be a scalar");
5740 
5741  gmm::mult(gmm::transposed(cB),
5742  gmm::scaled(ccL, gmm::abs((*COEFF)[0])), vecl[0]);
5743  gmm::mult(gmm::transposed(cB),
5744  gmm::scaled(cB, gmm::abs((*COEFF)[0])), matl[0]);
5745  } else {
5746  gmm::copy(ccL, vecl[0]);
5747  gmm::copy(cB, matl[0]);
5748  }
5749  }
5750  }
5751 
5752  virtual std::string declare_volume_assembly_string
5753  (const model &, size_type, const model::varnamelist &,
5754  const model::varnamelist &) const {
5755  return std::string();
5756  }
5757 
5758  constraint_brick(bool penalized) {
5759  set_flags(penalized ? "Constraint with penalization brick"
5760  : "Constraint with multipliers brick",
5761  true /* is linear*/,
5762  true /* is symmetric */, penalized /* is coercive */,
5763  true /* is real */, true /* is complex */,
5764  false /* compute each time */);
5765  }
5766 
5767  };
5768 
5769  model_real_sparse_matrix &set_private_data_brick_real_matrix
5770  (model &md, size_type indbrick) {
5771  pbrick pbr = md.brick_pointer(indbrick);
5772  md.touch_brick(indbrick);
5773  have_private_data_brick *p = dynamic_cast<have_private_data_brick *>
5774  (const_cast<virtual_brick *>(pbr.get()));
5775  GMM_ASSERT1(p, "Wrong type of brick");
5776  return p->rB;
5777  }
5778 
5779  model_real_plain_vector &set_private_data_brick_real_rhs
5780  (model &md, size_type indbrick) {
5781  pbrick pbr = md.brick_pointer(indbrick);
5782  md.touch_brick(indbrick);
5783  have_private_data_brick *p = dynamic_cast<have_private_data_brick *>
5784  (const_cast<virtual_brick *>(pbr.get()));
5785  GMM_ASSERT1(p, "Wrong type of brick");
5786  if (p->nameL.compare("") != 0) GMM_WARNING1("Rhs already set by data name");
5787  return p->rL;
5788  }
5789 
5790  model_complex_sparse_matrix &set_private_data_brick_complex_matrix
5791  (model &md, size_type indbrick) {
5792  pbrick pbr = md.brick_pointer(indbrick);
5793  md.touch_brick(indbrick);
5794  have_private_data_brick *p = dynamic_cast<have_private_data_brick *>
5795  (const_cast<virtual_brick *>(pbr.get()));
5796  GMM_ASSERT1(p, "Wrong type of brick");
5797  return p->cB;
5798  }
5799 
5800  model_complex_plain_vector &set_private_data_brick_complex_rhs
5801  (model &md, size_type indbrick) {
5802  pbrick pbr = md.brick_pointer(indbrick);
5803  md.touch_brick(indbrick);
5804  have_private_data_brick *p = dynamic_cast<have_private_data_brick *>
5805  (const_cast<virtual_brick *>(pbr.get()));
5806  GMM_ASSERT1(p, "Wrong type of brick");
5807  if (p->nameL.compare("") != 0) GMM_WARNING1("Rhs already set by data name");
5808  return p->cL;
5809  }
5810 
5811  void set_private_data_rhs
5812  (model &md, size_type indbrick, const std::string &varname) {
5813  pbrick pbr = md.brick_pointer(indbrick);
5814  md.touch_brick(indbrick);
5815  have_private_data_brick *p = dynamic_cast<have_private_data_brick *>
5816  (const_cast<virtual_brick *>(pbr.get()));
5817  GMM_ASSERT1(p, "Wrong type of brick");
5818  if (p->nameL.compare(varname) != 0) {
5819  model::varnamelist dl = md.datanamelist_of_brick(indbrick);
5820  if (p->nameL.compare("") == 0) dl.push_back(varname);
5821  else dl.back() = varname;
5822  md.change_data_of_brick(indbrick, dl);
5823  p->nameL = varname;
5824  }
5825  }
5826 
5827  size_type add_constraint_with_penalization
5828  (model &md, const std::string &varname, scalar_type penalisation_coeff) {
5829  std::string coeffname = md.new_name("penalization_on_" + varname);
5830  md.add_fixed_size_data(coeffname, 1);
5831  if (md.is_complex())
5832  md.set_complex_variable(coeffname)[0] = penalisation_coeff;
5833  else
5834  md.set_real_variable(coeffname)[0] = penalisation_coeff;
5835  pbrick pbr = std::make_shared<constraint_brick>(true);
5836  model::termlist tl;
5837  tl.push_back(model::term_description(varname, varname, true));
5838  model::varnamelist vl(1, varname);
5839  model::varnamelist dl(1, coeffname);
5840  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), size_type(-1));
5841  }
5842 
5843  size_type add_constraint_with_multipliers
5844  (model &md, const std::string &varname, const std::string &multname) {
5845  pbrick pbr = std::make_shared<constraint_brick>(false);
5846  model::termlist tl;
5847  tl.push_back(model::term_description(multname, varname, true));
5848  model::varnamelist vl(1, varname);
5849  vl.push_back(multname);
5850  model::varnamelist dl;
5851  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), size_type(-1));
5852  }
5853 
5854 
5855  // ----------------------------------------------------------------------
5856  //
5857  // Explicit matrix brick
5858  //
5859  // ----------------------------------------------------------------------
5860 
5861  struct explicit_matrix_brick : public have_private_data_brick {
5862 
5863  virtual void real_pre_assembly_in_serial(const model &, size_type,
5864  const model::varnamelist &vl,
5865  const model::varnamelist &dl,
5866  const model::mimlist &mims,
5867  model::real_matlist &matl,
5868  model::real_veclist &vecl,
5869  model::real_veclist &,
5870  size_type, build_version) const {
5871  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5872  "Explicit matrix has one and only one term");
5873  GMM_ASSERT1(mims.size() == 0, "Explicit matrix need no mesh_im");
5874  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() == 0,
5875  "Wrong number of variables for explicit matrix brick");
5876  GMM_ASSERT1(gmm::mat_ncols(rB) == gmm::mat_ncols(matl[0]) &&
5877  gmm::mat_nrows(rB) == gmm::mat_nrows(matl[0]),
5878  "Explicit matrix brick dimension mismatch ("<<
5879  gmm::mat_ncols(rB)<<"x"<<gmm::mat_nrows(rB)<<") != ("<<
5880  gmm::mat_ncols(matl[0])<<"x"<<gmm::mat_nrows(matl[0])<<")");
5881  gmm::copy(rB, matl[0]);
5882  }
5883 
5884  virtual void complex_pre_assembly_in_serial(const model &, size_type,
5885  const model::varnamelist &vl,
5886  const model::varnamelist &dl,
5887  const model::mimlist &mims,
5888  model::complex_matlist &matl,
5889  model::complex_veclist &vecl,
5890  model::complex_veclist &,
5891  size_type,
5892  build_version) const {
5893  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5894  "Explicit matrix has one and only one term");
5895  GMM_ASSERT1(mims.size() == 0, "Explicit matrix need no mesh_im");
5896  GMM_ASSERT1(vl.size() >= 1 && vl.size() <= 2 && dl.size() == 0,
5897  "Wrong number of variables for explicit matrix brick");
5898  gmm::copy(cB, matl[0]);
5899  }
5900 
5901  virtual std::string declare_volume_assembly_string
5902  (const model &, size_type, const model::varnamelist &,
5903  const model::varnamelist &) const {
5904  return std::string();
5905  }
5906 
5907  explicit_matrix_brick(bool symmetric_, bool coercive_) {
5908  set_flags("Explicit matrix brick",
5909  true /* is linear*/,
5910  symmetric_ /* is symmetric */, coercive_ /* is coercive */,
5911  true /* is real */, true /* is complex */,
5912  true /* is to be computed each time */);
5913  }
5914  };
5915 
5916  size_type add_explicit_matrix
5917  (model &md, const std::string &varname1, const std::string &varname2,
5918  bool issymmetric, bool iscoercive) {
5919  pbrick pbr = std::make_shared<explicit_matrix_brick>(issymmetric,
5920  iscoercive);
5921  model::termlist tl;
5922  tl.push_back(model::term_description(varname1, varname2, issymmetric));
5923  model::varnamelist vl(1, varname1);
5924  vl.push_back(varname2);
5925  model::varnamelist dl;
5926  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), size_type(-1));
5927  }
5928 
5929  // ----------------------------------------------------------------------
5930  //
5931  // Explicit rhs brick
5932  //
5933  // ----------------------------------------------------------------------
5934 
5935  struct explicit_rhs_brick : public have_private_data_brick {
5936 
5937  virtual void real_pre_assembly_in_serial(const model &, size_type,
5938  const model::varnamelist &vl,
5939  const model::varnamelist &dl,
5940  const model::mimlist &mims,
5941  model::real_matlist &matl,
5942  model::real_veclist &vecl,
5943  model::real_veclist &,
5944  size_type, build_version) const {
5945  if (MPI_IS_MASTER()) {
5946  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5947  "Explicit rhs has one and only one term");
5948  GMM_ASSERT1(mims.size() == 0, "Explicit rhs need no mesh_im");
5949  GMM_ASSERT1(vl.size() == 1 && dl.size() == 0,
5950  "Wrong number of variables for explicit rhs brick");
5951  gmm::copy(rL, vecl[0]);
5952  }
5953  }
5954 
5955  virtual void complex_pre_assembly_in_serial(const model &, size_type,
5956  const model::varnamelist &vl,
5957  const model::varnamelist &dl,
5958  const model::mimlist &mims,
5959  model::complex_matlist &matl,
5960  model::complex_veclist &vecl,
5961  model::complex_veclist &,
5962  size_type,
5963  build_version) const {
5964  if (MPI_IS_MASTER()) {
5965  GMM_ASSERT1(vecl.size() == 1 && matl.size() == 1,
5966  "Explicit rhs has one and only one term");
5967  GMM_ASSERT1(mims.size() == 0, "Explicit rhs need no mesh_im");
5968  GMM_ASSERT1(vl.size() == 1 && dl.size() == 0,
5969  "Wrong number of variables for explicit rhs brick");
5970  gmm::copy(cL, vecl[0]);
5971  }
5972 
5973  }
5974 
5975  virtual std::string declare_volume_assembly_string
5976  (const model &, size_type, const model::varnamelist &,
5977  const model::varnamelist &) const {
5978  return std::string();
5979  }
5980 
5981  explicit_rhs_brick() {
5982  set_flags("Explicit rhs brick",
5983  true /* is linear*/,
5984  true /* is symmetric */, true /* is coercive */,
5985  true /* is real */, true /* is complex */,
5986  true /* is to be computed each time */);
5987  }
5988 
5989  };
5990 
5991  size_type add_explicit_rhs
5992  (model &md, const std::string &varname) {
5993  pbrick pbr = std::make_shared<explicit_rhs_brick>();
5994  model::termlist tl;
5995  tl.push_back(model::term_description(varname));
5996  model::varnamelist vl(1, varname);
5997  model::varnamelist dl;
5998  return md.add_brick(pbr, vl, dl, tl, model::mimlist(), size_type(-1));
5999  }
6000 
6001 
6002  // ----------------------------------------------------------------------
6003  //
6004  // Isotropic linearized elasticity brick
6005  //
6006  // ----------------------------------------------------------------------
6007 
6008  struct iso_lin_elasticity_new_brick : public virtual_brick {
6009 
6010  std::string expr, dataname3;
6011 
6012  void asm_real_tangent_terms(const model &md, size_type ib,
6013  const model::varnamelist &vl,
6014  const model::varnamelist &dl,
6015  const model::mimlist &mims,
6016  model::real_matlist &matl,
6017  model::real_veclist &vecl,
6018  model::real_veclist &,
6019  size_type region,
6020  build_version version) const override {
6021  GMM_ASSERT1(vl.size() == 1, "Linearized isotropic elasticity brick "
6022  "has one and only one variable");
6023  GMM_ASSERT1(matl.size() == 1, "Linearized isotropic elasticity brick "
6024  "has one and only one term");
6025  GMM_ASSERT1(mims.size() == 1, "Linearized isotropic elasticity brick "
6026  "needs one and only one mesh_im");
6027 
6028  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
6029  for (size_type i = 0; i < dl.size(); ++i) {
6030  recompute_matrix = recompute_matrix ||
6031  md.is_var_newer_than_brick(dl[i], ib);
6032  }
6033 
6034  if (recompute_matrix) {
6035  // reenables disabled variables
6036  ga_workspace workspace(md, ga_workspace::inherit::ALL);
6037  workspace.add_expression(expr, *(mims[0]), region);
6038  GMM_TRACE2(name << ": generic matrix assembly");
6039  workspace.assembly(2);
6040  scalar_type alpha = scalar_type(1)
6041  / (workspace.factor_of_variable(vl[0]));
6042  const auto &R=workspace.assembled_matrix();
6043  gmm::sub_interval I = workspace.interval_of_variable(vl[0]);
6044  gmm::copy(gmm::scaled(gmm::sub_matrix(R, I, I), alpha),
6045  matl[0]);
6046  }
6047 
6048  if (dataname3.size()) { // Pre-constraints given by an "initial"
6049  // displacement u0. Means that the computed displacement will be u - u0
6050  // The displacement u0 should be discribed on the same fem as the
6051  // variable.
6052  gmm::clear(vecl[0]);
6053  gmm::mult(matl[0],
6054  gmm::scaled(md.real_variable(dataname3), scalar_type(-1)),
6055  vecl[0]);
6056  }
6057 
6058  }
6059 
6060  void real_post_assembly_in_serial(const model &md, size_type ib,
6061  const model::varnamelist &/* vl */,
6062  const model::varnamelist &/* dl */,
6063  const model::mimlist &/* mims */,
6064  model::real_matlist &/*matl*/,
6065  model::real_veclist &vecl,
6066  model::real_veclist &,
6067  size_type /*region*/,
6068  build_version) const override {
6069  md.add_external_load(ib, gmm::vect_norm1(vecl[0]));
6070  }
6071 
6072 
6073  virtual std::string declare_volume_assembly_string
6074  (const model &, size_type, const model::varnamelist &,
6075  const model::varnamelist &) const {
6076  return expr;
6077  }
6078 
6079  iso_lin_elasticity_new_brick(const std::string &expr_,
6080  const std::string &dataname3_) {
6081  expr = expr_; dataname3 = dataname3_;
6082  set_flags("Linearized isotropic elasticity", true /* is linear*/,
6083  true /* is symmetric */, true /* is coercive */,
6084  true /* is real */, false /* is complex */);
6085  }
6086 
6087  };
6088 
6089 
6091  (model &md, const mesh_im &mim, const std::string &varname,
6092  const std::string &dataexpr1, const std::string &dataexpr2,
6093  size_type region, const std::string &dataname3) {
6094  std::string test_varname
6095  = "Test_" + sup_previous_and_dot_to_varname(varname);
6096 
6097  std::string expr1 = "((("+dataexpr1+")*(Div_"+varname+"-Div_"+dataname3
6098  +"))*Id(meshdim)+(2*("+dataexpr2+"))*(Sym(Grad_"+varname
6099  +")-Sym(Grad_"+dataname3+"))):Grad_" +test_varname;
6100  std::string expr2 = "(Div_"+varname+"*(("+dataexpr1+")*Id(meshdim))"
6101  +"+(2*("+dataexpr2+"))*Sym(Grad_"+varname+")):Grad_"+test_varname;
6102 
6103  bool is_lin;
6104  model::varnamelist vl, dl;
6105  { // reenables disabled variables
6106  ga_workspace workspace(md, ga_workspace::inherit::ALL);
6107  workspace.add_expression(expr2, mim, region);
6108  model::varnamelist vl_test1, vl_test2;
6109  is_lin = workspace.used_variables(vl, vl_test1, vl_test2, dl, 2);
6110  }
6111  if (is_lin) {
6112  pbrick pbr = std::make_shared<iso_lin_elasticity_new_brick>
6113  (expr2, dataname3);
6114  model::termlist tl;
6115  tl.push_back(model::term_description(varname,
6116  sup_previous_and_dot_to_varname(varname), true));
6117  if (dataname3.size()) dl.push_back(dataname3);
6118  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
6119  } else {
6120  return add_nonlinear_generic_assembly_brick
6121  (md, mim, dataname3.size() ? expr1 : expr2, region, false, false,
6122  "Linearized isotropic elasticity (with nonlinear dependance)");
6123  }
6124  }
6125 
6127  (model &md, const mesh_im &mim, const std::string &varname,
6128  const std::string &data_E, const std::string &data_nu,
6129  size_type region) {
6130  std::string test_varname
6131  = "Test_" + sup_previous_and_dot_to_varname(varname);
6132 
6133  std::string mu = "(("+data_E+")/(2*(1+("+data_nu+"))))";
6134  std::string lambda = "(("+data_E+")*("+data_nu+")/((1+("+data_nu+"))*(1-2*("
6135  +data_nu+"))))";
6136  std::string expr = lambda+"*Div_"+varname+"*Div_"+test_varname
6137  + "+"+mu+"*(Grad_"+varname+"+Grad_"+varname+"'):Grad_"+test_varname;
6138 
6139  bool is_lin;
6140  { // reenables disabled variables
6141  ga_workspace workspace(md, ga_workspace::inherit::ALL);
6142  workspace.add_expression(expr, mim, region);
6143  is_lin = workspace.is_linear(2);
6144  }
6145  if (is_lin) {
6146  return add_linear_term(md, mim, expr, region, false, false,
6147  "Linearized isotropic elasticity");
6148  } else {
6149  return add_nonlinear_term
6150  (md, mim, expr, region, false, false,
6151  "Linearized isotropic elasticity (with nonlinear dependance)");
6152  }
6153  }
6154 
6156  (model &md, const mesh_im &mim, const std::string &varname,
6157  const std::string &data_E, const std::string &data_nu,
6158  size_type region) {
6159  std::string test_varname
6160  = "Test_" + sup_previous_and_dot_to_varname(varname);
6161 
6162  const mesh_fem *mfu = md.pmesh_fem_of_variable(varname);
6163  GMM_ASSERT1(mfu, "The variable should be a fem variable");
6164  size_type N = mfu->linked_mesh().dim();
6165 
6166  std::string mu = "(("+data_E+")/(2*(1+("+data_nu+"))))";
6167  std::string lambda = "(("+data_E+")*("+data_nu+")/((1+("+data_nu+"))*(1-2*("
6168  +data_nu+"))))";
6169  if (N == 2)
6170  lambda = "(("+data_E+")*("+data_nu+")/((1-sqr("+data_nu+"))))";
6171  std::string expr = lambda+"*Div_"+varname+"*Div_"+test_varname
6172  + "+"+mu+"*(Grad_"+varname+"+Grad_"+varname+"'):Grad_"+test_varname;
6173 
6174  bool is_lin;
6175  { // reenables disabled variables
6176  ga_workspace workspace(md, ga_workspace::inherit::ALL);
6177  workspace.add_expression(expr, mim, region);
6178  is_lin = workspace.is_linear(2);
6179  }
6180  if (is_lin) {
6181  return add_linear_term(md, mim, expr, region, false, false,
6182  "Linearized isotropic elasticity");
6183  } else {
6184  return add_nonlinear_term
6185  (md, mim, expr, region, false, false,
6186  "Linearized isotropic elasticity (with nonlinear dependance)");
6187  }
6188  }
6189 
6190  // Tresca to be implemented with generic interpolation
6191  void compute_isotropic_linearized_Von_Mises_or_Tresca
6192  (model &md, const std::string &varname, const std::string &data_lambda,
6193  const std::string &data_mu, const mesh_fem &mf_vm,
6194  model_real_plain_vector &VM, bool tresca) {
6195 
6196  if (tresca) {
6197  const mesh_fem &mf_u = md.mesh_fem_of_variable(varname);
6198  const mesh_fem *mf_lambda = md.pmesh_fem_of_variable(data_lambda);
6199  const model_real_plain_vector *lambda=&(md.real_variable(data_lambda));
6200  const mesh_fem *mf_mu = md.pmesh_fem_of_variable(data_mu);
6201  const model_real_plain_vector *mu = &(md.real_variable(data_mu));
6202 
6203  size_type sl = gmm::vect_size(*lambda);
6204  if (mf_lambda) sl = sl * mf_lambda->get_qdim() / mf_lambda->nb_dof();
6205  size_type sm = gmm::vect_size(*mu);
6206  if (mf_mu) sm = sm * mf_mu->get_qdim() / mf_mu->nb_dof();
6207 
6208  GMM_ASSERT1(sl == 1 && sm == 1, "Bad format for Lame coefficients");
6209  GMM_ASSERT1(mf_lambda == mf_mu,
6210  "The two Lame coefficients should be described on the same "
6211  "finite element method.");
6212 
6213  if (mf_lambda) {
6215  md.real_variable(varname), VM,
6216  *mf_lambda, *lambda,
6217  *mf_lambda, *mu,
6218  tresca);
6219  } else {
6220  mf_lambda = &(classical_mesh_fem(mf_u.linked_mesh(), 0));
6221  model_real_plain_vector LAMBDA(mf_lambda->nb_dof(), (*lambda)[0]);
6222  model_real_plain_vector MU(mf_lambda->nb_dof(), (*mu)[0]);
6224  md.real_variable(varname), VM,
6225  *mf_lambda, LAMBDA,
6226  *mf_lambda, MU,
6227  tresca);
6228  }
6229  } else {
6230  // The Lambda part is not necessary for Von Mises stress ...
6231  // std::string sigma = "("+data_lambda+")*Div_"+varname+"*Id(meshdim)+("
6232  // + data_mu+")*(Grad_"+varname+"+Grad_"+varname+"')";
6233  std::string sigma_d="("+data_mu+")*(Grad_"+varname+"+Grad_"+varname+"')";
6234  std::string expr = "sqrt(3/2)*Norm(Deviator("+sigma_d+"))";
6235  ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM);
6236  }
6237  }
6238 
6239 
6241  (model &md, const std::string &varname, const std::string &data_E,
6242  const std::string &data_nu, const mesh_fem &mf_vm,
6243  model_real_plain_vector &VM) {
6244  // The Lambda part is not necessary for Von Mises stress ...
6245  // std::string lambda = "(("+data_E+")*("+data_nu+")/((1+("+data_nu+"))*(1-2*("
6246  // +data_nu+"))))";
6247  std::string mu = "(("+data_E+")/(2*(1+("+data_nu+"))))";
6248  // std::string sigma = lambda+"*Div_"+varname+"*Id(meshdim)+"
6249  // + mu+"*(Grad_"+varname+"+Grad_"+varname+"')";
6250  std::string sigma_d = mu+"*(Grad_"+varname+"+Grad_"+varname+"')";
6251  std::string expr = "sqrt(3/2)*Norm(Deviator("+sigma_d+"))";
6252  ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM);
6253  }
6254 
6256  (model &md, const std::string &varname, const std::string &data_E,
6257  const std::string &data_nu, const mesh_fem &mf_vm,
6258  model_real_plain_vector &VM) {
6259  // The Lambda part is not necessary for Von Mises stress ...
6260  // const mesh_fem *mfu = md.pmesh_fem_of_variable(varname);
6261  // GMM_ASSERT1(mfu, "The variable should be a fem variable");
6262  // size_type N = mfu->linked_mesh().dim();
6263  // std::string lambda = "(("+data_E+")*("+data_nu+")/((1+("+data_nu
6264  // +"))*(1-2*("+data_nu+"))))";
6265  // if (N == 2)
6266  // lambda = "(("+data_E+")*("+data_nu+")/((1-sqr("+data_nu+"))))";
6267  std::string mu = "(("+data_E+")/(2*(1+("+data_nu+"))))";
6268  // std::string sigma = lambda+"*Div_"+varname+"*Id(meshdim)+"
6269  // + mu+"*(Grad_"+varname+"+Grad_"+varname+"')";
6270  std::string sigma_d = mu+"*(Grad_"+varname+"+Grad_"+varname+"')";
6271  std::string expr = "sqrt(3/2)*Norm(Deviator("+sigma_d+"))";
6272  ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM);
6273  }
6274 
6275 
6276  // --------------------------------------------------------------------
6277  //
6278  // linearized incompressibility brick (div u = 0)
6279  //
6280  // ----------------------------------------------------------------------
6281 
6282  struct linear_incompressibility_brick : public virtual_brick {
6283 
6284  virtual void asm_real_tangent_terms(const model &md, size_type /*ib*/,
6285  const model::varnamelist &vl,
6286  const model::varnamelist &dl,
6287  const model::mimlist &mims,
6288  model::real_matlist &matl,
6289  model::real_veclist &,
6290  model::real_veclist &,
6291  size_type region,
6292  build_version) const {
6293 
6294  GMM_ASSERT1((matl.size() == 1 && dl.size() == 0)
6295  || (matl.size() == 2 && dl.size() == 1),
6296  "Wrong term and/or data number for Linear incompressibility "
6297  "brick.");
6298  GMM_ASSERT1(mims.size() == 1, "Linear incompressibility brick need one "
6299  "and only one mesh_im");
6300  GMM_ASSERT1(vl.size() == 2, "Wrong number of variables for linear "
6301  "incompressibility brick");
6302 
6303  bool penalized = (dl.size() == 1);
6304  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6305  const mesh_fem &mf_p = md.mesh_fem_of_variable(vl[1]);
6306  const mesh_im &mim = *mims[0];
6307  const model_real_plain_vector *COEFF = 0;
6308  const mesh_fem *mf_data = 0;
6309 
6310  if (penalized) {
6311  COEFF = &(md.real_variable(dl[0]));
6312  mf_data = md.pmesh_fem_of_variable(dl[0]);
6313  size_type s = gmm::vect_size(*COEFF);
6314  if (mf_data) s = s * mf_data->get_qdim() / mf_data->nb_dof();
6315  GMM_ASSERT1(s == 1, "Bad format for the penalization parameter");
6316  }
6317 
6318  mesh_region rg(region);
6319  mim.linked_mesh().intersect_with_mpi_region(rg);
6320 
6321  GMM_TRACE2("Stokes term assembly");
6322  gmm::clear(matl[0]);
6323  asm_stokes_B(matl[0], mim, mf_u, mf_p, rg);
6324 
6325  if (penalized) {
6326  gmm::clear(matl[1]);
6327  if (mf_data) {
6328  asm_mass_matrix_param(matl[1], mim, mf_p, *mf_data, *COEFF, rg);
6329  gmm::scale(matl[1], scalar_type(-1));
6330  }
6331  else {
6332  asm_mass_matrix(matl[1], mim, mf_p, rg);
6333  gmm::scale(matl[1], -(*COEFF)[0]);
6334  }
6335  }
6336 
6337  }
6338 
6339 
6340  virtual void real_post_assembly_in_serial(const model &, size_type,
6341  const model::varnamelist &,
6342  const model::varnamelist &/*dl*/,
6343  const model::mimlist &/*mims*/,
6344  model::real_matlist &/*matl*/,
6345  model::real_veclist &,
6346  model::real_veclist &,
6347  size_type /*region*/,
6348  build_version) const
6349  { }
6350 
6351 
6352  linear_incompressibility_brick() {
6353  set_flags("Linear incompressibility brick",
6354  true /* is linear*/,
6355  true /* is symmetric */, false /* is coercive */,
6356  true /* is real */, false /* is complex */);
6357  }
6358 
6359  };
6360 
6362  (model &md, const mesh_im &mim, const std::string &varname,
6363  const std::string &multname, size_type region,
6364  const std::string &dataexpr) {
6365 #if 0
6366  pbrick pbr = std::make_shared<linear_incompressibility_brick>();
6367  model::termlist tl;
6368  tl.push_back(model::term_description(multname, varname, true));
6369  model::varnamelist vl(1, varname);
6370  vl.push_back(multname);
6371  model::varnamelist dl;
6372  if (dataname.size()) {
6373  dl.push_back(dataexpr);
6374  tl.push_back(model::term_description(multname, multname, true));
6375  }
6376  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
6377 #else
6378  std::string test_varname
6379  = "Test_" + sup_previous_and_dot_to_varname(varname);
6380  std::string test_multname
6381  = "Test_" + sup_previous_and_dot_to_varname(multname);
6382  std::string expr;
6383  if (dataexpr.size())
6384  expr = "-"+multname+"*Div_"+test_varname + "-"+test_multname
6385  +"*Div_"+varname+"+(("+dataexpr+")*"+multname+")*"+test_multname;
6386  else
6387  expr = "-"+multname+"*Div_"+test_varname + "-"+test_multname
6388  +"*Div_"+varname;
6389  size_type ib = add_linear_term(md, mim, expr, region, true, true,
6390  "Linear incompressibility", true);
6391  if (ib == size_type(-1))
6392  ib = add_nonlinear_term
6393  (md, mim, expr, region, false, false,
6394  "Linear incompressibility (with nonlinear dependance)");
6395  return ib;
6396 #endif
6397  }
6398 
6399 
6400 
6401  // ----------------------------------------------------------------------
6402  //
6403  // Mass brick
6404  //
6405  // ----------------------------------------------------------------------
6406 
6407  struct mass_brick : public virtual_brick {
6408 
6409  virtual void asm_real_tangent_terms(const model &md, size_type,
6410  const model::varnamelist &vl,
6411  const model::varnamelist &dl,
6412  const model::mimlist &mims,
6413  model::real_matlist &matl,
6414  model::real_veclist &,
6415  model::real_veclist &,
6416  size_type region,
6417  build_version) const {
6418  GMM_ASSERT1(matl.size() == 1,
6419  "Mass brick has one and only one term");
6420  GMM_ASSERT1(mims.size() == 1,
6421  "Mass brick need one and only one mesh_im");
6422  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
6423  "Wrong number of variables for mass brick");
6424 
6425  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6426  const mesh &m = mf_u.linked_mesh();
6427  const mesh_im &mim = *mims[0];
6428  mesh_region rg(region);
6429  m.intersect_with_mpi_region(rg);
6430 
6431  const mesh_fem *mf_rho = 0;
6432  const model_real_plain_vector *rho = 0;
6433 
6434  if (dl.size()) {
6435  mf_rho = md.pmesh_fem_of_variable(dl[0]);
6436  rho = &(md.real_variable(dl[0]));
6437  size_type sl = gmm::vect_size(*rho);
6438  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6439  GMM_ASSERT1(sl == 1, "Bad format of mass brick coefficient");
6440  }
6441 
6442  GMM_TRACE2("Mass matrix assembly");
6443  gmm::clear(matl[0]);
6444  if (dl.size() && mf_rho) {
6445  asm_mass_matrix_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6446  } else {
6447  asm_mass_matrix(matl[0], mim, mf_u, rg);
6448  if (dl.size()) gmm::scale(matl[0], (*rho)[0]);
6449  }
6450  }
6451 
6452  virtual void asm_complex_tangent_terms(const model &md, size_type,
6453  const model::varnamelist &vl,
6454  const model::varnamelist &dl,
6455  const model::mimlist &mims,
6456  model::complex_matlist &matl,
6457  model::complex_veclist &,
6458  model::complex_veclist &,
6459  size_type region,
6460  build_version) const {
6461  GMM_ASSERT1(matl.size() == 1,
6462  "Mass brick has one and only one term");
6463  GMM_ASSERT1(mims.size() == 1,
6464  "Mass brick need one and only one mesh_im");
6465  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
6466  "Wrong number of variables for mass brick");
6467 
6468  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6469  const mesh &m = mf_u.linked_mesh();
6470  const mesh_im &mim = *mims[0];
6471  mesh_region rg(region);
6472  m.intersect_with_mpi_region(rg);
6473 
6474  const mesh_fem *mf_rho = 0;
6475  const model_complex_plain_vector *rho = 0;
6476 
6477  if (dl.size()) {
6478  mf_rho = md.pmesh_fem_of_variable(dl[0]);
6479  rho = &(md.complex_variable(dl[0]));
6480  size_type sl = gmm::vect_size(*rho);
6481  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6482  GMM_ASSERT1(sl == 1, "Bad format of mass brick coefficient");
6483  }
6484 
6485  GMM_TRACE2("Mass matrix assembly");
6486  gmm::clear(matl[0]);
6487  if (dl.size() && mf_rho) {
6488  asm_mass_matrix_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6489  } else {
6490  asm_mass_matrix(matl[0], mim, mf_u, rg);
6491  if (dl.size()) gmm::scale(matl[0], (*rho)[0]);
6492  }
6493  }
6494 
6495  virtual std::string declare_volume_assembly_string
6496  (const model &, size_type, const model::varnamelist &,
6497  const model::varnamelist &) const {
6498  return std::string();
6499  }
6500 
6501  mass_brick() {
6502  set_flags("Mass brick", true /* is linear*/,
6503  true /* is symmetric */, true /* is coercive */,
6504  true /* is real */, true /* is complex */,
6505  false /* compute each time */);
6506  }
6507 
6508  };
6509 
6511  (model &md, const mesh_im &mim, const std::string &varname,
6512  const std::string &dataexpr_rho, size_type region) {
6513  if (md.is_complex()) {
6514  pbrick pbr = std::make_shared<mass_brick>();
6515  model::termlist tl;
6516  tl.push_back(model::term_description(varname, varname, true));
6517  model::varnamelist dl;
6518  if (dataexpr_rho.size())
6519  dl.push_back(dataexpr_rho);
6520  return md.add_brick(pbr, model::varnamelist(1, varname), dl, tl,
6521  model::mimlist(1, &mim), region);
6522  } else {
6523  std::string test_varname
6524  = "Test_" + sup_previous_and_dot_to_varname(varname);
6525  std::string expr;
6526  if (dataexpr_rho.size())
6527  expr ="(("+dataexpr_rho+")*"+varname+")."+test_varname;
6528  else
6529  expr = varname+"."+test_varname;
6530  size_type ib = add_linear_term(md, mim, expr, region, true, true,
6531  "Mass matrix", true);
6532  if (ib == size_type(-1))
6533  ib = add_nonlinear_term(md, mim, expr, region, false, false,
6534  "Mass matrix (nonlinear)");
6535  return ib;
6536  }
6537  }
6538 
6539  // ----------------------------------------------------------------------
6540  //
6541  // Lumped Mass brick for first order
6542  //
6543  // ----------------------------------------------------------------------
6544 
6545  struct lumped_mass_brick_for_first_order : public virtual_brick {
6546 
6547  virtual void asm_real_tangent_terms(const model &md, size_type,
6548  const model::varnamelist &vl,
6549  const model::varnamelist &dl,
6550  const model::mimlist &mims,
6551  model::real_matlist &matl,
6552  model::real_veclist &,
6553  model::real_veclist &,
6554  size_type region,
6555  build_version) const {
6556  GMM_ASSERT1(matl.size() == 1,
6557  "Lumped Mass brick has one and only one term");
6558  GMM_ASSERT1(mims.size() == 1,
6559  "Lumped Mass brick needs one and only one mesh_im");
6560  GMM_ASSERT1(vl.size() == 1 && dl.size() <= 1,
6561  "Wrong number of variables for lumped mass brick");
6562 
6563  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6564  const mesh &m = mf_u.linked_mesh();
6565  const mesh_im &mim = *mims[0];
6566  mesh_region rg(region);
6567  m.intersect_with_mpi_region(rg);
6568 
6569  const mesh_fem *mf_rho = 0;
6570  const model_real_plain_vector *rho = 0;
6571 
6572  if (dl.size()) {
6573  mf_rho = md.pmesh_fem_of_variable(dl[0]);
6574  rho = &(md.real_variable(dl[0]));
6575  size_type sl = gmm::vect_size(*rho);
6576  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6577  GMM_ASSERT1(sl == 1, "Bad format of mass brick coefficient");
6578  }
6579 
6580  GMM_TRACE2("Lumped mass matrix assembly (please check that integration is 1st order.)");
6581  gmm::clear(matl[0]);
6582  if (dl.size() && mf_rho) {
6583  asm_lumped_mass_matrix_for_first_order_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6584  } else {
6585  asm_lumped_mass_matrix_for_first_order(matl[0], mim, mf_u, rg);
6586  if (dl.size()) gmm::scale(matl[0], (*rho)[0]);
6587  }
6588 
6589  }
6590 
6591  lumped_mass_brick_for_first_order() {
6592  set_flags("Lumped mass brick", true /* is linear*/,
6593  true /* is symmetric */, true /* is coercive */,
6594  true /* is real */, false /* no complex version */,
6595  false /* compute each time */);
6596  }
6597 
6598  };
6599 
6601  (model & md, const mesh_im &mim, const std::string &varname,
6602  const std::string &dataexpr_rho, size_type region) {
6603  pbrick pbr = std::make_shared<lumped_mass_brick_for_first_order>();
6604  model::termlist tl;
6605  tl.push_back(model::term_description(varname, varname, true));
6606  model::varnamelist dl;
6607  if (dataexpr_rho.size())
6608  dl.push_back(dataexpr_rho);
6609  return md.add_brick(pbr, model::varnamelist(1, varname), dl, tl,
6610  model::mimlist(1, &mim), region);
6611  }
6612 
6613  // ----------------------------------------------------------------------
6614  //
6615  // From now on, DEPRECATED PART
6616  //
6617  // ----------------------------------------------------------------------
6618 
6619  // ----------------------------------------------------------------------
6620  //
6621  // Generic first order time derivative brick.
6622  // Represents M(U^{n+1} - U^n) / dt
6623  //
6624  // ----------------------------------------------------------------------
6625 
6626  struct basic_d_on_dt_brick : public virtual_brick {
6627 
6628  virtual void asm_real_tangent_terms(const model &md, size_type ib,
6629  const model::varnamelist &vl,
6630  const model::varnamelist &dl,
6631  const model::mimlist &mims,
6632  model::real_matlist &matl,
6633  model::real_veclist &vecl,
6634  model::real_veclist &,
6635  size_type region,
6636  build_version version) const {
6637  GMM_ASSERT1(matl.size() == 1,
6638  "Basic d/dt brick has one and only one term");
6639  GMM_ASSERT1(mims.size() == 1,
6640  "Basic d/dt brick need one and only one mesh_im");
6641  GMM_ASSERT1(vl.size() == 1 && dl.size() >= 2 && dl.size() <= 3,
6642  "Wrong number of variables for basic d/dt brick");
6643 
6644  // It should me more convenient not to recompute the matrix if only
6645  // dt is modified
6646  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
6647  || (md.is_var_newer_than_brick(dl[1], ib));
6648  if (dl.size() > 2)
6649  recompute_matrix = recompute_matrix ||
6650  md.is_var_newer_than_brick(dl[2], ib);
6651 
6652 
6653  if (recompute_matrix) {
6654  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6655  const mesh &m = mf_u.linked_mesh();
6656  const mesh_im &mim = *mims[0];
6657  mesh_region rg(region);
6658  m.intersect_with_mpi_region(rg);
6659 
6660  const model_real_plain_vector &dt = md.real_variable(dl[1]);
6661  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for time step");
6662 
6663  const mesh_fem *mf_rho = 0;
6664  const model_real_plain_vector *rho = 0;
6665 
6666  if (dl.size() > 2) {
6667  mf_rho = md.pmesh_fem_of_variable(dl[2]);
6668  rho = &(md.real_variable(dl[2]));
6669  size_type sl = gmm::vect_size(*rho);
6670  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6671  GMM_ASSERT1(sl == 1, "Bad format for density");
6672  }
6673 
6674  GMM_TRACE2("Mass matrix assembly for d_on_dt brick");
6675  if (dl.size() > 2 && mf_rho) {
6676  gmm::clear(matl[0]);
6677  asm_mass_matrix_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6678  gmm::scale(matl[0], scalar_type(1) / dt[0]);
6679  } else {
6680  gmm::clear(matl[0]);
6681  asm_mass_matrix(matl[0], mim, mf_u, rg);
6682  if (dl.size() > 2) gmm::scale(matl[0], (*rho)[0] / dt[0]);
6683  else gmm::scale(matl[0], scalar_type(1) / dt[0]);
6684  }
6685  }
6686  gmm::mult(matl[0], md.real_variable(dl[0], 1), vecl[0]);
6687  }
6688 
6689  virtual void asm_complex_tangent_terms(const model &md, size_type ib,
6690  const model::varnamelist &vl,
6691  const model::varnamelist &dl,
6692  const model::mimlist &mims,
6693  model::complex_matlist &matl,
6694  model::complex_veclist &vecl,
6695  model::complex_veclist &,
6696  size_type region,
6697  build_version version) const {
6698  GMM_ASSERT1(matl.size() == 1,
6699  "Basic d/dt brick has one and only one term");
6700  GMM_ASSERT1(mims.size() == 1,
6701  "Basic d/dt brick need one and only one mesh_im");
6702  GMM_ASSERT1(vl.size() == 1 && dl.size() >= 2 && dl.size() <= 3,
6703  "Wrong number of variables for basic d/dt brick");
6704 
6705  // It should me more convenient not to recompute the matrix if only
6706  // dt is modified
6707  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0)
6708  || (md.is_var_newer_than_brick(dl[1], ib));
6709  if (dl.size() > 2)
6710  recompute_matrix = recompute_matrix ||
6711  md.is_var_newer_than_brick(dl[2], ib);
6712 
6713  if (recompute_matrix) {
6714  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6715  const mesh &m = mf_u.linked_mesh();
6716  const mesh_im &mim = *mims[0];
6717 
6718  mesh_region rg(region);
6719  m.intersect_with_mpi_region(rg);
6720 
6721  const model_complex_plain_vector &dt = md.complex_variable(dl[1]);
6722  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for time step");
6723 
6724  const mesh_fem *mf_rho = 0;
6725  const model_complex_plain_vector *rho = 0;
6726 
6727  if (dl.size() > 2) {
6728  mf_rho = md.pmesh_fem_of_variable(dl[2]);
6729  rho = &(md.complex_variable(dl[2]));
6730  size_type sl = gmm::vect_size(*rho);
6731  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6732  GMM_ASSERT1(sl == 1, "Bad format for density");
6733  }
6734 
6735  GMM_TRACE2("Mass matrix assembly for d_on_dt brick");
6736  if (dl.size() > 2 && mf_rho) {
6737  gmm::clear(matl[0]);
6738  asm_mass_matrix_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6739  gmm::scale(matl[0], scalar_type(1) / dt[0]);
6740  } else {
6741  gmm::clear(matl[0]);
6742  asm_mass_matrix(matl[0], mim, mf_u, rg);
6743  if (dl.size() > 2) gmm::scale(matl[0], (*rho)[0] / dt[0]);
6744  else gmm::scale(matl[0], scalar_type(1) / dt[0]);
6745  }
6746  }
6747  gmm::mult(matl[0], md.complex_variable(dl[0], 1), vecl[0]);
6748  }
6749 
6750  virtual std::string declare_volume_assembly_string
6751  (const model &, size_type, const model::varnamelist &,
6752  const model::varnamelist &) const {
6753  return std::string();
6754  }
6755 
6756  basic_d_on_dt_brick() {
6757  set_flags("Basic d/dt brick", true /* is linear*/,
6758  true /* is symmetric */, true /* is coercive */,
6759  true /* is real */, true /* is complex */,
6760  false /* compute each time */);
6761  }
6762 
6763  };
6764 
6766  (model &md, const mesh_im &mim, const std::string &varname,
6767  const std::string &dataname_dt, const std::string &dataname_rho,
6768  size_type region) {
6769  pbrick pbr = std::make_shared<basic_d_on_dt_brick>();
6770  model::termlist tl;
6771  tl.push_back(model::term_description(varname, varname, true));
6772  model::varnamelist dl(1, varname);
6773  dl.push_back(dataname_dt);
6774  if (dataname_rho.size())
6775  dl.push_back(dataname_rho);
6776  return md.add_brick(pbr, model::varnamelist(1, varname), dl, tl,
6777  model::mimlist(1, &mim), region);
6778  }
6779 
6780  // ----------------------------------------------------------------------
6781  //
6782  // Generic second order time derivative brick. The velocity is considered
6783  // as a separate data.
6784  // Represents M(U^{n+1} - U^n) / (\alpha dt^2) - M V^n / (\alpha dt)
6785  //
6786  // ----------------------------------------------------------------------
6787 
6788  struct basic_d2_on_dt2_brick : public virtual_brick {
6789 
6790  mutable scalar_type old_alphadt2;
6791 
6792  virtual void asm_real_tangent_terms(const model &md, size_type ib,
6793  const model::varnamelist &vl,
6794  const model::varnamelist &dl,
6795  const model::mimlist &mims,
6796  model::real_matlist &matl,
6797  model::real_veclist &vecl,
6798  model::real_veclist &,
6799  size_type region,
6800  build_version version) const {
6801  GMM_ASSERT1(matl.size() == 1,
6802  "Basic d2/dt2 brick has one and only one term");
6803  GMM_ASSERT1(mims.size() == 1,
6804  "Basic d2/dt2 brick need one and only one mesh_im");
6805  GMM_ASSERT1(vl.size() == 1 && dl.size() >= 4 && dl.size() <= 5,
6806  "Wrong number of variables for basic d2/dt2 brick");
6807 
6808  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
6809 
6810  recompute_matrix = recompute_matrix || md.is_var_newer_than_brick(dl[2], ib);
6811  if (dl.size() > 4) recompute_matrix || md.is_var_newer_than_brick(dl[4], ib);
6812 
6813  const model_real_plain_vector &dt = md.real_variable(dl[2]);
6814  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for time step");
6815  const model_real_plain_vector &alpha = md.real_variable(dl[3]);
6816  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for parameter alpha");
6817  scalar_type alphadt2 = gmm::sqr(dt[0]) * alpha[0];
6818 
6819  if (!recompute_matrix && alphadt2 != old_alphadt2)
6820  gmm::scale(matl[0], old_alphadt2/alphadt2);
6821  old_alphadt2 = alphadt2;
6822 
6823  if (recompute_matrix) {
6824  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6825  const mesh &m = mf_u.linked_mesh();
6826  const mesh_im &mim = *mims[0];
6827  mesh_region rg(region);
6828  m.intersect_with_mpi_region(rg);
6829 
6830  const mesh_fem *mf_rho = 0;
6831  const model_real_plain_vector *rho = 0;
6832 
6833  if (dl.size() > 4) {
6834  mf_rho = md.pmesh_fem_of_variable(dl[4]);
6835  rho = &(md.real_variable(dl[4]));
6836  size_type sl = gmm::vect_size(*rho);
6837  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6838  GMM_ASSERT1(sl == 1, "Bad format for density");
6839  }
6840 
6841  GMM_TRACE2("Mass matrix assembly for d2_on_dt2 brick");
6842  if (dl.size() > 4 && mf_rho) {
6843  gmm::clear(matl[0]);
6844  asm_mass_matrix_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6845  gmm::scale(matl[0], scalar_type(1) / alphadt2);
6846  } else {
6847  gmm::clear(matl[0]);
6848  asm_mass_matrix(matl[0], mim, mf_u, rg);
6849  if (dl.size() > 4) gmm::scale(matl[0], (*rho)[0] / alphadt2);
6850  else gmm::scale(matl[0], scalar_type(1) / alphadt2);
6851  }
6852  }
6853  gmm::mult(matl[0], md.real_variable(dl[0], 1), vecl[0]);
6854  gmm::mult_add(matl[0], gmm::scaled(md.real_variable(dl[1], 1), dt[0]),
6855  vecl[0]);
6856  }
6857 
6858  virtual void asm_complex_tangent_terms(const model &md, size_type ib,
6859  const model::varnamelist &vl,
6860  const model::varnamelist &dl,
6861  const model::mimlist &mims,
6862  model::complex_matlist &matl,
6863  model::complex_veclist &vecl,
6864  model::complex_veclist &,
6865  size_type region,
6866  build_version version) const {
6867  GMM_ASSERT1(matl.size() == 1,
6868  "Basic d2/dt2 brick has one and only one term");
6869  GMM_ASSERT1(mims.size() == 1,
6870  "Basic d2/dt2 brick need one and only one mesh_im");
6871  GMM_ASSERT1(vl.size() == 1 && dl.size() >= 4 && dl.size() <= 5,
6872  "Wrong number of variables for basic d2/dt2 brick");
6873 
6874  bool recompute_matrix = !((version & model::BUILD_ON_DATA_CHANGE) != 0);
6875 
6876  recompute_matrix = recompute_matrix || md.is_var_newer_than_brick(dl[2], ib);
6877  if (dl.size() > 4) recompute_matrix || md.is_var_newer_than_brick(dl[4], ib);
6878 
6879 
6880  const model_complex_plain_vector &dt = md.complex_variable(dl[2]);
6881  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for time step");
6882  const model_complex_plain_vector &alpha = md.complex_variable(dl[3]);
6883  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for parameter alpha");
6884  scalar_type alphadt2 = gmm::real(gmm::sqr(dt[0]) * alpha[0]);
6885 
6886  if (!recompute_matrix && alphadt2 != old_alphadt2)
6887  gmm::scale(matl[0], old_alphadt2/alphadt2);
6888  old_alphadt2 = alphadt2;
6889 
6890  if (recompute_matrix) {
6891  const mesh_fem &mf_u = md.mesh_fem_of_variable(vl[0]);
6892  const mesh &m = mf_u.linked_mesh();
6893  const mesh_im &mim = *mims[0];
6894  mesh_region rg(region);
6895  m.intersect_with_mpi_region(rg);
6896 
6897  const mesh_fem *mf_rho = 0;
6898  const model_complex_plain_vector *rho = 0;
6899 
6900  if (dl.size() > 4) {
6901  mf_rho = md.pmesh_fem_of_variable(dl[4]);
6902  rho = &(md.complex_variable(dl[4]));
6903  size_type sl = gmm::vect_size(*rho);
6904  if (mf_rho) sl = sl * mf_rho->get_qdim() / mf_rho->nb_dof();
6905  GMM_ASSERT1(sl == 1, "Bad format for density");
6906  }
6907 
6908  GMM_TRACE2("Mass matrix assembly for d2_on_dt2 brick");
6909  if (dl.size() > 4 && mf_rho) {
6910  gmm::clear(matl[0]);
6911  asm_mass_matrix_param(matl[0], mim, mf_u, *mf_rho, *rho, rg);
6912  gmm::scale(matl[0], scalar_type(1) / alphadt2);
6913  } else {
6914  gmm::clear(matl[0]);
6915  asm_mass_matrix(matl[0], mim, mf_u, rg);
6916  if (dl.size() > 4) gmm::scale(matl[0], (*rho)[0] / alphadt2);
6917  else gmm::scale(matl[0], scalar_type(1) / alphadt2);
6918  }
6919  }
6920  gmm::mult(matl[0], md.complex_variable(dl[0], 1), vecl[0]);
6921  gmm::mult_add(matl[0], gmm::scaled(md.complex_variable(dl[1], 1), dt[0]),
6922  vecl[0]);
6923  }
6924 
6925  virtual std::string declare_volume_assembly_string
6926  (const model &, size_type, const model::varnamelist &,
6927  const model::varnamelist &) const {
6928  return std::string();
6929  }
6930 
6931  basic_d2_on_dt2_brick() {
6932  set_flags("Basic d2/dt2 brick", true /* is linear*/,
6933  true /* is symmetric */, true /* is coercive */,
6934  true /* is real */, true /* is complex */,
6935  false /* compute each time */);
6936  }
6937 
6938  };
6939 
6941  (model &md, const mesh_im &mim, const std::string &varnameU,
6942  const std::string &datanameV,
6943  const std::string &dataname_dt,
6944  const std::string &dataname_alpha,
6945  const std::string &dataname_rho,
6946  size_type region) {
6947  pbrick pbr = std::make_shared<basic_d2_on_dt2_brick>();
6948  model::termlist tl;
6949  tl.push_back(model::term_description(varnameU, varnameU, true));
6950  model::varnamelist dl(1, varnameU);
6951  dl.push_back(datanameV);
6952  dl.push_back(dataname_dt);
6953  dl.push_back(dataname_alpha);
6954  if (dataname_rho.size())
6955  dl.push_back(dataname_rho);
6956  return md.add_brick(pbr, model::varnamelist(1, varnameU), dl, tl,
6957  model::mimlist(1, &mim), region);
6958  }
6959 
6960 
6961 
6962  // ----------------------------------------------------------------------
6963  //
6964  //
6965  // Standard time dispatchers
6966  //
6967  //
6968  // ----------------------------------------------------------------------
6969 
6970  // ----------------------------------------------------------------------
6971  //
6972  // theta-method dispatcher
6973  //
6974  // ----------------------------------------------------------------------
6975 
6976  void theta_method_dispatcher::set_dispatch_coeff(const model &md, size_type ib) const {
6977  scalar_type theta;
6978  if (md.is_complex())
6979  theta = gmm::real(md.complex_variable(param_names[0])[0]);
6980  else
6981  theta = md.real_variable(param_names[0])[0];
6982  // coefficient for the matrix term
6983  md.matrix_coeff_of_brick(ib) = theta;
6984  // coefficient for the standard rhs
6985  md.rhs_coeffs_of_brick(ib)[0] = theta;
6986  // coefficient for the additional rhs
6987  md.rhs_coeffs_of_brick(ib)[1] = (scalar_type(1) - theta);
6988  }
6989 
6990 
6991  void theta_method_dispatcher::next_real_iter
6992  (const model &md, size_type ib, const model::varnamelist &vl,
6993  const model::varnamelist &dl, model::real_matlist &matl,
6994  std::vector<model::real_veclist> &vectl,
6995  std::vector<model::real_veclist> &vectl_sym, bool first_iter) const {
6996  next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
6997  }
6998 
6999  void theta_method_dispatcher::next_complex_iter
7000  (const model &md, size_type ib, const model::varnamelist &vl,
7001  const model::varnamelist &dl,
7002  model::complex_matlist &matl,
7003  std::vector<model::complex_veclist> &vectl,
7004  std::vector<model::complex_veclist> &vectl_sym,
7005  bool first_iter) const {
7006  next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
7007  }
7008 
7009  void theta_method_dispatcher::asm_real_tangent_terms
7010  (const model &md, size_type ib, model::real_matlist &/* matl */,
7011  std::vector<model::real_veclist> &/* vectl */,
7012  std::vector<model::real_veclist> &/* vectl_sym */,
7013  build_version version) const
7014  { md.brick_call(ib, version, 0); }
7015 
7016  void theta_method_dispatcher::asm_complex_tangent_terms
7017  (const model &md, size_type ib, model::complex_matlist &/* matl */,
7018  std::vector<model::complex_veclist> &/* vectl */,
7019  std::vector<model::complex_veclist> &/* vectl_sym */,
7020  build_version version) const
7021  { md.brick_call(ib, version, 0); }
7022 
7023  theta_method_dispatcher::theta_method_dispatcher(const std::string &THETA)
7024  : virtual_dispatcher(2) {
7025  param_names.push_back(THETA);
7026  }
7027 
7029  (model &md, dal::bit_vector ibricks, const std::string &THETA) {
7030  pdispatcher pdispatch = std::make_shared<theta_method_dispatcher>(THETA);
7031  for (dal::bv_visitor i(ibricks); !i.finished(); ++i)
7032  md.add_time_dispatcher(i, pdispatch);
7033  }
7034 
7036  (model &md, const std::string &U, const std::string &V,
7037  const std::string &pdt, const std::string &ptheta) {
7038 
7039  // V^{n+1} = (1-1/theta)*V^n + (1/theta)*(U^{n+1} - U^n)/dt
7040 
7041  if (md.is_complex()) {
7042  const model_complex_plain_vector &dt = md.complex_variable(pdt);
7043  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for time step");
7044  const model_complex_plain_vector &theta = md.complex_variable(ptheta);
7045  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for parameter theta");
7046 
7047  gmm::copy(gmm::scaled(md.complex_variable(V, 1),
7048  scalar_type(1) - scalar_type(1) / theta[0]),
7049  md.set_complex_variable(V, 0));
7050  gmm::add(gmm::scaled(md.complex_variable(U, 0),
7051  scalar_type(1) / (theta[0]*dt[0])),
7052  md.set_complex_variable(V, 0));
7053  gmm::add(gmm::scaled(md.complex_variable(U, 1),
7054  -scalar_type(1) / (theta[0]*dt[0])),
7055  md.set_complex_variable(V, 0));
7056  } else {
7057  const model_real_plain_vector &dt = md.real_variable(pdt);
7058  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for time step");
7059  const model_real_plain_vector &theta = md.real_variable(ptheta);
7060  GMM_ASSERT1(gmm::vect_size(dt) == 1, "Bad format for parameter theta");
7061 
7062  gmm::copy(gmm::scaled(md.real_variable(V, 1),
7063  scalar_type(1) - scalar_type(1) / theta[0]),
7064  md.set_real_variable(V, 0));
7065  gmm::add(gmm::scaled(md.real_variable(U, 0),
7066  scalar_type(1) / (theta[0]*dt[0])),
7067  md.set_real_variable(V, 0));
7068  gmm::add(gmm::scaled(md.real_variable(U, 1),
7069  -scalar_type(1) / (theta[0]*dt[0])),
7070  md.set_real_variable(V, 0));
7071  }
7072  }
7073 
7074  // ----------------------------------------------------------------------
7075  //
7076  // Newmark scheme dispatcher
7077  //
7078  // ----------------------------------------------------------------------
7079 
7081  (model &md, size_type id2dt2b, const std::string &U, const std::string &V,
7082  const std::string &pdt, const std::string &ptwobeta,
7083  const std::string &pgamma) {
7084 
7085  md.disable_brick(id2dt2b);
7086 
7087  if (md.is_complex()) {
7088  complex_type twobeta = md.complex_variable(ptwobeta)[0];
7089  complex_type gamma = md.complex_variable(pgamma)[0];
7090  complex_type dt = md.complex_variable(pdt)[0];
7091 
7092  // Modification of the parameter for the theta-method.
7093  if (twobeta != gamma) {
7094  md.set_complex_variable(ptwobeta)[0] = gamma;
7095  md.set_dispatch_coeff(); // valid the change of coefficients.
7096  }
7097 
7098  // Computation of the residual (including the linear parts).
7099  md.assembly(model::BUILD_RHS_WITH_LIN);
7100 
7101  size_type nbdof = gmm::vect_size(md.complex_variable(U));
7102  model_complex_plain_vector W(nbdof), RHS(nbdof);
7103  gmm::copy(gmm::sub_vector(md.complex_rhs(), md.interval_of_variable(U)),
7104  RHS);
7105 
7106  // Compute the velocity. Inversion with CG.
7107  gmm::iteration iter(1e-12, 0, 100000);
7108  gmm::cg(md.linear_complex_matrix_term(id2dt2b, 0),
7109  W, RHS, gmm::identity_matrix(), iter);
7110  GMM_ASSERT1(iter.converged(), "Velocity not well computed");
7111  gmm::add(md.complex_variable(V, 1),
7112  gmm::scaled(W, complex_type(1)/(twobeta*dt)),
7113  md.set_complex_variable(V, 0));
7114 
7115  // Cancel the modification of the parameter for the theta-method.
7116  if (twobeta != gamma) {
7117  md.set_complex_variable(ptwobeta)[0] = twobeta;
7118  md.set_dispatch_coeff(); // valid the change of coefficients.
7119  }
7120 
7121 
7122  GMM_ASSERT1(false, "to be done");
7123  } else {
7124  scalar_type twobeta = md.real_variable(ptwobeta)[0];
7125  scalar_type gamma = md.real_variable(pgamma)[0];
7126  scalar_type dt = md.real_variable(pdt)[0];
7127 
7128 
7129 
7130  // Modification of the parameter for the theta-method.
7131  if (twobeta != gamma) {
7132  md.set_real_variable(ptwobeta)[0] = gamma;
7133  md.set_dispatch_coeff(); // valid the change of coefficients.
7134  }
7135 
7136  // Computation of the residual (including the linear parts).
7137  md.assembly(model::BUILD_RHS_WITH_LIN);
7138 
7139  size_type nbdof = gmm::vect_size(md.real_variable(U));
7140  model_real_plain_vector W(nbdof), RHS(nbdof);
7141  gmm::copy(gmm::sub_vector(md.real_rhs(), md.interval_of_variable(U)),
7142  RHS);
7143 
7144  // Compute the velocity. Inversion with CG.
7145  gmm::iteration iter(1e-12, 0, 100000);
7146  gmm::cg(md.linear_real_matrix_term(id2dt2b, 0),
7147  W, RHS, gmm::identity_matrix(), iter);
7148  GMM_ASSERT1(iter.converged(), "Velocity not well computed");
7149  gmm::add(md.real_variable(V, 1),
7150  gmm::scaled(W, scalar_type(1)/(twobeta*dt)),
7151  md.set_real_variable(V, 0));
7152 
7153  // Cancel the modification of the parameter for the theta-method.
7154  if (twobeta != gamma) {
7155  md.set_real_variable(ptwobeta)[0] = twobeta;
7156  md.set_dispatch_coeff(); // valid the change of coefficients.
7157  }
7158 
7159  }
7160  md.enable_brick(id2dt2b);
7161  }
7162 
7163 
7164  // ----------------------------------------------------------------------
7165  //
7166  // midpoint dispatcher
7167  //
7168  // ----------------------------------------------------------------------
7169 
7170 
7171  class midpoint_dispatcher : public virtual_dispatcher {
7172 
7173  gmm::uint64_type id_num;
7174 
7175  public :
7176 
7177  typedef model::build_version build_version;
7178 
7179  void set_dispatch_coeff(const model &md, size_type ib) const {
7180  md.matrix_coeff_of_brick(ib) = scalar_type(1)/scalar_type(2);
7181  md.rhs_coeffs_of_brick(ib)[0] = scalar_type(1);
7182  md.rhs_coeffs_of_brick(ib)[1] = scalar_type(1)/scalar_type(2);
7183  }
7184 
7185  template <typename MATLIST, typename VECTLIST>
7186  inline void next_iter(const model &md, size_type ib,
7187  const model::varnamelist &vl,
7188  const model::varnamelist &dl,
7189  MATLIST &/* matl */,
7190  VECTLIST &vectl, VECTLIST &vectl_sym,
7191  bool first_iter) const {
7192 
7193  pbrick pbr = md.brick_pointer(ib);
7194 
7195  if (first_iter) { // For the moment, temporaries are deleted by
7196  // model::first_iter before the call to virtual_dispatcher::next_iter
7197  if (!(pbr->is_linear()))
7198  md.add_temporaries(vl, id_num); // add temporaries for all variables
7199  md.add_temporaries(dl, id_num); // add temporaries for versionned data
7200  for (auto &&v : vectl[1]) gmm::clear(v);
7201  for (auto &&v : vectl_sym[1]) gmm::clear(v);
7202  }
7203 
7204  if (pbr->is_linear()) { // If the problem is linear, add the term
7205  // coming from the previous iteration as a second rhs.
7206  // This rhs is only used for this.
7207  if (first_iter) md.update_brick(ib, model::BUILD_RHS);
7208  for (auto &&v : vectl[1]) gmm::clear(v);
7209  for (auto &&v : vectl_sym[1]) gmm::clear(v);
7210  md.linear_brick_add_to_rhs(ib, 1, 0);
7211  }
7212  }
7213 
7214  void next_real_iter
7215  (const model &md, size_type ib, const model::varnamelist &vl,
7216  const model::varnamelist &dl, model::real_matlist &matl,
7217  std::vector<model::real_veclist> &vectl,
7218  std::vector<model::real_veclist> &vectl_sym, bool first_iter) const {
7219  next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
7220  }
7221 
7222  void next_complex_iter
7223  (const model &md, size_type ib, const model::varnamelist &vl,
7224  const model::varnamelist &dl,
7225  model::complex_matlist &matl,
7226  std::vector<model::complex_veclist> &vectl,
7227  std::vector<model::complex_veclist> &vectl_sym,
7228  bool first_iter) const {
7229  next_iter(md, ib, vl, dl, matl, vectl, vectl_sym, first_iter);
7230  }
7231 
7232  void asm_real_tangent_terms
7233  (const model &md, size_type ib, model::real_matlist &/* matl */,
7234  std::vector<model::real_veclist> &vectl,
7235  std::vector<model::real_veclist> &vectl_sym,
7236  build_version version) const {
7237 
7238  scalar_type half = scalar_type(1)/scalar_type(2);
7239  pbrick pbr = md.brick_pointer(ib);
7240  size_type ind;
7241 
7242  const model::varnamelist &vl = md.varnamelist_of_brick(ib);
7243  const model::varnamelist &dl = md.datanamelist_of_brick(ib);
7244 
7245  if (!(pbr->is_linear())) { // compute the mean variables
7246  for (size_type i = 0; i < vl.size(); ++i) {
7247  bool is_uptodate = md.temporary_uptodate(vl[i], id_num, ind);
7248  if (!is_uptodate && ind != size_type(-1))
7249  gmm::add(gmm::scaled(md.real_variable(vl[i], 0), half),
7250  gmm::scaled(md.real_variable(vl[i], 1), half),
7251  md.set_real_variable(vl[i], ind));
7252  md.set_default_iter_of_variable(vl[i], ind);
7253  }
7254  }
7255 
7256  // compute the mean data
7257  for (size_type i = 0; i < dl.size(); ++i) {
7258  bool is_uptodate = md.temporary_uptodate(dl[i], id_num, ind);
7259  if (!is_uptodate && ind != size_type(-1)) {
7260  gmm::add(gmm::scaled(md.real_variable(dl[i], 0), half),
7261  gmm::scaled(md.real_variable(dl[i], 1), half),
7262  md.set_real_variable(dl[i], ind));
7263  }
7264  md.set_default_iter_of_variable(dl[i], ind);
7265  }
7266 
7267  // call the brick for the mid-time step.
7268  md.brick_call(ib, version, 0);
7269  if (pbr->is_linear()) { // update second rhs (is updated by next_iter
7270  // but the call to the brick may have changed the matrices.
7271  for (auto &&v : vectl[1]) gmm::clear(v);
7272  for (auto &&v : vectl_sym[1]) gmm::clear(v);
7273  md.linear_brick_add_to_rhs(ib, 1, 1);
7274  }
7275 
7276  md.reset_default_iter_of_variables(dl);
7277  if (!(pbr->is_linear()))
7278  md.reset_default_iter_of_variables(vl);
7279  }
7280 
7281  virtual void asm_complex_tangent_terms
7282  (const model &md, size_type ib, model::complex_matlist &/* matl */,
7283  std::vector<model::complex_veclist> &vectl,
7284  std::vector<model::complex_veclist> &vectl_sym,
7285  build_version version) const {
7286 
7287  scalar_type half = scalar_type(1)/scalar_type(2);
7288  pbrick pbr = md.brick_pointer(ib);
7289  size_type ind;
7290 
7291  const model::varnamelist &vl = md.varnamelist_of_brick(ib);
7292  const model::varnamelist &dl = md.datanamelist_of_brick(ib);
7293 
7294  if (!(pbr->is_linear())) { // compute the mean variables
7295  for (size_type i = 0; i < vl.size(); ++i) {
7296  bool is_uptodate = md.temporary_uptodate(vl[i], id_num, ind);
7297  if (!is_uptodate && ind != size_type(-1))
7298  gmm::add(gmm::scaled(md.complex_variable(vl[i], 0), half),
7299  gmm::scaled(md.complex_variable(vl[i], 1), half),
7300  md.set_complex_variable(vl[i], ind));
7301  md.set_default_iter_of_variable(vl[i], ind);
7302  }
7303  }
7304 
7305  // compute the mean data
7306  for (size_type i = 0; i < dl.size(); ++i) {
7307  bool is_uptodate = md.temporary_uptodate(dl[i], id_num, ind);
7308  if (!is_uptodate && ind != size_type(-1)) {
7309  gmm::add(gmm::scaled(md.complex_variable(dl[i], 0), half),
7310  gmm::scaled(md.complex_variable(dl[i], 1), half),
7311  md.set_complex_variable(dl[i], ind));
7312  }
7313  md.set_default_iter_of_variable(dl[i], ind);
7314  }
7315 
7316  // call the brick for the mid-time step.
7317  md.brick_call(ib, version, 0);
7318  if (pbr->is_linear()) { // update second rhs (is updated by next_iter
7319  // but the call to the brick may have changed the matrices.
7320  for (auto &&v : vectl[1]) gmm::clear(v);
7321  for (auto &&v : vectl_sym[1]) gmm::clear(v);
7322  md.linear_brick_add_to_rhs(ib, 1, 1);
7323  }
7324 
7325  md.reset_default_iter_of_variables(dl);
7326  if (!(pbr->is_linear()))
7327  md.reset_default_iter_of_variables(vl);
7328  }
7329 
7330  midpoint_dispatcher() : virtual_dispatcher(2)
7331  { id_num = act_counter(); }
7332 
7333  };
7334 
7335  void add_midpoint_dispatcher(model &md, dal::bit_vector ibricks) {
7336  pdispatcher pdispatch = std::make_shared<midpoint_dispatcher>();
7337  for (dal::bv_visitor i(ibricks); !i.finished(); ++i)
7338  md.add_time_dispatcher(i, pdispatch);
7339  }
7340 
7341 
7342 } /* end of namespace getfem. */
7343 
getfem::model::is_complex
bool is_complex() const
Boolean which says if the model deals with real or complex unknowns and data.
Definition: getfem_models.h:562
getfem::change_penalization_coeff
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.
Definition: getfem_models.cc:4827
getfem::add_nonlinear_twodomain_term
size_type APIDECL add_nonlinear_twodomain_term(model &md, const mesh_im &mim, const std::string &expr, size_type region, const std::string &secondary_domain, bool is_sym=false, bool is_coercive=false, const std::string &brickname="")
Adds a nonlinear term given by a weak form language expression like add_nonlinear_term function but f...
Definition: getfem_models.cc:3670
getfem::mult_varname_Dirichlet
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...
Definition: getfem_models.cc:4690
getfem::mesh_fem::get_qdim
virtual dim_type get_qdim() const
Return the Q dimension.
Definition: getfem_mesh_fem.h:312
getfem::model::variable_exists
bool variable_exists(const std::string &name) const
States if a name corresponds to a declared variable.
Definition: getfem_models.cc:943
getfem::model::assembly
virtual void assembly(build_version version)
Assembly of the tangent system taking into account the terms from all bricks.
Definition: getfem_models.cc:2328
getfem::model::add_mim_to_brick
void add_mim_to_brick(size_type ib, const mesh_im &mim)
Add an integration method to a brick.
Definition: getfem_models.cc:1078
getfem::add_normal_Dirichlet_condition_with_multipliers
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...
Definition: getfem_models.cc:4715
getfem::compute_isotropic_linearized_Von_Mises_pstrain
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 ...
Definition: getfem_models.cc:6241
getfem::add_generalized_Dirichlet_condition_with_penalization
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.
Definition: getfem_models.cc:4806
getfem::add_linear_twodomain_term
size_type APIDECL add_linear_twodomain_term(model &md, const mesh_im &mim, const std::string &expr, size_type region, const std::string &secondary_domain, bool is_sym=false, bool is_coercive=false, const std::string &brickname="", bool return_if_nonlin=false)
Adds a linear term given by a weak form language expression like add_linear_term function but for an ...
Definition: getfem_models.cc:3579
getfem::mesh::region
const mesh_region region(size_type id) const
Return the region of index 'id'.
Definition: getfem_mesh.h:421
getfem::model::macro_exists
bool macro_exists(const std::string &name) const
Says if a macro of that name has been defined.
Definition: getfem_models.h:898
getfem::add_midpoint_dispatcher
void APIDECL add_midpoint_dispatcher(model &md, dal::bit_vector ibricks)
Add a midpoint time dispatcher to a list of bricks.
Definition: getfem_models.cc:7335
getfem::im_data::nb_tensor_elem
size_type nb_tensor_elem() const
sum of tensor elements, M(3,3) will have 3*3=9 elements
Definition: getfem_im_data.cc:229
getfem::asm_mass_matrix_param
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...
Definition: getfem_assembling.h:765
getfem::asm_stokes_B
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 .
Definition: getfem_assembling.h:1074
gmm::resize
void resize(M &v, size_type m, size_type n)
*‍/
Definition: gmm_blas.h:231
getfem::asm_stiffness_matrix_for_laplacian
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.
Definition: getfem_assembling.h:1152
bgeot::size_type
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
gmm::clear
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
getfem::model::is_linear
bool is_linear() const
Return true if all the model terms are linear.
Definition: getfem_models.h:580
getfem::model::disable_brick
void disable_brick(size_type ib)
Disable a brick.
Definition: getfem_models.h:512
getfem::model::pmesh_fem_of_variable
const mesh_fem * pmesh_fem_of_variable(const std::string &name) const
Gives a pointer to the mesh_fem of a variable if any.
Definition: getfem_models.cc:2883
getfem::mesh_im
Describe an integration method linked to a mesh.
Definition: getfem_mesh_im.h:47
getfem::model::check_brick_stiffness_rhs
void check_brick_stiffness_rhs(size_type ind_brick) const
check consistency of RHS and Stiffness matrix for brick with
Definition: getfem_models.cc:3085
getfem::add_pointwise_constraints_with_penalization
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.
Definition: getfem_models.cc:5347
getfem_generic_assembly_tree.h
Compilation and execution operations.
getfem::asm_stiffness_matrix_for_homogeneous_laplacian_componentwise
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 .
Definition: getfem_assembling.h:1140
getfem::add_Dirichlet_condition_with_multipliers
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.
Definition: getfem_models.cc:4656
getfem::mesh_region::region_is_faces_of
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.
Definition: getfem_mesh_region.cc:467
getfem::add_linear_term
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, const std::string &brickname="", bool return_if_nonlin=false)
Add a term given by the weak form language expression expr which will be assembled in region region a...
Definition: getfem_models.cc:3571
getfem::model::disable_variable
void disable_variable(const std::string &name)
Disable a variable (and its attached mutlipliers).
Definition: getfem_models.cc:922
gmm_solver_cg.h
Conjugate gradient iterative solver.
getfem::model::new_name
std::string new_name(const std::string &name)
Gives a non already existing variable name begining by name.
Definition: getfem_models.cc:175
getfem::model::delete_variable
void delete_variable(const std::string &varname)
Delete a variable or data of the model.
Definition: getfem_models.cc:984
getfem::model::add_fixed_size_data
void add_fixed_size_data(const std::string &name, size_type size, size_type niter=1)
Add a fixed size data to the model.
Definition: getfem_models.cc:758
getfem::add_nonlinear_term
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, const std::string &brickname="")
Add a nonlinear term given by the weak form language expression expr which will be assembled in regio...
Definition: getfem_models.cc:3663
getfem::add_Dirichlet_condition_with_Nitsche_method
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.
Definition: getfem_models.cc:5025
getfem::model::enable_brick
void enable_brick(size_type ib)
Enable a brick.
Definition: getfem_models.h:518
getfem::asm_stiffness_matrix_for_homogeneous_scalar_elliptic_componentwise
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.
Definition: getfem_assembling.h:1229
getfem::asm_mass_matrix
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)
Definition: getfem_assembling.h:697
getfem::add_generic_elliptic_brick
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.
Definition: getfem_models.cc:3931
getfem::add_theta_method_dispatcher
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.
Definition: getfem_models.cc:7029
getfem::add_generalized_Dirichlet_condition_with_multipliers
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.
Definition: getfem_models.cc:4770
getfem::model::enable_variable
void enable_variable(const std::string &name, bool enabled=true)
Enable a variable (and its attached mutlipliers).
Definition: getfem_models.cc:926
getfem::add_mass_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 ( ).
Definition: getfem_models.cc:6511
getfem::interpolate_transformation_neighbor_instance
pinterpolate_transformation interpolate_transformation_neighbor_instance()
Create a new instance of a transformation corresponding to the interpolation on the neighbor element.
Definition: getfem_generic_assembly_interpolation.cc:866
getfem::add_linear_incompressibility
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.
Definition: getfem_models.cc:6362
getfem::velocity_update_for_order_two_theta_method
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 ...
Definition: getfem_models.cc:7036
getfem::mesh_fem
Describe a finite element method linked to a mesh.
Definition: getfem_mesh_fem.h:148
getfem::model::listbricks
void listbricks(std::ostream &ost, size_type base_id=0) const
List the model bricks.
Definition: getfem_models.cc:1755
getfem::PREFIX_OLD
const auto PREFIX_OLD
A prefix to refer to the previous version of a variable.
Definition: getfem_models.h:98
getfem::model::change_terms_of_brick
void change_terms_of_brick(size_type ib, const termlist &terms)
Change the term list of a brick.
Definition: getfem_models.cc:1085
getfem::interpolation
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.
Definition: getfem_interpolation.h:693
getfem::add_Helmholtz_brick
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.
Definition: getfem_models.cc:5501
getfem::model::is_data
bool is_data(const std::string &name) const
States if a name corresponds to a declared data or disabled variable.
Definition: getfem_models.cc:235
getfem::model
`‘Model’' variables store the variables, the data and the description of a model.
Definition: getfem_models.h:114
getfem::asm_homogeneous_source_term
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).
Definition: getfem_assembling.h:893
getfem::model::add_fixed_size_variable
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.
Definition: getfem_models.cc:722
getfem::model::resize_fixed_size_variable
void resize_fixed_size_variable(const std::string &name, size_type size)
Resize a fixed size variable (or data) of the model.
Definition: getfem_models.cc:741
gmm::iteration
The Iteration object calculates whether the solution has reached the desired accuracy,...
Definition: gmm_iter.h:53
getfem::model::change_mims_of_brick
void change_mims_of_brick(size_type ib, const mimlist &ml)
Change the mim list of a brick.
Definition: getfem_models.cc:1116
getfem
GEneric Tool for Finite Element Methods.
Definition: getfem_accumulated_distro.h:46
getfem::model::add_initialized_tensor_data
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.
Definition: getfem_models.cc:791
getfem::model::complex_rhs
const model_complex_plain_vector & complex_rhs() const
Gives access to the right hand side of the tangent linear system.
Definition: getfem_models.h:978
getfem::asm_homogeneous_Helmholtz
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 ).
Definition: getfem_assembling.h:1344
getfem::add_normal_source_term_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.
Definition: getfem_models.cc:4264
getfem_models.h
Model representation in Getfem.
getfem::add_basic_d_on_dt_brick
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 ( ).
Definition: getfem_models.cc:6766
getfem::model::varname_of_brick
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.
Definition: getfem_models.cc:1739
getfem_generic_assembly.h
A language for generic assembly of pde boundary value problems.
getfem::compute_isotropic_linearized_Von_Mises_pstress
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 ...
Definition: getfem_models.cc:6256
getfem::asm_normal_source_term
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).
Definition: getfem_assembling.h:905
getfem::add_pointwise_constraints_with_given_multipliers
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.
Definition: getfem_models.cc:5369
getfem::model::delete_brick
void delete_brick(size_type ib)
Delete the brick of index ib from the model.
Definition: getfem_models.cc:955
getfem::model::is_true_data
bool is_true_data(const std::string &name) const
States if a name corresponds to a declared data.
Definition: getfem_models.cc:243
getfem::model::touch_brick
void touch_brick(size_type ib)
Force the re-computation of a brick for the next assembly.
Definition: getfem_models.h:1028
getfem::asm_source_term
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).
Definition: getfem_assembling.h:877
getfem::velocity_update_for_Newmark_scheme
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 ...
Definition: getfem_models.cc:7081
getfem::model::add_interpolate_transformation
void add_interpolate_transformation(const std::string &name, pinterpolate_transformation ptrans)
Add an interpolate transformation to the model to be used with the generic assembly.
Definition: getfem_models.h:1103
getfem::model::add_fem_variable
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.
Definition: getfem_models.cc:830
getfem::model::add_im_variable
void add_im_variable(const std::string &name, const im_data &imd, size_type niter=1)
Add variable defined at integration points.
Definition: getfem_models.cc:805
getfem::model::add_initialized_matrix_data
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.
Definition: getfem_models.cc:775
getfem_accumulated_distro.h
Distribution of assembly results (matrices/vectors) for parallel assembly.
getfem::asm_stiffness_matrix_for_laplacian_componentwise
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...
Definition: getfem_assembling.h:1165
getfem::omp_distribute< model_real_sparse_matrix >
getfem::model::add_affine_dependent_variable
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.
Definition: getfem_models.cc:852
getfem::model::has_internal_variables
bool has_internal_variables() const
Return true if the model has at least one internal variable.
Definition: getfem_models.h:569
GETFEM_OMP_PARALLEL
#define GETFEM_OMP_PARALLEL(body)
Organizes a proper parallel omp section:
Definition: getfem_omp.h:483
getfem::pfem
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:244
getfem::model::mesh_fem_of_variable
const mesh_fem & mesh_fem_of_variable(const std::string &name) const
Gives the access to the mesh_fem of a variable if any.
Definition: getfem_models.cc:2877
getfem::asm_homogeneous_normal_source_term
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).
Definition: getfem_assembling.h:919
getfem::model::add_brick
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.
Definition: getfem_models.cc:1029
getfem::asm_stiffness_matrix_for_scalar_elliptic_componentwise
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.
Definition: getfem_assembling.h:1217
getfem_derivatives.h
Compute the gradient of a field on a getfem::mesh_fem.
getfem::mesh_fem::linked_mesh
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
Definition: getfem_mesh_fem.h:279
getfem::model::change_data_of_brick
void change_data_of_brick(size_type ib, const varnamelist &vl)
Change the data list of a brick.
Definition: getfem_models.cc:1108
getfem::model::next_iter
virtual void next_iter()
For transient problems.
Definition: getfem_models.cc:1967
getfem::model::complex_variable
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.
Definition: getfem_models.cc:2974
getfem::model::add_macro
void add_macro(const std::string &name, const std::string &expr)
Add a macro definition for the high generic assembly language.
Definition: getfem_models.cc:947
getfem::im_data::nb_filtered_index
size_type nb_filtered_index() const
Total numbers of filtered index (integration points)
Definition: getfem_im_data.h:118
gmm_range_basis.h
Extract a basis of the range of a (large sparse) matrix from the columns of this matrix.
getfem::model::change_variables_of_brick
void change_variables_of_brick(size_type ib, const varnamelist &vl)
Change the variable list of a brick.
Definition: getfem_models.cc:1100
getfem::model::is_disabled_variable
bool is_disabled_variable(const std::string &name) const
States if a variable is disabled (treated as data).
Definition: getfem_models.cc:226
getfem::model::is_internal_variable
bool is_internal_variable(const std::string &name) const
States if a variable is condensed out of the global system.
Definition: getfem_models.cc:247
getfem::model::del_macro
void del_macro(const std::string &name)
Delete a previously defined macro definition.
Definition: getfem_models.cc:952
getfem::model::add_fem_data
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.
Definition: getfem_models.cc:866
getfem::model::real_rhs
const model_real_plain_vector & real_rhs(bool with_internal=false) const
Gives access to the right hand side of the tangent linear system.
Definition: getfem_models.h:932
getfem::asm_stiffness_matrix_for_scalar_elliptic
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.
Definition: getfem_assembling.h:1195
gmm::range_basis
void range_basis(const Mat &B, std::set< size_type > &columns, double EPS=1E-12)
Range Basis : Extract a basis of the range of a (large sparse) matrix selecting some column vectors o...
Definition: gmm_range_basis.h:490
getfem::model::listvar
void listvar(std::ostream &ost) const
List the model variables and constant.
Definition: getfem_models.cc:659
getfem::model::add_filtered_fem_variable
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.
Definition: getfem_models.cc:841
bgeot::alpha
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree .
Definition: bgeot_poly.cc:47
getfem::asm_stiffness_matrix_for_vector_elliptic
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.
Definition: getfem_assembling.h:1243
getfem::asm_Helmholtz
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 ).
Definition: getfem_assembling.h:1274
getfem::virtual_brick::asm_real_tangent_terms
virtual void asm_real_tangent_terms(const model &, size_type, const model::varnamelist &, const model::varnamelist &, const model::mimlist &, model::real_matlist &, model::real_veclist &, model::real_veclist &, size_type, build_version) const
Assembly of bricks real tangent terms.
Definition: getfem_models.h:1490
getfem::add_Dirichlet_condition_with_penalization
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.
Definition: getfem_models.cc:4695
getfem::add_normal_Dirichlet_condition_with_Nitsche_method
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.
Definition: getfem_models.cc:5059
getfem::interpolation_von_mises_or_tresca
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)
Definition: getfem_derivatives.h:259
getfem::asm_lumped_mass_matrix_for_first_order_param
void asm_lumped_mass_matrix_for_first_order_param(MAT &M, const mesh_im &mim, const mesh_fem &mf_u, const mesh_fem &mf_data, const VECT &F, const mesh_region &rg=mesh_region::all_convexes())
lumped mass matrix assembly with an additional parameter (on the whole mesh or on the specified bound...
Definition: getfem_assembling.h:866
getfem::mesh
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:95
getfem::im_data
im_data provides indexing to the integration points of a mesh im object.
Definition: getfem_im_data.h:69
getfem_interpolation.h
Interpolation of fields from a mesh_fem onto another.
getfem::add_generalized_Dirichlet_condition_with_Nitsche_method
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.
Definition: getfem_models.cc:5092
getfem::add_twodomain_source_term
size_type APIDECL add_twodomain_source_term(model &md, const mesh_im &mim, const std::string &expr, size_type region, const std::string &secondary_domain, const std::string &brickname=std::string(), const std::string &directvarname=std::string(), const std::string &directdataname=std::string(), bool return_if_nonlin=false)
Adds a source term given by a weak form language expression like add_source_term function but for an ...
Definition: getfem_models.cc:3419
getfem::model::add_internal_im_variable
void add_internal_im_variable(const std::string &name, const im_data &imd)
Add internal variable, defined at integration points and condensed.
Definition: getfem_models.cc:815
getfem::virtual_brick::real_pre_assembly_in_serial
virtual void real_pre_assembly_in_serial(const model &, size_type, const model::varnamelist &, const model::varnamelist &, const model::mimlist &, model::real_matlist &, model::real_veclist &, model::real_veclist &, size_type, build_version) const
Peform any pre assembly action for real term assembly.
Definition: getfem_models.h:1534
getfem::virtual_brick
The virtual brick has to be derived to describe real model bricks.
Definition: getfem_models.h:1437
getfem::add_normal_Dirichlet_condition_with_penalization
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...
Definition: getfem_models.cc:4749
getfem::model::Neumann_term
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.
Definition: getfem_models.cc:2279
getfem::model::set_complex_variable
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.
Definition: getfem_models.cc:3030
getfem::add_source_term_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.
Definition: getfem_models.cc:4112
getfem::context_dependencies::context_check
bool context_check() const
return true if update_from_context was called
Definition: getfem_context.h:126
getfem::add_isotropic_linearized_elasticity_brick_pstrain
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 ( ).
Definition: getfem_models.cc:6127
getfem::add_isotropic_linearized_elasticity_brick
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 ( ).
Definition: getfem_models.cc:6091
getfem::add_pointwise_constraints_with_multipliers
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.
Definition: getfem_models.cc:5385
getfem::asm_stiffness_matrix_for_homogeneous_vector_elliptic
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.
Definition: getfem_assembling.h:1257
getfem::accumulated_distro
Takes a matrix or vector, or vector of matrices or vectors and creates an empty copy on each thread.
Definition: getfem_accumulated_distro.h:159
getfem::asm_lumped_mass_matrix_for_first_order
void asm_lumped_mass_matrix_for_first_order(const MAT &M, const mesh_im &mim, const mesh_fem &mf1, const mesh_region &rg=mesh_region::all_convexes())
lumped mass matrix assembly (on the whole mesh or on the specified boundary)
Definition: getfem_assembling.h:853
getfem::virtual_brick::real_post_assembly_in_serial
virtual void real_post_assembly_in_serial(const model &, size_type, const model::varnamelist &, const model::varnamelist &, const model::mimlist &, model::real_matlist &, model::real_veclist &, model::real_veclist &, size_type, build_version) const
Peform any post assembly action for real terms.
Definition: getfem_models.h:1562
gmm_condition_number.h
computation of the condition number of dense matrices.
getfem::add_basic_d2_on_dt2_brick
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 ( ).
Definition: getfem_models.cc:6941
getfem::model::first_iter
virtual void first_iter()
For transient problems.
Definition: getfem_models.cc:1945
getfem::add_isotropic_linearized_elasticity_brick_pstress
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 ( ).
Definition: getfem_models.cc:6156
getfem::add_Laplacian_brick
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)).
Definition: getfem_models.cc:3906
getfem::pbrick
std::shared_ptr< const virtual_brick > pbrick
type of pointer on a brick
Definition: getfem_models.h:49
getfem::add_Dirichlet_condition_with_simplification
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.
Definition: getfem_models.cc:5008
getfem::add_Fourier_Robin_brick
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.
Definition: getfem_models.cc:5622
getfem::add_lumped_mass_brick_for_first_order
size_type APIDECL add_lumped_mass_brick_for_first_order(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr_rho=std::string(), size_type region=size_type(-1))
Lumped mass brick for first order.
Definition: getfem_models.cc:6601
getfem::is_old
bool is_old(const std::string &name)
Does the variable have Old_ prefix.
Definition: getfem_models.cc:218
gmm::mult_add
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1781
getfem::mesh_fem::nb_dof
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
Definition: getfem_mesh_fem.h:562
getfem::virtual_brick::check_stiffness_matrix_and_rhs
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
Definition: getfem_models.cc:3128
getfem::model::set_real_variable
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.
Definition: getfem_models.cc:3002
getfem::model::dataname_of_brick
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.
Definition: getfem_models.cc:1747
getfem::model::add_multiplier
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.
Definition: getfem_models.cc:884
getfem::model::change_update_flag_of_brick
void change_update_flag_of_brick(size_type ib, bool flag)
Change the update flag of a brick.
Definition: getfem_models.cc:1123
getfem::model::add_time_dispatcher
void add_time_dispatcher(size_type ibrick, pdispatcher pdispatch)
Add a time dispacther to a brick.
Definition: getfem_models.cc:1711
getfem::asm_qu_term
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
Definition: getfem_assembling.h:944
getfem::model::nb_dof
size_type nb_dof(bool with_internal=false) const
Total number of degrees of freedom in the model.
Definition: getfem_models.cc:295
getfem::model::real_variable
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.
Definition: getfem_models.cc:2948
getfem::model::add_im_data
void add_im_data(const std::string &name, const im_data &imd, size_type niter=1)
Add data defined at integration points.
Definition: getfem_models.cc:821
getfem::asm_stiffness_matrix_for_homogeneous_laplacian
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 .
Definition: getfem_assembling.h:1110
getfem_assembling.h
Miscelleanous assembly routines for common terms. Use the low-level generic assembly....
getfem::asm_stiffness_matrix_for_homogeneous_scalar_elliptic
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.
Definition: getfem_assembling.h:1206
getfem::classical_mesh_fem
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.
Definition: getfem_mesh_fem.cc:862
getfem::add_source_term
size_type APIDECL add_source_term(model &md, const mesh_im &mim, const std::string &expr, size_type region=size_type(-1), const std::string &brickname=std::string(), const 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...
Definition: getfem_models.cc:3411
getfem::no_old_prefix_name
std::string no_old_prefix_name(const std::string &name)
Strip the variable name from prefix Old_ if it has one.
Definition: getfem_models.cc:222