GetFEM++  5.3
getfem_generic_assembly_workspace.cc
1 /*===========================================================================
2 
3  Copyright (C) 2013-2018 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  void ga_workspace::init() {
35  // allocate own storage for K an V to be used unless/until external
36  // storage is provided with set_assembled_matrix/vector
37  K = std::make_shared<model_real_sparse_matrix>(2,2);
38  V = std::make_shared<base_vector>(2);
39  // add default transformations
40  add_interpolate_transformation
42  }
43 
44  // variables and variable groups
45  void ga_workspace::add_fem_variable
46  (const std::string &name, const mesh_fem &mf,
47  const gmm::sub_interval &I, const model_real_plain_vector &VV) {
48  variables[name] = var_description(true, true, &mf, I, &VV, 0, 1);
49  }
50 
51  void ga_workspace::add_fixed_size_variable
52  (const std::string &name,
53  const gmm::sub_interval &I, const model_real_plain_vector &VV) {
54  variables[name] = var_description(true, false, 0, I, &VV, 0,
55  dim_type(gmm::vect_size(VV)));
56  }
57 
58  void ga_workspace::add_fem_constant
59  (const std::string &name, const mesh_fem &mf,
60  const model_real_plain_vector &VV) {
61  GMM_ASSERT1(mf.nb_dof(), "The provided mesh_fem of variable" << name
62  << "has zero degrees of freedom.");
63  size_type Q = gmm::vect_size(VV)/mf.nb_dof();
64  if (Q == 0) Q = size_type(1);
65  variables[name] = var_description(false, true, &mf,
66  gmm::sub_interval(), &VV, 0, Q);
67  }
68 
69  void ga_workspace::add_fixed_size_constant
70  (const std::string &name, const model_real_plain_vector &VV) {
71  variables[name] = var_description(false, false, 0,
72  gmm::sub_interval(), &VV, 0,
73  gmm::vect_size(VV));
74  }
75 
76  void ga_workspace::add_im_data(const std::string &name, const im_data &imd,
77  const model_real_plain_vector &VV) {
78  variables[name] = var_description
79  (false, false, 0, gmm::sub_interval(), &VV, &imd,
80  gmm::vect_size(VV)/(imd.nb_filtered_index() * imd.nb_tensor_elem()));
81  }
82 
83 
84  bool ga_workspace::variable_exists(const std::string &name) const {
85  return (md && md->variable_exists(name)) ||
86  (parent_workspace && parent_workspace->variable_exists(name)) ||
87  (variables.find(name) != variables.end());
88  }
89 
90  bool ga_workspace::variable_group_exists(const std::string &name) const {
91  return (variable_groups.find(name) != variable_groups.end()) ||
92  (md && md->variable_group_exists(name)) ||
93  (parent_workspace && parent_workspace->variable_group_exists(name));
94  }
95 
96  const std::vector<std::string>&
97  ga_workspace::variable_group(const std::string &group_name) const {
98  std::map<std::string, std::vector<std::string> >::const_iterator
99  it = variable_groups.find(group_name);
100  if (it != variable_groups.end())
101  return (variable_groups.find(group_name))->second;
102  if (md && md->variable_group_exists(group_name))
103  return md->variable_group(group_name);
104  if (parent_workspace &&
105  parent_workspace->variable_group_exists(group_name))
106  return parent_workspace->variable_group(group_name);
107  GMM_ASSERT1(false, "Undefined variable group " << group_name);
108  }
109 
110  const std::string&
111  ga_workspace::first_variable_of_group(const std::string &name) const {
112  const std::vector<std::string> &t = variable_group(name);
113  GMM_ASSERT1(t.size(), "Variable group " << name << " is empty");
114  return t[0];
115  }
116 
117  bool ga_workspace::is_constant(const std::string &name) const {
118  VAR_SET::const_iterator it = variables.find(name);
119  if (it != variables.end()) return !(it->second.is_variable);
120  if (variable_group_exists(name))
121  return is_constant(first_variable_of_group(name));
122  if (md && md->variable_exists(name)) {
123  if (enable_all_md_variables) return md->is_true_data(name);
124  return md->is_data(name);
125  }
126  if (parent_workspace && parent_workspace->variable_exists(name))
127  return parent_workspace->is_constant(name);
128  GMM_ASSERT1(false, "Undefined variable " << name);
129  }
130 
131  bool ga_workspace::is_disabled_variable(const std::string &name) const {
132  VAR_SET::const_iterator it = variables.find(name);
133  if (it != variables.end()) return false;
134  if (variable_group_exists(name))
135  return is_disabled_variable(first_variable_of_group(name));
136  if (md && md->variable_exists(name)) {
137  if (enable_all_md_variables) return false;
138  return md->is_disabled_variable(name);
139  }
140  if (parent_workspace && parent_workspace->variable_exists(name))
141  return parent_workspace->is_disabled_variable(name);
142  GMM_ASSERT1(false, "Undefined variable " << name);
143  }
144 
145  const scalar_type &
146  ga_workspace::factor_of_variable(const std::string &name) const {
147  static const scalar_type one(1);
148  VAR_SET::const_iterator it = variables.find(name);
149  if (it != variables.end()) return one;
150  if (variable_group_exists(name))
151  return one;
152  if (md && md->variable_exists(name)) return md->factor_of_variable(name);
153  if (parent_workspace && parent_workspace->variable_exists(name))
154  return parent_workspace->factor_of_variable(name);
155  GMM_ASSERT1(false, "Undefined variable " << name);
156  }
157 
158  const gmm::sub_interval &
159  ga_workspace::interval_of_disabled_variable(const std::string &name) const {
160  std::map<std::string, gmm::sub_interval>::const_iterator
161  it1 = int_disabled_variables.find(name);
162  if (it1 != int_disabled_variables.end()) return it1->second;
163  if (md->is_affine_dependent_variable(name))
164  return interval_of_disabled_variable(md->org_variable(name));
165 
166  size_type first = md->nb_dof();
167  for (const std::pair<std::string, gmm::sub_interval> &p
168  : int_disabled_variables)
169  first = std::max(first, p.second.last());
170 
171  int_disabled_variables[name]
172  = gmm::sub_interval(first, gmm::vect_size(value(name)));
173  return int_disabled_variables[name];
174  }
175 
176  const gmm::sub_interval &
177  ga_workspace::interval_of_variable(const std::string &name) const {
178  VAR_SET::const_iterator it = variables.find(name);
179  if (it != variables.end()) return it->second.I;
180  if (md && md->variable_exists(name)) {
181  if (enable_all_md_variables && md->is_disabled_variable(name))
182  return interval_of_disabled_variable(name);
183  return md->interval_of_variable(name);
184  }
185  if (parent_workspace && parent_workspace->variable_exists(name))
186  return parent_workspace->interval_of_variable(name);
187  GMM_ASSERT1(false, "Undefined variable " << name);
188  }
189 
190  const mesh_fem *
191  ga_workspace::associated_mf(const std::string &name) const {
192  VAR_SET::const_iterator it = variables.find(name);
193  if (it != variables.end())
194  return it->second.is_fem_dofs ? it->second.mf : 0;
195  if (md && md->variable_exists(name))
196  return md->pmesh_fem_of_variable(name);
197  if (parent_workspace && parent_workspace->variable_exists(name))
198  return parent_workspace->associated_mf(name);
199  if (variable_group_exists(name))
200  return associated_mf(first_variable_of_group(name));
201  GMM_ASSERT1(false, "Undefined variable or group " << name);
202  }
203 
204  const im_data *
205  ga_workspace::associated_im_data(const std::string &name) const {
206  VAR_SET::const_iterator it = variables.find(name);
207  if (it != variables.end()) return it->second.imd;
208  if (md && md->variable_exists(name))
209  return md->pim_data_of_variable(name);
210  if (parent_workspace && parent_workspace->variable_exists(name))
211  return parent_workspace->associated_im_data(name);
212  if (variable_group_exists(name)) return 0;
213  GMM_ASSERT1(false, "Undefined variable " << name);
214  }
215 
216  size_type ga_workspace::qdim(const std::string &name) const {
217  VAR_SET::const_iterator it = variables.find(name);
218  if (it != variables.end()) {
219  const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
220  const im_data *imd = it->second.imd;
221  size_type n = it->second.qdim();
222  if (mf) {
223  return n * mf->get_qdim();
224  } else if (imd) {
225  return n * imd->tensor_size().total_size();
226  }
227  return n;
228  }
229  if (md && md->variable_exists(name))
230  return md->qdim_of_variable(name);
231  if (parent_workspace && parent_workspace->variable_exists(name))
232  return parent_workspace->qdim(name);
233  if (variable_group_exists(name))
234  return qdim(first_variable_of_group(name));
235  GMM_ASSERT1(false, "Undefined variable or group " << name);
236  }
237 
238  bgeot::multi_index
239  ga_workspace::qdims(const std::string &name) const {
240  VAR_SET::const_iterator it = variables.find(name);
241  if (it != variables.end()) {
242  const mesh_fem *mf = it->second.is_fem_dofs ? it->second.mf : 0;
243  const im_data *imd = it->second.imd;
244  size_type n = it->second.qdim();
245  if (mf) {
246  bgeot::multi_index mi = mf->get_qdims();
247  if (n > 1 || it->second.qdims.size() > 1) {
248  size_type i = 0;
249  if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
250  for (; i < it->second.qdims.size(); ++i)
251  mi.push_back(it->second.qdims[i]);
252  }
253  return mi;
254  } else if (imd) {
255  bgeot::multi_index mi = imd->tensor_size();
256  size_type q = n / imd->nb_filtered_index();
257  GMM_ASSERT1(q % imd->nb_tensor_elem() == 0,
258  "Invalid mesh im data vector");
259  if (n > 1 || it->second.qdims.size() > 1) {
260  size_type i = 0;
261  if (mi.back() == 1) { mi.back() *= it->second.qdims[0]; ++i; }
262  for (; i < it->second.qdims.size(); ++i)
263  mi.push_back(it->second.qdims[i]);
264  }
265  return mi;
266  }
267  return it->second.qdims;
268  }
269  if (md && md->variable_exists(name))
270  return md->qdims_of_variable(name);
271  if (parent_workspace && parent_workspace->variable_exists(name))
272  return parent_workspace->qdims(name);
273  if (variable_group_exists(name))
274  return qdims(first_variable_of_group(name));
275  GMM_ASSERT1(false, "Undefined variable or group " << name);
276  }
277 
278  const model_real_plain_vector &
279  ga_workspace::value(const std::string &name) const {
280  VAR_SET::const_iterator it = variables.find(name);
281  if (it != variables.end())
282  return *(it->second.V);
283  if (md && md->variable_exists(name))
284  return md->real_variable(name);
285  if (parent_workspace && parent_workspace->variable_exists(name))
286  return parent_workspace->value(name);
287  if (variable_group_exists(name))
288  return value(first_variable_of_group(name));
289  GMM_ASSERT1(false, "Undefined variable or group " << name);
290  }
291 
292  scalar_type ga_workspace::get_time_step() const {
293  if (md) return md->get_time_step();
294  if (parent_workspace) return parent_workspace->get_time_step();
295  GMM_ASSERT1(false, "No time step defined here");
296  }
297 
298  void ga_workspace::add_interpolate_transformation
299  (const std::string &name, pinterpolate_transformation ptrans) {
300  if (transformations.find(name) != transformations.end())
301  GMM_ASSERT1(name.compare("neighbour_elt"), "neighbour_elt is a "
302  "reserved interpolate transformation name");
303  transformations[name] = ptrans;
304  }
305 
306  bool ga_workspace::interpolate_transformation_exists
307  (const std::string &name) const {
308  return (md && md->interpolate_transformation_exists(name)) ||
309  (parent_workspace &&
310  parent_workspace->interpolate_transformation_exists(name)) ||
311  (transformations.find(name) != transformations.end());
312  }
313 
314  pinterpolate_transformation
315  ga_workspace::interpolate_transformation(const std::string &name) const {
316  std::map<std::string, pinterpolate_transformation>::const_iterator
317  it = transformations.find(name);
318  if (it != transformations.end()) return it->second;
319  if (md && md->interpolate_transformation_exists(name))
320  return md->interpolate_transformation(name);
321  if (parent_workspace &&
322  parent_workspace->interpolate_transformation_exists(name))
323  return parent_workspace->interpolate_transformation(name);
324  GMM_ASSERT1(false, "Inexistent transformation " << name);
325  }
326 
327  bool ga_workspace::elementary_transformation_exists
328  (const std::string &name) const {
329  return (md && md->elementary_transformation_exists(name)) ||
330  (parent_workspace &&
331  parent_workspace->elementary_transformation_exists(name)) ||
332  (elem_transformations.find(name) != elem_transformations.end());
333  }
334 
335  pelementary_transformation
336  ga_workspace::elementary_transformation(const std::string &name) const {
337  std::map<std::string, pelementary_transformation>::const_iterator
338  it = elem_transformations.find(name);
339  if (it != elem_transformations.end()) return it->second;
340  if (md && md->elementary_transformation_exists(name))
341  return md->elementary_transformation(name);
342  if (parent_workspace &&
343  parent_workspace->elementary_transformation_exists(name))
344  return parent_workspace->elementary_transformation(name);
345  GMM_ASSERT1(false, "Inexistent elementary transformation " << name);
346  }
347 
348  const mesh_region &
349  ga_workspace::register_region(const mesh &m, const mesh_region &region) {
350  if (&m == &dummy_mesh())
351  return dummy_mesh_region();
352 
353  std::list<mesh_region> &lmr = registred_mesh_regions[&m];
354  for (const mesh_region &rg : lmr)
355  if (rg.compare(m, region, m)) return rg;
356  lmr.push_back(region);
357  return lmr.back();
358  }
359 
360 
361  void ga_workspace::add_tree(ga_tree &tree, const mesh &m,
362  const mesh_im &mim, const mesh_region &rg,
363  const std::string &expr,
364  size_type add_derivative_order,
365  bool function_expr, size_type for_interpolation,
366  const std::string varname_interpolation) {
367  if (tree.root) {
368 
369  // Eliminate the term if it corresponds to disabled variables
370  if ((tree.root->test_function_type >= 1 &&
371  is_disabled_variable(tree.root->name_test1)) ||
372  (tree.root->test_function_type >= 2 &&
373  is_disabled_variable(tree.root->name_test2))) {
374  // cout<<"disabling term "; ga_print_node(tree.root, cout); cout<<endl;
375  return;
376  }
377  // cout << "add tree with tests functions of " << tree.root->name_test1
378  // << " and " << tree.root->name_test2 << endl;
379  // ga_print_node(tree.root, cout); cout << endl;
380  bool remain = true;
381  size_type order = 0, ind_tree = 0;
382 
383  if (for_interpolation)
384  order = size_type(-1) - add_derivative_order;
385  else {
386  switch(tree.root->test_function_type) {
387  case 0: order = 0; break;
388  case 1: order = 1; break;
389  case 3: order = 2; break;
390  default: GMM_ASSERT1(false, "Inconsistent term "
391  << tree.root->test_function_type);
392  }
393  }
394 
395  bool found = false;
396  for (size_type i = 0; i < trees.size(); ++i) {
397  if (trees[i].mim == &mim && trees[i].m == &m &&
398  trees[i].order == order &&
399  trees[i].name_test1.compare(tree.root->name_test1) == 0 &&
400  trees[i].interpolate_name_test1.compare
401  (tree.root->interpolate_name_test1) == 0 &&
402  trees[i].name_test2.compare(tree.root->name_test2) == 0 &&
403  trees[i].interpolate_name_test2.compare
404  (tree.root->interpolate_name_test2) == 0 &&
405  trees[i].rg == &rg && trees[i].interpolation == for_interpolation &&
406  trees[i].varname_interpolation.compare(varname_interpolation)==0) {
407  ga_tree &ftree = *(trees[i].ptree);
408 
409  ftree.insert_node(ftree.root, GA_NODE_OP);
410  ftree.root->op_type = GA_PLUS;
411  ftree.root->children.resize(2, nullptr);
412  ftree.copy_node(tree.root, ftree.root, ftree.root->children[1]);
413  ga_semantic_analysis(ftree, *this, m,
414  ref_elt_dim_of_mesh(m), false, function_expr);
415  found = true;
416  break;
417  }
418  }
419 
420  if (!found) {
421  ind_tree = trees.size(); remain = false;
422  trees.push_back(tree_description());
423  trees.back().mim = &mim; trees.back().m = &m;
424  trees.back().rg = &rg;
425  trees.back().ptree = new ga_tree;
426  trees.back().ptree->swap(tree);
427  pga_tree_node root = trees.back().ptree->root;
428  trees.back().name_test1 = root->name_test1;
429  trees.back().name_test2 = root->name_test2;
430  trees.back().interpolate_name_test1 = root->interpolate_name_test1;
431  trees.back().interpolate_name_test2 = root->interpolate_name_test2;
432  trees.back().order = order;
433  trees.back().interpolation = for_interpolation;
434  trees.back().varname_interpolation = varname_interpolation;
435  }
436 
437  if (for_interpolation == 0 && order < add_derivative_order) {
438  std::set<var_trans_pair> expr_variables;
439  ga_extract_variables((remain ? tree : *(trees[ind_tree].ptree)).root,
440  *this, m, expr_variables, true);
441  for (const var_trans_pair &var : expr_variables) {
442  if (!(is_constant(var.varname))) {
443  ga_tree dtree = (remain ? tree : *(trees[ind_tree].ptree));
444  // cout << "Derivation with respect to " << var.first << " : "
445  // << var.second << " of " << ga_tree_to_string(dtree) << endl;
446  GA_TIC;
447  ga_derivative(dtree, *this, m, var.varname, var.transname, 1+order);
448  // cout << "Result : " << ga_tree_to_string(dtree) << endl;
449  GA_TOCTIC("Derivative time");
450  ga_semantic_analysis(dtree, *this, m,
451  ref_elt_dim_of_mesh(m), false, function_expr);
452  GA_TOCTIC("Analysis after Derivative time");
453  // cout << "after analysis " << ga_tree_to_string(dtree) << endl;
454  add_tree(dtree, m, mim, rg, expr, add_derivative_order,
455  function_expr, for_interpolation, varname_interpolation);
456  }
457  }
458  }
459  }
460  }
461 
462  ga_workspace::m_tree::~m_tree() { if (ptree) delete ptree; }
463  ga_workspace::m_tree::m_tree(const m_tree& o)
464  : ptree(o.ptree), meshdim(o.meshdim), ignore_X(o.ignore_X)
465  { if (o.ptree) ptree = new ga_tree(*(o.ptree)); }
466  ga_workspace::m_tree &ga_workspace::m_tree::operator =(const m_tree& o) {
467  if (ptree) delete ptree;
468  ptree = o.ptree; meshdim = o.meshdim; ignore_X = o.ignore_X;
469  if (o.ptree) ptree = new ga_tree(*(o.ptree));
470  return *this;
471  }
472 
473  size_type ga_workspace::add_expression(const std::string &expr,
474  const mesh_im &mim,
475  const mesh_region &rg_,
476  size_type add_derivative_order) {
477  const mesh_region &rg = register_region(mim.linked_mesh(), rg_);
478  // cout << "adding expression " << expr << endl;
479  GA_TIC;
480  size_type max_order = 0;
481  std::vector<ga_tree> ltrees(1);
482  ga_read_string(expr, ltrees[0], macro_dictionnary());
483  // cout << "read : " << ga_tree_to_string(ltrees[0]) << endl;
484  ga_semantic_analysis(ltrees[0], *this, mim.linked_mesh(),
485  ref_elt_dim_of_mesh(mim.linked_mesh()),
486  false, false, 1);
487  // cout << "analysed : " << ga_tree_to_string(ltrees[0]) << endl;
488  GA_TOC("First analysis time");
489  if (ltrees[0].root) {
490  if (test1.size() > 1 || test2.size() > 1) {
491  size_type ntest2 = std::max(size_type(1), test2.size());
492  size_type nb_ltrees = test1.size()*ntest2;
493  ltrees.resize(nb_ltrees);
494  for (size_type i = 1; i < nb_ltrees; ++i) ltrees[i] = ltrees[0];
495  std::set<var_trans_pair>::iterator it1 = test1.begin();
496  for (size_type i = 0; i < test1.size(); ++i, ++it1) {
497  std::set<var_trans_pair>::iterator it2 = test2.begin();
498  for (size_type j = 0; j < ntest2; ++j) {
499  selected_test1 = *it1;
500  if (test2.size()) selected_test2 = *it2++;
501  // cout << "analysis with " << selected_test1.first << endl;
502  ga_semantic_analysis(ltrees[i*ntest2+j], *this,
503  mim.linked_mesh(),
504  ref_elt_dim_of_mesh(mim.linked_mesh()),
505  false, false, 2);
506  // cout <<"split: "<< ga_tree_to_string(ltrees[i*ntest2+j]) << endl;
507  }
508  }
509  }
510 
511  for (size_type i = 0; i < ltrees.size(); ++i) {
512  if (ltrees[i].root) {
513  // cout << "adding tree " << ga_tree_to_string(ltrees[i]) << endl;
514  max_order = std::max(ltrees[i].root->nb_test_functions(), max_order);
515  add_tree(ltrees[i], mim.linked_mesh(), mim, rg, expr,
516  add_derivative_order, true, 0, "");
517  }
518  }
519  }
520  GA_TOC("Time for add expression");
521  return max_order;
522  }
523 
524  void ga_workspace::add_function_expression(const std::string &expr) {
525  ga_tree tree;
526  ga_read_string(expr, tree, macro_dictionnary());
527  ga_semantic_analysis(tree, *this, *((const mesh *)(0)), 1, false, true);
528  if (tree.root) {
529  // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
530  // "Invalid function expression");
531  add_tree(tree, dummy_mesh(), dummy_mesh_im(), dummy_mesh_region(),
532  expr, 0, true, 0, "");
533  }
534  }
535 
536  void ga_workspace::add_interpolation_expression(const std::string &expr,
537  const mesh &m,
538  const mesh_region &rg_) {
539  const mesh_region &rg = register_region(m, rg_);
540  ga_tree tree;
541  ga_read_string(expr, tree, macro_dictionnary());
542  ga_semantic_analysis(tree, *this, m, ref_elt_dim_of_mesh(m),
543  false, false);
544  if (tree.root) {
545  // GMM_ASSERT1(tree.root->nb_test_functions() == 0,
546  // "Invalid expression containing test functions");
547  add_tree(tree, m, dummy_mesh_im(), rg, expr, 0, false, 1, "");
548  }
549  }
550 
551  void ga_workspace::add_interpolation_expression(const std::string &expr,
552  const mesh_im &mim,
553  const mesh_region &rg_) {
554  const mesh &m = mim.linked_mesh();
555  const mesh_region &rg = register_region(m, rg_);
556  ga_tree tree;
557  ga_read_string(expr, tree, macro_dictionnary());
558  ga_semantic_analysis(tree, *this, m, ref_elt_dim_of_mesh(m),
559  false, false);
560  if (tree.root) {
561  GMM_ASSERT1(tree.root->nb_test_functions() == 0,
562  "Invalid expression containing test functions");
563  add_tree(tree, m, mim, rg, expr, 0, false, 1, "");
564  }
565  }
566 
567  void ga_workspace::add_assignment_expression
568  (const std::string &varname, const std::string &expr, const mesh_region &rg_,
569  size_type order, bool before) {
570  const im_data *imd = associated_im_data(varname);
571  GMM_ASSERT1(imd != 0, "Only applicable to im_data");
572  const mesh_im &mim = imd->linked_mesh_im();
573  const mesh &m = mim.linked_mesh();
574  const mesh_region &rg = register_region(m, rg_);
575  ga_tree tree;
576  ga_read_string(expr, tree, macro_dictionnary());
577  ga_semantic_analysis(tree, *this, m, ref_elt_dim_of_mesh(m), false, false);
578  if (tree.root) {
579  GMM_ASSERT1(tree.root->nb_test_functions() == 0,
580  "Invalid expression containing test functions");
581  add_tree(tree, m, mim, rg, expr, order+1, false, (before ? 1 : 2),
582  varname);
583  }
584  }
585 
586  size_type ga_workspace::nb_trees() const { return trees.size(); }
587 
588  ga_workspace::tree_description &ga_workspace::tree_info(size_type i)
589  { return trees[i]; }
590 
591  bool ga_workspace::used_variables(std::vector<std::string> &vl,
592  std::vector<std::string> &vl_test1,
593  std::vector<std::string> &vl_test2,
594  std::vector<std::string> &dl,
595  size_type order) {
596  bool islin = true;
597  std::set<var_trans_pair> vll, dll;
598  for (size_type i = 0; i < vl.size(); ++i)
599  vll.insert(var_trans_pair(vl[i], ""));
600  for (size_type i = 0; i < dl.size(); ++i)
601  dll.insert(var_trans_pair(dl[i], ""));
602 
603  for (size_type i = 0; i < trees.size(); ++i) {
604  ga_workspace::tree_description &td = trees[i];
605  std::set<var_trans_pair> dllaux;
606  bool fv = ga_extract_variables(td.ptree->root, *this, *(td.m),
607  dllaux, false);
608 
609  if (td.order == order) {
610  for (std::set<var_trans_pair>::iterator it = dllaux.begin();
611  it!=dllaux.end(); ++it)
612  dll.insert(*it);
613  }
614  switch (td.order) {
615  case 0: break;
616  case 1:
617  if (td.order == order) {
618  if (variable_group_exists(td.name_test1)) {
619  for (const std::string &t : variable_group(td.name_test1))
620  vll.insert(var_trans_pair(t, td.interpolate_name_test1));
621  } else {
622  vll.insert(var_trans_pair(td.name_test1,
623  td.interpolate_name_test1));
624  }
625  bool found = false;
626  for (const std::string &t : vl_test1)
627  if (td.name_test1.compare(t) == 0)
628  found = true;
629  if (!found)
630  vl_test1.push_back(td.name_test1);
631  }
632  break;
633  case 2:
634  if (td.order == order) {
635  if (variable_group_exists(td.name_test1)) {
636  for (const std::string &t : variable_group(td.name_test1))
637  vll.insert(var_trans_pair(t, td.interpolate_name_test1));
638  } else {
639  vll.insert(var_trans_pair(td.name_test1,
640  td.interpolate_name_test1));
641  }
642  if (variable_group_exists(td.name_test2)) {
643  for (const std::string &t : variable_group(td.name_test2))
644  vll.insert(var_trans_pair(t, td.interpolate_name_test2));
645  } else {
646  vll.insert(var_trans_pair(td.name_test2,
647  td.interpolate_name_test2));
648  }
649  bool found = false;
650  for (size_type j = 0; j < vl_test1.size(); ++j)
651  if ((td.name_test1.compare(vl_test1[j]) == 0) &&
652  (td.name_test2.compare(vl_test2[j]) == 0))
653  found = true;
654  if (!found) {
655  vl_test1.push_back(td.name_test1);
656  vl_test2.push_back(td.name_test2);
657  }
658  }
659  if (fv) islin = false;
660  break;
661  }
662  }
663  vl.clear();
664  for (const auto &var : vll)
665  if (vl.size() == 0 || var.varname.compare(vl.back()))
666  vl.push_back(var.varname);
667  dl.clear();
668  for (const auto &var : dll)
669  if (dl.size() == 0 || var.varname.compare(dl.back()))
670  dl.push_back(var.varname);
671 
672  return islin;
673  }
674 
675  void ga_workspace::define_variable_group(const std::string &group_name,
676  const std::vector<std::string> &nl) {
677  GMM_ASSERT1(!(variable_exists(group_name)), "The name of a group of "
678  "variables cannot be the same as a variable name");
679 
680  std::set<const mesh *> ms;
681  bool is_data_ = false;
682  for (size_type i = 0; i < nl.size(); ++i) {
683  if (i == 0)
684  is_data_ = is_constant(nl[i]);
685  else {
686  GMM_ASSERT1(is_data_ == is_constant(nl[i]),
687  "It is not possible to mix variables and data in a group");
688  }
689  GMM_ASSERT1(variable_exists(nl[i]),
690  "All variables in a group have to exist in the model");
691  const mesh_fem *mf = associated_mf(nl[i]);
692  GMM_ASSERT1(mf, "Variables in a group should be fem variables");
693  GMM_ASSERT1(ms.find(&(mf->linked_mesh())) == ms.end(),
694  "Two variables in a group cannot share the same mesh");
695  ms.insert(&(mf->linked_mesh()));
696  }
697  variable_groups[group_name] = nl;
698  }
699 
700 
701  const std::string &ga_workspace::variable_in_group
702  (const std::string &group_name, const mesh &m) const {
703  if (variable_group_exists(group_name)) {
704  for (const std::string &t : variable_group(group_name))
705  if (&(associated_mf(t)->linked_mesh()) == &m)
706  return t;
707  GMM_ASSERT1(false, "No variable in this group for the given mesh");
708  } else
709  return group_name;
710  }
711 
712 
713  void ga_workspace::assembly(size_type order) {
714  size_type ndof;
715  const ga_workspace *w = this;
716  while (w->parent_workspace) w = w->parent_workspace;
717  if (w->md) ndof = w->md->nb_dof(); // To eventually call actualize_sizes()
718 
719  GA_TIC;
720  ga_instruction_set gis;
721  ga_compile(*this, gis, order);
722  ndof = gis.nb_dof;
723  size_type max_dof = gis.max_dof;
724  GA_TOCTIC("Compile time");
725 
726  if (order == 2) {
727  if (K.use_count()) {
728  gmm::clear(*K);
729  gmm::resize(*K, max_dof, max_dof);
730  }
731  gmm::clear(unreduced_K);
732  gmm::resize(unreduced_K, ndof, ndof);
733  }
734  if (order == 1) {
735  if (V.use_count()) {
736  gmm::clear(*V);
737  gmm::resize(*V, max_dof);
738  }
739  gmm::clear(unreduced_V);
740  gmm::resize(unreduced_V, ndof);
741  }
742  gmm::clear(assembled_tensor().as_vector());
743  GA_TOCTIC("Init time");
744 
745  ga_exec(gis, *this);
746  GA_TOCTIC("Exec time");
747 
748  if (order == 1) {
749  MPI_SUM_VECTOR(assembled_vector());
750  MPI_SUM_VECTOR(unreduced_V);
751  } else if (order == 0) {
752  MPI_SUM_VECTOR(assembled_tensor().as_vector());
753  }
754 
755  // Deal with reduced fems.
756  if (order > 0) {
757  std::set<std::string> vars_vec_done;
758  std::set<std::pair<std::string, std::string> > vars_mat_done;
759  for (ga_tree &tree : gis.trees) {
760  if (tree.root) {
761  if (order == 1) {
762  const std::string &name = tree.root->name_test1;
763  const std::vector<std::string> vnames_(1,name);
764  const std::vector<std::string> &vnames
765  = variable_group_exists(name) ? variable_group(name)
766  : vnames_;
767  for (const std::string &vname : vnames) {
768  const mesh_fem *mf = associated_mf(vname);
769  if (mf && mf->is_reduced() &&
770  vars_vec_done.find(vname) == vars_vec_done.end()) {
771  gmm::mult_add(gmm::transposed(mf->extension_matrix()),
772  gmm::sub_vector(unreduced_V,
773  gis.var_intervals[vname]),
774  gmm::sub_vector(*V,
775  interval_of_variable(vname)));
776  vars_vec_done.insert(vname);
777  }
778  }
779  } else {
780  std::string &name1 = tree.root->name_test1;
781  std::string &name2 = tree.root->name_test2;
782  const std::vector<std::string> vnames1_(1,name1),
783  vnames2_(2,name2);
784  const std::vector<std::string> &vnames1
785  = variable_group_exists(name1) ? variable_group(name1)
786  : vnames1_;
787  const std::vector<std::string> &vnames2
788  = variable_group_exists(name2) ? variable_group(name2)
789  : vnames2_;
790  for (const std::string &vname1 : vnames1) {
791  for (const std::string &vname2 : vnames2) {
792  const mesh_fem *mf1 = associated_mf(vname1);
793  const mesh_fem *mf2 = associated_mf(vname2);
794  if (((mf1 && mf1->is_reduced())
795  || (mf2 && mf2->is_reduced()))) {
796  std::pair<std::string, std::string> p(vname1, vname2);
797  if (vars_mat_done.find(p) == vars_mat_done.end()) {
798  gmm::sub_interval uI1 = gis.var_intervals[vname1];
799  gmm::sub_interval uI2 = gis.var_intervals[vname2];
800  gmm::sub_interval I1 = interval_of_variable(vname1);
801  gmm::sub_interval I2 = interval_of_variable(vname2);
802  if ((mf1 && mf1->is_reduced()) &&
803  (mf2 && mf2->is_reduced())) {
804  model_real_sparse_matrix aux(I1.size(), uI2.size());
805  model_real_row_sparse_matrix M(I1.size(), I2.size());
806  gmm::mult(gmm::transposed(mf1->extension_matrix()),
807  gmm::sub_matrix(unreduced_K, uI1, uI2), aux);
808  gmm::mult(aux, mf2->extension_matrix(), M);
809  gmm::add(M, gmm::sub_matrix(*K, I1, I2));
810  } else if (mf1 && mf1->is_reduced()) {
811  model_real_sparse_matrix M(I1.size(), I2.size());
812  gmm::mult(gmm::transposed(mf1->extension_matrix()),
813  gmm::sub_matrix(unreduced_K, uI1, uI2), M);
814  gmm::add(M, gmm::sub_matrix(*K, I1, I2));
815  } else {
816  model_real_row_sparse_matrix M(I1.size(), I2.size());
817  gmm::mult(gmm::sub_matrix(unreduced_K, uI1, uI2),
818  mf2->extension_matrix(), M);
819  gmm::add(M, gmm::sub_matrix(*K, I1, I2));
820  }
821  vars_mat_done.insert(p);
822  }
823  }
824  }
825  }
826  }
827  }
828  }
829  }
830  }
831 
832  void ga_workspace::set_include_empty_int_points(bool include) {
833  include_empty_int_pts = include;
834  }
835 
836  bool ga_workspace::include_empty_int_points() const {
837  return include_empty_int_pts;
838  }
839 
840  void ga_workspace::clear_expressions() { trees.clear(); }
841 
842  void ga_workspace::print(std::ostream &str) {
843  for (size_type i = 0; i < trees.size(); ++i)
844  if (trees[i].ptree->root) {
845  cout << "Expression tree " << i << " of order " <<
846  trees[i].ptree->root->nb_test_functions() << " :" << endl;
847  ga_print_node(trees[i].ptree->root, str);
848  cout << endl;
849  }
850  }
851 
852  void ga_workspace::tree_description::copy(const tree_description& td) {
853  order = td.order;
854  interpolation = td.interpolation;
855  varname_interpolation = td.varname_interpolation;
856  name_test1 = td.name_test1;
857  name_test2 = td.name_test2;
858  interpolate_name_test1 = td.interpolate_name_test1;
859  interpolate_name_test2 = td.interpolate_name_test2;
860  mim = td.mim;
861  m = td.m;
862  rg = td.rg;
863  ptree = 0;
864  if (td.ptree) ptree = new ga_tree(*(td.ptree));
865  }
866 
867  ga_workspace::tree_description &ga_workspace::tree_description::operator =
868  (const ga_workspace::tree_description& td)
869  { if (ptree) delete ptree; ptree = 0; copy(td); return *this; }
870  ga_workspace::tree_description::~tree_description()
871  { if (ptree) delete ptree; ptree = 0; }
872 
873  ga_workspace::ga_workspace(const getfem::model &md_,
874  bool enable_all_variables)
875  : md(&md_), parent_workspace(0),
876  enable_all_md_variables(enable_all_variables),
877  macro_dict(md_.macro_dictionnary())
878  { init(); }
879  ga_workspace::ga_workspace(bool, const ga_workspace &gaw)
880  : md(0), parent_workspace(&gaw), enable_all_md_variables(false),
881  macro_dict(gaw.macro_dictionnary())
882  { init(); }
883  ga_workspace::ga_workspace()
884  : md(0), parent_workspace(0), enable_all_md_variables(false)
885  { init(); }
886  ga_workspace::~ga_workspace() { clear_expressions(); }
887 
888  //=========================================================================
889  // Extract the constant term of degree 1 expressions
890  //=========================================================================
891 
892  std::string ga_workspace::extract_constant_term(const mesh &m) {
893  std::string constant_term;
894  for (size_type i = 0; i < trees.size(); ++i) {
895  ga_workspace::tree_description &td = trees[i];
896 
897  if (td.order == 1) {
898  ga_tree local_tree = *(td.ptree);
899  if (local_tree.root)
900  ga_node_extract_constant_term(local_tree, local_tree.root, *this, m);
901  if (local_tree.root)
902  ga_semantic_analysis(local_tree, *this, m,
903  ref_elt_dim_of_mesh(m), false, false);
904  if (local_tree.root && local_tree.root->node_type != GA_NODE_ZERO) {
905  constant_term += "-("+ga_tree_to_string(local_tree)+")";
906  }
907  }
908  }
909  return constant_term;
910  }
911 
912  //=========================================================================
913  // Extract the order zero term
914  //=========================================================================
915 
916  std::string ga_workspace::extract_order0_term() {
917  std::string term;
918  for (size_type i = 0; i < trees.size(); ++i) {
919  ga_workspace::tree_description &td = trees[i];
920  if (td.order == 0) {
921  ga_tree &local_tree = *(td.ptree);
922  if (term.size())
923  term += "+("+ga_tree_to_string(local_tree)+")";
924  else
925  term = "("+ga_tree_to_string(local_tree)+")";
926  }
927  }
928  return term;
929  }
930 
931 
932  //=========================================================================
933  // Extract the order one term corresponding to a certain test function
934  //=========================================================================
935 
936  std::string ga_workspace::extract_order1_term(const std::string &varname) {
937  std::string term;
938  for (size_type i = 0; i < trees.size(); ++i) {
939  ga_workspace::tree_description &td = trees[i];
940  if (td.order == 1 && td.name_test1.compare(varname) == 0) {
941  ga_tree &local_tree = *(td.ptree);
942  if (term.size())
943  term += "+("+ga_tree_to_string(local_tree)+")";
944  else
945  term = "("+ga_tree_to_string(local_tree)+")";
946  }
947  }
948  return term;
949  }
950 
951  //=========================================================================
952  // Extract Neumann terms
953  //=========================================================================
954 
955  std::string ga_workspace::extract_Neumann_term(const std::string &varname) {
956  std::string result;
957  for (size_type i = 0; i < trees.size(); ++i) {
958  ga_workspace::tree_description &td = trees[i];
959  if (td.order == 1 && td.name_test1.compare(varname) == 0) {
960  ga_tree &local_tree = *(td.ptree);
961  if (local_tree.root)
962  ga_extract_Neumann_term(local_tree, varname, *this,
963  local_tree.root, result);
964  }
965  }
966  return result;
967  }
968 
969 } /* end of namespace */
const mesh_im & dummy_mesh_im()
Dummy mesh_im for default parameter of functions.
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.
pinterpolate_transformation interpolate_transformation_neighbour_instance()
Create a new instance of a transformation corresponding to the interpolation on the neighbour element...
Semantic analysis of assembly trees and semantic manipulations.
``Model&#39;&#39; variables store the variables, the data and the description of a model. ...
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
void copy(const L1 &l1, L2 &l2)
*/
Definition: gmm_blas.h:977
GEneric Tool for Finite Element Methods.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*/
Definition: gmm_blas.h:1779
Compilation and execution operations.
void resize(M &v, size_type m, size_type n)
*/
Definition: gmm_blas.h:231