37 #ifndef GETFEM_ASSEMBLING_TENSORS_H__ 38 #define GETFEM_ASSEMBLING_TENSORS_H__ 48 #define ASM_THROW_PARSE_ERROR(x) \ 49 GMM_ASSERT1(false, "parse error: " << x << endl << "found here:\n " \ 50 << syntax_err_print()); 51 #define ASM_THROW_TENSOR_ERROR(x) \ 52 GMM_ASSERT1(false, "tensor error: " << x); 53 #define ASM_THROW_ERROR(x) GMM_ASSERT1(false, "error: " << x); 56 using bgeot::stride_type;
57 using bgeot::index_type;
58 using bgeot::index_set;
59 using bgeot::tensor_ranges;
60 using bgeot::tensor_strides;
61 using bgeot::tensor_mask;
62 using bgeot::tensor_shape;
63 using bgeot::tensor_ref;
64 using bgeot::multi_tensor_iterator;
74 std::deque< ATN_tensor* > childs_;
79 dim_type current_face;
81 ATN(
const std::string& n=std::string(
"unnamed")) :
82 name_(n), number_(unsigned(-1)), current_cv(
size_type(-1)),
83 current_face(dim_type(-1)) {}
86 void add_child(ATN_tensor& a) { childs_.push_back(&a); }
87 ATN_tensor& child(
size_type n) {
return *childs_[n]; }
88 size_type nchilds() {
return childs_.size(); }
91 void reinit() {
if (!is_zero_size()) reinit_(); }
94 if (cv != current_cv || face != current_face) {
101 const std::string& name() {
return name_; }
102 void set_name(
const std::string& n) { name_ = n; }
106 virtual void update_childs_required_shape();
108 virtual bool is_zero_size();
112 void set_number(
unsigned &gcnt);
113 unsigned number()
const {
return number_; }
115 virtual void reinit_() = 0;
116 virtual void exec_(
size_type , dim_type ) {}
119 class ATN_tensors_sum_scaled;
122 class ATN_tensor :
public ATN {
127 tensor_shape req_shape;
133 ATN_tensor() { shape_updated_ =
false; frozen_ =
false; }
134 bool is_shape_updated()
const {
return shape_updated_; }
135 void freeze() { frozen_ =
true; }
136 bool is_frozen()
const {
return frozen_; }
137 const tensor_ranges& ranges()
const {
return r_; }
138 const tensor_shape& required_shape()
const {
return req_shape; }
144 virtual void check_shape_update(
size_type , dim_type) {}
146 virtual void init_required_shape() { req_shape.set_empty(r_); }
149 virtual void update_childs_required_shape() {
150 for (dim_type i=0; i < nchilds(); ++i) {
151 child(i).merge_required_shape(req_shape);
157 tensor_ref& tensor() {
161 bool is_zero_size() {
return r_.is_zero_size(); }
163 void merge_required_shape(
const tensor_shape& shape_from_parent) {
164 req_shape.merge(shape_from_parent,
false);
169 virtual ATN_tensors_sum_scaled* is_tensors_sum_scaled() {
return 0; }
178 bool is_mf_ref()
const {
return (pmf != 0); }
179 vdim_specif() { dim =
size_type(-1); pmf = 0; }
180 vdim_specif(
size_type i) { dim = i; pmf = 0; }
181 vdim_specif(
const mesh_fem *pmf_) { dim = pmf_->nb_dof(); pmf = pmf_; }
183 class vdim_specif_list :
public std::vector< vdim_specif > {
185 vdim_specif_list() { reserve(8); }
188 void build_strides_for_cv(
size_type cv, tensor_ranges& r,
189 std::vector<tensor_strides >& str)
const;
195 template<
typename VEC >
class ATN_array_output :
public ATN {
197 vdim_specif_list vdim;
198 multi_tensor_iterator mti;
199 tensor_strides strides;
202 ATN_array_output(ATN_tensor& a, VEC& v_, vdim_specif_list &d)
205 strides.resize(vdim.size()+1);
209 for (
size_type i=0; i < vdim.size(); ++i) {
210 if (vdim[i].pmf) pmf = vdim[i].pmf;
211 strides[i+1] = strides[i]*int(vdim[i].dim);
213 if (gmm::vect_size(v) !=
size_type(strides[vdim.size()]))
214 ASM_THROW_TENSOR_ERROR(
"wrong size for output vector: supplied " 215 "vector size is " << gmm::vect_size(v)
216 <<
" while it should be " 217 << strides[vdim.size()]);
221 mti = multi_tensor_iterator(child(0).tensor(),
true);
226 std::vector< tensor_strides > str;
227 vdim.build_strides_for_cv(cv, r, str);
228 if (child(0).ranges() != r) {
229 ASM_THROW_TENSOR_ERROR(
"can't output a tensor of dimensions " 230 << child(0).ranges() <<
231 " into an output array of size " << r);
234 if (pmf && pmf->is_reduced()) {
235 if ( pmf->nb_dof() != 0)
239 dim_type qqdim = dim_type(gmm::vect_size(v) / nb_dof);
243 for (dim_type j=0; j < mti.ndim(); ++j) i += str[j][mti.index(j)];
244 gmm::add(gmm::scaled(gmm::mat_row(pmf->extension_matrix(), i),
248 GMM_ASSERT1(
false,
"To be verified ... ");
250 for (dim_type j=0; j < mti.ndim(); ++j) i += str[j][mti.index(j)];
251 gmm::add(gmm::scaled(gmm::mat_row(pmf->extension_matrix(),i/qqdim),
253 gmm::sub_vector(v, gmm::sub_slice(i%qqdim,nb_dof,qqdim)));
255 }
while (mti.qnext1());
260 typename gmm::linalg_traits<VEC>::iterator it = gmm::vect_begin(v);
261 for (dim_type j = 0; j < mti.ndim(); ++j) it += str[j][mti.index(j)];
263 }
while (mti.qnext1());
268 template <
typename MAT,
typename ROW,
typename COL>
269 void asmrankoneupdate(
const MAT &m_,
const ROW &row,
const COL &col,
271 MAT &m =
const_cast<MAT &
>(m_);
272 typename gmm::linalg_traits<ROW>::const_iterator itr = row.begin();
273 for (; itr != row.end(); ++itr) {
274 typename gmm::linalg_traits<COL>::const_iterator itc = col.begin();
275 for (; itc != col.end(); ++itc)
276 m(itr.index(), itc.index()) += (*itr) * (*itc) * r;
280 template <
typename MAT,
typename ROW>
281 void asmrankoneupdate(
const MAT &m_,
const ROW &row,
size_type j, scalar_type r) {
282 MAT &m =
const_cast<MAT &
>(m_);
283 typename gmm::linalg_traits<ROW>::const_iterator itr = row.begin();
284 for (; itr != row.end(); ++itr) m(itr.index(), j) += (*itr) * r;
287 template <
typename MAT,
typename COL>
288 void asmrankoneupdate(
const MAT &m_,
size_type j,
const COL &col, scalar_type r) {
289 MAT &m =
const_cast<MAT &
>(m_);
290 typename gmm::linalg_traits<COL>::const_iterator itc = col.begin();
291 for (; itc != col.end(); ++itc) m(j, itc.index()) += (*itc) * r;
295 template<
typename MAT >
class ATN_smatrix_output :
public ATN {
296 const mesh_fem &mf_r, &mf_c;
298 multi_tensor_iterator mti;
306 ATN_smatrix_output(ATN_tensor& a,
const mesh_fem& mf_r_,
307 const mesh_fem& mf_c_, MAT& m_)
308 : mf_r(mf_r_), mf_c(mf_c_), m(m_) {
314 mti = multi_tensor_iterator(child(0).tensor(),
true);
318 size_type nb_r = mf_r.nb_basic_dof_of_element(cv);
319 size_type nb_c = mf_c.nb_basic_dof_of_element(cv);
320 if (child(0).tensor().ndim() != 2)
321 ASM_THROW_TENSOR_ERROR(
"cannot write a " <<
322 int(child(0).tensor().ndim()) <<
323 "D-tensor into a matrix!");
324 if (child(0).tensor().dim(0) != nb_r ||
325 child(0).tensor().dim(1) != nb_c) {
326 ASM_THROW_TENSOR_ERROR(
"size mismatch for sparse matrix output:" 327 " tensor dimension is " << child(0).ranges()
328 <<
", while the elementary matrix for convex " 329 << cv <<
" should have " << nb_r <<
"x" 330 << nb_c <<
" elements");
332 std::vector<size_type> cvdof_r(mf_r.ind_basic_dof_of_element(cv).begin(),
333 mf_r.ind_basic_dof_of_element(cv).end());
334 std::vector<size_type> cvdof_c(mf_c.ind_basic_dof_of_element(cv).begin(),
335 mf_c.ind_basic_dof_of_element(cv).end());
337 if (it.size() == 0) {
345 }
while (mti.qnext1());
348 bool valid_mf_r = mf_r.nb_dof() > 0;
349 bool valid_mf_c = mf_c.nb_dof() > 0;
351 if (mf_r.is_reduced()) {
352 if (mf_c.is_reduced() && valid_mf_r && valid_mf_c) {
353 for (
unsigned i = 0; i < it.size(); ++i)
355 asmrankoneupdate(m, gmm::mat_row(mf_r.extension_matrix(),
357 gmm::mat_row(mf_c.extension_matrix(),
361 else if (valid_mf_r) {
362 for (
unsigned i = 0; i < it.size(); ++i)
364 asmrankoneupdate(m, gmm::mat_row(mf_r.extension_matrix(),
366 cvdof_c[it[i].j], *it[i].p);
370 if (mf_c.is_reduced() && valid_mf_c) {
371 for (
unsigned i = 0; i < it.size(); ++i)
373 asmrankoneupdate(m, cvdof_r[it[i].i],
374 gmm::mat_row(mf_c.extension_matrix(),
379 for (
unsigned i = 0; i < it.size(); ++i)
381 m(cvdof_r[it[i].i], cvdof_c[it[i].j]) += *it[i].p;
393 class base_asm_data {
396 virtual void copy_with_mti(
const std::vector<tensor_strides> &,
397 multi_tensor_iterator &,
398 const mesh_fem *)
const = 0;
399 virtual ~base_asm_data() {}
402 template<
typename VEC >
class asm_data :
public base_asm_data {
405 asm_data(
const VEC *v_) : v(*v_) {}
407 return gmm::vect_size(v);
411 void copy_with_mti(
const std::vector<tensor_strides> &str,
412 multi_tensor_iterator &mti,
const mesh_fem *pmf)
const {
414 if (pmf && pmf->is_reduced()) {
417 for (dim_type i = 0; i < mti.ndim(); ++i) ppos+=str[i][mti.index(i)];
419 = gmm::vect_sp(gmm::mat_row(pmf->extension_matrix(), ppos), v);
420 }
while (mti.qnext1());
426 for (dim_type i = 0; i < mti.ndim(); ++i) ppos+=str[i][mti.index(i)];
428 }
while (mti.qnext1());
435 virtual std::unique_ptr<ATN> build_output_tensor(ATN_tensor &a,
436 vdim_specif_list& vdim)=0;
437 virtual ~base_asm_vec() {}
440 template<
typename VEC >
class asm_vec :
public base_asm_vec {
441 std::shared_ptr<VEC> v;
443 asm_vec(
const std::shared_ptr<VEC> &v_) : v(v_) {}
444 asm_vec(VEC *v_) : v(
std::shared_ptr<VEC>(), v_) {}
445 virtual std::unique_ptr<ATN> build_output_tensor(ATN_tensor &a,
446 vdim_specif_list& vdim) {
447 return std::make_unique<ATN_array_output<VEC>>(a, *v, vdim);
449 VEC *vec() {
return v.get(); }
455 class base_vec_factory {
457 virtual base_asm_vec* create_vec(
const tensor_ranges& r) = 0;
458 virtual ~base_vec_factory() {}
461 template<
typename VEC >
class vec_factory
462 :
public base_vec_factory,
private std::deque<asm_vec<VEC> > {
464 base_asm_vec* create_vec(
const tensor_ranges& r) {
467 ASM_THROW_TENSOR_ERROR(
"can't create a vector of size " << r);
468 this->push_back(asm_vec<VEC>(std::make_shared<VEC>(sz)));
469 return &this->back();
477 virtual std::unique_ptr<ATN>
478 build_output_tensor(ATN_tensor& a,
const mesh_fem& mf1,
479 const mesh_fem& mf2) = 0;
480 virtual ~base_asm_mat() {}
483 template<
typename MAT >
class asm_mat :
public base_asm_mat {
484 std::shared_ptr<MAT> m;
486 asm_mat(
const std::shared_ptr<MAT> &m_) : m(m_) {}
487 asm_mat(MAT *m_) : m(
std::shared_ptr<MAT>(), m_) {}
489 build_output_tensor(ATN_tensor& a,
const mesh_fem& mf1,
490 const mesh_fem& mf2) {
491 return std::make_unique<ATN_smatrix_output<MAT>>(a, mf1, mf2, *m);
493 MAT *mat() {
return m.get(); }
497 class base_mat_factory {
500 virtual ~base_mat_factory() {};
503 template<
typename MAT >
class mat_factory
504 :
public base_mat_factory,
private std::deque<asm_mat<MAT> > {
507 this->push_back(asm_mat<MAT>(std::make_shared<MAT>(m, n)));
508 return &this->back();
515 typedef enum { TNCONST, TNTENSOR, TNNONE } node_type;
521 tnode() : type_(TNNONE), x(1e300), t(NULL) {}
522 tnode(scalar_type x_) { assign(x_); }
523 tnode(ATN_tensor *t_) { assign(t_); }
524 void assign(scalar_type x_) { type_ = TNCONST; t = NULL; x = x_; }
525 void assign(ATN_tensor *t_) { type_ = TNTENSOR; t = t_; x = 1e300; }
526 ATN_tensor* tensor() { assert(type_ == TNTENSOR);
return t; }
527 scalar_type xval() { assert(type_ == TNCONST);
return x; }
528 node_type type() {
return type_; }
529 void check0() {
if (xval() == 0) ASM_THROW_ERROR(
"division by zero"); }
532 class asm_tokenizer {
534 typedef enum { OPEN_PAR=
'(', CLOSE_PAR=
')', COMMA=
',',
535 SEMICOLON=
';', COLON=
':', EQUAL=
'=', MFREF=
'#', IMREF=
'%',
536 PLUS=
'+',MINUS=
'-', PRODUCT=
'.',MULTIPLY=
'*',
537 DIVIDE=
'/', ARGNUM_SELECTOR=
'$',
538 OPEN_BRACE=
'{', CLOSE_BRACE=
'}',
539 END=0, IDENT=1, NUMBER=2 } tok_type_enum;
543 tok_type_enum curr_tok_type;
544 std::string curr_tok;
546 double curr_tok_dval;
548 std::deque<size_type> marks;
551 void set_str(
const std::string& s_) {
552 str = s_; tok_pos = 0; tok_len =
size_type(-1); curr_tok_type = END;
553 err_msg_mark = 0; get_tok();
555 std::string tok()
const {
return curr_tok; }
556 tok_type_enum tok_type()
const {
return curr_tok_type; }
559 {
return str.substr(i1, i2-i1); }
560 void err_set_mark() {
561 err_msg_mark = tok_pos;
563 void push_mark() { marks.push_back(tok_pos); }
564 void pop_mark() { assert(marks.size()); marks.pop_back(); }
565 std::string mark_txt() {
566 assert(marks.size());
567 return tok_substr(marks.back(),tok_pos);
571 std::string syntax_err_print();
572 void accept(tok_type_enum t,
const char *msg_=
"syntax error") {
573 if (tok_type() != t) ASM_THROW_PARSE_ERROR(msg_); advance();
575 void accept(tok_type_enum t, tok_type_enum t2,
576 const char *msg_=
"syntax error") {
577 if (tok_type() != t && tok_type() != t2)
578 ASM_THROW_PARSE_ERROR(msg_);
581 bool advance_if(tok_type_enum t) {
582 if (tok_type() == t) { advance();
return true; }
else return false;
584 void advance() { tok_pos += tok_len; get_tok(); }
586 double tok_number_dval()
587 { assert(tok_type()==NUMBER);
return curr_tok_dval; }
588 int tok_number_ival(
int maxval=10000000) {
589 int n=int(tok_number_dval());
590 if (n != curr_tok_dval) ASM_THROW_PARSE_ERROR(
"not an integer");
591 if (n > maxval) ASM_THROW_PARSE_ERROR(
"out of bound integer");
595 { assert(tok_type()==MFREF);
return curr_tok_ival; }
597 { assert(tok_type()==IMREF);
return curr_tok_ival; }
599 { assert(tok_type()==ARGNUM_SELECTOR);
return curr_tok_ival; }
608 std::vector<const mesh_fem *> mftab;
609 std::vector<const mesh_im *> imtab;
610 std::vector<pnonlinear_elem_term> innonlin;
612 std::vector<std::unique_ptr<base_asm_data>> indata;
613 std::vector<std::shared_ptr<base_asm_vec>> outvec;
615 std::vector<std::shared_ptr<base_asm_mat>> outmat;
618 base_vec_factory *vec_fact;
620 base_mat_factory *mat_fact;
623 std::vector<std::unique_ptr<ATN>> outvars;
626 std::map<std::string, ATN_tensor *> vars;
627 std::vector<std::unique_ptr<ATN_tensor>> atn_tensors;
638 vec_fact(0), mat_fact(0), parse_done(
false)
642 void set(
const std::string& s_) { set_str(s_); }
643 const std::vector<const mesh_fem*>& mf()
const {
return mftab; }
644 const std::vector<const mesh_im*>& im()
const {
return imtab; }
645 const std::vector<pnonlinear_elem_term> nonlin()
const {
return innonlin; }
646 const std::vector<std::unique_ptr<base_asm_data>>& data()
const {
return indata; }
647 const std::vector<std::shared_ptr<base_asm_vec>>& vec()
const {
return outvec; }
648 const std::vector<std::shared_ptr<base_asm_mat>>& mat()
const {
return outmat; }
653 void push_im(
const mesh_im& im_) { imtab.push_back(&im_); }
656 innonlin.push_back(net);
660 indata.push_back(std::make_unique<asm_data<VEC>>(&d));
664 outvec.push_back(std::make_shared<asm_vec<VEC>>(&(gmm::linalg_cast(v))));
667 template<
typename VEC >
void push_vec(
const VEC& v) {
668 outvec.push_back(std::make_shared<asm_vec<VEC>>(&(gmm::linalg_cast(v))));
671 template<
typename MAT >
void push_mat(
const MAT& m) {
672 outmat.push_back(std::make_shared<asm_mat<MAT>>(&(gmm::linalg_cast(m))));
676 outmat.push_back(std::make_shared<asm_mat<MAT>>(&(gmm::linalg_cast(m))));
679 template <
typename T>
void push_mat_or_vec(T &v) {
680 push_mat_or_vec(v,
typename gmm::linalg_traits<T>::linalg_type());
685 void set_mat_factory(base_mat_factory *fact) { mat_fact = fact; }
688 ATN_tensor* record(std::unique_ptr<ATN_tensor> &&t) {
689 t->set_name(mark_txt());
690 atn_tensors.push_back(std::move(t));
return atn_tensors.back().get();
692 ATN* record_out(std::unique_ptr<ATN> t) {
693 t->set_name(mark_txt());
694 outvars.push_back(std::move(t));
return outvars.back().get();
697 const mesh_fem& do_mf_arg(std::vector<const mesh_fem*> *multimf = 0);
698 void do_dim_spec(vdim_specif_list& lst);
699 std::string do_comp_red_ops();
700 ATN_tensor* do_comp();
701 ATN_tensor* do_data();
702 std::pair<ATN_tensor*, std::string> do_red_ops(ATN_tensor* t);
705 tnode do_prod_trans();
710 void consistency_check();
711 template <
typename T>
void push_mat_or_vec(T &v, gmm::abstract_vector) {
714 template <
typename T>
void push_mat_or_vec(T &v, gmm::abstract_matrix) {
structure used to hold a set of convexes and/or convex faces.
void push_data(const VEC &d)
Add a new data (dense array)
static mesh_region all_convexes()
provide a default value for the mesh_region parameters of assembly procedures etc.
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.
Define the getfem::mesh_im class (integration of getfem::mesh_fem).
Define the getfem::mesh_fem class.
Describe an integration method linked to a mesh.
void push_vec(const VEC &v)
Add a new output vector (fake const version..)
void push_mf(const mesh_fem &mf_)
Add a new mesh_fem.
Generic assembly of vectors, matrices.
size_t size_type
used as the common size type in the library
Sparse tensors, used during the assembly.
void push_mat(MAT &m)
Add a new output matrix.
void set_vec_factory(base_vec_factory *fact)
used by the getfem_interface..
Include the base gmm files.
elementary computations (used by the generic assembly).
GEneric Tool for Finite Element Methods.
Build elementary tensors descriptors, used by generic assembly.
Describe a finite element method linked to a mesh.
void push_mat(const MAT &m)
Add a new output matrix (fake const version..)
abstract class for integration of non-linear terms into the mat_elem computations the nonlinear term ...
void push_vec(VEC &v)
Add a new output vector.