31 for (dal::bv_visitor cv(fe_convex); !cv.finished(); ++cv) {
33 if (v_num_update < linked_mesh_->convex_version_number(cv)) {
34 if (auto_add_elt_pf != 0)
37 else if (auto_add_elt_K != dim_type(-1)) {
38 if (auto_add_elt_disc)
41 (cv, auto_add_elt_K, auto_add_elt_alpha,
42 auto_add_elt_complete);
46 auto_add_elt_complete);
55 !cv.finished(); ++cv) {
56 if (!fe_convex.is_in(cv)
58 if (auto_add_elt_pf != 0)
61 else if (auto_add_elt_K != dim_type(-1)) {
62 if (auto_add_elt_disc)
65 (cv, auto_add_elt_K, auto_add_elt_alpha, auto_add_elt_complete);
69 auto_add_elt_complete);
74 v_num = v_num_update = act_counter();
106 template <
typename V>
107 static void add_e_line__(
const V &v, dal::bit_vector &r) {
108 typedef typename gmm::linalg_traits<V>::value_type T;
109 typename gmm::linalg_traits<V>::const_iterator it = gmm::vect_begin(v);
110 typename gmm::linalg_traits<V>::const_iterator ite = gmm::vect_end(v);
111 for (; it != ite; ++it)
if (*it != T(0)) r.add(it.index());
117 if (
nb_dof() == 0)
return dal::bit_vector();
118 dal::bit_vector basic = res;
120 for (dal::bv_visitor i(basic); !i.finished(); ++i)
121 add_e_line__(gmm::mat_row(E_, i), res);
128 GMM_ASSERT1(linked_mesh_ != 0,
"Uninitialized mesh_fem");
131 if (fe_convex.is_in(cv)) {
133 dof_enumeration_made =
false;
134 touch(); v_num = act_counter();
139 == pf->basic_structure(cv),
140 "Incompatibility between fem " <<
name_of_fem(pf) <<
141 " and mesh element " <<
142 name_of_geometric_trans(linked_mesh_->trans_of_convex(cv)));
143 GMM_ASSERT1((Qdim % pf->target_dim()) == 0 || pf->target_dim() == 1,
144 "Incompatibility between Qdim=" <<
int(Qdim) <<
145 " and target_dim " <<
int(pf->target_dim()) <<
" of " <<
149 if (cv == f_elems.size()) {
150 f_elems.push_back(pf);
152 dof_enumeration_made =
false;
153 touch(); v_num = act_counter();
155 if (cv > f_elems.size()) f_elems.resize(cv+1);
156 if (!fe_convex.is_in(cv) || f_elems[cv] != pf) {
159 dof_enumeration_made =
false;
160 touch(); v_num = act_counter();
167 for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv)
178 fem_degree, complete);
185 for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
187 fem_degree, complete);
200 (
size_type cv, dim_type fem_degree, scalar_type alpha,
bool complete) {
202 (linked_mesh().trans_of_convex(cv), fem_degree, alpha, complete);
203 set_finite_element(cv, pf);
207 (
const dal::bit_vector &cvs, dim_type fem_degree, scalar_type alpha,
209 for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
211 (linked_mesh().trans_of_convex(cv), fem_degree, alpha, complete);
212 set_finite_element(cv, pf);
217 (dim_type fem_degree, scalar_type alpha,
bool complete) {
218 set_classical_discontinuous_finite_element
219 (linked_mesh().convex_index(), fem_degree, alpha, complete);
220 set_auto_add(fem_degree,
true, alpha);
225 pfem pf = f_elems[cv];
226 return linked_mesh().trans_of_convex(cv)->transform
227 (pf->node_of_dof(cv, i * pf->target_dim() / Qdim),
236 pfem pf = f_elems[cv];
237 return linked_mesh().trans_of_convex(cv)->transform
242 GMM_ASSERT1(
false,
"Inexistent dof");
250 size_type tdim = f_elems[cv]->target_dim();
251 return dim_type((d-i) / tdim);
254 GMM_ASSERT1(
false,
"Inexistent dof");
273 GMM_ASSERT1(
false,
"Inexistent dof");
283 bool operator()(
const fem_dof& m,
const fem_dof& n)
const {
284 if (m.ind_node < n.ind_node)
return true;
285 if (m.ind_node > n.ind_node)
return false;
286 if (m.part == n.part)
288 else if (m.part < n.part)
return true;
295 ind.resize(nb_total_dof);
297 for (dal::bv_visitor cv(
convex_index()); !cv.finished(); ++cv) {
299 for (
size_type j=0; j < pf->nb_dof(cv); j++) {
300 size_type gid = pf->index_of_global_dof(cv,j);
303 for (
size_type i=0; i < Qdim/pf->target_dim(); ++i)
310 bool mesh_fem::is_uniform()
const {
315 bool mesh_fem::is_uniformly_vectorized()
const {
317 return is_uniformly_vectorized_;
324 is_uniformly_vectorized_ = (
get_qdim() > 1);
325 GMM_ASSERT1(linked_mesh_ != 0,
"Uninitialized mesh_fem");
327 if (fe_convex.card() == 0)
328 { dof_enumeration_made =
true; nb_total_dof = 0;
return; }
329 pfem first_pf = f_elems[fe_convex.first_true()];
330 if (first_pf && first_pf->is_on_real_element()) is_uniform_ =
false;
331 if (first_pf && first_pf->target_dim() > 1) is_uniformly_vectorized_=
false;
338 std::vector<bgeot::kdtree> dof_nodes(nb_max_cv);
339 std::vector<scalar_type> elt_car_sizes(nb_max_cv);
340 std::vector<std::map<fem_dof, size_type, dof_comp_>> dof_sorts(nb_max_cv);
343 dal::bit_vector encountered_global_dof, processed_elt;
347 std::vector<size_type> itab;
351 bgeot::mesh_structure::ind_set s;
353 dof_structure.
clear();
354 bgeot::pstored_point_tab pspt_old = 0;
356 bgeot::pgeotrans_precomp pgp = 0;
359 !cv.finished(); ++cv) {
360 if (fe_convex.is_in(cv)) {
361 gmm::copy(
linked_mesh().points_of_convex(cv)[0], bmin);
362 gmm::copy(bmin, bmax);
364 const base_node &pt =
linked_mesh().points_of_convex(cv)[i];
365 for (
size_type d = 1; d < bmin.size(); ++d) {
366 bmin[d] = std::min(bmin[d], pt[d]);
367 bmax[d] = std::max(bmax[d], pt[d]);
370 elt_car_sizes[cv] = gmm::vect_dist2_sqr(bmin, bmax);
374 dal::bit_vector cv_done;
377 !cv.finished(); ++cv) {
378 if (!fe_convex.is_in(cv))
continue;
380 if (pf != first_pf) is_uniform_ =
false;
381 if (pf->target_dim() > 1) is_uniformly_vectorized_ =
false;
383 bgeot::pstored_point_tab pspt = pf->node_tab(cv);
384 if (pgt != pgt_old || pspt != pspt_old)
385 pgp = bgeot::geotrans_precomp(pgt, pspt, pf);
386 pgt_old = pgt; pspt_old = pspt;
392 fd.pnd = pf->dof_types()[i];
393 fd.part = get_dof_partition(cv);
395 if (fd.pnd == andof) {
396 size_type num = pf->index_of_global_dof(cv, i);
397 if (!(encountered_global_dof[num])) {
398 ind_global_dof[num] = nbdof;
399 nbdof += Qdim / pf->target_dim();
400 encountered_global_dof[num] =
true;
402 itab[i] = ind_global_dof[num];
405 nbdof += Qdim / pf->target_dim();
407 pgp->transform(
linked_mesh().points_of_convex(cv), i, P);
410 if (dof_nodes[cv].nb_points() > 0) {
411 scalar_type dist = dof_nodes[cv].nearest_neighbor(ipt, P);
412 if (gmm::abs(dist) <= 1e-6*elt_car_sizes[cv]) {
414 auto it = dof_sorts[cv].find(fd);
415 if (it != dof_sorts[cv].end()) idof = it->second;
420 nbdof += Qdim / pf->target_dim();
424 if (!cv_done[ncv] && fe_convex.is_in(ncv)) {
427 if (dof_nodes[ncv].nb_points() > 0) {
428 scalar_type dist = dof_nodes[ncv].nearest_neighbor(ipt, P);
429 if (gmm::abs(dist) <= 1e-6*elt_car_sizes[ncv])
433 fd.ind_node = dof_nodes[ncv].add_point(P);
434 dof_sorts[ncv][fd] = idof;
442 dof_sorts[cv].clear(); dof_nodes[cv].clear();
443 dof_structure.add_convex_noverif(pf->structure(cv), itab.begin(), cv);
446 dof_enumeration_made =
true;
447 nb_total_dof = nbdof;
451 gmm::row_matrix<gmm::rsvector<scalar_type> >
454 for (dal::bv_visitor i(kept_dof); !i.finished(); ++i, ++j)
455 RR(j, i) = scalar_type(1);
460 gmm::row_matrix<gmm::rsvector<scalar_type> >
463 for (std::set<size_type>::const_iterator it = kept_dof.begin();
464 it != kept_dof.end(); ++it, ++j)
465 RR(j, *it) = scalar_type(1);
469 void mesh_fem::clear() {
471 dof_enumeration_made =
false;
473 touch(); v_num = act_counter();
474 dof_structure.
clear();
475 use_reduction =
false;
476 R_ = REDUCTION_MATRIX();
477 E_ = EXTENSION_MATRIX();
480 void mesh_fem::init_with_mesh(
const mesh &me, dim_type Q) {
481 GMM_ASSERT1(linked_mesh_ == 0,
"Mesh level set already initialized");
482 dof_enumeration_made =
false;
485 auto_add_elt_K = dim_type(-1);
487 mi.resize(1); mi[0] = Q;
489 use_reduction =
false;
490 this->add_dependency(me);
491 v_num = v_num_update = act_counter();
494 void mesh_fem::copy_from(
const mesh_fem &mf) {
495 clear_dependencies();
497 init_with_mesh(*mf.linked_mesh_, mf.get_qdim());
499 f_elems = mf.f_elems;
500 fe_convex = mf.fe_convex;
503 dof_structure = mf.dof_structure;
504 dof_enumeration_made = mf.dof_enumeration_made;
505 is_uniform_ = mf.is_uniform_;
506 nb_total_dof = mf.nb_total_dof;
507 auto_add_elt_pf = mf.auto_add_elt_pf;
508 auto_add_elt_K = mf.auto_add_elt_K;
509 auto_add_elt_disc = mf.auto_add_elt_disc;
510 auto_add_elt_complete = mf.auto_add_elt_complete;
511 auto_add_elt_alpha = mf.auto_add_elt_alpha;
513 dof_partition = mf.dof_partition;
514 v_num_update = mf.v_num_update;
516 use_reduction = mf.use_reduction;
519 mesh_fem::mesh_fem(
const mesh_fem &mf) : context_dependencies() {
520 linked_mesh_ = 0; copy_from(mf);
523 mesh_fem &mesh_fem::operator=(
const mesh_fem &mf) {
528 mesh_fem::mesh_fem(
const mesh &me, dim_type Q)
529 { linked_mesh_ = 0; init_with_mesh(me, Q); }
531 mesh_fem::mesh_fem() {
533 dof_enumeration_made =
false;
538 mesh_fem::~mesh_fem() { }
541 GMM_ASSERT1(linked_mesh_ != 0,
"Uninitialized mesh_fem");
542 gmm::stream_standard_locale sl(ist);
545 std::string tmp(
"nop"), tmp2(
"nop"); tmp.clear(); tmp2.clear();
546 bool dof_read =
false;
547 gmm::col_matrix< gmm::wsvector<scalar_type> > RR, EE;
550 ist.seekg(0);ist.clear();
551 bgeot::read_until(ist,
"BEGIN MESH_FEM");
555 if (bgeot::casecmp(tmp,
"END")==0) {
557 }
else if (bgeot::casecmp(tmp,
"CONVEX")==0) {
561 " does not exist, are you sure "
562 "that the mesh attached to this object is right one ?");
567 while (!isspace(c)) { tmp.push_back(c); ist.get(c); }
570 GMM_ASSERT1(
fem,
"could not create the FEM '" << tmp <<
"'");
572 }
else if (bgeot::casecmp(tmp,
"BEGIN")==0) {
574 if (bgeot::casecmp(tmp,
"DOF_PARTITION") == 0) {
575 for (dal::bv_visitor cv(
convex_index()); !cv.finished(); ++cv) {
576 size_type d; ist >> d; set_dof_partition(cv,
unsigned(d));
578 ist >> bgeot::skip(
"END DOF_PARTITION");
579 }
else if (bgeot::casecmp(tmp,
"DOF_ENUMERATION") == 0) {
580 dal::bit_vector doflst;
581 dof_structure.
clear(); dof_enumeration_made =
false;
584 touch(); v_num = act_counter();
587 if (bgeot::casecmp(tmp,
"END")==0) {
593 std::vector<size_type> tab;
595 isdigit(tmp[0]) && tmp2 ==
":") {
599 else if (nbdof_unif != nbd)
607 doflst.add(tab[i]+q);
609 dof_structure.add_convex_noverif
611 }
else GMM_ASSERT1(
false,
"Missing convex or wrong number "
612 <<
"in dof enumeration: '"
614 << std::streamoff(ist.tellg())<<
"]");
619 this->dof_enumeration_made =
true;
620 touch(); v_num = act_counter();
621 this->nb_total_dof = doflst.card();
622 ist >> bgeot::skip(
"DOF_ENUMERATION");
623 }
else if (bgeot::casecmp(tmp,
"REDUCTION_MATRIX")==0) {
625 GMM_ASSERT1(bgeot::casecmp(tmp,
"NROWS")==0,
626 "Missing number of rows");
629 GMM_ASSERT1(bgeot::casecmp(tmp,
"NCOLS")==0,
630 "Missing number of columns");
633 GMM_ASSERT1(bgeot::casecmp(tmp,
"NNZ")==0,
634 "Missing number of nonzero elements");
636 gmm::clear(RR); gmm::resize(RR, nrows, ncols);
639 GMM_ASSERT1(bgeot::casecmp(tmp,
"COL")==0,
640 "Missing some columns");
644 scalar_type val; ist >> val;
648 R_ = REDUCTION_MATRIX(nrows, ncols);
650 use_reduction =
true;
651 ist >> bgeot::skip(
"END");
652 ist >> bgeot::skip(
"REDUCTION_MATRIX");
653 }
else if (bgeot::casecmp(tmp,
"EXTENSION_MATRIX")==0) {
655 GMM_ASSERT1(bgeot::casecmp(tmp,
"NROWS")==0,
656 "Missing number of rows");
659 GMM_ASSERT1(bgeot::casecmp(tmp,
"NCOLS")==0,
660 "Missing number of columns");
663 GMM_ASSERT1(bgeot::casecmp(tmp,
"NNZ")==0,
664 "Missing number of nonzero elements");
666 gmm::clear(EE); gmm::resize(EE, nrows, ncols);
669 GMM_ASSERT1(bgeot::casecmp(tmp,
"ROW")==0,
670 "Missing some rows");
674 scalar_type val; ist >> val;
678 E_ = EXTENSION_MATRIX(nrows, ncols);
680 use_reduction =
true;
681 ist >> bgeot::skip(
"END");
682 ist >> bgeot::skip(
"EXTENSION_MATRIX");
685 GMM_ASSERT1(
false,
"Syntax error in file at token '"
686 << tmp <<
"' [pos=" << std::streamoff(ist.tellg())
688 }
else if (bgeot::casecmp(tmp,
"QDIM")==0) {
689 GMM_ASSERT1(!dof_read,
"Can't change QDIM after dof enumeration");
691 int q = atoi(tmp.c_str());
692 GMM_ASSERT1(q > 0 && q <= 250,
"invalid qdim: " << q);
694 }
else if (tmp.size()) {
695 GMM_ASSERT1(
false,
"Unexpected token '" << tmp <<
696 "' [pos=" << std::streamoff(ist.tellg()) <<
"]");
697 }
else if (ist.eof()) {
698 GMM_ASSERT1(
false,
"Unexpected end of stream "
699 <<
"(missing BEGIN MESH_FEM/END MESH_FEM ?)");
705 std::ifstream o(name.c_str());
706 GMM_ASSERT1(o,
"Mesh_fem file '" << name <<
"' does not exist");
710 template<
typename VECT>
static void
711 write_col(std::ostream &ost,
const VECT &v) {
712 typename gmm::linalg_traits<VECT>::const_iterator it = v.begin();
714 for (; it != v.end(); ++it)
715 ost <<
" " << it.index() <<
" " << *it;
719 void mesh_fem::write_reduction_matrices_to_file(std::ostream &ost)
const {
722 ost <<
" BEGIN REDUCTION_MATRIX " <<
'\n';
723 ost <<
" NROWS " << gmm::mat_nrows(R_) <<
'\n';
724 ost <<
" NCOLS " << gmm::mat_ncols(R_) <<
'\n';
725 ost <<
" NNZ " << gmm::nnz(R_) <<
'\n';
726 for (
size_type i = 0; i < gmm::mat_ncols(R_); ++i) {
728 write_col(ost, gmm::mat_col(R_, i));
730 ost <<
" END REDUCTION_MATRIX " <<
'\n';
731 ost <<
" BEGIN EXTENSION_MATRIX " <<
'\n';
732 ost <<
" NROWS " << gmm::mat_nrows(E_) <<
'\n';
733 ost <<
" NCOLS " << gmm::mat_ncols(E_) <<
'\n';
734 ost <<
" NNZ " << gmm::nnz(E_) <<
'\n';
735 for (
size_type i = 0; i < gmm::mat_nrows(E_); ++i) {
737 write_col(ost, gmm::mat_row(E_, i));
739 ost <<
" END EXTENSION_MATRIX " <<
'\n';
743 void mesh_fem::write_basic_to_file(std::ostream &ost)
const {
745 for (dal::bv_visitor cv(
convex_index()); !cv.finished(); ++cv) {
746 ost <<
" CONVEX " << cv;
751 if (!dof_partition.empty()) {
752 ost <<
" BEGIN DOF_PARTITION\n";
754 for (dal::bv_visitor cv(
convex_index()); !cv.finished(); ++cv) {
755 ost <<
" " << get_dof_partition(cv);
if ((++i % 20) == 0) ost <<
"\n";
758 ost <<
" END DOF_PARTITION\n";
761 ost <<
" BEGIN DOF_ENUMERATION " <<
'\n';
762 for (dal::bv_visitor cv(
convex_index()); !cv.finished(); ++cv) {
763 ost <<
" " << cv <<
": ";
774 ost <<
" END DOF_ENUMERATION " <<
'\n';
779 gmm::stream_standard_locale sl(ost);
780 ost <<
'\n' <<
"BEGIN MESH_FEM" <<
'\n' <<
'\n';
781 write_basic_to_file(ost);
782 write_reduction_matrices_to_file(ost);
783 ost <<
"END MESH_FEM" <<
'\n';
787 std::ofstream o(name.c_str());
788 GMM_ASSERT1(o,
"impossible to open file '" << name <<
"'");
789 o <<
"% GETFEM MESH_FEM FILE " <<
'\n';
790 o <<
"% GETFEM VERSION " << GETFEM_VERSION <<
'\n' <<
'\n' <<
'\n';
797 dim_type order, qdim;
799 mf__key_(
const mesh &msh, dim_type o, dim_type q,
bool complete_)
800 : pmsh(&msh), order(o), qdim(q), complete(complete_)
801 { add_dependency(msh); }
802 bool operator <(
const mf__key_ &a)
const {
803 if (pmsh < a.pmsh)
return true;
804 else if (pmsh > a.pmsh)
return false;
805 else if (order < a.order)
return true;
806 else if (order > a.order)
return false;
807 else if (qdim < a.qdim)
return true;
808 else if (qdim > a.qdim)
return false;
809 else if (complete < a.complete)
return true;
812 void update_from_context()
const {}
813 mf__key_(
const mf__key_ &mfk) : context_dependencies( ) {
817 complete = mfk.complete;
818 add_dependency(*pmsh);
821 mf__key_& operator=(
const mf__key_ &mfk);
825 class classical_mesh_fem_pool {
827 typedef std::shared_ptr<const mesh_fem> pmesh_fem;
828 typedef std::map<mf__key_, pmesh_fem> mesh_fem_tab;
834 const mesh_fem &operator()(
const mesh &msh, dim_type o, dim_type qdim,
835 bool complete=
false) {
836 mesh_fem_tab::iterator itt = mfs.begin(), itn = mfs.begin();
837 if (itn != mfs.end()) itn++;
838 while (itt != mfs.end()) {
839 if (!(itt->first.is_context_valid()))
842 if (itn != mfs.end()) itn++;
845 mf__key_ key(msh, o, qdim, complete);
846 mesh_fem_tab::iterator it = mfs.find(key);
847 assert(it == mfs.end() || it->second->is_context_valid());
849 if (it == mfs.end()) {
851 auto pmf = (p_torus_mesh) ? std::make_shared<torus_mesh_fem>(*p_torus_mesh, qdim)
852 : std::make_shared<mesh_fem>(msh, qdim);
853 pmf->set_classical_finite_element(o);
854 pmf->set_auto_add(o,
false);
855 return *(mfs[key] = pmf);
857 else return *(it->second);
863 dim_type order, dim_type qdim,
865 classical_mesh_fem_pool &pool
867 return pool(msh, order, qdim, complete);
870 struct dummy_mesh_fem_ {
872 dummy_mesh_fem_() : mf(dummy_mesh()) {}
879 void vectorize_base_tensor(
const base_tensor &t, base_matrix &vt,
881 GMM_ASSERT1(qdim == N || qdim == 1,
"mixed intrinsic vector and "
882 "tensorised fem is not supported");
883 gmm::resize(vt, ndof, N);
884 ndof = (ndof*qdim)/N;
887 gmm::copy(t.as_vector(), vt.as_vector());
888 }
else if (qdim == 1) {
890 base_tensor::const_iterator it = t.begin();
891 for (
size_type i = 0; i < ndof; ++i, ++it)
892 for (
size_type j = 0; j < N; ++j) vt(i*N+j, j) = *it;
896 void vectorize_grad_base_tensor(
const base_tensor &t, base_tensor &vt,
899 GMM_ASSERT1(qdim == Q || qdim == 1,
"mixed intrinsic vector and "
900 "tensorised fem is not supported");
901 vt.adjust_sizes(bgeot::multi_index(ndof, Q, N));
902 ndof = (ndof*qdim)/Q;
905 gmm::copy(t.as_vector(), vt.as_vector());
906 }
else if (qdim == 1) {
908 base_tensor::const_iterator it = t.begin();
910 for (
size_type i = 0; i < ndof; ++i, ++it)
911 for (
size_type j = 0; j < Q; ++j) vt(i*Q+j, j, k) = *it;