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