GetFEM  5.5
getfem_assembling_tensors.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2003-2026 Julien Pommier
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program. If not, see https://www.gnu.org/licenses/.
19 
20  As a special exception, you may use this file as it is a part of a free
21  software library without restriction. Specifically, if other files
22  instantiate templates or use macros or inline functions from this file,
23  or you compile this file and link it with other files to produce an
24  executable, this file does not by itself cause the resulting executable
25  to be covered by the GNU Lesser General Public License. This exception
26  does not however invalidate any other reasons why the executable file
27  might be covered by the GNU Lesser General Public License.
28 
29 ===========================================================================*/
30 
31 /**@file getfem_assembling_tensors.h
32  @author Julien Pommier <Julien.Pommier@insa-toulouse.fr>
33  @date January 2003.
34  @brief Generic assembly implementation.
35 */
36 #ifndef GETFEM_ASSEMBLING_TENSORS_H__
37 #define GETFEM_ASSEMBLING_TENSORS_H__
38 
39 #include "gmm/gmm_kernel.h"
40 #include "getfem_mesh_fem.h"
41 #include "getfem_mesh_im.h"
42 #include "bgeot_sparse_tensors.h"
43 #include "getfem_mat_elem_type.h"
44 #include "getfem_mat_elem.h"
45 #include <map>
46 
47 #define ASM_THROW_PARSE_ERROR(x) \
48  GMM_ASSERT1(false, "parse error: " << x << endl << "found here:\n " \
49  << syntax_err_print());
50 #define ASM_THROW_TENSOR_ERROR(x) \
51  GMM_ASSERT1(false, "tensor error: " << x);
52 #define ASM_THROW_ERROR(x) GMM_ASSERT1(false, "error: " << x);
53 
54 namespace getfem {
55  using bgeot::stride_type;
56  using bgeot::index_type;
57  using bgeot::index_set;
58  using bgeot::tensor_ranges;
59  using bgeot::tensor_strides;
60  using bgeot::tensor_mask;
61  using bgeot::tensor_shape;
62  using bgeot::tensor_ref;
63  using bgeot::multi_tensor_iterator;
64  using bgeot::TDIter;
65 
66  class ATN_tensor;
67 
68  /*
69  base class for the tree built from the expression of the tensor assembly
70  (ATN == Assembly Tree Node)
71  */
72  class ATN {
73  std::deque< ATN_tensor* > childs_;
74  std::string name_;/* the name is a part of the parsed string */
75  unsigned number_; /* a unique number, used for the ordering of the tree */
76  protected:
77  size_type current_cv;
78  dim_type current_face;
79  public:
80  ATN(const std::string& n=std::string("unnamed")) :
81  name_(n), number_(unsigned(-1)), current_cv(size_type(-1)),
82  current_face(dim_type(-1)) {}
83  virtual ~ATN() {}
84 
85  void add_child(ATN_tensor& a) { childs_.push_back(&a); }
86  ATN_tensor& child(size_type n) { return *childs_[n]; }
87  size_type nchilds() { return childs_.size(); }
88  /* reinit is called each time the object need to reset itself
89  (when the shape of one of its childs has changed) */
90  void reinit() { if (!is_zero_size()) reinit_(); }
91  /* do the computations for a given convex */
92  void exec(size_type cv, dim_type face) {
93  if (cv != current_cv || face != current_face) {
94  if (!is_zero_size())
95  exec_(cv,face);
96  current_cv = cv;
97  current_face = face;
98  }
99  }
100  const std::string& name() { return name_; }
101  void set_name(const std::string& n) { name_ = n; }
102  /* the "root" nodes expect to get all tensor values
103  others nodes have a more specific behavior
104  */
105  virtual void update_childs_required_shape();
106 
107  virtual bool is_zero_size();
108 
109  /* numbering og tensors, such that if i < j then tensor(j)
110  cannot be in the sub-tree of tensor(i) */
111  void set_number(unsigned &gcnt);
112  unsigned number() const { return number_; }
113  private:
114  virtual void reinit_() = 0;
115  virtual void exec_(size_type , dim_type ) {}
116  };
117 
118  class ATN_tensors_sum_scaled;
119 
120  /* Base class for every node except the "final" ones */
121  class ATN_tensor : public ATN {
122  protected:
123  tensor_ranges r_;
124  bool shape_updated_;
125  tensor_ref tr;
126  tensor_shape req_shape;
127  bool frozen_; /* used to recognize intermediate results of
128  computations stored in a temporary variable: they
129  cannot be modified a posteriori (like it could
130  happen with an ATN_tensors_sum_scaled) */
131  public:
132  ATN_tensor() { shape_updated_ = false; frozen_ = false; }
133  bool is_shape_updated() const { return shape_updated_; }
134  void freeze() { frozen_ = true; }
135  bool is_frozen() const { return frozen_; }
136  const tensor_ranges& ranges() const { return r_; }
137  const tensor_shape& required_shape() const { return req_shape; }
138  /* check_shape_update is called for each node of the tree
139  if the shape of the tensor has been modified, the flag
140  shape_updated_ should be set, and r_ should contain the
141  new dimensions. This function is called in such an order
142  that the shape updates are automatically propagated in the tree */
143  virtual void check_shape_update(size_type , dim_type) {}
144  /* if the shape was updated, the node should initialise its req_shape */
145  virtual void init_required_shape() { req_shape.set_empty(r_); }
146  /* then each node update the req_shape of its childs.
147  */
148  virtual void update_childs_required_shape() {
149  for (dim_type i=0; i < nchilds(); ++i) {
150  child(i).merge_required_shape(req_shape);
151  }
152  }
153  /* ... then reserve some memory if necessary for tensor storage
154  in 'reinit' (inherited here from ATN)
155  */
156  tensor_ref& tensor() {
157  return tr;
158  }
159 
160  bool is_zero_size() { return r_.is_zero_size(); }
161 
162  void merge_required_shape(const tensor_shape& shape_from_parent) {
163  req_shape.merge(shape_from_parent, false);
164  }
165  /* recognize sums of scaled tensors
166  (in order to stack those sums on the same object)
167  (dynamic_cast prohibited for the moment: crashes matlab) */
168  virtual ATN_tensors_sum_scaled* is_tensors_sum_scaled() { return 0; }
169  };
170 
171 
172  /* simple list of "virtual" dimensions, i.e. which may be constant
173  or be given by a mesh_fem */
174  struct vdim_specif {
175  size_type dim;
176  const mesh_fem *pmf;
177  bool is_mf_ref() const { return (pmf != 0); }
178  vdim_specif() { dim = size_type(-1); pmf = 0; }
179  vdim_specif(size_type i) { dim = i; pmf = 0; }
180  vdim_specif(const mesh_fem *pmf_) { dim = pmf_->nb_dof(); pmf = pmf_; }
181  };
182  class vdim_specif_list : public std::vector< vdim_specif > {
183  public:
184  vdim_specif_list() { reserve(8); }
185  size_type nb_mf() const;
186  size_type nbelt() const;
187  void build_strides_for_cv(size_type cv, tensor_ranges& r,
188  std::vector<tensor_strides >& str) const;
189  };
190 
191  /* final node for array output: array means full array of 0,1,2,3 or
192  more dimensions, stored in a vector VEC in fortran order
193  */
194  template< typename VEC > class ATN_array_output : public ATN {
195  VEC& v;
196  vdim_specif_list vdim;
197  multi_tensor_iterator mti;
198  tensor_strides strides;
199  const mesh_fem *pmf;
200  public:
201  ATN_array_output(ATN_tensor& a, VEC& v_, vdim_specif_list &d)
202  : v(v_), vdim(d) {
203 
204  strides.resize(vdim.size()+1);
205  add_child(a);
206  strides[0] = 1;
207  pmf = 0;
208  for (size_type i=0; i < vdim.size(); ++i) {
209  if (vdim[i].pmf) pmf = vdim[i].pmf;
210  strides[i+1] = strides[i]*int(vdim[i].dim);
211  }
212  if (gmm::vect_size(v) != size_type(strides[vdim.size()]))
213  ASM_THROW_TENSOR_ERROR("wrong size for output vector: supplied "
214  "vector size is " << gmm::vect_size(v)
215  << " while it should be "
216  << strides[vdim.size()]);
217  }
218  private:
219  void reinit_() {
220  mti = multi_tensor_iterator(child(0).tensor(),true);
221  }
222 
223  void exec_(size_type cv, dim_type) {
224  tensor_ranges r;
225  std::vector< tensor_strides > str;
226  vdim.build_strides_for_cv(cv, r, str);
227  if (child(0).ranges() != r) {
228  ASM_THROW_TENSOR_ERROR("can't output a tensor of dimensions "
229  << child(0).ranges() <<
230  " into an output array of size " << r);
231  }
232  mti.rewind();
233  if (pmf && pmf->is_reduced()) {
234  if ( pmf->nb_dof() != 0)
235  {
236  do {
237  size_type nb_dof = pmf->nb_dof();
238  dim_type qqdim = dim_type(gmm::vect_size(v) / nb_dof);
239 
240  if (qqdim == 1) {
241  size_type i = 0;
242  for (dim_type j=0; j < mti.ndim(); ++j) i += str[j][mti.index(j)];
243  gmm::add(gmm::scaled(gmm::mat_row(pmf->extension_matrix(), i),
244  mti.p(0)), v);
245  }
246  else {
247  GMM_ASSERT1(false, "To be verified ... ");
248  size_type i = 0;
249  for (dim_type j=0; j < mti.ndim(); ++j) i += str[j][mti.index(j)];
250  gmm::add(gmm::scaled(gmm::mat_row(pmf->extension_matrix(),i/qqdim),
251  mti.p(0)),
252  gmm::sub_vector(v, gmm::sub_slice(i%qqdim,nb_dof,qqdim)));
253  }
254  } while (mti.qnext1());
255  }
256  }
257  else {
258  do {
259  typename gmm::linalg_traits<VEC>::iterator it = gmm::vect_begin(v);
260  for (dim_type j = 0; j < mti.ndim(); ++j) it += str[j][mti.index(j)];
261  *it += mti.p(0);
262  } while (mti.qnext1());
263  }
264  }
265  };
266 
267  template <typename MAT, typename ROW, typename COL>
268  void asmrankoneupdate(const MAT &m_, const ROW &row, const COL &col,
269  scalar_type r) {
270  MAT &m = const_cast<MAT &>(m_);
271  typename gmm::linalg_traits<ROW>::const_iterator itr = row.begin();
272  for (; itr != row.end(); ++itr) {
273  typename gmm::linalg_traits<COL>::const_iterator itc = col.begin();
274  for (; itc != col.end(); ++itc)
275  m(itr.index(), itc.index()) += (*itr) * (*itc) * r;
276  }
277  }
278 
279  template <typename MAT, typename ROW>
280  void asmrankoneupdate(const MAT &m_, const ROW &row, size_type j, scalar_type r) {
281  MAT &m = const_cast<MAT &>(m_);
282  typename gmm::linalg_traits<ROW>::const_iterator itr = row.begin();
283  for (; itr != row.end(); ++itr) m(itr.index(), j) += (*itr) * r;
284  }
285 
286  template <typename MAT, typename COL>
287  void asmrankoneupdate(const MAT &m_, size_type j, const COL &col, scalar_type r) {
288  MAT &m = const_cast<MAT &>(m_);
289  typename gmm::linalg_traits<COL>::const_iterator itc = col.begin();
290  for (; itc != col.end(); ++itc) m(j, itc.index()) += (*itc) * r;
291  }
292 
293  /* final node for sparse matrix output */
294  template< typename MAT > class ATN_smatrix_output : public ATN {
295  const mesh_fem &mf_r, &mf_c;
296  MAT& m;
297  multi_tensor_iterator mti;
298  struct ijv { // just a fast cache for the mti output
299  // (yes it makes a small difference)
300  scalar_type *p;
301  unsigned i,j;
302  };
303  std::vector<ijv> it;
304  public:
305  ATN_smatrix_output(ATN_tensor& a, const mesh_fem& mf_r_,
306  const mesh_fem& mf_c_, MAT& m_)
307  : mf_r(mf_r_), mf_c(mf_c_), m(m_) {
308  add_child(a);
309  it.reserve(100);
310  }
311  private:
312  void reinit_() {
313  mti = multi_tensor_iterator(child(0).tensor(),true);
314  it.resize(0);
315  }
316  void exec_(size_type cv, dim_type) {
317  size_type nb_r = mf_r.nb_basic_dof_of_element(cv);
318  size_type nb_c = mf_c.nb_basic_dof_of_element(cv);
319  if (child(0).tensor().ndim() != 2)
320  ASM_THROW_TENSOR_ERROR("cannot write a " <<
321  int(child(0).tensor().ndim()) <<
322  "D-tensor into a matrix!");
323  if (child(0).tensor().dim(0) != nb_r ||
324  child(0).tensor().dim(1) != nb_c) {
325  ASM_THROW_TENSOR_ERROR("size mismatch for sparse matrix output:"
326  " tensor dimension is " << child(0).ranges()
327  << ", while the elementary matrix for convex "
328  << cv << " should have " << nb_r << "x"
329  << nb_c << " elements");
330  }
331  std::vector<size_type> cvdof_r(mf_r.ind_basic_dof_of_element(cv).begin(),
332  mf_r.ind_basic_dof_of_element(cv).end());
333  std::vector<size_type> cvdof_c(mf_c.ind_basic_dof_of_element(cv).begin(),
334  mf_c.ind_basic_dof_of_element(cv).end());
335 
336  if (it.size() == 0) {
337  mti.rewind();
338  do {
339  ijv v;
340  v.p = &mti.p(0);
341  v.i = mti.index(0);
342  v.j = mti.index(1);
343  it.push_back(v);
344  } while (mti.qnext1());
345  }
346 
347  bool valid_mf_r = mf_r.nb_dof() > 0;
348  bool valid_mf_c = mf_c.nb_dof() > 0;
349 
350  if (mf_r.is_reduced()) {
351  if (mf_c.is_reduced() && valid_mf_r && valid_mf_c) {
352  for (unsigned i = 0; i < it.size(); ++i)
353  if (*it[i].p)
354  asmrankoneupdate(m, gmm::mat_row(mf_r.extension_matrix(),
355  cvdof_r[it[i].i]),
356  gmm::mat_row(mf_c.extension_matrix(),
357  cvdof_c[it[i].j]),
358  *it[i].p);
359  }
360  else if (valid_mf_r) {
361  for (unsigned i = 0; i < it.size(); ++i)
362  if (*it[i].p)
363  asmrankoneupdate(m, gmm::mat_row(mf_r.extension_matrix(),
364  cvdof_r[it[i].i]),
365  cvdof_c[it[i].j], *it[i].p);
366  }
367  }
368  else {
369  if (mf_c.is_reduced() && valid_mf_c) {
370  for (unsigned i = 0; i < it.size(); ++i)
371  if (*it[i].p)
372  asmrankoneupdate(m, cvdof_r[it[i].i],
373  gmm::mat_row(mf_c.extension_matrix(),
374  cvdof_c[it[i].j]),
375  *it[i].p);
376  }
377  else {
378  for (unsigned i = 0; i < it.size(); ++i)
379  if (*it[i].p)
380  m(cvdof_r[it[i].i], cvdof_c[it[i].j]) += *it[i].p;
381  }
382  }
383  }
384  };
385 
386 
387 
388  /* some wrappers : their aim is to provide a better genericity,
389  and to avoid the whole templatization of the 'generic_assembly' class,
390  which is quite(!) big
391  */
392  class base_asm_data {
393  public:
394  virtual size_type vect_size() const = 0;
395  virtual void copy_with_mti(const std::vector<tensor_strides> &,
396  multi_tensor_iterator &,
397  const mesh_fem *) const = 0;
398  virtual ~base_asm_data() {}
399  };
400 
401  template< typename VEC > class asm_data : public base_asm_data {
402  const VEC &v;
403  public:
404  asm_data(const VEC *v_) : v(*v_) {}
405  size_type vect_size() const {
406  return gmm::vect_size(v);
407  }
408  /* used to transfer the data for the current convex to the mti of
409  ATN_tensor_from_dofs_data */
410  void copy_with_mti(const std::vector<tensor_strides> &str,
411  multi_tensor_iterator &mti, const mesh_fem *pmf) const {
412  size_type ppos;
413  if (pmf && pmf->is_reduced()) {
414  do {
415  ppos = 0;
416  for (dim_type i = 0; i < mti.ndim(); ++i) ppos+=str[i][mti.index(i)];
417  mti.p(0)
418  = gmm::vect_sp(gmm::mat_row(pmf->extension_matrix(), ppos), v);
419  } while (mti.qnext1());
420 
421  }
422  else {
423  do {
424  ppos = 0;
425  for (dim_type i = 0; i < mti.ndim(); ++i) ppos+=str[i][mti.index(i)];
426  mti.p(0) = v[ppos];
427  } while (mti.qnext1());
428  }
429  }
430  };
431 
432  class base_asm_vec {
433  public:
434  virtual std::unique_ptr<ATN> build_output_tensor(ATN_tensor &a,
435  vdim_specif_list& vdim)=0;
436  virtual ~base_asm_vec() {}
437  };
438 
439  template< typename VEC > class asm_vec : public base_asm_vec {
440  std::shared_ptr<VEC> v;
441  public:
442  asm_vec(const std::shared_ptr<VEC> &v_) : v(v_) {}
443  asm_vec(VEC *v_) : v(std::shared_ptr<VEC>(), v_) {}
444  virtual std::unique_ptr<ATN> build_output_tensor(ATN_tensor &a,
445  vdim_specif_list& vdim) {
446  return std::make_unique<ATN_array_output<VEC>>(a, *v, vdim);
447  }
448  VEC *vec() { return v.get(); }
449  };
450 
451  /* the "factory" is only useful for the matlab interface,
452  since the number of output arrays and sparse matrices is unknown
453  for user-supplied assemblies. Hence they are created "on-the-fly" */
454  class base_vec_factory {
455  public:
456  virtual base_asm_vec* create_vec(const tensor_ranges& r) = 0;
457  virtual ~base_vec_factory() {}
458  };
459 
460  template< typename VEC > class vec_factory
461  : public base_vec_factory, private std::deque<asm_vec<VEC> > {
462  public:
463  base_asm_vec* create_vec(const tensor_ranges& r) {
464  size_type sz = 1; for (size_type i=0; i < r.size(); ++i) sz *= r[i];
465  if (sz == 0)
466  ASM_THROW_TENSOR_ERROR("can't create a vector of size " << r);
467  this->push_back(asm_vec<VEC>(std::make_shared<VEC>(sz)));
468  return &this->back();
469  }
470  };
471 
472 
473  /* matrix wrappers */
474  class base_asm_mat {
475  public:
476  virtual std::unique_ptr<ATN>
477  build_output_tensor(ATN_tensor& a, const mesh_fem& mf1,
478  const mesh_fem& mf2) = 0;
479  virtual ~base_asm_mat() {}
480  };
481 
482  template< typename MAT > class asm_mat : public base_asm_mat {
483  std::shared_ptr<MAT> m;
484  public:
485  asm_mat(const std::shared_ptr<MAT> &m_) : m(m_) {}
486  asm_mat(MAT *m_) : m(std::shared_ptr<MAT>(), m_) {}
487  std::unique_ptr<ATN>
488  build_output_tensor(ATN_tensor& a, const mesh_fem& mf1,
489  const mesh_fem& mf2) {
490  return std::make_unique<ATN_smatrix_output<MAT>>(a, mf1, mf2, *m);
491  }
492  MAT *mat() { return m.get(); }
493  ~asm_mat() {}
494  };
495 
496  class base_mat_factory {
497  public:
498  virtual base_asm_mat* create_mat(size_type m, size_type n) = 0;
499  virtual ~base_mat_factory() {};
500  };
501 
502  template< typename MAT > class mat_factory
503  : public base_mat_factory, private std::deque<asm_mat<MAT> > {
504  public:
505  base_asm_mat* create_mat(size_type m, size_type n) {
506  this->push_back(asm_mat<MAT>(std::make_shared<MAT>(m, n)));
507  return &this->back();
508  }
509  };
510 
511 
512  class tnode {
513  public:
514  typedef enum { TNCONST, TNTENSOR, TNNONE } node_type;
515  private:
516  node_type type_;
517  scalar_type x;
518  ATN_tensor *t;
519  public:
520  tnode() : type_(TNNONE), x(1e300), t(NULL) {}
521  tnode(scalar_type x_) { assign(x_); }
522  tnode(ATN_tensor *t_) { assign(t_); }
523  void assign(scalar_type x_) { type_ = TNCONST; t = NULL; x = x_; }
524  void assign(ATN_tensor *t_) { type_ = TNTENSOR; t = t_; x = 1e300; }
525  ATN_tensor* tensor() { assert(type_ == TNTENSOR); return t; }
526  scalar_type xval() { assert(type_ == TNCONST); return x; }
527  node_type type() { return type_; }
528  void check0() { if (xval() == 0) ASM_THROW_ERROR("division by zero"); }
529  };
530 
531  class asm_tokenizer {
532  public:
533  typedef enum { OPEN_PAR='(', CLOSE_PAR=')', COMMA=',',
534  SEMICOLON=';', COLON=':', EQUAL='=', MFREF='#', IMREF='%',
535  PLUS='+',MINUS='-', PRODUCT='.',MULTIPLY='*',
536  DIVIDE='/', ARGNUM_SELECTOR='$',
537  OPEN_BRACE='{', CLOSE_BRACE='}',
538  END=0, IDENT=1, NUMBER=2 } tok_type_enum;
539  private:
540  std::string str;
541  size_type tok_pos, tok_len;
542  tok_type_enum curr_tok_type;
543  std::string curr_tok;
544  int curr_tok_ival;
545  double curr_tok_dval;
546  size_type err_msg_mark;
547  std::deque<size_type> marks;
548  public:
549  asm_tokenizer() {}
550  void set_str(const std::string& s_) {
551  str = s_; tok_pos = 0; tok_len = size_type(-1); curr_tok_type = END;
552  err_msg_mark = 0; get_tok();
553  }
554  std::string tok() const { return curr_tok; }
555  tok_type_enum tok_type() const { return curr_tok_type; }
556  size_type tok_mark() { return tok_pos; }
557  std::string tok_substr(size_type i1, size_type i2)
558  { return str.substr(i1, i2-i1); }
559  void err_set_mark() {
560  err_msg_mark = tok_pos;
561  }
562  void push_mark() { marks.push_back(tok_pos); }
563  void pop_mark() { assert(marks.size()); marks.pop_back(); }
564  std::string mark_txt() {
565  assert(marks.size());
566  return tok_substr(marks.back(),tok_pos);
567  }
568 
569  /* returns a friendly message indicated the location of the syntax error */
570  std::string syntax_err_print();
571  void accept(tok_type_enum t, const char *msg_="syntax error") {
572  if (tok_type() != t) ASM_THROW_PARSE_ERROR(msg_); advance();
573  }
574  void accept(tok_type_enum t, tok_type_enum t2,
575  const char *msg_="syntax error") {
576  if (tok_type() != t && tok_type() != t2)
577  ASM_THROW_PARSE_ERROR(msg_);
578  advance();
579  }
580  bool advance_if(tok_type_enum t) {
581  if (tok_type() == t) { advance(); return true; } else return false;
582  }
583  void advance() { tok_pos += tok_len; get_tok(); }
584  void get_tok();
585  double tok_number_dval()
586  { assert(tok_type()==NUMBER); return curr_tok_dval; }
587  int tok_number_ival(int maxval=10000000) {
588  int n=int(tok_number_dval());
589  if (n != curr_tok_dval) ASM_THROW_PARSE_ERROR("not an integer");
590  if (n > maxval) ASM_THROW_PARSE_ERROR("out of bound integer");
591  return n-1; /* -1 pour un indicage qui commence à 1! */
592  }
593  size_type tok_mfref_num()
594  { assert(tok_type()==MFREF); return curr_tok_ival; }
595  size_type tok_imref_num()
596  { assert(tok_type()==IMREF); return curr_tok_ival; }
597  size_type tok_argnum()
598  { assert(tok_type()==ARGNUM_SELECTOR); return curr_tok_ival; }
599  };
600 
601 
602  /** Generic assembly of vectors, matrices.
603 
604  Many examples of use available @link asm here@endlink.
605  */
606  class generic_assembly : public asm_tokenizer {
607  std::vector<const mesh_fem *> mftab; /* list of the mesh_fem used. */
608  std::vector<const mesh_im *> imtab; /* list of the mesh_im used. */
609  std::vector<pnonlinear_elem_term> innonlin; /* alternatives to base, */
610  /* grad, hess in comp() for non-linear computations) */
611  std::vector<std::unique_ptr<base_asm_data>> indata; /* data sources */
612  std::vector<std::shared_ptr<base_asm_vec>> outvec; /* vectors in which is done the */
613  /* assembly */
614  std::vector<std::shared_ptr<base_asm_mat>> outmat; /* matrices in which is done the */
615  /* assembly */
616 
617  base_vec_factory *vec_fact; /* if non null, used to fill the outvec */
618  /* list with a given vector class */
619  base_mat_factory *mat_fact; /* if non null, used to fill the outmat */
620  /* list with a given matrix class */
621 
622  std::vector<std::unique_ptr<ATN>> outvars; /* the list of "final tensors"*/
623  /* which produce some output in outvec and outmat. */
624 
625  std::map<std::string, ATN_tensor *> vars; /* the list of user variables */
626  std::vector<std::unique_ptr<ATN_tensor>> atn_tensors; /* keep track of */
627  /* all tensors objects (except the ones listed in 'outvars') for */
628  /* deallocation when all is done. Note that they are not stored in a */
629  /* random order, but are reordered such that the childs of the */
630  /* i-th ATN_tensor are all stored at indices j < i. This assumption is */
631  /* largely used for calls to shape updates and exec(cv,f). */
632  bool parse_done;
633 
634  public:
635  generic_assembly() : vec_fact(0), mat_fact(0), parse_done(false) {}
636  generic_assembly(const std::string& s_) :
637  vec_fact(0), mat_fact(0), parse_done(false)
638  { set_str(s_); }
639  ~generic_assembly() {}
640 
641  void set(const std::string& s_) { set_str(s_); }
642  const std::vector<const mesh_fem*>& mf() const { return mftab; }
643  const std::vector<const mesh_im*>& im() const { return imtab; }
644  const std::vector<pnonlinear_elem_term> nonlin() const { return innonlin; }
645  const std::vector<std::unique_ptr<base_asm_data>>& data() const { return indata; }
646  const std::vector<std::shared_ptr<base_asm_vec>>& vec() const { return outvec; }
647  const std::vector<std::shared_ptr<base_asm_mat>>& mat() const { return outmat; }
648  /// Add a new mesh_fem
649  void push_mf(const mesh_fem& mf_) { mftab.push_back(&mf_); }
650  /// Add a new mesh_im
651  void push_mi(const mesh_im& im_) { imtab.push_back(&im_); }
652  void push_im(const mesh_im& im_) { imtab.push_back(&im_); }
653  /// Add a new non-linear term
655  innonlin.push_back(net);
656  }
657  /// Add a new data (dense array)
658  template< typename VEC > void push_data(const VEC& d) {
659  indata.push_back(std::make_unique<asm_data<VEC>>(&d));
660  }
661  /// Add a new output vector
662  template< typename VEC > void push_vec(VEC& v) {
663  outvec.push_back(std::make_shared<asm_vec<VEC>>(&(gmm::linalg_cast(v))));
664  }
665  /// Add a new output vector (fake const version..)
666  template< typename VEC > void push_vec(const VEC& v) {
667  outvec.push_back(std::make_shared<asm_vec<VEC>>(&(gmm::linalg_cast(v))));
668  }
669  /// Add a new output matrix (fake const version..)
670  template< typename MAT > void push_mat(const MAT& m) {
671  outmat.push_back(std::make_shared<asm_mat<MAT>>(&(gmm::linalg_cast(m))));
672  }
673  /// Add a new output matrix
674  template< typename MAT > void push_mat(MAT& m) {
675  outmat.push_back(std::make_shared<asm_mat<MAT>>(&(gmm::linalg_cast(m))));
676  }
677 
678  template <typename T> void push_mat_or_vec(T &v) {
679  push_mat_or_vec(v, typename gmm::linalg_traits<T>::linalg_type());
680  }
681 
682  /// used by the getfem_interface..
683  void set_vec_factory(base_vec_factory *fact) { vec_fact = fact; }
684  void set_mat_factory(base_mat_factory *fact) { mat_fact = fact; }
685 
686  private:
687  ATN_tensor* record(std::unique_ptr<ATN_tensor> &&t) {
688  t->set_name(mark_txt());
689  atn_tensors.push_back(std::move(t)); return atn_tensors.back().get();
690  }
691  ATN* record_out(std::unique_ptr<ATN> t) {
692  t->set_name(mark_txt());
693  outvars.push_back(std::move(t)); return outvars.back().get();
694  }
695  const mesh_fem& do_mf_arg_basic();
696  const mesh_fem& do_mf_arg(std::vector<const mesh_fem*> *multimf = 0);
697  void do_dim_spec(vdim_specif_list& lst);
698  std::string do_comp_red_ops();
699  ATN_tensor* do_comp();
700  ATN_tensor* do_data();
701  std::pair<ATN_tensor*, std::string> do_red_ops(ATN_tensor* t);
702  tnode do_tens();
703  tnode do_prod();
704  tnode do_prod_trans();
705  tnode do_term();
706  tnode do_expr();
707  void do_instr();
708  void exec(size_type cv, dim_type face);
709  void consistency_check();
710  template <typename T> void push_mat_or_vec(T &v, gmm::abstract_vector) {
711  push_vec(v);
712  }
713  template <typename T> void push_mat_or_vec(T &v, gmm::abstract_matrix) {
714  push_mat(v);
715  }
716  public:
717  /* parse the string 'str' and build the tree of vtensors */
718  void parse();
719 
720  /** do the assembly on the specified region (boundary or set of convexes)*/
721  void assembly(const mesh_region &region =
723  };
724 } /* end of namespace getfem. */
725 
726 
727 #endif /* GETFEM_ASSEMBLING_TENSORS_H__ */
Sparse tensors, used during the assembly.
Generic assembly of vectors, matrices.
void push_vec(const VEC &v)
Add a new output vector (fake const version..)
void push_mat(MAT &m)
Add a new output matrix.
void push_vec(VEC &v)
Add a new output vector.
void push_data(const VEC &d)
Add a new data (dense array)
void set_vec_factory(base_vec_factory *fact)
used by the getfem_interface..
void push_mat(const MAT &m)
Add a new output matrix (fake const version..)
void assembly(const mesh_region &region=mesh_region::all_convexes())
do the assembly on the specified region (boundary or set of convexes)
void push_nonlinear_term(pnonlinear_elem_term net)
Add a new non-linear term.
void push_mi(const mesh_im &im_)
Add a new mesh_im.
void push_mf(const mesh_fem &mf_)
Add a new mesh_fem.
Describe a finite element method linked to a mesh.
Describe an integration method linked to a mesh.
static mesh_region all_convexes()
provide a default value for the mesh_region parameters of assembly procedures etc.
abstract class for integration of non-linear terms into the mat_elem computations the nonlinear term ...
elementary computations (used by the generic assembly).
Build elementary tensors descriptors, used by generic assembly.
Define the getfem::mesh_fem class.
Define the getfem::mesh_im class (integration of getfem::mesh_fem).
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*‍/
Definition: gmm_blas.h:263
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1275
Include the base gmm files.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
GEneric Tool for Finite Element Methods.