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