GetFEM  5.4.2
getfem_generic_assembly_workspace.cc
1 /*===========================================================================
2 
3  Copyright (C) 2013-2020 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
24 #include "getfem/getfem_generic_assembly_compile_and_exec.h"
25 #include "getfem/getfem_generic_assembly_functions_and_operators.h"
26 
27 namespace getfem {
28 
29  //=========================================================================
30  // Structure dealing with user defined environment : constant, variables,
31  // functions, operators.
32  //=========================================================================
33 
34 
35  void ga_workspace::init() {
36  // allocate own storage for K an V to be used unless/until external
37  // storage is provided with set_assembled_matrix/vector
38  K = std::make_shared<model_real_sparse_matrix>(2,2);
39  V = std::make_shared<base_vector>(2);
40  KQJpr = std::make_shared<model_real_sparse_matrix>(2,2);
41  // add default transformations
42  add_interpolate_transformation // deprecated version
44  add_interpolate_transformation
45  ("neighbor_element", interpolate_transformation_neighbor_instance());
46 
47  ga_tree tree1;
48  pstring s1 = std::make_shared<std::string>("Hess_u");
49  tree1.add_name(s1->c_str(), 6, 0, s1);
50  tree1.root->name = "u";
51  tree1.root->op_type = GA_NAME;
52  tree1.root->node_type = GA_NODE_MACRO_PARAM;
53  tree1.root->nbc1 = 0;
54  tree1.root->nbc2 = ga_parse_prefix_operator(*s1);
55  tree1.root->nbc3 = ga_parse_prefix_test(*s1);
56  ga_macro gam1("Hess", tree1, 1);
57  macro_dict.add_macro(gam1);
58 
59  ga_tree tree2;
60  pstring s2 = std::make_shared<std::string>("Div_u");
61  tree2.add_name(s2->c_str(), 5, 0, s2);
62  tree2.root->name = "u";
63  tree2.root->op_type = GA_NAME;
64  tree2.root->node_type = GA_NODE_MACRO_PARAM;
65  tree2.root->nbc1 = 0;
66  tree2.root->nbc2 = ga_parse_prefix_operator(*s2);
67  tree2.root->nbc3 = ga_parse_prefix_test(*s2);
68  ga_macro gam2("Div", tree2, 1);
69  macro_dict.add_macro(gam2);
70  }
71 
72  // variables and variable groups
73  void ga_workspace::add_fem_variable
74  (const std::string &name, const mesh_fem &mf,
75  const gmm::sub_interval &I, const model_real_plain_vector &VV) {
76  GMM_ASSERT1(nb_intern_dof == 0 || I.last() < first_intern_dof,
77  "The provided interval overlaps with internal dofs");
78  nb_prim_dof = std::max(nb_prim_dof, I.last());
79  variables.emplace(name, var_description(true, &mf, 0, I, &VV, 1));
80  }
81 
82  void ga_workspace::add_im_variable
83  (const std::string &name, const im_data &imd,
84  const gmm::sub_interval &I, const model_real_plain_vector &VV) {
85  GMM_ASSERT1(nb_intern_dof == 0 || I.last() <= first_intern_dof,
86  "The provided interval overlaps with internal dofs");
87  nb_prim_dof = std::max(nb_prim_dof, I.last());
88  variables.emplace(name, var_description(true, 0, &imd, I, &VV, 1));
89  }
90 
91  void ga_workspace::add_internal_im_variable
92  (const std::string &name, const im_data &imd,
93  const gmm::sub_interval &I, const model_real_plain_vector &VV) {
94  GMM_ASSERT1(I.first() >= nb_prim_dof,
95  "The provided interval overlaps with primary dofs");
96  nb_intern_dof += first_intern_dof - std::min(first_intern_dof, I.first());
97  first_intern_dof = std::min(first_intern_dof, I.first());
98  nb_intern_dof += first_intern_dof + nb_intern_dof
99  - std::min(first_intern_dof + nb_intern_dof, I.last());
100  variables.emplace(name, var_description(true, 0, &imd, I, &VV, 1, true));
101  }
102 
103  void ga_workspace::add_fixed_size_variable
104  (const std::string &name,
105  const gmm::sub_interval &I, const model_real_plain_vector &VV) {
106  GMM_ASSERT1(nb_intern_dof == 0 || I.last() <= first_intern_dof,
107  "The provided interval overlaps with internal dofs");
108  nb_prim_dof = std::max(nb_prim_dof, I.last());
109  variables.emplace(name, var_description(true, 0, 0, I, &VV,
110  dim_type(gmm::vect_size(VV))));
111  }
112 
113  void ga_workspace::add_fem_constant
114  (const std::string &name, const mesh_fem &mf,
115  const model_real_plain_vector &VV) {
116  GMM_ASSERT1(mf.nb_dof(), "The provided mesh_fem of variable" << name
117  << "has zero degrees of freedom");
118  size_type Q = gmm::vect_size(VV)/mf.nb_dof();
119  if (Q == 0) Q = size_type(1);
120  variables.emplace(name, var_description(false, &mf, 0,
121  gmm::sub_interval(), &VV, Q));
122  }
123 
124  void ga_workspace::add_fixed_size_constant
125  (const std::string &name, const model_real_plain_vector &VV) {
126  variables.emplace(name, var_description(false, 0, 0,
127  gmm::sub_interval(), &VV,
128  gmm::vect_size(VV)));
129  }
130 
131  void ga_workspace::add_im_data(const std::string &name, const im_data &imd,
132  const model_real_plain_vector &VV) {
133  variables.emplace(name, var_description
134  (false, 0, &imd, gmm::sub_interval(), &VV,
135  gmm::vect_size(VV)/(imd.nb_filtered_index() * imd.nb_tensor_elem())));
136  }
137 
138  bool ga_workspace::is_internal_variable(const std::string &name) const {
139 
140  if ((md && md->variable_exists(name) && md->is_internal_variable(name)) ||
141  (parent_workspace && parent_workspace->variable_exists(name)
142  && parent_workspace->is_internal_variable(name)))
143  return true;
144  else {
145  VAR_SET::const_iterator it = variables.find(name);
146  return it == variables.end() ? false : it->second.is_internal;
147  }
148  }
149 
150  bool ga_workspace::variable_exists(const std::string &name) const {
151  return (md && md->variable_exists(name)) ||
152  (parent_workspace && parent_workspace->variable_exists(name)) ||
153  (variables.find(name) != variables.end());
154  }
155 
156  bool ga_workspace::variable_group_exists(const std::string &name) const {
157  return (variable_groups.find(name) != variable_groups.end()) ||
158  (md && md->variable_group_exists(name)) ||
159  (parent_workspace && parent_workspace->variable_group_exists(name));
160  }
161 
162  const std::vector<std::string>&
163  ga_workspace::variable_group(const std::string &group_name) const {
164  std::map<std::string, std::vector<std::string> >::const_iterator
165  it = variable_groups.find(group_name);
166  if (it != variable_groups.end())
167  return (variable_groups.find(group_name))->second;
168  if (md && md->variable_group_exists(group_name))
169  return md->variable_group(group_name);
170  if (parent_workspace &&
171  parent_workspace->variable_group_exists(group_name))
172  return parent_workspace->variable_group(group_name);
173  GMM_ASSERT1(false, "Undefined variable group " << group_name);
174  }
175 
176  const std::string&
177  ga_workspace::first_variable_of_group(const std::string &name) const {
178  const std::vector<std::string> &t = variable_group(name);
179  GMM_ASSERT1(t.size(), "Variable group " << name << " is empty");
180  return t[0];
181  }
182 
183  bool ga_workspace::is_constant(const std::string &name) const {
184  VAR_SET::const_iterator it = variables.find(name);
185  if (it != variables.end())
186  return !(it->second.is_variable);
187  else if (variable_group_exists(name))
188  return is_constant(first_variable_of_group(name));
189  else if (reenabled_var_intervals.count(name))
190  return false;
191  else if (md && md->variable_exists(name))
192  return md->is_data(name);
193  else if (parent_workspace && parent_workspace->variable_exists(name))
194  return parent_workspace->is_constant(name);
195  GMM_ASSERT1(false, "Undefined variable " << name);
196  }
197 
198  bool ga_workspace::is_disabled_variable(const std::string &name) const {
199  VAR_SET::const_iterator it = variables.find(name);
200  if (it != variables.end())
201  return false;
202  else if (variable_group_exists(name))
203  return is_disabled_variable(first_variable_of_group(name));
204  else if (reenabled_var_intervals.count(name))
205  return false;
206  else if (md && md->variable_exists(name))
207  return md->is_disabled_variable(name);
208  else if (parent_workspace && parent_workspace->variable_exists(name))
209  return parent_workspace->is_disabled_variable(name);
210  GMM_ASSERT1(false, "Undefined variable " << name);
211  }
212 
213  const scalar_type &
214  ga_workspace::factor_of_variable(const std::string &name) const {
215  static const scalar_type one(1);
216  VAR_SET::const_iterator it = variables.find(name);
217  if (it != variables.end()) return one;
218  if (variable_group_exists(name))
219  return one;
220  if (md && md->variable_exists(name)) return md->factor_of_variable(name);
221  if (parent_workspace && parent_workspace->variable_exists(name))
222  return parent_workspace->factor_of_variable(name);
223  GMM_ASSERT1(false, "Undefined variable " << name);
224  }
225 
226  const gmm::sub_interval &
227  ga_workspace::interval_of_variable(const std::string &name) const {
228  VAR_SET::const_iterator it = variables.find(name);
229  if (it != variables.end()) return it->second.I;
230  const auto it2 = reenabled_var_intervals.find(name);
231  if (it2 != reenabled_var_intervals.end()) return it2->second;
232  if (with_parent_variables && md && md->variable_exists(name))
233  return md->interval_of_variable(name);
234  else if (with_parent_variables &&
235  parent_workspace && parent_workspace->variable_exists(name))
236  return parent_workspace->interval_of_variable(name);
237  GMM_ASSERT1(false, "Undefined variable " << name);
238  }
239 
240  const mesh_fem *
241  ga_workspace::associated_mf(const std::string &name) const {
242  VAR_SET::const_iterator it = variables.find(name);
243  if (it != variables.end())
244  return it->second.is_fem_dofs ? it->second.mf : 0;
245  if (md && md->variable_exists(name))
246  return md->pmesh_fem_of_variable(name);
247  if (parent_workspace && parent_workspace->variable_exists(name))
248  return parent_workspace->associated_mf(name);
249  if (variable_group_exists(name))
250  return associated_mf(first_variable_of_group(name));
251  GMM_ASSERT1(false, "Undefined variable or group " << name);
252  }
253 
254  const im_data *
255  ga_workspace::associated_im_data(const std::string &name) const {
256  VAR_SET::const_iterator it = variables.find(name);
257  if (it != variables.end()) return it->second.imd;
258  if (md && md->variable_exists(name))
259  return md->pim_data_of_variable(name);
260  if (parent_workspace && parent_workspace->variable_exists(name))
261  return parent_workspace->associated_im_data(name);
262  if (variable_group_exists(name)) return 0;
263  GMM_ASSERT1(false, "Undefined variable " << name);
264  }
265 
266  size_type ga_workspace::qdim(const std::string &name) const {
267  VAR_SET::const_iterator it = variables.find(name);
268  if (it != variables.end()) {
269  const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
270  const im_data *imd = it->second.imd;
271  size_type n = it->second.qdim();
272  if (mf) {
273  return n * mf->get_qdim();
274  } else if (imd) {
275  return n * imd->tensor_size().total_size();
276  }
277  return n;
278  }
279  if (md && md->variable_exists(name))
280  return md->qdim_of_variable(name);
281  if (parent_workspace && parent_workspace->variable_exists(name))
282  return parent_workspace->qdim(name);
283  if (variable_group_exists(name))
284  return qdim(first_variable_of_group(name));
285  GMM_ASSERT1(false, "Undefined variable or group " << name);
286  }
287 
288  bgeot::multi_index
289  ga_workspace::qdims(const std::string &name) const {
290  VAR_SET::const_iterator it = variables.find(name);
291  if (it != variables.end()) {
292  const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
293  const im_data *imd = it->second.imd;
294  size_type n = it->second.qdim();
295  if (mf) {
296  bgeot::multi_index mi = mf->get_qdims();
297  if (n > 1 || it->second.qdims.size() > 1) {
298  size_type i = 0;
299  if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
300  for (; i < it->second.qdims.size(); ++i)
301  mi.push_back(it->second.qdims[i]);
302  }
303  return mi;
304  } else if (imd) {
305  bgeot::multi_index mi = imd->tensor_size();
306  size_type q = n / imd->nb_filtered_index();
307  GMM_ASSERT1(q % imd->nb_tensor_elem() == 0,
308  "Invalid mesh im data vector");
309  if (n > 1 || it->second.qdims.size() > 1) {
310  size_type i = 0;
311  if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
312  for (; i < it->second.qdims.size(); ++i)
313  mi.push_back(it->second.qdims[i]);
314  }
315  return mi;
316  }
317  return it->second.qdims;
318  }
319  if (md && md->variable_exists(name))
320  return md->qdims_of_variable(name);
321  if (parent_workspace && parent_workspace->variable_exists(name))
322  return parent_workspace->qdims(name);
323  if (variable_group_exists(name))
324  return qdims(first_variable_of_group(name));
325  GMM_ASSERT1(false, "Undefined variable or group " << name);
326  }
327 
328  const model_real_plain_vector &
329  ga_workspace::value(const std::string &name) const {
330  VAR_SET::const_iterator it = variables.find(name);
331  if (it != variables.end())
332  return *(it->second.V);
333  if (md && md->variable_exists(name))
334  return md->real_variable(name);
335  if (parent_workspace && parent_workspace->variable_exists(name))
336  return parent_workspace->value(name);
337  if (variable_group_exists(name))
338  return value(first_variable_of_group(name));
339  GMM_ASSERT1(false, "Undefined variable or group " << name);
340  }
341 
342  scalar_type ga_workspace::get_time_step() const {
343  if (md) return md->get_time_step();
344  if (parent_workspace) return parent_workspace->get_time_step();
345  GMM_ASSERT1(false, "No time step defined here");
346  }
347 
348  void ga_workspace::add_interpolate_transformation
349  (const std::string &name, pinterpolate_transformation ptrans) {
350  if (secondary_domain_exists(name))
351  GMM_ASSERT1(false, "A secondary domain with the same "
352  "name already exists");
353  if (transformations.find(name) != transformations.end())
354  GMM_ASSERT1(name != "neighbor_element", "neighbor_element is a "
355  "reserved interpolate transformation name");
356  transformations[name] = ptrans;
357  }
358 
359  bool ga_workspace::interpolate_transformation_exists
360  (const std::string &name) const {
361  return (md && md->interpolate_transformation_exists(name)) ||
362  (parent_workspace &&
363  parent_workspace->interpolate_transformation_exists(name)) ||
364  (transformations.find(name) != transformations.end());
365  }
366 
367  pinterpolate_transformation
368  ga_workspace::interpolate_transformation(const std::string &name) const {
369  auto it = transformations.find(name);
370  if (it != transformations.end()) return it->second;
371  if (md && md->interpolate_transformation_exists(name))
372  return md->interpolate_transformation(name);
373  if (parent_workspace &&
374  parent_workspace->interpolate_transformation_exists(name))
375  return parent_workspace->interpolate_transformation(name);
376  GMM_ASSERT1(false, "Inexistent transformation " << name);
377  }
378 
379  bool ga_workspace::elementary_transformation_exists
380  (const std::string &name) const {
381  return (md && md->elementary_transformation_exists(name)) ||
382  (parent_workspace &&
383  parent_workspace->elementary_transformation_exists(name)) ||
384  (elem_transformations.find(name) != elem_transformations.end());
385  }
386 
387  pelementary_transformation
388  ga_workspace::elementary_transformation(const std::string &name) const {
389  auto it = elem_transformations.find(name);
390  if (it != elem_transformations.end()) return it->second;
391  if (md && md->elementary_transformation_exists(name))
392  return md->elementary_transformation(name);
393  if (parent_workspace &&
394  parent_workspace->elementary_transformation_exists(name))
395  return parent_workspace->elementary_transformation(name);
396  GMM_ASSERT1(false, "Inexistent elementary transformation " << name);
397  }
398 
399  void ga_workspace::add_secondary_domain(const std::string &name,
400  psecondary_domain psecdom) {
401  if (interpolate_transformation_exists(name))
402  GMM_ASSERT1(false, "An interpolate transformation with the same "
403  "name already exists");
404  secondary_domains[name] = psecdom;
405  }
406 
407  bool ga_workspace::secondary_domain_exists
408  (const std::string &name) const {
409  return (md && md->secondary_domain_exists(name)) ||
410  (parent_workspace &&
411  parent_workspace->secondary_domain_exists(name)) ||
412  (secondary_domains.find(name) != secondary_domains.end());
413  }
414 
415  psecondary_domain
416  ga_workspace::secondary_domain(const std::string &name) const {
417  auto it = secondary_domains.find(name);
418  if (it != secondary_domains.end()) return it->second;
419  if (md && md->secondary_domain_exists(name))
420  return md->secondary_domain(name);
421  if (parent_workspace &&
422  parent_workspace->secondary_domain_exists(name))
423  return parent_workspace->secondary_domain(name);
424  GMM_ASSERT1(false, "Inexistent secondary domain " << name);
425  }
426 
427 
428  const mesh_region &
429  ga_workspace::register_region(const mesh &m, const mesh_region &region) {
430  if (&m == &dummy_mesh())
431  return dummy_mesh_region();
432 
433  std::list<mesh_region> &lmr = registred_mesh_regions[&m];
434  for (const mesh_region &rg : lmr)
435  if (rg.compare(m, region, m)) return rg;
436  lmr.push_back(region);
437  return lmr.back();
438  }
439 
440  void ga_workspace::add_tree(ga_tree &tree, const mesh &m,
441  const mesh_im &mim, const mesh_region &rg,
442  const std::string &expr,
443  size_type add_derivative_order,
444  bool function_expr, operation_type op_type,
445  const std::string varname_interpolation) {
446  if (tree.root) {
447  // cout << "add tree with tests functions of " << tree.root->name_test1
448  // << " and " << tree.root->name_test2 << endl;
449  // ga_print_node(tree.root, cout); cout << endl;
450 
451  // Eliminate the term if it corresponds to disabled variables
452  if ((tree.root->test_function_type >= 1 &&
453  is_disabled_variable(tree.root->name_test1)) ||
454  (tree.root->test_function_type >= 2 &&
455  is_disabled_variable(tree.root->name_test2))) {
456  // cout<<"disabling term "; ga_print_node(tree.root, cout); cout<<endl;
457  return;
458  }
459 
460  bool remain = true;
461  size_type order = 0, ind_tree = 0;
462 
463  if (op_type != ga_workspace::ASSEMBLY)
464  order = add_derivative_order;
465  else {
466  switch(tree.root->test_function_type) {
467  case 0: order = 0; break;
468  case 1: order = 1; break;
469  case 3: order = 2; break;
470  default: GMM_ASSERT1(false, "Inconsistent term "
471  << tree.root->test_function_type);
472  }
473  }
474 
475  bool found = false;
476  for (const ga_workspace::tree_description &td : trees) {
477  if (td.mim == &mim &&
478  td.m == &m &&
479  td.secondary_domain == tree.secondary_domain &&
480  td.order == order &&
481  td.name_test1 == tree.root->name_test1 &&
482  td.interpolate_name_test1 == tree.root->interpolate_name_test1 &&
483  td.name_test2 == tree.root->name_test2 &&
484  td.interpolate_name_test2 == tree.root->interpolate_name_test2 &&
485  td.rg == &rg &&
486  td.operation == op_type &&
487  td.varname_interpolation == varname_interpolation) {
488  ga_tree &ftree = *(td.ptree);
489 
490  ftree.insert_node(ftree.root, GA_NODE_OP);
491  ftree.root->op_type = GA_PLUS;
492  ftree.root->children.resize(2, nullptr);
493  ftree.copy_node(tree.root, ftree.root, ftree.root->children[1]);
494  ga_semantic_analysis(ftree, *this, m,
495  ref_elt_dim_of_mesh(m,rg), false, function_expr);
496  found = true;
497  break;
498  }
499  }
500 
501  if (!found) {
502  ind_tree = trees.size();
503  remain = false;
504  trees.push_back(tree_description());
505  trees.back().mim = &mim;
506  trees.back().m = &m;
507  trees.back().rg = &rg;
508  trees.back().secondary_domain = tree.secondary_domain;
509  trees.back().ptree = new ga_tree;
510  trees.back().ptree->swap(tree);
511  pga_tree_node root = trees.back().ptree->root;
512  trees.back().name_test1 = root->name_test1;
513  trees.back().name_test2 = root->name_test2;
514  trees.back().interpolate_name_test1 = root->interpolate_name_test1;
515  trees.back().interpolate_name_test2 = root->interpolate_name_test2;
516  trees.back().order = order;
517  trees.back().operation = op_type;
518  trees.back().varname_interpolation = varname_interpolation;
519  }
520 
521  if (op_type == ga_workspace::ASSEMBLY && order < add_derivative_order) {
522  std::set<var_trans_pair> expr_variables;
523  ga_extract_variables((remain ? tree : *(trees[ind_tree].ptree)).root,
524  *this, m, expr_variables, true);
525  for (const var_trans_pair &var : expr_variables) {
526  if (!(is_constant(var.varname))) {
527  ga_tree dtree = (remain ? tree : *(trees[ind_tree].ptree));
528  // cout << "Derivation with respect to " << var.varname << " : "
529  // << var.transname << " of " << ga_tree_to_string(dtree) << endl;
530  // GA_TIC;
531  ga_derivative(dtree, *this, m, var.varname, var.transname, 1+order);
532  // cout << "Result : " << ga_tree_to_string(dtree) << endl;
533  // GA_TOCTIC("Derivative time");
534  ga_semantic_analysis(dtree, *this, m,
535  ref_elt_dim_of_mesh(m,rg),false,function_expr);
536  // GA_TOCTIC("Analysis after Derivative time");
537  // cout << "after analysis " << ga_tree_to_string(dtree) << endl;
538  add_tree(dtree, m, mim, rg, expr, add_derivative_order,
539  function_expr, op_type, varname_interpolation);
540  }
541  }
542  }
543  }
544  }
545 
546  size_type ga_workspace::add_expression(const std::string &expr,
547  const mesh_im &mim,
548  const mesh_region &rg_,
549  size_type add_derivative_order,
550  const std::string &secondary_dom) {
551  const mesh_region &rg = register_region(mim.linked_mesh(), rg_);
552  // cout << "adding expression " << expr << endl;
553  GA_TIC;
554  size_type max_order = 0;
555  std::vector<ga_tree> ltrees(1);
556  ga_read_string(expr, ltrees[0], macro_dictionary());
557  if (secondary_dom.size()) {
558  GMM_ASSERT1(secondary_domain_exists(secondary_dom),
559  "Unknown secondary domain " << secondary_dom);
560  ltrees[0].secondary_domain = secondary_dom;
561  }
562  // cout << "read : " << ga_tree_to_string(ltrees[0]) << endl;
563  ga_semantic_analysis(ltrees[0], *this, mim.linked_mesh(),
564  ref_elt_dim_of_mesh(mim.linked_mesh(),rg),
565  false, false, 1);
566  // cout << "analysed : " << ga_tree_to_string(ltrees[0]) << endl;
567  GA_TOC("First analysis time");
568  if (ltrees[0].root) {
569  if (test1.size() > 1 || test2.size() > 1) {
570  size_type ntest2 = test2.size();
571  if (ntest2 == 0) // temporarily add an element to
572  test2.insert(var_trans_pair()); // allow entering the inner loop
573  ltrees.resize(test1.size()*test2.size(), ltrees[0]);
574  auto ltree = ltrees.begin();
575  for (const auto &t1 : test1) {
576  for (const auto &t2 : test2) {
577  selected_test1 = t1;
578  if (ntest2 > 0) selected_test2 = t2;
579  // cout << "analysis with " << selected_test1.first << endl;
580  ga_semantic_analysis(*ltree, *this, mim.linked_mesh(),
581  ref_elt_dim_of_mesh(mim.linked_mesh(),rg),
582  false, false, 2);
583  // cout <<"split: "<< ga_tree_to_string(*ltree) << endl;
584  if (ltree != ltrees.end()) ++ltree;
585  }
586  }
587  if (ntest2 == 0) test2.clear(); // remove temporarily added element
588  }
589 
590  for (ga_tree &ltree : ltrees) {
591  if (ltree.root) {
592  // cout << "adding tree " << ga_tree_to_string(ltree) << endl;
593  max_order = std::max(ltree.root->nb_test_functions(), max_order);
594  add_tree(ltree, mim.linked_mesh(), mim, rg, expr,
595  add_derivative_order, true);
596  }
597  }
598  }
599  GA_TOC("Time for add expression");
600  return max_order;
601  }
602 
603  void ga_workspace::add_function_expression(const std::string &expr) {
604  ga_tree tree;
605  ga_read_string(expr, tree, macro_dictionary());
606  ga_semantic_analysis(tree, *this, dummy_mesh(), 1, false, true);
607  if (tree.root) {
608  // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
609  // "Invalid function expression");
610  add_tree(tree, dummy_mesh(), dummy_mesh_im(), dummy_mesh_region(),
611  expr, 0, true);
612  }
613  }
614 
615  void ga_workspace::add_interpolation_expression(const std::string &expr,
616  const mesh &m,
617  const mesh_region &rg_) {
618  const mesh_region &rg = register_region(m, rg_);
619  ga_tree tree;
620  ga_read_string(expr, tree, macro_dictionary());
621  ga_semantic_analysis(tree, *this, m, ref_elt_dim_of_mesh(m,rg),
622  false, false);
623  if (tree.root) {
624  // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
625  // "Invalid expression containing test functions");
626  add_tree(tree, m, dummy_mesh_im(), rg, expr, 0, false,
627  ga_workspace::PRE_ASSIGNMENT);
628  }
629  }
630 
631  void ga_workspace::add_interpolation_expression(const std::string &expr,
632  const mesh_im &mim,
633  const mesh_region &rg_) {
634  const mesh &m = mim.linked_mesh();
635  const mesh_region &rg = register_region(m, rg_);
636  ga_tree tree;
637  ga_read_string(expr, tree, macro_dictionary());
638  ga_semantic_analysis(tree, *this, m, ref_elt_dim_of_mesh(m,rg),
639  false, false);
640  if (tree.root) {
641  GMM_ASSERT1(tree.root->nb_test_functions() == 0,
642  "Invalid expression containing test functions");
643  add_tree(tree, m, mim, rg, expr, 0, false,
644  ga_workspace::PRE_ASSIGNMENT);
645  }
646  }
647 
648  void ga_workspace::add_assignment_expression
649  (const std::string &varname, const std::string &expr, const mesh_region &rg_,
650  size_type order, bool before) {
651  const im_data *imd = associated_im_data(varname);
652  GMM_ASSERT1(imd != 0, "Only applicable to im_data");
653  const mesh_im &mim = imd->linked_mesh_im();
654  const mesh &m = mim.linked_mesh();
655  const mesh_region &rg = register_region(m, rg_);
656  ga_tree tree;
657  ga_read_string(expr, tree, macro_dictionary());
658  ga_semantic_analysis(tree, *this, m, ref_elt_dim_of_mesh(m,rg),false,false);
659  if (tree.root) {
660  GMM_ASSERT1(tree.root->nb_test_functions() == 0,
661  "Invalid expression containing test functions");
662  add_tree(tree, m, mim, rg, expr, order, false,
663  before ? ga_workspace::PRE_ASSIGNMENT
664  : ga_workspace::POST_ASSIGNMENT,
665  varname);
666  }
667  }
668 
669  size_type ga_workspace::nb_trees() const { return trees.size(); }
670 
671  ga_workspace::tree_description &ga_workspace::tree_info(size_type i)
672  { return trees[i]; }
673 
674  bool ga_workspace::used_variables(std::vector<std::string> &vl,
675  std::vector<std::string> &vl_test1,
676  std::vector<std::string> &vl_test2,
677  std::vector<std::string> &dl,
678  size_type order) {
679  bool islin = true;
680  std::set<var_trans_pair> vll, dll;
681  for (const std::string &v : vl) vll.insert(var_trans_pair(v, ""));
682  for (const std::string &d : dl) dll.insert(var_trans_pair(d, ""));
683 
684  for (const ga_workspace::tree_description &td : trees) {
685  std::set<var_trans_pair> dllaux;
686  bool fv = ga_extract_variables(td.ptree->root, *this, *(td.m),
687  dllaux, false);
688 
689  if (td.order == order)
690  for (const auto &t : dllaux)
691  dll.insert(t);
692 
693  switch (td.order) {
694  case 0: break;
695  case 1:
696  if (td.order == order) {
697  if (variable_group_exists(td.name_test1)) {
698  for (const std::string &t : variable_group(td.name_test1))
699  vll.insert(var_trans_pair(t, td.interpolate_name_test1));
700  } else {
701  vll.insert(var_trans_pair(td.name_test1,
702  td.interpolate_name_test1));
703  }
704  bool found = false;
705  for (const std::string &t : vl_test1)
706  if (td.name_test1 == t)
707  found = true;
708  if (!found)
709  vl_test1.push_back(td.name_test1);
710  }
711  break;
712  case 2:
713  if (td.order == order) {
714  if (variable_group_exists(td.name_test1)) {
715  for (const std::string &t : variable_group(td.name_test1))
716  vll.insert(var_trans_pair(t, td.interpolate_name_test1));
717  } else {
718  vll.insert(var_trans_pair(td.name_test1,
719  td.interpolate_name_test1));
720  }
721  if (variable_group_exists(td.name_test2)) {
722  for (const std::string &t : variable_group(td.name_test2))
723  vll.insert(var_trans_pair(t, td.interpolate_name_test2));
724  } else {
725  vll.insert(var_trans_pair(td.name_test2,
726  td.interpolate_name_test2));
727  }
728  bool found = false;
729  for (size_type j = 0; j < vl_test1.size(); ++j)
730  if ((td.name_test1 == vl_test1[j]) &&
731  (td.name_test2 == vl_test2[j]))
732  found = true;
733  if (!found) {
734  vl_test1.push_back(td.name_test1);
735  vl_test2.push_back(td.name_test2);
736  }
737  }
738  if (fv) islin = false;
739  break;
740  }
741  }
742  vl.clear();
743  for (const auto &var : vll)
744  if (vl.size() == 0 || var.varname != vl.back())
745  vl.push_back(var.varname);
746  dl.clear();
747  for (const auto &var : dll)
748  if (dl.size() == 0 || var.varname != dl.back())
749  dl.push_back(var.varname);
750 
751  return islin;
752  }
753 
754  bool ga_workspace::is_linear(size_type order) {
755  std::vector<std::string> vl, vl_test1, vl_test2, dl;
756  return used_variables(vl, vl_test1, vl_test2, dl, order);
757  }
758 
759  void ga_workspace::define_variable_group(const std::string &group_name,
760  const std::vector<std::string> &nl) {
761  GMM_ASSERT1(!(variable_exists(group_name)), "The name of a group of "
762  "variables cannot be the same as a variable name");
763 
764  std::set<const mesh *> ms;
765  bool is_data_ = false;
766  for (size_type i = 0; i < nl.size(); ++i) {
767  if (i == 0)
768  is_data_ = is_constant(nl[i]);
769  else {
770  GMM_ASSERT1(is_data_ == is_constant(nl[i]),
771  "It is not possible to mix variables and data in a group");
772  }
773  GMM_ASSERT1(variable_exists(nl[i]),
774  "All variables in a group have to exist in the model");
775  const mesh_fem *mf = associated_mf(nl[i]);
776  GMM_ASSERT1(mf, "Variables in a group should be fem variables");
777  GMM_ASSERT1(ms.find(&(mf->linked_mesh())) == ms.end(),
778  "Two variables in a group cannot share the same mesh");
779  ms.insert(&(mf->linked_mesh()));
780  }
781  variable_groups[group_name] = nl;
782  }
783 
784 
785  const std::string &ga_workspace::variable_in_group
786  (const std::string &group_name, const mesh &m) const {
787  if (variable_group_exists(group_name)) {
788  for (const std::string &t : variable_group(group_name))
789  if (&(associated_mf(t)->linked_mesh()) == &m)
790  return t;
791  GMM_ASSERT1(false, "No variable in this group for the given mesh");
792  } else
793  return group_name;
794  }
795 
796 
797  void ga_workspace::assembly(size_type order, bool condensation) {
798 
799  const ga_workspace *w = this;
800  while (w->parent_workspace) w = w->parent_workspace;
801  if (w->md) w->md->nb_dof(); // To eventually call actualize_sizes()
802 
803  GA_TIC;
804  ga_instruction_set gis;
805  ga_compile(*this, gis, order, condensation);
806  GA_TOCTIC("Compile time");
807 
808  size_type nb_tot_dof = condensation ? nb_prim_dof + nb_intern_dof
809  : nb_prim_dof;
810  if (order == 2) {
811  if (K.use_count()) {
812  gmm::clear(*K);
813  gmm::resize(*K, nb_prim_dof, nb_prim_dof);
814  } // else
815  // We trust that the caller has provided a matrix large enough for the
816  // terms to be assembled (can actually be smaller than the full matrix)
817  // GMM_ASSERT1(gmm::mat_nrows(*K) == nb_prim_dof &&
818  // gmm::mat_ncols(*K) == nb_prim_dof, "Wrong sizes");
819  if (KQJpr.use_count()) {
820  gmm::clear(*KQJpr);
821  if (condensation)
822  gmm::resize(*KQJpr, nb_tot_dof, nb_prim_dof);
823  } else if (condensation)
824  GMM_ASSERT1(gmm::mat_nrows(*KQJpr) == nb_tot_dof &&
825  gmm::mat_ncols(*KQJpr) == nb_prim_dof, "Wrong sizes");
826  gmm::clear(col_unreduced_K);
827  gmm::clear(row_unreduced_K);
828  gmm::clear(row_col_unreduced_K);
829  gmm::resize(col_unreduced_K, nb_tot_dof, nb_tmp_dof);
830  gmm::resize(row_unreduced_K, nb_tmp_dof, nb_prim_dof);
831  gmm::resize(row_col_unreduced_K, nb_tmp_dof, nb_tmp_dof);
832  if (condensation) {
833  gmm::clear(unreduced_V);
834  gmm::resize(unreduced_V, nb_tmp_dof);
835  }
836  }
837 
838  if (order == 1 || (order == 2 && condensation)) {
839  if (order == 2 && condensation) {
840  GMM_ASSERT1(V->size() == nb_tot_dof,
841  "Wrong size of assembled vector in workspace");
842  gmm::resize(cached_V, nb_tot_dof);
843  gmm::copy(*V, cached_V); // current residual is used in condensation
844  gmm::fill(*V, scalar_type(0));
845  } else if (V.use_count()) {
846  gmm::clear(*V);
847  gmm::resize(*V, nb_tot_dof);
848  } else
849  GMM_ASSERT1(V->size() == nb_tot_dof,
850  "Wrong size of assembled vector in workspace");
851  gmm::clear(unreduced_V);
852  gmm::resize(unreduced_V, nb_tmp_dof);
853  }
854  gmm::clear(assembled_tensor().as_vector());
855 
856  GA_TOCTIC("Init time");
857  ga_exec(gis, *this); // --> unreduced_V, *V,
858  GA_TOCTIC("Exec time"); // unreduced_K, *K
859 
860  if (order == 0) {
861  MPI_SUM_VECTOR(assemb_t.as_vector());
862  } else if (order == 1 || (order == 2 && condensation)) {
863  MPI_SUM_VECTOR(*V);
864  MPI_SUM_VECTOR(unreduced_V);
865  }
866 
867  // Deal with reduced fems, unreduced_K --> *K, *KQJpr,
868  // unreduced_V --> *V
869  if (order > 0) {
870  std::set<std::string> vars_vec_done;
871  std::set<std::pair<std::string, std::string> > vars_mat_done;
872  for (const auto &term : gis.unreduced_terms) {
873  const std::string &name1 = term.first;
874  const std::string &name2 = term.second;
875  const std::vector<std::string>
876  vg1_(1,name1), vg2_(1,name2),
877  &vg1 = variable_group_exists(name1) ? variable_group(name1) : vg1_,
878  &vg2 = variable_group_exists(name2) ? variable_group(name2) : vg2_;
879  if (order == 1) {
880  for (const std::string &vname1 : vg1) {
881  const mesh_fem *mf1 = associated_mf(vname1);
882  if (mf1 && mf1->is_reduced() && vars_vec_done.count(vname1) == 0) {
883  gmm::sub_interval uI1 = temporary_interval_of_variable(vname1),
884  I1 = interval_of_variable(vname1);
885  gmm::mult_add(gmm::transposed(mf1->extension_matrix()),
886  gmm::sub_vector(unreduced_V, uI1),
887  gmm::sub_vector(*V, I1));
888  vars_vec_done.insert(vname1);
889  }
890  }
891  } else {
892  for (const std::string &vname1 : vg1) {
893  for (const std::string &vname2 : vg2) {
894  const mesh_fem *mf1 = associated_mf(vname1),
895  *mf2 = associated_mf(vname2);
896  if (((mf1 && mf1->is_reduced()) || (mf2 && mf2->is_reduced()))
897  && vars_mat_done.count(std::make_pair(vname1,vname2)) == 0) {
898  gmm::sub_interval
899  uI1 = temporary_interval_of_variable(vname1),
900  uI2 = temporary_interval_of_variable(vname2),
901  I1 = interval_of_variable(vname1),
902  I2 = interval_of_variable(vname2);
903  if (mf1 && mf1->is_reduced()) {
904  if (condensation && vars_vec_done.count(vname1) == 0) {
905  gmm::mult_add(gmm::transposed(mf1->extension_matrix()),
906  gmm::sub_vector(unreduced_V, uI1),
907  gmm::sub_vector(*V, I1));
908  vars_vec_done.insert(vname1);
909  }
910  if (mf2 && mf2->is_reduced()) {
911  model_real_sparse_matrix aux(I1.size(), uI2.size());
912  model_real_row_sparse_matrix M(I1.size(), I2.size());
913  gmm::mult(gmm::transposed(mf1->extension_matrix()),
914  gmm::sub_matrix(row_col_unreduced_K, uI1, uI2),
915  aux);
916  gmm::mult(aux, mf2->extension_matrix(), M);
917  gmm::add(M, gmm::sub_matrix(*K, I1, I2));
918  } else if (I2.first() < nb_prim_dof) { // !is_internal_variable(vname2)
919  model_real_sparse_matrix M(I1.size(), I2.size());
920  gmm::mult(gmm::transposed(mf1->extension_matrix()),
921  gmm::sub_matrix(row_unreduced_K, uI1, I2), M);
922  gmm::add(M, gmm::sub_matrix(*K, I1, I2));
923  }
924  } else {
925  model_real_row_sparse_matrix M(I1.size(), I2.size());
926  gmm::mult(gmm::sub_matrix(col_unreduced_K, I1, uI2),
927  mf2->extension_matrix(), M);
928  if (I1.first() < nb_prim_dof) {
929  GMM_ASSERT1(I1.last() <= nb_prim_dof, "Internal error");
930  gmm::add(M, gmm::sub_matrix(*K, I1, I2)); // -> *K
931  } else { // vname1 is an internal variable
932  gmm::add(M, gmm::sub_matrix(*KQJpr, I1, I2)); // -> *KQJpr
933  }
934  }
935  vars_mat_done.insert(std::make_pair(vname1,vname2));
936  }
937  }
938  }
939  }
940  }
941  }
942  }
943 
944  void ga_workspace::set_include_empty_int_points(bool include) {
945  include_empty_int_pts = include;
946  }
947 
948  bool ga_workspace::include_empty_int_points() const {
949  return include_empty_int_pts;
950  }
951 
952  void ga_workspace::add_temporary_interval_for_unreduced_variable
953  (const std::string &name)
954  {
955  if (variable_group_exists(name)) {
956  for (const std::string &v : variable_group(name))
957  add_temporary_interval_for_unreduced_variable(v);
958  } else if (tmp_var_intervals.count(name) == 0) {
959  const mesh_fem *mf = associated_mf(name);
960  if (mf && mf->is_reduced()) {
961  size_type nd = mf->nb_basic_dof();
962  tmp_var_intervals[name] = gmm::sub_interval(nb_tmp_dof, nd);
963  nb_tmp_dof += nd;
964  }
965  }
966  }
967 
968  void ga_workspace::clear_expressions() { trees.clear(); }
969 
970  void ga_workspace::print(std::ostream &str) {
971  for (size_type i = 0; i < trees.size(); ++i)
972  if (trees[i].ptree->root) {
973  cout << "Expression tree " << i << " of order " <<
974  trees[i].ptree->root->nb_test_functions() << " :" << endl;
975  ga_print_node(trees[i].ptree->root, str);
976  cout << endl;
977  }
978  }
979 
980  void ga_workspace::tree_description::copy(const tree_description& td) {
981  order = td.order;
982  operation = td.operation;
983  varname_interpolation = td.varname_interpolation;
984  name_test1 = td.name_test1;
985  name_test2 = td.name_test2;
986  interpolate_name_test1 = td.interpolate_name_test1;
987  interpolate_name_test2 = td.interpolate_name_test2;
988  mim = td.mim;
989  m = td.m;
990  rg = td.rg;
991  ptree = 0;
992  if (td.ptree) ptree = new ga_tree(*(td.ptree));
993  }
994 
995  ga_workspace::tree_description &ga_workspace::tree_description::operator =
996  (const ga_workspace::tree_description& td)
997  { if (ptree) delete ptree; ptree = 0; copy(td); return *this; }
998  ga_workspace::tree_description::~tree_description()
999  { if (ptree) delete ptree; ptree = 0; }
1000 
1001  ga_workspace::ga_workspace(const getfem::model &md_,
1002  const inherit var_inherit)
1003  : md(&md_), parent_workspace(0),
1004  with_parent_variables(var_inherit == inherit::ENABLED ||
1005  var_inherit == inherit::ALL),
1006  nb_tmp_dof(0), macro_dict(md_.macro_dictionary())
1007  {
1008  init();
1009  nb_prim_dof = with_parent_variables ? md->nb_primary_dof() : 0;
1010  nb_intern_dof = with_parent_variables ? md->nb_internal_dof() : 0;
1011  if (var_inherit == inherit::ALL) { // enable model's disabled variables
1012  model::varnamelist vlmd;
1013  md->variable_list(vlmd);
1014  for (const auto &varname : vlmd)
1015  if (md->is_disabled_variable(varname)) {
1016  if (md->is_affine_dependent_variable(varname)) {
1017  std::string orgvarname = md->org_variable(varname);
1018  if (reenabled_var_intervals.count(orgvarname) == 0) {
1019  size_type varsize = gmm::vect_size(md->real_variable(orgvarname));
1020  reenabled_var_intervals[orgvarname]
1021  = gmm::sub_interval (nb_prim_dof, varsize);
1022  nb_prim_dof += varsize;
1023  }
1024  reenabled_var_intervals[varname]
1025  = reenabled_var_intervals[orgvarname];
1026  } else if (reenabled_var_intervals.count(varname) == 0) {
1027  size_type varsize = gmm::vect_size(md->real_variable(varname));
1028  reenabled_var_intervals[varname]
1029  = gmm::sub_interval(nb_prim_dof, varsize);
1030  nb_prim_dof += varsize;
1031  }
1032  }
1033  }
1034  first_intern_dof = nb_prim_dof; // dofs are contiguous in getfem::model
1035  }
1036  ga_workspace::ga_workspace(const ga_workspace &gaw,
1037  const inherit var_inherit)
1038  : md(0), parent_workspace(&gaw),
1039  with_parent_variables(var_inherit == inherit::ENABLED ||
1040  var_inherit == inherit::ALL),
1041  nb_tmp_dof(0), macro_dict(gaw.macro_dictionary())
1042  {
1043  init();
1044  nb_prim_dof = with_parent_variables ? gaw.nb_primary_dof() : 0;
1045  nb_intern_dof = with_parent_variables ? gaw.nb_internal_dof() : 0;
1046  first_intern_dof = with_parent_variables ? gaw.first_internal_dof() : 0;
1047  }
1048  ga_workspace::ga_workspace()
1049  : md(0), parent_workspace(0), with_parent_variables(false),
1050  nb_prim_dof(0), nb_intern_dof(0), first_intern_dof(0), nb_tmp_dof(0)
1051  { init(); }
1052  ga_workspace::~ga_workspace() { clear_expressions(); }
1053 
1054  //=========================================================================
1055  // Extract the constant term of degree 1 expressions
1056  //=========================================================================
1057 
1058  std::string ga_workspace::extract_constant_term(const mesh &m) {
1059  std::string constant_term;
1060  for (const ga_workspace::tree_description &td : trees) {
1061  if (td.order == 1) {
1062  ga_tree local_tree = *(td.ptree);
1063  if (local_tree.root)
1064  ga_node_extract_constant_term(local_tree, local_tree.root, *this, m);
1065  if (local_tree.root)
1066  ga_semantic_analysis(local_tree, *this, m,
1067  ref_elt_dim_of_mesh(m,-1), false, false);
1068  if (local_tree.root && local_tree.root->node_type != GA_NODE_ZERO) {
1069  constant_term += "-("+ga_tree_to_string(local_tree)+")";
1070  }
1071  }
1072  }
1073  return constant_term;
1074  }
1075 
1076  //=========================================================================
1077  // Extract the order zero term
1078  //=========================================================================
1079 
1080  std::string ga_workspace::extract_order0_term() {
1081  std::string term;
1082  for (const ga_workspace::tree_description &td : trees) {
1083  if (td.order == 0) {
1084  ga_tree &local_tree = *(td.ptree);
1085  if (term.size())
1086  term += "+("+ga_tree_to_string(local_tree)+")";
1087  else
1088  term = "("+ga_tree_to_string(local_tree)+")";
1089  }
1090  }
1091  return term;
1092  }
1093 
1094 
1095  //=========================================================================
1096  // Extract the order one term corresponding to a certain test function
1097  //=========================================================================
1098 
1099  std::string ga_workspace::extract_order1_term(const std::string &varname) {
1100  std::string term;
1101  for (const ga_workspace::tree_description &td : trees) {
1102  if (td.order == 1 && td.name_test1 == varname) {
1103  ga_tree &local_tree = *(td.ptree);
1104  if (term.size())
1105  term += "+("+ga_tree_to_string(local_tree)+")";
1106  else
1107  term = "("+ga_tree_to_string(local_tree)+")";
1108  }
1109  }
1110  return term;
1111  }
1112 
1113  //=========================================================================
1114  // Extract Neumann terms
1115  //=========================================================================
1116 
1117  std::string ga_workspace::extract_Neumann_term(const std::string &varname) {
1118  std::string result;
1119  for (const ga_workspace::tree_description &td : trees) {
1120  if (td.order == 1 && td.name_test1 == varname) {
1121  ga_tree &local_tree = *(td.ptree);
1122  if (local_tree.root)
1123  ga_extract_Neumann_term(local_tree, varname, *this,
1124  local_tree.root, result);
1125  }
1126  }
1127  return result;
1128  }
1129 
1130 } /* end of namespace */
gmm::resize
void resize(M &v, size_type m, size_type n)
*‍/
Definition: gmm_blas.h:231
bgeot::size_type
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
gmm::clear
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
getfem_generic_assembly_semantic.h
Semantic analysis of assembly trees and semantic manipulations.
getfem_generic_assembly_tree.h
Compilation and execution operations.
getfem::dummy_mesh_region
const mesh_region & dummy_mesh_region()
Dummy mesh_region for default parameter of functions.
Definition: getfem_mesh_region.cc:617
getfem::interpolate_transformation_neighbor_instance
pinterpolate_transformation interpolate_transformation_neighbor_instance()
Create a new instance of a transformation corresponding to the interpolation on the neighbor element.
Definition: getfem_generic_assembly_interpolation.cc:866
getfem::model
`‘Model’' variables store the variables, the data and the description of a model.
Definition: getfem_models.h:114
getfem
GEneric Tool for Finite Element Methods.
Definition: getfem_accumulated_distro.h:46
getfem::dummy_mesh_im
const mesh_im & dummy_mesh_im()
Dummy mesh_im for default parameter of functions.
Definition: getfem_mesh_im.cc:234
gmm::copy
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:977
gmm::mult_add
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1781