27 size_type vdim_specif_list::nb_mf()
const {
28 return std::count_if(begin(), end(),
29 std::mem_fn(&vdim_specif::is_mf_ref));
31 size_type vdim_specif_list::nbelt()
const {
33 for (const_iterator it = begin(); it != end(); ++it) sz *= (*it).dim;
36 void vdim_specif_list::build_strides_for_cv
37 (
size_type cv, tensor_ranges& r, std::vector<tensor_strides >& str)
const {
38 stride_type s = 1, cnt = 0;
41 for (const_iterator it = begin(); it != end(); ++it, ++cnt) {
42 if ((*it).is_mf_ref()) {
43 r[cnt] = unsigned((*it).pmf->nb_basic_dof_of_element(cv));
46 str[cnt].resize(r[cnt]);
47 for (index_type j=0; j < r[cnt]; ++j) {
48 str[cnt][j] = int((*it).pmf->ind_basic_dof_of_element(cv)[j]*s);
51 r[cnt] = int((*it).dim);
52 str[cnt].resize(r[cnt]);
53 for (index_type j=0; j < (*it).dim; ++j) {
57 s *= stride_type((*it).dim);
61 void ATN::update_childs_required_shape() {
62 for (dim_type i=0; i < nchilds(); ++i) {
63 child(i).merge_required_shape(tensor_shape(child(i).ranges()));
66 void ATN::set_number(
unsigned &gcnt) {
67 if (number_ ==
unsigned(-1)) {
68 for (
unsigned i=0; i < nchilds(); ++i) child(i).set_number(gcnt);
73 bool ATN::is_zero_size() {
74 return child(0).is_zero_size();
80 class ATN_tensor_w_data :
public ATN_tensor {
83 std::vector<scalar_type> data;
86 { ATN_tensor_w_data::reinit_(); std::fill(data.begin(), data.end(),0); }
90 void ATN_tensor_w_data::reinit_() {
91 tr.assign_shape(req_shape);
93 if (tr.card() > 10000000) {
94 cerr <<
"warning, a tensor of size " << tr.card()
95 <<
" will be created, it needs "
96 << tr.card()*
sizeof(scalar_type) <<
" bytes of memory\n";
99 cerr <<
"WARNING: tensor " << name()
100 <<
" will be created with a size of "
101 << ranges() <<
" and 0 non-null elements!" << endl;
103 data.resize(tr.card());
104 data_base = &data[0];
105 tr.set_base(data_base);
115 typedef std::vector<std::pair<ATN_tensor*,std::string> >
116 reduced_tensor_arg_type;
118 class ATN_reduced_tensor :
public ATN_tensor_w_data {
120 reduced_tensor_arg_type red;
121 bgeot::tensor_reduction tred;
123 void check_shape_update(
size_type , dim_type) {
124 shape_updated_ =
false;
125 for (dim_type i=0; i < nchilds(); ++i) {
126 if (child(i).is_shape_updated()) {
127 shape_updated_ =
true;
130 if (shape_updated_) {
132 for (dim_type i=0; i < nchilds(); ++i) {
133 std::string s = red_n(i);
134 if (s.size() != child(i).ranges().size()) {
135 ASM_THROW_TENSOR_ERROR(
"wrong number of indexes for the "
137 <<
"th argument of the reduction "
139 <<
" (ranges=" << child(i).ranges() <<
")");
141 for (
size_type j=0; j < s.length(); ++j) {
142 if (s[j] ==
' ') r_.push_back(child(i).ranges()[j]);
147 void update_childs_required_shape() {
150 for (dim_type n=0; n < nchilds(); ++n) {
151 tensor_shape ts(child(n).ranges());
152 tensor_ranges rn(child(n).ranges());
153 const std::string &s = red[n].second;
154 GMM_ASSERT1(rn.size() == s.size(),
"Wrong size !");
155 for (
unsigned i=0; i < rn.size(); ++i) {
158 if (p !=
size_type(-1) && p < i && rn[p] != rn[i])
159 ASM_THROW_TENSOR_ERROR(
"can't reduce the diagonal of a tensor "
160 "of size " << rn <<
" with '"
164 bgeot::tensor_reduction::diag_shape(ts, red[n].second);
165 child(n).merge_required_shape(ts);
176 ATN_reduced_tensor(reduced_tensor_arg_type& r) : red(r) {
177 for (
size_type i=0; i < r.size(); ++i) add_child(*red[i].first);
181 std::string s = red[n].second;
183 s.append(red[n].first->ranges().size(),
' ');
190 for (dim_type i=0; i < red.size(); ++i) {
201 tred.insert(red[i].first->tensor(), red_n(i));
207 ATN_tensor_w_data::reinit0();
209 tred.prepare(&tensor());
213 std::fill(data.begin(), data.end(), 0.);
225 class ATN_sliced_tensor :
public ATN_tensor {
229 ATN_sliced_tensor(ATN_tensor& a, dim_type slice_dim_,
231 slice_dim(slice_dim_), slice_idx(slice_idx_) { add_child(a); }
232 void check_shape_update(
size_type , dim_type) {
233 if ((shape_updated_ = child(0).is_shape_updated())) {
234 if (slice_dim >= child(0).ranges().size() ||
235 slice_idx >= child(0).ranges()[slice_dim]) {
236 ASM_THROW_TENSOR_ERROR(
"can't slice tensor " << child(0).ranges()
237 <<
" at index " <<
int(slice_idx)
238 <<
" of dimension " <<
int(slice_dim));
240 r_ = child(0).ranges(); r_.erase(r_.begin()+slice_dim);
243 void update_childs_required_shape() {
244 tensor_shape ts = req_shape;
245 ts.set_ndim_noclean(dim_type(ts.ndim()+1));
246 ts.shift_dim_num_ge(slice_dim,+1);
247 ts.push_mask(tensor_mask(child(0).ranges()[slice_dim],
248 tensor_mask::Slice(slice_dim, index_type(slice_idx))));
249 child(0).merge_required_shape(ts);
253 tensor() = tensor_ref(child(0).tensor(),
254 tensor_mask::Slice(slice_dim, index_type(slice_idx)));
263 class ATN_permuted_tensor :
public ATN_tensor {
264 std::vector<dim_type> reorder;
267 ATN_permuted_tensor(ATN_tensor& a,
const std::vector<dim_type>& reorder_) :
268 reorder(reorder_) { add_child(a); }
270 void check_shape_update(
size_type , dim_type) {
271 if ((shape_updated_ = child(0).is_shape_updated())) {
272 if (reorder.size() != child(0).ranges().size())
273 ASM_THROW_TENSOR_ERROR(
"can't reorder tensor '" << name()
274 <<
"' of dimensions " << child(0).ranges()
275 <<
" with this permutation: " << vref(reorder));
276 r_.resize(reorder.size());
277 std::fill(r_.begin(), r_.end(), dim_type(-1));
282 for (
size_type i=0; i < reorder.size(); ++i)
283 r_[i] = child(0).ranges()[reorder[i]];
286 void update_childs_required_shape() {
287 tensor_shape ts = req_shape;
288 ts.permute(reorder,
true);
289 child(0).merge_required_shape(ts);
292 tensor() = child(0).tensor();
293 tensor().permute(reorder);
303 class ATN_diagonal_tensor :
public ATN_tensor {
306 ATN_diagonal_tensor(ATN_tensor& a, dim_type i1_, dim_type i2_) :
307 i1(i1_), i2(i2_) { add_child(a); }
309 void check_shape_update(
size_type , dim_type) {
310 if ((shape_updated_ = child(0).is_shape_updated())) {
311 if (i1 >= child(0).ranges().size() || i2 >= child(0).ranges().size() ||
312 i1 == i2 || child(0).ranges()[i1] != child(0).ranges()[i2])
313 ASM_THROW_TENSOR_ERROR(
"can't take the diagonal of a tensor of "
314 "sizes " << child(0).ranges() <<
315 " at indexes " <<
int(i1) <<
" and "
317 r_ = child(0).ranges();
320 void update_childs_required_shape() {
321 tensor_shape ts = req_shape.diag_shape(tensor_mask::Diagonal(i1,i2));
322 child(0).merge_required_shape(ts);
325 tensor() = tensor_ref(child(0).tensor(), tensor_mask::Diagonal(i1,i2));
332 struct computed_tensor_integration_callback
333 :
public mat_elem_integration_callback {
334 bgeot::tensor_reduction red;
336 std::vector<TDIter> tensor_bases;
338 virtual void exec(bgeot::base_tensor &t,
bool first, scalar_type c) {
341 std::fill(t.begin(), t.end(), 0.);
345 for (
unsigned k=0; k!=eltm.size(); ++k) {
346 tensor_bases[k] =
const_cast<TDIter
>(&(*eltm[k]->begin()));
349 #if defined(GMM_USES_BLAS)
350 BLAS_INT one = BLAS_INT(1), n = BLAS_INT(red.out_data.size());
352 gmm::daxpy_(&n, &c,
const_cast<double*
>(&(red.out_data[0])),
353 &one, (
double*)&(t[0]), &one);
358 t[k] += c * red.out_data[k];
362 void resize_t(bgeot::base_tensor &t) {
363 bgeot::multi_index r;
364 if (red.reduced_range.size())
365 r.assign(red.reduced_range.begin(), red.reduced_range.end());
366 else { r.resize(1); r[0]=1; }
385 pnonlinear_elem_term nlt;
390 std::vector<const mesh_fem*> auxmf;
391 typedef enum { BASE=1, GRAD=2, HESS=3, NORMAL=4, GRADGT=5, GRADGTINV=6,
392 NONLIN=7, DATA=8 } op_type;
393 typedef enum { PLAIN_SHAPE = 0, VECTORIZED_SHAPE = 1,
394 MATRIXIZED_SHAPE = 2 } field_shape_type;
397 field_shape_type vshape;
403 std::string reduction;
415 mf_comp(mf_comp_vect *ow,
const mesh_fem* pmf_, op_type op_,
416 field_shape_type fst) :
417 nlt(0), pmf(pmf_), owner(ow), data(0), op(op_), vshape(fst) { }
418 mf_comp(mf_comp_vect *ow,
const std::vector<const mesh_fem*> vmf,
419 pnonlinear_elem_term nlt_) :
420 nlt(nlt_), pmf(vmf[0]), owner(ow), data(0),
421 auxmf(vmf.begin()+1, vmf.end()), op(NONLIN),
422 vshape(PLAIN_SHAPE) { }
423 mf_comp(mf_comp_vect *ow, ATN_tensor *t) :
424 nlt(0), pmf(0), owner(ow), data(t), op(DATA), vshape(PLAIN_SHAPE) {}
425 void push_back_dimensions(
size_type cv, tensor_ranges &rng,
426 bool only_reduced=
false)
const;
427 bool reduced(
unsigned i)
const {
428 if (i >= reduction.size())
return false;
429 else return reduction[i] !=
' ';
433 struct mf_comp_vect :
public std::vector<mf_comp> {
434 const mesh_im *main_im;
436 mf_comp_vect() : std::vector<mf_comp>(), main_im(0) { }
437 mf_comp_vect(
const mf_comp_vect &other)
438 : std::vector<mf_comp>(other), main_im(other.main_im) {
439 for (
size_type i=0; i < size(); ++i) (*
this)[i].owner =
this;
441 void set_im(
const mesh_im &mim) { main_im = &mim; }
442 const mesh_im& get_im()
const {
return *main_im; }
444 mf_comp_vect& operator=(
const mf_comp_vect &other);
447 void mf_comp::push_back_dimensions(
size_type cv, tensor_ranges &rng,
448 bool only_reduced)
const {
452 const bgeot::multi_index &sizes = nlt->sizes(cv);
453 for (
unsigned j=0; j < sizes.size(); ++j)
454 if (!only_reduced || !reduced(j))
459 for (
unsigned i=0; i < data->ranges().size(); ++i)
460 if (!only_reduced || !reduced(i))
461 rng.push_back(data->ranges()[i]);
465 assert(&owner->get_im());
466 assert(owner->get_im().linked_mesh().dim() != dim_type(-1));
467 rng.push_back(owner->get_im().linked_mesh().dim());
472 assert(&owner->get_im());
473 rng.push_back(owner->get_im().linked_mesh().dim());
474 rng.push_back(owner->get_im().linked_mesh().structure_of_convex(cv)->dim());
478 if (!only_reduced || !reduced(d))
479 rng.push_back(
unsigned(pmf->nb_basic_dof_of_element(cv)));
481 if (vshape == mf_comp::VECTORIZED_SHAPE) {
482 if (!only_reduced || !reduced(d)) rng.push_back(pmf->get_qdim());
485 if (vshape == mf_comp::MATRIXIZED_SHAPE) {
486 if (!only_reduced || !reduced(d)) {
487 GMM_ASSERT1(pmf->get_qdims().size() == 2,
"Non matrix field");
488 rng.push_back(dim_type(pmf->get_qdims()[0]));
491 if (!only_reduced || !reduced(d)) rng.push_back(dim_type(pmf->get_qdims()[1]));
495 if (op == GRAD || op == HESS) {
496 if (!only_reduced || !reduced(d))
497 rng.push_back(pmf->linked_mesh().dim());
501 if (!only_reduced || !reduced(d))
502 rng.push_back(pmf->linked_mesh().dim());
510 class ATN_computed_tensor :
public ATN_tensor {
513 pmat_elem_computation pmec;
515 pintegration_method pim;
518 std::vector<scalar_type> data;
521 dal::bit_vector req_bv;
524 bool has_inline_reduction;
526 computed_tensor_integration_callback icb;
531 bgeot::tensor_reduction fallback_red;
532 bool fallback_red_uptodate;
533 TDIter fallback_base;
538 ATN_computed_tensor(
const mf_comp_vect &mfcomp_) :
539 mfcomp(mfcomp_), pmec(0), pme(0), pim(0), pgt(0), data_base(0) {
540 has_inline_reduction =
false;
541 bool in_data =
false;
542 for (
size_type i=0; i < mfcomp.size(); ++i) {
543 if (mfcomp[i].reduction.size() || mfcomp[i].op == mf_comp::DATA) {
544 has_inline_reduction =
true;
545 if (mfcomp[i].op == mf_comp::DATA) { add_child(*mfcomp[i].data); in_data =
true; }
547 if (mfcomp[i].op != mf_comp::DATA && in_data) {
549 ASM_THROW_ERROR(
"data tensors inside comp() cannot be intermixed with Grad() and Base() etc., they must appear LAST");
561 stride_type add_dim(
const tensor_ranges& rng, dim_type d, stride_type s, tensor_ref &tref) {
562 assert(d < rng.size());
564 index_type r = rng[d];
565 tensor_mask m; m.set_full(d, r);
567 for (index_type i=0; i < r; ++i) v[i] = s*i;
568 assert(tref.masks().size() == tref.strides().size());
569 tref.set_ndim_noclean(dim_type(tref.ndim()+1));
571 tref.strides().push_back(v);
578 stride_type add_vdim(
const tensor_ranges& rng, dim_type d,
579 index_type target_dim, stride_type s,
581 assert(d < rng.size()-1);
582 index_type r = rng[d], q=rng[d+1];
583 index_type qmult = q/target_dim;
584 assert(r%qmult == 0); assert(q%qmult==0);
587 tensor_ranges trng(2); trng[0] = q; trng[1] = r;
588 index_set ti(2); ti[0] = dim_type(d+1); ti[1] = d;
589 tensor_mask m(trng,ti);
590 v.resize(r*target_dim);
591 tensor_ranges cnt(2);
592 for (index_type i=0; i < r; ++i) {
598 for (index_type k=0; k < target_dim; ++k) {
599 cnt[0] = k*qmult + (cnt[1]%qmult);
600 m.set_mask_val(m.lpos(cnt),
true);
601 v[cnt[1]*target_dim+k] = s*( k * r/qmult + cnt[1]/qmult);
604 assert(tref.masks().size() == tref.strides().size());
605 tref.set_ndim_noclean(dim_type(tref.ndim()+2));
607 tref.strides().push_back(v);
608 return s*(r/qmult)*target_dim;
634 stride_type add_mdim(
const tensor_ranges& rng, dim_type d,
635 index_type target_dim, stride_type s, tensor_ref &tref) {
636 assert(d < rng.size()-2);
639 index_type r = rng[d], q=rng[d+1], p=rng[d+2];
640 index_type qmult = (q*p)/target_dim;
643 assert(p % target_dim == 0);
644 assert(r % (p/target_dim) == 0);
647 tensor_ranges trng(3); trng[0] = q; trng[1] = p; trng[2] = r;
648 index_set ti(3); ti[0] = dim_type(d+1); ti[1] = dim_type(d+2); ti[2] = d;
649 tensor_mask m(trng,ti);
650 v.resize(r*target_dim);
651 tensor_ranges cnt(3);
652 for (cnt[2]=0; cnt[2] < r; cnt[2]++) {
653 for (index_type k=0; k < target_dim; ++k) {
654 unsigned pos = (cnt[2]*target_dim+k) % (q*p);
656 unsigned ii = (pos/p), jj = (pos%p);
657 cnt[0] = ii; cnt[1] = jj;
659 m.set_mask_val(m.lpos(cnt),
true);
660 v[cnt[2]*target_dim+k] = s*(k * r/qmult + cnt[2]/qmult);
663 assert(tref.masks().size() == tref.strides().size());
664 tref.set_ndim_noclean(dim_type(tref.ndim()+3));
669 tref.strides().push_back(v);
670 return s*(r/qmult)*target_dim;
677 for (
size_type i=0; i < mfcomp.size(); ++i) {
678 if (mfcomp[i].op == mf_comp::DATA)
continue;
679 pfem fem = (mfcomp[i].pmf ? mfcomp[i].pmf->fem_of_element(cv)
681 pmat_elem_type pme2 = 0;
682 switch (mfcomp[i].op) {
687 case mf_comp::GRADGT:
688 case mf_comp::GRADGTINV:
691 case mf_comp::NONLIN: {
692 std::vector<pfem> ftab(1+mfcomp[i].auxmf.size());
694 for (
unsigned k=0; k < mfcomp[i].auxmf.size(); ++k)
695 ftab[k+1] = mfcomp[i].auxmf[k]->fem_of_element(cv);
698 case mf_comp::DATA: ;
700 if (pme == 0) pme = pme2;
704 if (pme == 0) pme = mat_elem_empty();
711 push_back_mfcomp_dimensions(
size_type cv,
const mf_comp& mc,
712 unsigned &d,
const bgeot::tensor_ranges &rng,
713 bgeot::tensor_ref &tref,
size_type tsz=1) {
714 if (mc.op == mf_comp::NONLIN) {
715 for (
size_type j=0; j < mc.nlt->sizes(cv).size(); ++j)
716 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
717 }
else if (mc.op == mf_comp::DATA) {
719 tref = mc.data->tensor();
722 }
else if (mc.op == mf_comp::NORMAL) {
723 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
724 }
else if (mc.op == mf_comp::GRADGT ||
725 mc.op == mf_comp::GRADGTINV) {
726 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
727 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
729 size_type target_dim = mc.pmf->fem_of_element(cv)->target_dim();
733 if (mc.vshape == mf_comp::VECTORIZED_SHAPE) {
734 if (target_dim == qdim) {
735 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
736 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
738 tsz = add_vdim(rng,dim_type(d),index_type(target_dim),
739 stride_type(tsz), tref);
742 }
else if (mc.vshape == mf_comp::MATRIXIZED_SHAPE) {
743 if (target_dim == qdim) {
744 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
745 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
746 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
748 tsz = add_mdim(rng, dim_type(d), index_type(target_dim),
749 stride_type(tsz), tref);
752 }
else tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
753 if (mc.op == mf_comp::GRAD || mc.op == mf_comp::HESS) {
754 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
756 if (mc.op == mf_comp::HESS) {
757 tsz = add_dim(rng, dim_type(d++), stride_type(tsz), tref);
763 void update_shape_with_inline_reduction(
size_type cv) {
764 fallback_red_uptodate =
false;
765 icb.tensor_bases.resize(mfcomp.size());
767 for (
size_type i=0; i < mfcomp.size(); ++i) {
771 mfcomp[i].push_back_dimensions(cv,rng);
772 push_back_mfcomp_dimensions(cv,mfcomp[i], d, rng, tref);
773 assert(tref.ndim() == rng.size() && d == rng.size());
774 if (mfcomp[i].reduction.size() == 0)
775 mfcomp[i].reduction.insert(
size_type(0), tref.ndim(),
' ');
776 if (mfcomp[i].op != mf_comp::DATA)
777 tref.set_base(icb.tensor_bases[i]);
778 tref.update_idx2mask();
779 if (mfcomp[i].reduction.size() != tref.ndim()) {
780 ASM_THROW_TENSOR_ERROR(
"wrong number of indices for the "<<
int(i+1)
781 <<
"th argument of the reduction "<< name()
782 <<
" (expected " <<
int(tref.ndim())
784 << mfcomp[i].reduction.size());
786 icb.red.insert(tref, mfcomp[i].reduction);
789 icb.red.result(tensor());
790 r_.resize(tensor().ndim());
791 for (dim_type i=0; i < tensor().ndim(); ++i) r_[i] = tensor().dim(i);
792 tsize = tensor().card();
797 void update_shape_with_expanded_tensor(
size_type cv) {
800 for (
size_type i=0; i < mfcomp.size(); ++i) {
801 tsize = stride_type(push_back_mfcomp_dimensions(cv, mfcomp[i], d, r_, tensor(), tsize));
803 assert(d == r_.size());
804 tensor().update_idx2mask();
807 void check_shape_update(
size_type cv, dim_type) {
808 const mesh_im& mi = mfcomp.get_im();
809 pintegration_method pim2;
811 bool fem_changed =
false;
812 pgt2 = mi.linked_mesh().trans_of_convex(cv);
813 pim2 = mi.int_method_of_element(cv);
818 cv_shape_update = cv;
819 shape_updated_ = (pme == 0);
821 shape_updated_ = shape_updated_ || child(i).is_shape_updated();
822 for (
size_type i=0; shape_updated_ ==
false && i < mfcomp.size(); ++i) {
823 if (mfcomp[i].pmf == 0)
continue;
825 shape_updated_ =
true; fem_changed =
true;
827 fem_changed = fem_changed ||
828 (mfcomp[i].pmf->fem_of_element(current_cv) !=
829 mfcomp[i].pmf->fem_of_element(cv));
831 shape_updated_ = shape_updated_ ||
832 (mfcomp[i].pmf->nb_basic_dof_of_element(current_cv) !=
833 mfcomp[i].pmf->nb_basic_dof_of_element(cv));
836 if (shape_updated_) {
839 for (
unsigned i=0; i < mfcomp.size(); ++i)
840 mfcomp[i].push_back_dimensions(cv, r_,
true);
842 if (fem_changed || shape_updated_) {
844 update_pmat_elem(cv);
846 if (shape_updated_ || fem_changed || pgt != pgt2 || pim != pim2) {
847 pgt = pgt2; pim = pim2;
848 pmec = mep(pme, pim, pgt, has_inline_reduction);
853 if (!shape_updated_)
return;
856 if (has_inline_reduction) {
857 update_shape_with_inline_reduction(cv_shape_update);
859 update_shape_with_expanded_tensor(cv_shape_update);
862 tensor().set_base(data_base);
864 void update_childs_required_shape() {
870 if (!fallback_red_uptodate) {
871 fallback_red_uptodate =
true;
874 tensor_ref tref; tensor_ranges r;
877 for (cnt=0; cnt < mfcomp.size() && mfcomp[cnt].op != mf_comp::DATA; ++cnt) {
878 mfcomp[cnt].push_back_dimensions(cv,r);
879 sz = push_back_mfcomp_dimensions(cv, mfcomp[cnt], d, r, tref, sz);
880 s += mfcomp[cnt].reduction;
882 fallback_red.clear();
883 tref.set_base(fallback_base);
884 fallback_red.insert(tref, s);
886 for ( ; cnt < mfcomp.size(); ++cnt) {
887 assert(mfcomp[cnt].op == mf_comp::DATA);
888 fallback_red.insert(mfcomp[cnt].data->tensor(), mfcomp[cnt].reduction);
890 fallback_red.prepare();
891 fallback_red.result(tensor());
892 assert(icb.red.reduced_range == fallback_red.reduced_range);
895 fallback_base = &(*t.begin());
896 fallback_red.do_reduction();
899 void exec_(
size_type cv, dim_type face) {
900 const mesh_im& mim = mfcomp.get_im();
901 for (
unsigned i=0; i < mfcomp.size(); ++i) {
902 if (mfcomp[i].op == mf_comp::DATA) {
904 for (
unsigned j=0; j < mfcomp[i].data->ranges().size(); ++j)
905 fullsz *= mfcomp[i].data->ranges()[j];
906 if (fullsz !=
size_type(mfcomp[i].data->tensor().card()))
907 ASM_THROW_TENSOR_ERROR(
"aaarg inline reduction will explode with non-full tensors. "
908 "Complain to the author, I was too lazy to do that properly");
911 icb.was_called =
false;
912 if (face == dim_type(-1)) {
913 pmec->gen_compute(t, mim.linked_mesh().points_of_convex(cv), cv,
914 has_inline_reduction ? &icb : 0);
916 pmec->gen_compute_on_face(t, mim.linked_mesh().points_of_convex(cv), face, cv,
917 has_inline_reduction ? &icb : 0);
920 if (has_inline_reduction && icb.was_called ==
false) {
921 do_post_reduction(cv);
922 data_base = &fallback_red.out_data[0];
923 }
else data_base = &(*t.begin());
924 GMM_ASSERT1(t.size() ==
size_type(tsize),
925 "Internal error: bad size " << t.size() <<
" should be " << tsize);
931 class ATN_tensor_from_dofs_data :
public ATN_tensor_w_data {
932 const base_asm_data *basm;
933 vdim_specif_list vdim;
934 multi_tensor_iterator mti;
936 std::vector< tensor_strides > e_str;
938 ATN_tensor_from_dofs_data(
const base_asm_data *basm_,
939 const vdim_specif_list& d) :
940 basm(basm_), vdim(d) {
942 void check_shape_update(
size_type cv, dim_type) {
943 shape_updated_ =
false;
944 r_.resize(vdim.size());
945 for (dim_type i=0; i < vdim.size(); ++i) {
946 if (vdim[i].is_mf_ref()) {
947 size_type nbde = vdim[i].pmf->nb_basic_dof_of_element(cv);
948 if (nbde != ranges()[i])
949 { r_[i] = unsigned(nbde); shape_updated_ =
true; }
950 }
else if (vdim[i].dim != ranges()[i]) {
951 r_[i] = unsigned(vdim[i].dim);
952 shape_updated_ =
true;
956 virtual void init_required_shape() { req_shape = tensor_shape(ranges()); }
960 ATN_tensor_w_data::reinit_();
961 mti.assign(tensor(),
true);
964 vdim.build_strides_for_cv(cv, e_r, e_str);
965 assert(e_r == ranges());
967 basm->copy_with_mti(e_str, mti, (vdim.nb_mf() >= 1) ? vdim[0].pmf : 0);
974 class ATN_symmetrized_tensor :
public ATN_tensor_w_data {
975 multi_tensor_iterator mti;
977 ATN_symmetrized_tensor(ATN_tensor& a) { add_child(a); }
978 void check_shape_update(
size_type , dim_type) {
979 if ((shape_updated_ = child(0).is_shape_updated())) {
980 if (child(0).ranges().size() != 2 ||
981 child(0).ranges()[0] != child(0).ranges()[1])
982 ASM_THROW_TENSOR_ERROR(
"can't symmetrize a non-square tensor "
983 "of sizes " << child(0).ranges());
984 r_ = child(0).ranges();
987 void update_childs_required_shape() {
988 tensor_shape ts = req_shape;
989 tensor_shape ts2 = req_shape;
990 index_set perm(2); perm[0] = 1; perm[1] = 0; ts2.permute(perm);
991 ts.merge(ts2,
false);
992 tensor_mask dm; dm.set_triangular(ranges()[0],0,1);
993 tensor_shape tsdm(2); tsdm.push_mask(dm);
994 ts.merge(tsdm,
true);
995 child(0).merge_required_shape(ts);
1000 req_shape.set_full(ranges());
1001 ATN_tensor_w_data::reinit0();
1002 mti.assign(child(0).tensor(),
true);
1005 std::fill(data.begin(), data.end(), 0.);
1007 index_type n = ranges()[0];
1009 index_type i=mti.index(0), j=mti.index(1);
1010 data[i*n+j]=data[j*n+i]=mti.p(0);
1011 }
while (mti.qnext1());
1016 template<
class UnaryOp>
class ATN_unary_op_tensor
1017 :
public ATN_tensor_w_data {
1018 multi_tensor_iterator mti;
1020 ATN_unary_op_tensor(ATN_tensor& a) { add_child(a); }
1021 void check_shape_update(
size_type , dim_type) {
1022 if ((shape_updated_ = (ranges() != child(0).ranges())))
1023 r_ = child(0).ranges();
1027 ATN_tensor_w_data::reinit0();
1028 mti.assign(tensor(), child(0).tensor(),
false);
1033 mti.p(0) = UnaryOp()(mti.p(1));
1034 }
while (mti.qnext2());
1039 class ATN_tensors_sum_scaled :
public ATN_tensor_w_data {
1040 std::vector<multi_tensor_iterator> mti;
1041 std::vector<scalar_type> scales;
1043 ATN_tensors_sum_scaled(ATN_tensor& t1, scalar_type s1) {
1045 scales.resize(1); scales[0]=s1;
1047 void push_scaled_tensor(ATN_tensor& t, scalar_type s) {
1048 add_child(t); scales.push_back(s);
1050 void check_shape_update(
size_type , dim_type) {
1051 if ((shape_updated_ = child(0).is_shape_updated()))
1052 r_ = child(0).ranges();
1054 if (ranges() != child(i).ranges())
1055 ASM_THROW_TENSOR_ERROR(
"can't add two tensors of sizes " <<
1056 ranges() <<
" and " << child(i).ranges());
1058 void apply_scale(scalar_type s) {
1059 for (
size_type i=0; i < scales.size(); ++i) scales[i] *= s;
1061 ATN_tensors_sum_scaled* is_tensors_sum_scaled() {
return this; }
1064 ATN_tensor_w_data::reinit0();
1065 mti.resize(nchilds());
1067 mti[i].assign(tensor(), child(i).tensor(),
false);
1074 std::fill(data.begin(), data.end(), 0.);
1077 mti[0].p(0) = mti[0].p(1)*scales[0];
1078 }
while (mti[0].qnext2());
1079 for (
size_type i=1; i < nchilds(); ++i) {
1082 mti[i].p(0) = mti[i].p(0)+mti[i].p(1)*scales[i];
1083 }
while (mti[i].qnext2());
1088 class ATN_tensor_scalar_add :
public ATN_tensor_w_data {
1090 multi_tensor_iterator mti;
1093 ATN_tensor_scalar_add(ATN_tensor& a, scalar_type v_,
int sgn_) :
1094 v(v_), sgn(sgn_) { add_child(a); }
1095 void check_shape_update(
size_type , dim_type) {
1096 if ((shape_updated_ = child(0).is_shape_updated()))
1097 r_ = child(0).ranges();
1101 ATN_tensor_w_data::reinit_();
1102 mti.assign(tensor(), child(0).tensor(),
false);
1105 std::fill(data.begin(), data.end(), v);
1109 mti.p(0) += mti.p(1);
1110 else mti.p(0) -= mti.p(1);
1111 }
while (mti.qnext2());
1115 class ATN_print_tensor :
public ATN {
1118 ATN_print_tensor(ATN_tensor& a, std::string n_)
1119 : name(n_) { add_child(a); }
1122 void exec_(
size_type cv, dim_type face) {
1123 multi_tensor_iterator mti(child(0).tensor(),
true);
1124 cout <<
"------- > evaluation of " << name <<
", at" << endl;
1125 cout <<
"convex " << cv;
1126 if (face != dim_type(-1)) cout <<
", face " << int(face);
1128 cout <<
" size = " << child(0).ranges() << endl;
1132 for (
size_type i=0; i < child(0).ranges().size(); ++i)
1133 cout <<(i>0 ?
"," :
"") << mti.index(dim_type(i));
1134 cout <<
"] = " << mti.p(0) << endl;
1135 }
while (mti.qnext1());
1146 std::string asm_tokenizer::syntax_err_print() {
1148 if (tok_pos - err_msg_mark > 80) err_msg_mark = tok_pos - 40;
1149 if (str.length() - err_msg_mark < 80) s = tok_substr(err_msg_mark, str.length());
1150 else { s = tok_substr(err_msg_mark,err_msg_mark+70); s.append(
" ... (truncated)"); }
1151 s +=
"\n" + std::string(std::max(
int(tok_pos - err_msg_mark),0),
'-') +
"^^";
1155 void asm_tokenizer::get_tok() {
1158 while (tok_pos < str.length() && isspace(str[tok_pos])) ++tok_pos;
1159 if (tok_pos == str.length()) {
1160 curr_tok_type = END; tok_len = 0;
1161 }
else if (strchr(
"{}(),;:=-.*/+", str[tok_pos])) {
1162 curr_tok_type = tok_type_enum(str[tok_pos]); tok_len = 1;
1163 }
else if (str[tok_pos] ==
'$' || str[tok_pos] ==
'#' || str[tok_pos] ==
'%') {
1164 curr_tok_type = str[tok_pos] ==
'$' ? ARGNUM_SELECTOR :
1165 (str[tok_pos] ==
'#' ? MFREF : IMREF);
1168 while (isdigit(str[tok_pos+tok_len])) {
1170 curr_tok_ival += str[tok_pos+tok_len] -
'0';
1174 }
else if (isalpha(str[tok_pos])) {
1175 curr_tok_type = IDENT;
1177 while (isalnum(str[tok_pos+tok_len]) || str[tok_pos+tok_len] ==
'_') ++tok_len;
1178 }
else if (isdigit(str[tok_pos])) {
1179 curr_tok_type = NUMBER;
1181 curr_tok_dval = strtod(&str[0]+tok_pos, &p);
1182 tok_len = p - &str[0] - tok_pos;
1184 if (tok_pos < str.length())
1185 curr_tok = str.substr(tok_pos, tok_len);
1190 const mesh_fem& generic_assembly::do_mf_arg_basic() {
1191 if (tok_type() != MFREF) ASM_THROW_PARSE_ERROR(
"expecting mesh_fem reference");
1192 if (tok_mfref_num() >= mftab.size())
1193 ASM_THROW_PARSE_ERROR(
"reference to a non-existant mesh_fem #" << tok_mfref_num()+1);
1194 const mesh_fem& mf_ = *mftab[tok_mfref_num()]; advance();
1198 const mesh_fem& generic_assembly::do_mf_arg(std::vector<const mesh_fem*> * multimf) {
1199 if (!multimf) advance();
1200 accept(OPEN_PAR,
"expecting '('");
1201 const mesh_fem &mf_ = do_mf_arg_basic();
1203 multimf->resize(1); (*multimf)[0] = &mf_;
1204 while (advance_if(COMMA)) {
1205 if (tok_type() != MFREF) ASM_THROW_PARSE_ERROR(
"expecting mesh_fem reference");
1206 if (tok_mfref_num() >= mftab.size())
1207 ASM_THROW_PARSE_ERROR(
"reference to a non-existant mesh_fem #" << tok_mfref_num()+1);
1208 multimf->push_back(mftab[tok_mfref_num()]); advance();
1211 accept(CLOSE_PAR,
"expecting ')'");
1216 std::string generic_assembly::do_comp_red_ops() {
1218 if (advance_if(OPEN_PAR)) {
1221 if (tok_type() == COLON) {
1222 s.push_back(
' '); advance(); j++;
1223 }
else if (tok_type() == IDENT) {
1224 if ((tok().length()==1 && isalpha(tok()[0])) || islower(tok()[0])) {
1225 s.push_back(tok()[0]); advance(); j++;
1226 }
else ASM_THROW_PARSE_ERROR(
"invalid reduction index '" << tok() <<
1227 "', only lower case characters allowed");
1229 }
while (advance_if(COMMA));
1230 accept(CLOSE_PAR,
"expecting ')'");
1235 static mf_comp::field_shape_type get_shape(
const std::string &s) {
1236 if (s[0] ==
'v')
return mf_comp::VECTORIZED_SHAPE;
1237 else if (s[0] ==
'm')
return mf_comp::MATRIXIZED_SHAPE;
1238 else return mf_comp::PLAIN_SHAPE;
1241 ATN_tensor* generic_assembly::do_comp() {
1242 accept(OPEN_PAR,
"expecting '('");
1244 bool in_data =
false;
1252 if (tok_type() == IMREF) {
1253 if (tok_imref_num() >= imtab.size())
1254 ASM_THROW_PARSE_ERROR(
"reference to a non-existant mesh_im %" << tok_imref_num()+1);
1255 what.set_im(*imtab[tok_imref_num()]); advance();
1256 accept(COMMA,
"expecting ','");
1258 what.set_im(*imtab[0]);
1261 if (tok_type() == CLOSE_PAR)
break;
1262 if (tok_type() != IDENT) ASM_THROW_PARSE_ERROR(
"expecting Base or Grad or Hess, Normal, etc..");
1263 std::string f = tok();
1264 const mesh_fem *pmf = 0;
1265 if (f.compare(
"Base")==0 || f.compare(
"vBase")==0 || f.compare(
"mBase")==0) {
1267 what.push_back(mf_comp(&what, pmf, mf_comp::BASE, get_shape(f)));
1268 }
else if (f.compare(
"Grad")==0 || f.compare(
"vGrad")==0 || f.compare(
"mGrad")==0) {
1270 what.push_back(mf_comp(&what, pmf, mf_comp::GRAD, get_shape(f)));
1271 }
else if (f.compare(
"Hess")==0 || f.compare(
"vHess")==0 || f.compare(
"mHess")==0) {
1273 what.push_back(mf_comp(&what, pmf, mf_comp::HESS, get_shape(f)));
1274 }
else if (f.compare(
"NonLin")==0) {
1277 if (tok_type() == ARGNUM_SELECTOR) { num = tok_argnum(); advance(); }
1278 if (num >= innonlin.size()) ASM_THROW_PARSE_ERROR(
"NonLin$" << num <<
" does not exist");
1279 std::vector<const mesh_fem*> allmf;
1280 pmf = &do_mf_arg(&allmf); what.push_back(mf_comp(&what, allmf, innonlin[num]));
1281 }
else if (f.compare(
"Normal") == 0) {
1283 accept(OPEN_PAR,
"expecting '('"); accept(CLOSE_PAR,
"expecting ')'");
1284 pmf = 0; what.push_back(mf_comp(&what, pmf, mf_comp::NORMAL, mf_comp::PLAIN_SHAPE));
1285 }
else if (f.compare(
"GradGT") == 0 ||
1286 f.compare(
"GradGTInv") == 0) {
1288 accept(OPEN_PAR,
"expecting '('"); accept(CLOSE_PAR,
"expecting ')'");
1290 what.push_back(mf_comp(&what, pmf,
1291 f.compare(
"GradGT") == 0 ?
1293 mf_comp::GRADGTINV, mf_comp::PLAIN_SHAPE));
1295 if (vars.find(f) != vars.end()) {
1296 what.push_back(mf_comp(&what, vars[f]));
1300 ASM_THROW_PARSE_ERROR(
"expecting Base, Grad, vBase, NonLin ...");
1304 if (!in_data && f[0] !=
'v' && f[0] !=
'm' && pmf && pmf->get_qdim() != 1 && f.compare(
"NonLin")!=0) {
1305 ASM_THROW_PARSE_ERROR(
"Attempt to use a vector mesh_fem as a scalar mesh_fem");
1307 what.back().reduction = do_comp_red_ops();
1308 }
while (advance_if(PRODUCT));
1309 accept(CLOSE_PAR,
"expecting ')'");
1311 return record(std::make_unique<ATN_computed_tensor>(what));
1314 void generic_assembly::do_dim_spec(vdim_specif_list& lst) {
1316 accept(OPEN_PAR,
"expecting '('");
1318 if (tok_type() == IDENT) {
1319 if (tok().compare(
"mdim")==0) lst.push_back(vdim_specif(do_mf_arg().linked_mesh().dim()));
1320 else if (tok().compare(
"qdim")==0) lst.push_back(vdim_specif(do_mf_arg().get_qdim()));
1321 else ASM_THROW_PARSE_ERROR(
"expecting mdim(#mf) or qdim(#mf) or a number or a mesh_fem #id");
1322 }
else if (tok_type() == NUMBER) {
1323 lst.push_back(vdim_specif(tok_number_ival()+1));
1325 }
else if (tok_type() == MFREF) {
1326 lst.push_back(vdim_specif(&do_mf_arg_basic()));
1327 }
else if (tok_type() != CLOSE_PAR) ASM_THROW_PARSE_ERROR(
"expecting mdim(#mf) or qdim(#mf) or a number or a mesh_fem #id");
1330 if (advance_if(CLOSE_PAR))
break;
1331 accept(COMMA,
"expecting ',' or ')'");
1336 ATN_tensor* generic_assembly::do_data() {
1339 if (tok_type() != OPEN_PAR) {
1340 if (tok_type() != ARGNUM_SELECTOR)
1341 ASM_THROW_PARSE_ERROR(
"expecting dataset number");
1342 datanum = tok_argnum();
1345 if (datanum >= indata.size())
1346 ASM_THROW_PARSE_ERROR(
"wrong dataset number: " << datanum);
1348 vdim_specif_list sz;
1351 if (sz.nbelt() != indata[datanum]->vect_size())
1352 ASM_THROW_PARSE_ERROR(
"invalid size for data argument " << datanum+1 <<
1353 " real size is " << indata[datanum]->vect_size()
1354 <<
" expected size is " << sz.nbelt());
1355 return record(std::make_unique<ATN_tensor_from_dofs_data>(indata[datanum].get(), sz));
1358 std::pair<ATN_tensor*, std::string>
1359 generic_assembly::do_red_ops(ATN_tensor* t) {
1362 if (advance_if(OPEN_PAR)) {
1365 if (tok_type() == COLON) {
1366 s.push_back(
' '); advance(); j++;
1367 }
else if (tok_type() == NUMBER) {
1368 t = record(std::make_unique<ATN_sliced_tensor>(*t, dim_type(j),
1369 tok_number_ival())); advance();
1370 }
else if (tok_type() == IDENT) {
1371 if ((tok().length()==1 && isalpha(tok()[0])) || islower(tok()[0])) {
1372 s.push_back(tok()[0]); advance(); j++;
1373 }
else ASM_THROW_PARSE_ERROR(
"invalid reduction index '" << tok() <<
1374 "', only lower case chars allowed");
1376 }
while (advance_if(COMMA));
1377 accept(CLOSE_PAR,
"expecting ')'");
1379 return std::pair<ATN_tensor*,std::string>(t,s);
1388 tnode generic_assembly::do_tens() {
1391 if (advance_if(OPEN_PAR)) {
1393 accept(CLOSE_PAR,
"expecting ')'");
1394 }
else if (tok_type() == NUMBER) {
1395 t.assign(tok_number_dval()); advance();
1396 }
else if (tok_type() == IDENT) {
1397 if (vars.find(tok()) != vars.end()) {
1398 t.assign(vars[tok()]); advance();
1399 }
else if (tok().compare(
"comp")==0) {
1400 advance(); t.assign(do_comp());
1401 }
else if (tok().compare(
"data")==0) {
1402 advance(); t.assign(do_data());
1403 }
else if (tok().compare(
"sym")==0) {
1405 tnode t2 = do_expr();
1406 if (t2.type() != tnode::TNTENSOR)
1407 ASM_THROW_PARSE_ERROR(
"can't symmetrise a scalar!");
1408 t.assign(record(std::make_unique<ATN_symmetrized_tensor>(*t2.tensor())));
1409 }
else ASM_THROW_PARSE_ERROR(
"unknown identifier: " << tok());
1410 }
else ASM_THROW_PARSE_ERROR(
"unexpected token: " << tok());
1420 tnode generic_assembly::do_prod() {
1421 reduced_tensor_arg_type ttab;
1424 tnode t = do_tens();
1425 if (t.type() == tnode::TNCONST) {
1426 if (ttab.size() == 0)
return t;
1427 else ASM_THROW_PARSE_ERROR(
"can't mix tensor and scalar into a "
1428 "reduction expression");
1430 ttab.push_back(do_red_ops(t.tensor()));
1431 }
while (advance_if(PRODUCT));
1432 if (ttab.size() == 1 && ttab[0].second.length() == 0) {
1433 return tnode(ttab[0].first);
1435 return tnode(record(std::make_unique<ATN_reduced_tensor>(ttab)));
1441 tnode generic_assembly::do_prod_trans() {
1442 tnode t = do_prod();
1443 while (advance_if(OPEN_BRACE)) {
1446 dal::bit_vector check_permut;
1447 if (t.type() != tnode::TNTENSOR)
1448 ASM_THROW_PARSE_ERROR(
"can't use reorder braces on a constant!");
1451 if (tok_type() == COLON) i = j;
1452 else if (tok_type() == NUMBER) i = tok_number_ival(1000);
1453 else ASM_THROW_PARSE_ERROR(
"only numbers or colons allowed here");
1454 if (check_permut.is_in(i)) {
1455 t = tnode(record(std::make_unique<ATN_diagonal_tensor>(*t.tensor(), dim_type(i),
1457 check_permut.add(j);
1458 reorder.push_back(dim_type(j));
1460 check_permut.add(i);
1461 reorder.push_back(dim_type(i));
1464 if (advance_if(CLOSE_BRACE))
break;
1465 accept(COMMA,
"expecting ','");
1467 if (check_permut.first_false() != reorder.size()) {
1468 cerr << check_permut << endl;
1469 cerr << vref(reorder) << endl;
1470 ASM_THROW_PARSE_ERROR(
"you did not give a real permutation:"
1473 t = tnode(record(std::make_unique<ATN_permuted_tensor>(*t.tensor(), reorder)));
1481 tnode generic_assembly::do_term() {
1484 tnode t = do_prod_trans();
1487 if (advance_if(MULTIPLY))
mult =
true;
1488 else if (advance_if(DIVIDE))
mult =
false;
1490 tnode t2 = do_prod();
1491 if (mult ==
false && t.type() == tnode::TNCONST
1492 && t2.type() == tnode::TNTENSOR)
1493 ASM_THROW_PARSE_ERROR(
"can't divide a constant by a tensor");
1494 if (t.type() == tnode::TNTENSOR && t2.type() == tnode::TNTENSOR) {
1495 ASM_THROW_PARSE_ERROR(
"tensor term-by-term productor division not "
1496 "implemented yet! are you sure you need it ?");
1497 }
else if (t.type() == tnode::TNCONST && t2.type() == tnode::TNCONST) {
1499 t.assign(t.xval()*t2.xval());
1502 t.assign(t.xval()/t2.xval());
1505 if (t.type() != tnode::TNTENSOR) std::swap(t,t2);
1506 scalar_type v = t2.xval();
1508 if (v == 0.) { ASM_THROW_PARSE_ERROR(
"can't divide by zero"); }
1511 if (t.tensor()->is_tensors_sum_scaled() && !t.tensor()->is_frozen()) {
1512 t.tensor()->is_tensors_sum_scaled()->apply_scale(v);
1514 t.assign(record(std::make_unique<ATN_tensors_sum_scaled>(*t.tensor(), v)));
1527 tnode generic_assembly::do_expr() {
1530 if (advance_if(MINUS)) negt =
true;
1531 tnode t = do_term();
1533 if (t.type() == tnode::TNCONST) t.assign(-t.xval());
1534 else t.assign(record(std::make_unique<ATN_tensor_scalar_add>(*t.tensor(), 0., -1)));
1538 if (advance_if(PLUS)) plus = +1;
1539 else if (advance_if(MINUS)) plus = -1;
1541 tnode t2 = do_term();
1542 if (t.type() == tnode::TNTENSOR && t2.type() == tnode::TNTENSOR) {
1543 if (!t.tensor()->is_tensors_sum_scaled() || t.tensor()->is_frozen()) {
1544 t.assign(record(std::make_unique<ATN_tensors_sum_scaled>(*t.tensor(), +1)));
1546 t.tensor()->is_tensors_sum_scaled()
1547 ->push_scaled_tensor(*t2.tensor(), scalar_type(plus));
1548 }
else if (t.type() == tnode::TNCONST && t2.type() == tnode::TNCONST) {
1549 t.assign(t.xval()+t2.xval()*plus);
1552 if (t.type() != tnode::TNTENSOR)
1553 { std::swap(t,t2);
if (plus<0) tsgn = -1; }
1554 else if (plus<0) t2.assign(-t2.xval());
1555 t.assign(record(std::make_unique<ATN_tensor_scalar_add>(*t.tensor(), t2.xval(),
1567 void generic_assembly::do_instr() {
1568 enum { wALIAS, wOUTPUT_ARRAY, wOUTPUT_MATRIX, wPRINT, wERROR }
1573 if (tok_type() != IDENT) ASM_THROW_PARSE_ERROR(
"expecting identifier");
1574 if (vars.find(tok()) != vars.end())
1575 ASM_THROW_PARSE_ERROR(
"redefinition of identifier " << tok());
1584 vdim_specif_list vds;
1586 if (ident.compare(
"print") == 0) {
1587 print_mark = tok_mark();
1589 }
else if (tok_type() == ARGNUM_SELECTOR ||
1590 tok_type() == OPEN_PAR) {
1591 if (tok_type() == ARGNUM_SELECTOR) {
1592 arg_num = tok_argnum();
1594 }
else { arg_num = 0; }
1599 if (ident.compare(
"V")==0) {
1600 what = wOUTPUT_ARRAY;
1601 if (arg_num >= outvec.size())
1602 { outvec.resize(arg_num+1); outvec[arg_num] = 0; }
1604 if (outvec[arg_num] == 0) {
1605 if (vec_fact != 0) {
1606 tensor_ranges r(vds.size());
1607 for (
size_type i=0; i < vds.size(); ++i)
1608 r[i] =
unsigned(vds[i].dim);
1609 outvec[arg_num] = std::shared_ptr<base_asm_vec>(std::shared_ptr<base_asm_vec>(), vec_fact->create_vec(r));
1611 else ASM_THROW_PARSE_ERROR(
"output vector $" << arg_num+1
1612 <<
" does not exist");
1614 }
else if (vds.nb_mf()==2 && vds.size() == 2 && ident.compare(
"M")==0) {
1615 what = wOUTPUT_MATRIX;
1616 if (arg_num >= outmat.size())
1617 { outmat.resize(arg_num+1); outmat[arg_num] = 0; }
1619 if (outmat[arg_num] == 0) {
1621 outmat[arg_num] = std::shared_ptr<base_asm_mat>
1622 (std::shared_ptr<base_asm_mat>(),
1623 mat_fact->create_mat(vds[0].pmf->nb_dof(),
1624 vds[1].pmf->nb_dof()));
1625 else ASM_THROW_PARSE_ERROR(
"output matrix $" << arg_num+1
1626 <<
" does not exist");
1628 }
else ASM_THROW_PARSE_ERROR(
"not a valid output statement");
1632 }
else if (advance_if(EQUAL)) {
1634 }
else ASM_THROW_PARSE_ERROR(
"missing '=' or ':='");
1636 tnode t = do_expr();
1637 if (t.type() != tnode::TNTENSOR)
1638 ASM_THROW_PARSE_ERROR(
"left hand side is a constant, not a tensor!");
1642 record_out(std::make_unique<ATN_print_tensor>(*t.tensor(), tok_substr(print_mark,
1645 case wOUTPUT_ARRAY: {
1646 record_out(outvec[arg_num]->build_output_tensor(*t.tensor(), vds));
1648 case wOUTPUT_MATRIX: {
1649 record_out(outmat[arg_num]->build_output_tensor(*t.tensor(),
1654 vars[ident] = t.tensor(); t.tensor()->freeze();
1656 default: GMM_ASSERT3(
false,
"");
break;
1661 struct atn_number_compare {
1662 bool operator()(
const std::unique_ptr<ATN_tensor> &a,
1663 const std::unique_ptr<ATN_tensor> &b) {
1664 assert(a.get() && b.get());
1665 return (a->number() < b->number());
1669 struct outvar_compare {
1670 bool operator()(
const std::unique_ptr<ATN> &a,
1671 const std::unique_ptr<ATN> &b) {
1672 assert(a.get() && b.get());
1673 return (a->number() < b->number());
1677 void generic_assembly::parse() {
1678 if (parse_done)
return;
1680 if (tok_type() == END)
break;
1682 }
while (advance_if(SEMICOLON));
1683 if (tok_type() != END) ASM_THROW_PARSE_ERROR(
"unexpected token: '"
1685 if (outvars.size() == 0) cerr <<
"warning: assembly without output\n";
1689 for (
size_type i=0; i < outvars.size(); ++i)
1690 outvars[i]->set_number(gcnt);
1692 std::sort(atn_tensors.begin(), atn_tensors.end(), atn_number_compare());
1693 std::sort(outvars.begin(), outvars.end(), outvar_compare());
1696 while (atn_tensors.size()
1697 && atn_tensors.back()->number() ==
unsigned(-1)) {
1698 cerr <<
"warning: the expression " << atn_tensors.back()->name()
1699 <<
" won't be evaluated since it is not used!\n";
1700 atn_tensors.pop_back();
1706 void generic_assembly::exec(
size_type cv, dim_type face) {
1707 bool update_shapes =
false;
1708 for (
size_type i=0; i < atn_tensors.size(); ++i) {
1709 atn_tensors[i]->check_shape_update(cv,face);
1710 update_shapes = (update_shapes || atn_tensors[i]->is_shape_updated());
1720 if (update_shapes) {
1727 for (
auto &&t : atn_tensors)
1728 t->init_required_shape();
1730 for (
auto &&v : outvars)
1731 v->update_childs_required_shape();
1734 atn_tensors[i]->update_childs_required_shape();
1736 for (
auto &&t : atn_tensors)
1739 for (
auto &&v : outvars)
1742 for (
auto &&t : atn_tensors)
1744 for (
auto &&v : outvars)
1748 struct cv_fem_compare {
1749 const std::vector<const mesh_fem *> &mf;
1750 cv_fem_compare(
const std::vector<const mesh_fem *>& mf_) : mf(mf_) {}
1752 for (
size_type i=0; i < mf.size(); ++i) {
1753 pfem pfa(mf[i]->fem_of_element(a));
1754 pfem pfb(mf[i]->fem_of_element(b));
1756 unsigned nba = unsigned(pfa->nb_dof(a));
1757 unsigned nbb = unsigned(pfb->nb_dof(b));
1760 }
else if (nba > nbb) {
1762 }
else if (pfa < pfb) {
1773 static void get_convex_order(
const dal::bit_vector& cvlst,
1774 const std::vector<const mesh_im *>& imtab,
1775 const std::vector<const mesh_fem *>& mftab,
1776 const dal::bit_vector& candidates,
1777 std::vector<size_type>& cvorder) {
1778 cvorder.reserve(candidates.card()); cvorder.resize(0);
1780 for (dal::bv_visitor cv(candidates); !cv.finished(); ++cv) {
1781 if (cvlst.is_in(cv) &&
1782 imtab[0]->int_method_of_element(cv) !=
im_none()) {
1784 for (
size_type i=0; i < mftab.size(); ++i) {
1785 if (!mftab[i]->convex_index().is_in(cv)) {
1792 cvorder.push_back(cv);
1794 }
else if (!imtab[0]->linked_mesh().convex_index().is_in(cv)) {
1795 ASM_THROW_ERROR(
"the convex " << cv <<
" is not part of the mesh");
1803 void generic_assembly::consistency_check() {
1805 if (imtab.size() == 0)
1806 ASM_THROW_ERROR(
"no mesh_im (integration methods) given for assembly!");
1807 const mesh& m = imtab[0]->linked_mesh();
1808 for (
unsigned i=0; i < mftab.size(); ++i) {
1809 if (&mftab[i]->linked_mesh() != &m)
1810 ASM_THROW_ERROR(
"the mesh_fem/mesh_im live on different meshes!");
1812 for (
unsigned i=0; i < imtab.size(); ++i) {
1813 if (&imtab[i]->linked_mesh() != &m)
1814 ASM_THROW_ERROR(
"the mesh_fem/mesh_im live on different meshes!");
1816 if (imtab.size() == 0)
1817 ASM_THROW_ERROR(
"no integration method !");
1821 std::vector<size_type> cv;
1822 r.
from_mesh(imtab.at(0)->linked_mesh());
1823 r.error_if_not_homogeneous();
1826 consistency_check();
1827 get_convex_order(imtab.at(0)->convex_index(), imtab, mftab, r.
index(), cv);
1830 for (
size_type i=0; i < cv.size(); ++i) {
1831 mesh_region::face_bitset nf = r[cv[i]];
1832 dim_type f = dim_type(-1);
1835 if (nf[0]) exec(cv[i],f);
void assembly(const mesh_region ®ion=mesh_region::all_convexes())
do the assembly on the specified region (boundary or set of convexes)
structure used to hold a set of convexes and/or convex faces.
const mesh_region & from_mesh(const mesh &m) const
For regions which have been built with just a number 'id', from_mesh(m) sets the current region to 'm...
const dal::bit_vector & index() const
Index of the region convexes, or the convexes from the partition on the current thread.
Generic assembly implementation.
thread safe standard locale with RAII semantics
elementary computations (used by the generic assembly).
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
gmm interface for fortran BLAS.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
gmm::uint16_type short_type
used as the common short type integer in the library
size_t size_type
used as the common size type in the library
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
GEneric Tool for Finite Element Methods.
pmat_elem_type mat_elem_unit_normal(void)
Give a pointer to the structure describing the elementary matrix which compute the unit normal on the...
pmat_elem_type mat_elem_hessian(pfem pfi)
Give a pointer to the structure describing the elementary matrix which compute the integral of the he...
pmat_elem_type mat_elem_nonlinear(pnonlinear_elem_term, std::vector< pfem > pfi)
Give a pointer to the structure describing the elementary matrix which compute the integral of a nonl...
pmat_elem_type mat_elem_base(pfem pfi)
Give a pointer to the structure describing the elementary matrix which compute the integral of the ba...
pmat_elem_type mat_elem_grad_geotrans(bool inverted)
Return the gradient of the geometrical transformation ("K" in the getfem++ kernel doc....
pmat_elem_type mat_elem_product(pmat_elem_type a, pmat_elem_type b)
Give a pointer to the structure describing the elementary matrix which computes the integral of produ...
pintegration_method im_none(void)
return IM_NONE
pmat_elem_type mat_elem_grad(pfem pfi)
Give a pointer to the structure describing the elementary matrix which compute the integral of the gr...