GetFEM  5.4.3
getfem_mesh_fem.cc
1 /*===========================================================================
2 
3  Copyright (C) 1999-2020 Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 
23 #include <queue>
24 #include "getfem/dal_singleton.h"
25 #include "getfem/getfem_mesh_fem.h"
26 #include "getfem/getfem_torus.h"
27 
28 namespace getfem {
29 
31  for (dal::bv_visitor cv(fe_convex); !cv.finished(); ++cv) {
32  if (linked_mesh_->convex_index().is_in(cv)) {
33  if (v_num_update < linked_mesh_->convex_version_number(cv)) {
34  if (auto_add_elt_pf != 0)
35  const_cast<mesh_fem *>(this)
36  ->set_finite_element(cv, auto_add_elt_pf);
37  else if (auto_add_elt_K != dim_type(-1)) {
38  if (auto_add_elt_disc)
39  const_cast<mesh_fem *>(this)
41  (cv, auto_add_elt_K, auto_add_elt_alpha,
42  auto_add_elt_complete);
43  else
44  const_cast<mesh_fem *>(this)
45  ->set_classical_finite_element(cv, auto_add_elt_K,
46  auto_add_elt_complete);
47  }
48  else
49  const_cast<mesh_fem *>(this)->set_finite_element(cv, 0);
50  }
51  }
52  else const_cast<mesh_fem *>(this)->set_finite_element(cv, 0);
53  }
54  for (dal::bv_visitor cv(linked_mesh_->convex_index());
55  !cv.finished(); ++cv) {
56  if (!fe_convex.is_in(cv)
57  && v_num_update < linked_mesh_->convex_version_number(cv)) {
58  if (auto_add_elt_pf != 0)
59  const_cast<mesh_fem *>(this)
60  ->set_finite_element(cv, auto_add_elt_pf);
61  else if (auto_add_elt_K != dim_type(-1)) {
62  if (auto_add_elt_disc)
63  const_cast<mesh_fem *>(this)
65  (cv, auto_add_elt_K, auto_add_elt_alpha, auto_add_elt_complete);
66  else
67  const_cast<mesh_fem *>(this)
68  ->set_classical_finite_element(cv, auto_add_elt_K,
69  auto_add_elt_complete);
70  }
71  }
72  }
73  if (!dof_enumeration_made) enumerate_dof();
74  v_num = v_num_update = act_counter();
75  }
76 
77  dal::bit_vector mesh_fem::basic_dof_on_region(const mesh_region &b) const {
78  context_check(); if (!dof_enumeration_made) this->enumerate_dof();
79  dal::bit_vector res;
80  for (getfem::mr_visitor v(b,linked_mesh()); !v.finished(); ++v) {
81  size_type cv = v.cv();
82  if (convex_index().is_in(cv)) {
83  if (v.is_face()) {
84  short_type f = short_type(v.f());
85  size_type nbb =
86  dof_structure.structure_of_convex(cv)->nb_points_of_face(f);
87  for (size_type i = 0; i < nbb; ++i) {
88  size_type n = Qdim/fem_of_element(cv)->target_dim();
89  for (size_type ll = 0; ll < n; ++ll)
90  res.add(dof_structure.ind_points_of_face_of_convex(cv,f)[i]+ll);
91  }
92  } else {
93  size_type nbb =
94  dof_structure.structure_of_convex(cv)->nb_points();
95  for (size_type i = 0; i < nbb; ++i) {
96  size_type n = Qdim/fem_of_element(cv)->target_dim();
97  for (size_type ll = 0; ll < n; ++ll)
98  res.add(dof_structure.ind_points_of_convex(cv)[i]+ll);
99  }
100  }
101  }
102  }
103  return res;
104  }
105 
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());
112  }
113 
114  dal::bit_vector mesh_fem::dof_on_region(const mesh_region &b) const {
115  dal::bit_vector res = basic_dof_on_region(b);
116  if (is_reduced()) {
117  if (nb_dof() == 0) return dal::bit_vector();
118  dal::bit_vector basic = res;
119  res.clear();
120  for (dal::bv_visitor i(basic); !i.finished(); ++i)
121  add_e_line__(gmm::mat_row(E_, i), res);
122  }
123  return res;
124  }
125 
126 
128  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
129  context_check();
130  if (pf == 0) {
131  if (fe_convex.is_in(cv)) {
132  fe_convex.sup(cv);
133  dof_enumeration_made = false;
134  touch(); v_num = act_counter();
135  }
136  }
137  else {
138  GMM_ASSERT1(basic_structure(linked_mesh_->structure_of_convex(cv))
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 " <<
146  name_of_fem(pf));
147 
148 
149  if (cv == f_elems.size()) {
150  f_elems.push_back(pf);
151  fe_convex.add(cv);
152  dof_enumeration_made = false;
153  touch(); v_num = act_counter();
154  } else {
155  if (cv > f_elems.size()) f_elems.resize(cv+1);
156  if (!fe_convex.is_in(cv) || f_elems[cv] != pf) {
157  fe_convex.add(cv);
158  f_elems[cv] = pf;
159  dof_enumeration_made = false;
160  touch(); v_num = act_counter();
161  }
162  }
163  }
164  }
165 
166  void mesh_fem::set_finite_element(const dal::bit_vector &cvs, pfem ppf) {
167  for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv)
168  set_finite_element(cv, ppf);
169  }
170 
173 
175  dim_type fem_degree,
176  bool complete) {
177  pfem pf = getfem::classical_fem(linked_mesh().trans_of_convex(cv),
178  fem_degree, complete);
179  set_finite_element(cv, pf);
180  }
181 
182  void mesh_fem::set_classical_finite_element(const dal::bit_vector &cvs,
183  dim_type fem_degree,
184  bool complete) {
185  for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
186  pfem pf = getfem::classical_fem(linked_mesh().trans_of_convex(cv),
187  fem_degree, complete);
188  set_finite_element(cv, pf);
189  }
190  }
191 
192  void mesh_fem::set_classical_finite_element(dim_type fem_degree,
193  bool complete) {
195  complete);
196  set_auto_add(fem_degree, false);
197  }
198 
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);
204  }
205 
207  (const dal::bit_vector &cvs, dim_type fem_degree, scalar_type alpha,
208  bool complete) {
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);
213  }
214  }
215 
217  (dim_type fem_degree, scalar_type alpha, bool complete) {
219  (linked_mesh().convex_index(), fem_degree, alpha, complete);
220  set_auto_add(fem_degree, true, alpha);
221  }
222 
224  context_check(); if (!dof_enumeration_made) enumerate_dof();
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),
228  linked_mesh().points_of_convex(cv));
229  }
230 
232  context_check(); if (!dof_enumeration_made) enumerate_dof();
233  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
234  size_type cv = dof_structure.first_convex_of_point(i);
235  if (cv != size_type(-1)) {
236  pfem pf = f_elems[cv];
237  return linked_mesh().trans_of_convex(cv)->transform
238  (pf->node_of_dof(cv, dof_structure.ind_in_convex_of_point(cv, i)),
239  linked_mesh().points_of_convex(cv));
240  }
241  }
242  GMM_ASSERT1(false, "Inexistent dof");
243  }
244 
246  context_check(); if (!dof_enumeration_made) enumerate_dof();
247  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
248  size_type cv = dof_structure.first_convex_of_point(i);
249  if (cv != size_type(-1)) {
250  size_type tdim = f_elems[cv]->target_dim();
251  return dim_type((d-i) / tdim);
252  }
253  }
254  GMM_ASSERT1(false, "Inexistent dof");
255  return 0;
256  }
257 
259  context_check(); if (!dof_enumeration_made) enumerate_dof();
260  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
261  size_type cv = dof_structure.first_convex_of_point(i);
262  if (cv != size_type(-1)) return cv;
263  }
264  return size_type(-1);
265  }
266 
267  const mesh::ind_cv_ct &mesh_fem::convex_to_basic_dof(size_type d) const {
268  context_check(); if (!dof_enumeration_made) enumerate_dof();
269  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
270  size_type cv = dof_structure.first_convex_of_point(i);
271  if (cv != size_type(-1)) return dof_structure.convex_to_point(i);
272  }
273  GMM_ASSERT1(false, "Inexistent dof");
274  }
275 
276  struct fem_dof {
277  size_type ind_node;
278  pdof_description pnd;
279  size_type part;
280  };
281 
282  struct dof_comp_ {
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)
287  return dof_description_compare(m.pnd, n.pnd) < 0;
288  else if (m.part < n.part) return true;
289  else /*if (m.part > n.part)*/ return false;
290  }
291  };
292 
293  void mesh_fem::get_global_dof_index(std::vector<size_type> &ind) const {
294  context_check(); if (!dof_enumeration_made) enumerate_dof();
295  ind.resize(nb_total_dof);
296  gmm::fill(ind, size_type(-1));
297  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
298  pfem pf = fem_of_element(cv);
299  for (size_type j=0; j < pf->nb_dof(cv); j++) {
300  size_type gid = pf->index_of_global_dof(cv,j);
301  if (gid != size_type(-1)) {
302  size_type dof = dof_structure.ind_points_of_convex(cv)[j];
303  for (size_type i=0; i < Qdim/pf->target_dim(); ++i)
304  ind[dof+i] = gid;
305  }
306  }
307  }
308  }
309 
310  bool mesh_fem::is_uniform() const {
311  context_check(); if (!dof_enumeration_made) enumerate_dof();
312  return is_uniform_;
313  }
314 
315  bool mesh_fem::is_uniformly_vectorized() const {
316  context_check(); if (!dof_enumeration_made) enumerate_dof();
317  return is_uniformly_vectorized_;
318  }
319 
320  /// Enumeration of dofs
321  void mesh_fem::enumerate_dof() const {
323  is_uniform_ = true;
324  is_uniformly_vectorized_ = (get_qdim() > 1);
325  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
326  context_check();
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;
332 
333  // Dof counter
334  size_type nbdof = 0;
335 
336  // Information stored per element
337  size_type nb_max_cv = linked_mesh().nb_allocated_convex();
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);
341 
342  // Information for global dof
343  dal::bit_vector encountered_global_dof, processed_elt;
344  dal::dynamic_array<size_type> ind_global_dof;
345 
346  // Auxilliary variables
347  std::vector<size_type> itab;
348  base_node P(linked_mesh().dim());
349  base_node bmin(linked_mesh().dim()), bmax(linked_mesh().dim());
350  fem_dof fd;
351  bgeot::mesh_structure::ind_set s;
352 
353  dof_structure.clear();
354  bgeot::pstored_point_tab pspt_old = 0;
355  bgeot::pgeometric_trans pgt_old = 0;
356  bgeot::pgeotrans_precomp pgp = 0;
357 
358  for (dal::bv_visitor cv(linked_mesh().convex_index());
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);
363  for (const base_node &pt : linked_mesh().points_of_convex(cv)) {
364  for (size_type d = 1; d < bmin.size(); ++d) {
365  bmin[d] = std::min(bmin[d], pt[d]);
366  bmax[d] = std::max(bmax[d], pt[d]);
367  }
368  }
369  elt_car_sizes[cv] = gmm::vect_dist2_sqr(bmin, bmax);
370  }
371  }
372 
373  dal::bit_vector cv_done;
374 
375  for (dal::bv_visitor cv(linked_mesh().convex_index());
376  !cv.finished(); ++cv) { // Loop on elements
377  if (!fe_convex.is_in(cv)) continue;
378  pfem pf = fem_of_element(cv);
379  if (pf != first_pf) is_uniform_ = false;
380  if (pf->target_dim() > 1) is_uniformly_vectorized_ = false;
381  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
382  bgeot::pstored_point_tab pspt = pf->node_tab(cv);
383  if (pgt != pgt_old || pspt != pspt_old)
384  pgp = bgeot::geotrans_precomp(pgt, pspt, pf);
385  pgt_old = pgt; pspt_old = pspt;
386  size_type nbd = pf->nb_dof(cv);
387  pdof_description andof = global_dof(pf->dim());
388  itab.resize(nbd);
389 
390  for (size_type i = 0; i < nbd; i++) { // Loop on dofs
391  fd.pnd = pf->dof_types()[i];
392  fd.part = get_dof_partition(cv);
393 
394  if (fd.pnd == andof) { // If the dof is a global one
395  size_type num = pf->index_of_global_dof(cv, i);
396  if (!(encountered_global_dof[num])) {
397  ind_global_dof[num] = nbdof;
398  nbdof += Qdim / pf->target_dim();
399  encountered_global_dof[num] = true;
400  }
401  itab[i] = ind_global_dof[num];
402  } else if (!dof_linkable(fd.pnd)) { // If the dof is not linkable
403  itab[i] = nbdof;
404  nbdof += Qdim / pf->target_dim();
405  } else { // For a standard linkable dof
406  pgp->transform(linked_mesh().points_of_convex(cv), i, P);
407  size_type idof = nbdof;
408 
409  if (dof_nodes[cv].nb_points() > 0) {
410  scalar_type dist = dof_nodes[cv].nearest_neighbor(ipt, P);
411  if (gmm::abs(dist) <= 1e-6*elt_car_sizes[cv]) {
412  fd.ind_node=ipt.i;
413  auto it = dof_sorts[cv].find(fd);
414  if (it != dof_sorts[cv].end()) idof = it->second;
415  }
416  }
417 
418  if (idof == nbdof) {
419  nbdof += Qdim / pf->target_dim();
420 
421  linked_mesh().neighbors_of_convex(cv, pf->faces_of_dof(cv, i), s);
422  for (size_type ncv : s) { // For each unscanned neighbor
423  if (!cv_done[ncv] && fe_convex.is_in(ncv)) { // add the dof
424 
425  fd.ind_node = size_type(-1);
426  if (dof_nodes[ncv].nb_points() > 0) {
427  scalar_type dist = dof_nodes[ncv].nearest_neighbor(ipt, P);
428  if (gmm::abs(dist) <= 1e-6*elt_car_sizes[ncv])
429  fd.ind_node=ipt.i;
430  }
431  if (fd.ind_node == size_type(-1))
432  fd.ind_node = dof_nodes[ncv].add_point(P);
433  dof_sorts[ncv][fd] = idof;
434  }
435  }
436  }
437  itab[i] = idof;
438  }
439  }
440  cv_done.add(cv);
441  dof_sorts[cv].clear(); dof_nodes[cv].clear();
442  dof_structure.add_convex_noverif(pf->structure(cv), itab.begin(), cv);
443  }
444 
445  dof_enumeration_made = true;
446  nb_total_dof = nbdof;
447  }
448 
449  void mesh_fem::reduce_to_basic_dof(const dal::bit_vector &kept_dof) {
450  gmm::row_matrix<gmm::rsvector<scalar_type> >
451  RR(kept_dof.card(), nb_basic_dof());
452  size_type j = 0;
453  for (dal::bv_visitor i(kept_dof); !i.finished(); ++i, ++j)
454  RR(j, i) = scalar_type(1);
455  set_reduction_matrices(RR, gmm::transposed(RR));
456  }
457 
458  void mesh_fem::reduce_to_basic_dof(const std::set<size_type> &kept_dof) {
459  gmm::row_matrix<gmm::rsvector<scalar_type> >
460  RR(kept_dof.size(), nb_basic_dof());
461  size_type j = 0;
462  for (std::set<size_type>::const_iterator it = kept_dof.begin();
463  it != kept_dof.end(); ++it, ++j)
464  RR(j, *it) = scalar_type(1);
465  set_reduction_matrices(RR, gmm::transposed(RR));
466  }
467 
468  void mesh_fem::clear() {
469  fe_convex.clear();
470  dof_enumeration_made = false;
471  is_uniform_ = true;
472  touch(); v_num = act_counter();
473  dof_structure.clear();
474  use_reduction = false;
475  R_ = REDUCTION_MATRIX();
476  E_ = EXTENSION_MATRIX();
477  }
478 
479  void mesh_fem::init_with_mesh(const mesh &me, dim_type Q) {
480  GMM_ASSERT1(linked_mesh_ == 0, "Mesh level set already initialized");
481  dof_enumeration_made = false;
482  is_uniform_ = false;
483  auto_add_elt_pf = 0;
484  auto_add_elt_K = dim_type(-1);
485  Qdim = Q;
486  mi.resize(1); mi[0] = Q;
487  linked_mesh_ = &me;
488  use_reduction = false;
489  this->add_dependency(me);
490  v_num = v_num_update = act_counter();
491  }
492 
493  void mesh_fem::copy_from(const mesh_fem &mf) {
494  clear_dependencies();
495  linked_mesh_ = 0;
496  init_with_mesh(*mf.linked_mesh_, mf.get_qdim());
497 
498  f_elems = mf.f_elems;
499  fe_convex = mf.fe_convex;
500  R_ = mf.R_;
501  E_ = mf.E_;
502  dof_structure = mf.dof_structure;
503  dof_enumeration_made = mf.dof_enumeration_made;
504  is_uniform_ = mf.is_uniform_;
505  nb_total_dof = mf.nb_total_dof;
506  auto_add_elt_pf = mf.auto_add_elt_pf;
507  auto_add_elt_K = mf.auto_add_elt_K;
508  auto_add_elt_disc = mf.auto_add_elt_disc;
509  auto_add_elt_complete = mf.auto_add_elt_complete;
510  auto_add_elt_alpha = mf.auto_add_elt_alpha;
511  mi = mf.mi;
512  dof_partition = mf.dof_partition;
513  v_num_update = mf.v_num_update;
514  v_num = mf.v_num;
515  use_reduction = mf.use_reduction;
516  }
517 
518  mesh_fem::mesh_fem(const mesh_fem &mf) : context_dependencies() {
519  linked_mesh_ = 0; copy_from(mf);
520  }
521 
522  mesh_fem &mesh_fem::operator=(const mesh_fem &mf) {
523  copy_from(mf);
524  return *this;
525  }
526 
527  mesh_fem::mesh_fem(const mesh &me, dim_type Q)
528  { linked_mesh_ = 0; init_with_mesh(me, Q); }
529 
530  mesh_fem::mesh_fem() {
531  linked_mesh_ = 0;
532  dof_enumeration_made = false;
533  is_uniform_ = true;
534  set_qdim(1);
535  }
536 
537  mesh_fem::~mesh_fem() { }
538 
539  void mesh_fem::read_from_file(std::istream &ist) {
540  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
541  gmm::stream_standard_locale sl(ist);
542  dal::bit_vector npt;
544  std::string tmp("nop"), tmp2("nop"); tmp.clear(); tmp2.clear();
545  bool dof_read = false;
546  gmm::col_matrix< gmm::wsvector<scalar_type> > RR, EE;
547  ist.precision(16);
548  clear();
549  ist.seekg(0);ist.clear();
550  bgeot::read_until(ist, "BEGIN MESH_FEM");
551 
552  while (true) {
553  ist >> std::ws; bgeot::get_token(ist, tmp);
554  if (bgeot::casecmp(tmp, "END")==0) {
555  break;
556  } else if (bgeot::casecmp(tmp, "CONVEX")==0) {
557  bgeot::get_token(ist, tmp);
558  size_type ic = atoi(tmp.c_str());
559  GMM_ASSERT1(linked_mesh().convex_index().is_in(ic), "Convex " << ic <<
560  " does not exist, are you sure "
561  "that the mesh attached to this object is right one ?");
562 
563  int rgt = bgeot::get_token(ist, tmp);
564  if (rgt != 3) { // for backward compatibility
565  char c; ist.get(c);
566  while (!isspace(c)) { tmp.push_back(c); ist.get(c); }
567  }
569  GMM_ASSERT1(fem, "could not create the FEM '" << tmp << "'");
570  set_finite_element(ic, fem);
571  } else if (bgeot::casecmp(tmp, "BEGIN")==0) {
572  bgeot::get_token(ist, tmp);
573  if (bgeot::casecmp(tmp, "DOF_PARTITION") == 0) {
574  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
575  size_type d; ist >> d; set_dof_partition(cv, unsigned(d));
576  }
577  ist >> bgeot::skip("END DOF_PARTITION");
578  } else if (bgeot::casecmp(tmp, "DOF_ENUMERATION") == 0) {
579  dal::bit_vector doflst;
580  dof_structure.clear(); dof_enumeration_made = false;
581  is_uniform_ = true;
582  size_type nbdof_unif = size_type(-1);
583  touch(); v_num = act_counter();
584  while (true) {
585  bgeot::get_token(ist, tmp);
586  if (bgeot::casecmp(tmp, "END")==0) {
587  break;
588  }
589  bgeot::get_token(ist, tmp2);
590 
591  size_type ic = atoi(tmp.c_str());
592  std::vector<size_type> tab;
593  if (convex_index().is_in(ic) && tmp.size() &&
594  isdigit(tmp[0]) && tmp2 == ":") {
596  if (nbdof_unif == size_type(-1))
597  nbdof_unif = nbd;
598  else if (nbdof_unif != nbd)
599  is_uniform_ = false;
600  tab.resize(nb_basic_dof_of_element(ic));
601  for (size_type i=0; i < fem_of_element(ic)->nb_dof(ic);
602  i++) {
603  ist >> tab[i];
604  for (size_type q=0; q < size_type(get_qdim())
605  / fem_of_element(ic)->target_dim(); ++q)
606  doflst.add(tab[i]+q);
607  }
608  dof_structure.add_convex_noverif
609  (fem_of_element(ic)->structure(ic), tab.begin(), ic);
610  } else GMM_ASSERT1(false, "Missing convex or wrong number "
611  << "in dof enumeration: '"
612  << tmp << "' [pos="
613  << std::streamoff(ist.tellg())<<"]");
614  /*bgeot::get_token(ist, tmp);
615  cerr << " tok: '" << tmp << "'\n";*/
616  }
617  dof_read = true;
618  this->dof_enumeration_made = true;
619  touch(); v_num = act_counter();
620  this->nb_total_dof = doflst.card();
621  ist >> bgeot::skip("DOF_ENUMERATION");
622  } else if (bgeot::casecmp(tmp, "REDUCTION_MATRIX")==0) {
623  bgeot::get_token(ist, tmp);
624  GMM_ASSERT1(bgeot::casecmp(tmp, "NROWS")==0,
625  "Missing number of rows");
626  size_type nrows; ist >> nrows;
627  bgeot::get_token(ist, tmp);
628  GMM_ASSERT1(bgeot::casecmp(tmp, "NCOLS")==0,
629  "Missing number of columns");
630  size_type ncols; ist >> ncols;
631  bgeot::get_token(ist, tmp);
632  GMM_ASSERT1(bgeot::casecmp(tmp, "NNZ")==0,
633  "Missing number of nonzero elements");
634  size_type nnz; ist >> nnz;
635  gmm::clear(RR); gmm::resize(RR, nrows, ncols);
636  for (size_type i = 0; i < ncols; ++i) {
637  bgeot::get_token(ist, tmp);
638  GMM_ASSERT1(bgeot::casecmp(tmp, "COL")==0,
639  "Missing some columns");
640  size_type nnz_col; ist >> nnz_col;
641  for (size_type j=0; j<nnz_col; ++j) {
642  size_type ind; ist >> ind;
643  scalar_type val; ist >> val;
644  RR(ind, i) = val; // can be optimized using a csc matrix
645  }
646  }
647  R_ = REDUCTION_MATRIX(nrows, ncols);
648  gmm::copy(RR, R_);
649  use_reduction = true;
650  ist >> bgeot::skip("END");
651  ist >> bgeot::skip("REDUCTION_MATRIX");
652  } else if (bgeot::casecmp(tmp, "EXTENSION_MATRIX")==0) {
653  bgeot::get_token(ist, tmp);
654  GMM_ASSERT1(bgeot::casecmp(tmp, "NROWS")==0,
655  "Missing number of rows");
656  size_type nrows; ist >> nrows;
657  bgeot::get_token(ist, tmp);
658  GMM_ASSERT1(bgeot::casecmp(tmp, "NCOLS")==0,
659  "Missing number of columns");
660  size_type ncols; ist >> ncols;
661  bgeot::get_token(ist, tmp);
662  GMM_ASSERT1(bgeot::casecmp(tmp, "NNZ")==0,
663  "Missing number of nonzero elements");
664  size_type nnz; ist >> nnz;
665  gmm::clear(EE); gmm::resize(EE, nrows, ncols);
666  for (size_type i = 0; i < nrows; ++i) {
667  bgeot::get_token(ist, tmp);
668  GMM_ASSERT1(bgeot::casecmp(tmp, "ROW")==0,
669  "Missing some rows");
670  size_type nnz_row; ist >> nnz_row;
671  for (size_type j=0; j < nnz_row; ++j) {
672  size_type ind; ist >> ind;
673  scalar_type val; ist >> val;
674  EE(i, ind) = val; // can be optimized using a csc matrix
675  }
676  }
677  E_ = EXTENSION_MATRIX(nrows, ncols);
678  gmm::copy(EE, E_);
679  use_reduction = true;
680  ist >> bgeot::skip("END");
681  ist >> bgeot::skip("EXTENSION_MATRIX");
682  }
683  else if (tmp.size())
684  GMM_ASSERT1(false, "Syntax error in file at token '"
685  << tmp << "' [pos=" << std::streamoff(ist.tellg())
686  << "]");
687  } else if (bgeot::casecmp(tmp, "QDIM")==0) {
688  GMM_ASSERT1(!dof_read, "Can't change QDIM after dof enumeration");
689  bgeot::get_token(ist, tmp);
690  int q = atoi(tmp.c_str());
691  GMM_ASSERT1(q > 0 && q <= 250, "invalid qdim: " << q);
692  set_qdim(dim_type(q));
693  } else if (tmp.size()) {
694  GMM_ASSERT1(false, "Unexpected token '" << tmp <<
695  "' [pos=" << std::streamoff(ist.tellg()) << "]");
696  } else if (ist.eof()) {
697  GMM_ASSERT1(false, "Unexpected end of stream "
698  << "(missing BEGIN MESH_FEM/END MESH_FEM ?)");
699  }
700  }
701  }
702 
703  void mesh_fem::read_from_file(const std::string &name) {
704  std::ifstream o(name.c_str());
705  GMM_ASSERT1(o, "Mesh_fem file '" << name << "' does not exist");
706  read_from_file(o);
707  }
708 
709  template<typename VECT> static void
710  write_col(std::ostream &ost, const VECT &v) {
711  typename gmm::linalg_traits<VECT>::const_iterator it = v.begin();
712  ost << gmm::nnz(v);
713  for (; it != v.end(); ++it)
714  ost << " " << it.index() << " " << *it;
715  ost << "\n";
716  }
717 
718  void mesh_fem::write_reduction_matrices_to_file(std::ostream &ost) const {
719  if (use_reduction) {
720  ost.precision(16);
721  ost << " BEGIN REDUCTION_MATRIX " << '\n';
722  ost << " NROWS " << gmm::mat_nrows(R_) << '\n';
723  ost << " NCOLS " << gmm::mat_ncols(R_) << '\n';
724  ost << " NNZ " << gmm::nnz(R_) << '\n';
725  for (size_type i = 0; i < gmm::mat_ncols(R_); ++i) {
726  ost << " COL ";
727  write_col(ost, gmm::mat_col(R_, i));
728  }
729  ost << " END REDUCTION_MATRIX " << '\n';
730  ost << " BEGIN EXTENSION_MATRIX " << '\n';
731  ost << " NROWS " << gmm::mat_nrows(E_) << '\n';
732  ost << " NCOLS " << gmm::mat_ncols(E_) << '\n';
733  ost << " NNZ " << gmm::nnz(E_) << '\n';
734  for (size_type i = 0; i < gmm::mat_nrows(E_); ++i) {
735  ost << " ROW ";
736  write_col(ost, gmm::mat_row(E_, i));
737  }
738  ost << " END EXTENSION_MATRIX " << '\n';
739  }
740  }
741 
742  void mesh_fem::write_basic_to_file(std::ostream &ost) const {
743  ost << "QDIM " << size_type(get_qdim()) << '\n';
744  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
745  ost << " CONVEX " << cv;
746  ost << " \'" << name_of_fem(fem_of_element(cv));
747  ost << "\'\n";
748  }
749 
750  if (!dof_partition.empty()) {
751  ost << " BEGIN DOF_PARTITION\n";
752  unsigned i = 0;
753  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
754  ost << " " << get_dof_partition(cv); if ((++i % 20) == 0) ost << "\n";
755  }
756  ost << "\n";
757  ost << " END DOF_PARTITION\n";
758  }
759 
760  ost << " BEGIN DOF_ENUMERATION " << '\n';
761  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
762  ost << " " << cv << ": ";
763  ind_dof_ct::const_iterator it = ind_basic_dof_of_element(cv).begin();
764  while (it != ind_basic_dof_of_element(cv).end()) {
765  ost << " " << *it;
766  // skip repeated dofs for "pseudo" vector elements
767  for (size_type i=0;
768  i < size_type(get_qdim())/fem_of_element(cv)->target_dim();
769  ++i) ++it;
770  }
771  ost << '\n';
772  }
773  ost << " END DOF_ENUMERATION " << '\n';
774  }
775 
776  void mesh_fem::write_to_file(std::ostream &ost) const {
777  context_check();
778  gmm::stream_standard_locale sl(ost);
779  ost << '\n' << "BEGIN MESH_FEM" << '\n' << '\n';
780  write_basic_to_file(ost);
781  write_reduction_matrices_to_file(ost);
782  ost << "END MESH_FEM" << '\n';
783  }
784 
785  void mesh_fem::write_to_file(const std::string &name, bool with_mesh) const {
786  std::ofstream o(name.c_str());
787  GMM_ASSERT1(o, "impossible to open file '" << name << "'");
788  o << "% GETFEM MESH_FEM FILE " << '\n';
789  o << "% GETFEM VERSION " << GETFEM_VERSION << '\n' << '\n' << '\n';
790  if (with_mesh) linked_mesh().write_to_file(o);
791  write_to_file(o);
792  }
793 
794  struct mf__key_ : public context_dependencies {
795  const mesh *pmsh;
796  dim_type order, qdim;
797  bool complete;
798  mf__key_(const mesh &msh, dim_type o, dim_type q, bool complete_)
799  : pmsh(&msh), order(o), qdim(q), complete(complete_)
800  { add_dependency(msh); }
801  bool operator <(const mf__key_ &a) const {
802  if (pmsh < a.pmsh) return true;
803  else if (pmsh > a.pmsh) return false;
804  else if (order < a.order) return true;
805  else if (order > a.order) return false;
806  else if (qdim < a.qdim) return true;
807  else if (qdim > a.qdim) return false;
808  else if (complete < a.complete) return true;
809  return false;
810  }
811  void update_from_context() const {}
812  mf__key_(const mf__key_ &mfk) : context_dependencies( ) {
813  pmsh = mfk.pmsh;
814  order = mfk.order;
815  qdim = mfk.qdim;
816  complete = mfk.complete;
817  add_dependency(*pmsh);
818  }
819  private :
820  mf__key_& operator=(const mf__key_ &mfk);
821  };
822 
823 
824  class classical_mesh_fem_pool {
825 
826  typedef std::shared_ptr<const mesh_fem> pmesh_fem;
827  typedef std::map<mf__key_, pmesh_fem> mesh_fem_tab;
828 
829  mesh_fem_tab mfs;
830 
831  public :
832 
833  const mesh_fem &operator()(const mesh &msh, dim_type o, dim_type qdim,
834  bool complete=false) {
835  mesh_fem_tab::iterator itt = mfs.begin(), itn = mfs.begin();
836  if (itn != mfs.end()) itn++;
837  while (itt != mfs.end()) {
838  if (!(itt->first.is_context_valid()))
839  { mfs.erase(itt); }
840  itt=itn;
841  if (itn != mfs.end()) itn++;
842  }
843 
844  mf__key_ key(msh, o, qdim, complete);
845  mesh_fem_tab::iterator it = mfs.find(key);
846  assert(it == mfs.end() || it->second->is_context_valid());
847 
848  if (it == mfs.end()) {
849  auto p_torus_mesh = dynamic_cast<const getfem::torus_mesh *>(&msh);
850  auto pmf = (p_torus_mesh) ? std::make_shared<torus_mesh_fem>(*p_torus_mesh, qdim)
851  : std::make_shared<mesh_fem>(msh, qdim);
852  pmf->set_classical_finite_element(o);
853  pmf->set_auto_add(o, false);
854  return *(mfs[key] = pmf);
855  }
856  else return *(it->second);
857  }
858 
859  };
860 
861  const mesh_fem &classical_mesh_fem(const mesh &msh,
862  dim_type order, dim_type qdim,
863  bool complete) {
864  classical_mesh_fem_pool &pool
866  return pool(msh, order, qdim, complete);
867  }
868 
869  struct dummy_mesh_fem_ {
870  mesh_fem mf;
871  dummy_mesh_fem_() : mf(dummy_mesh()) {}
872  };
873 
876 
877 
878  void vectorize_base_tensor(const base_tensor &t, base_matrix &vt,
879  size_type ndof, size_type qdim, size_type N) {
880  GMM_ASSERT1(qdim == N || qdim == 1, "mixed intrinsic vector and "
881  "tensorised fem is not supported");
882  gmm::resize(vt, ndof, N);
883  ndof = (ndof*qdim)/N;
884 
885  if (qdim == N) {
886  gmm::copy(t.as_vector(), vt.as_vector());
887  } else if (qdim == 1) {
888  gmm::clear(vt);
889  base_tensor::const_iterator it = t.begin();
890  for (size_type i = 0; i < ndof; ++i, ++it)
891  for (size_type j = 0; j < N; ++j) vt(i*N+j, j) = *it;
892  }
893  }
894 
895  void vectorize_grad_base_tensor(const base_tensor &t, base_tensor &vt,
896  size_type ndof, size_type qdim, size_type Q) {
897  size_type N = t.sizes()[2];
898  GMM_ASSERT1(qdim == Q || qdim == 1, "mixed intrinsic vector and "
899  "tensorised fem is not supported");
900  vt.adjust_sizes(bgeot::multi_index(ndof, Q, N));
901  ndof = (ndof*qdim)/Q;
902 
903  if (qdim == Q) {
904  gmm::copy(t.as_vector(), vt.as_vector());
905  } else if (qdim == 1) {
906  gmm::clear(vt.as_vector());
907  base_tensor::const_iterator it = t.begin();
908  for (size_type k = 0; k < N; ++k)
909  for (size_type i = 0; i < ndof; ++i, ++it)
910  for (size_type j = 0; j < Q; ++j) vt(i*Q+j, j, k) = *it;
911  }
912  }
913 
914 
915 
916 } /* end of namespace getfem. */
917 
918 
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.
void clear()
erase the mesh
ind_pt_face_ct ind_points_of_face_of_convex(size_type ic, short_type f) const
Return a container of the (global) point number for face f or convex ic.
void neighbors_of_convex(size_type ic, short_type f, ind_set &s) const
Return in s a list of neighbors of a given convex face.
const ind_cv_ct & convex_to_point(size_type ip) const
Return a container of the convexes attached to point ip.
size_type first_convex_of_point(size_type ip) const
Convex ID of the first convex attached to the point ip.
pconvex_structure structure_of_convex(size_type ic) const
Return the pconvex_structure of the convex ic.
size_type ind_in_convex_of_point(size_type ic, size_type ip) const
Find the local index of the point of global index ip with respect to the convex cv.
const ind_set & ind_points_of_convex(size_type ic) const
Return a container to the list of points attached to convex ic.
size_type nb_allocated_convex() const
The number of convex indexes from 0 to the index of the last convex.
Dynamic Array.
Definition: dal_basic.h:196
static T & instance()
Instance from the current thread.
Deal with interdependencies of objects.
bool context_check() const
return true if update_from_context was called
virtual_fem implementation as a vector of generic functions.
Definition: getfem_fem.h:505
Describe a finite element method linked to a mesh.
virtual ind_dof_ct ind_basic_dof_of_element(size_type cv) const
Give an array of the dof numbers a of convex.
void set_classical_discontinuous_finite_element(size_type cv, dim_type fem_degree, scalar_type alpha=0, bool complete=false)
Similar to set_classical_finite_element, but uses discontinuous lagrange elements.
void set_auto_add(dim_type K, bool disc=false, scalar_type alpha=scalar_type(0), bool complete=false)
Set the degree of the fem for automatic addition of element option.
virtual void get_global_dof_index(std::vector< size_type > &ind) const
Give an array that contains the global dof indices corresponding to the mesh_fem dofs or size_type(-1...
void reduce_to_basic_dof(const dal::bit_vector &kept_basic_dof)
Allows to set the reduction and the extension matrices in order to keep only a certain number of dof.
virtual void enumerate_dof() const
Renumber the degrees of freedom.
virtual size_type first_convex_of_basic_dof(size_type d) const
Shortcut for convex_to_dof(d)[0].
virtual dim_type get_qdim() const
Return the Q dimension.
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
virtual dim_type basic_dof_qdim(size_type d) const
Return the dof component number (0<= x <Qdim)
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
void update_from_context() const
this function has to be defined and should update the object when the context is modified.
virtual void read_from_file(std::istream &ist)
Read the mesh_fem from a stream.
void set_finite_element(size_type cv, pfem pf)
Set the finite element method of a convex.
virtual void write_to_file(std::ostream &ost) const
Write the mesh_fem to a stream.
void set_reduction_matrices(const MATR &RR, const MATE &EE)
Allows to set the reduction and the extension matrices.
virtual size_type nb_basic_dof() const
Return the total number of basic degrees of freedom (before the optional reduction).
virtual dal::bit_vector basic_dof_on_region(const mesh_region &b) const
Get a list of basic dof lying on a given mesh_region.
virtual void set_qdim(dim_type q)
Change the Q dimension.
virtual base_node point_of_basic_dof(size_type cv, size_type i) const
Return the geometrical location of a degree of freedom.
void set_classical_finite_element(size_type cv, dim_type fem_degree, bool complete=false)
Set a classical (i.e.
virtual pfem fem_of_element(size_type cv) const
Return the basic fem associated with an element (if no fem is associated, the function will crash!...
const dal::bit_vector & convex_index() const
Get the set of convexes where a finite element has been assigned.
dal::bit_vector dof_on_region(const mesh_region &b) const
Get a list of dof lying on a given mesh_region.
virtual size_type nb_basic_dof_of_element(size_type cv) const
Return the number of degrees of freedom attached to a given convex.
bool is_reduced() const
Return true if a reduction matrix is applied to the dofs.
virtual const mesh::ind_cv_ct & convex_to_basic_dof(size_type d) const
Return the list of convexes attached to the specified dof.
"iterator" class for regions.
structure used to hold a set of convexes and/or convex faces.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:99
void write_to_file(const std::string &name) const
Write the mesh to a file.
Definition: getfem_mesh.cc:709
gmm::uint64_type convex_version_number(size_type ic) const
return the version number of the convex ic.
Definition: getfem_mesh.h:215
Copy an original 2D mesh to become a torus mesh with radial dimension.
Definition: getfem_torus.h:84
A simple singleton implementation.
Define the getfem::mesh_fem class.
Provides mesh and mesh fem of torus.
size_type nnz(const L &l)
count the number of non-zero entries of a vector or matrix.
Definition: gmm_blas.h:69
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:978
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
int dof_description_compare(pdof_description a, pdof_description b)
Gives a total order on the dof description compatible with the identification.
Definition: getfem_fem.cc:607
bool dof_linkable(pdof_description)
Says if the dof is linkable.
Definition: getfem_fem.cc:616
pdof_description global_dof(dim_type d)
Description of a global dof, i.e.
Definition: getfem_fem.cc:543
dof_description * pdof_description
Type representing a pointer on a dof_description.
Definition: getfem_fem.h:160
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:244
pfem fem_descriptor(const std::string &name)
get a fem descriptor from its string name.
Definition: getfem_fem.cc:4660
pfem classical_discontinuous_fem(bgeot::pgeometric_trans pg, short_type k, scalar_type alpha=0, bool complete=false)
Give a pointer on the structures describing the classical polynomial discontinuous fem of degree k on...
Definition: getfem_fem.cc:4572
pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k, bool complete=false)
Give a pointer on the structures describing the classical polynomial fem of degree k on a given conve...
Definition: getfem_fem.cc:4567
std::string name_of_fem(pfem p)
get the string name of a fem descriptor.
Definition: getfem_fem.cc:4669
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:73
int get_token(std::istream &ist, std::string &st, bool ignore_cr, bool to_up, bool read_un_pm, int *linenb)
Very simple lexical analysis of general interest for reading small languages with a "MATLAB like" syn...
Definition: bgeot_ftool.cc:50
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
pconvex_structure basic_structure(pconvex_structure cv)
Original structure (if concerned)
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
GEneric Tool for Finite Element Methods.
const mesh_fem & dummy_mesh_fem()
Dummy mesh_fem for default parameter of functions.
const mesh_fem & classical_mesh_fem(const mesh &mesh, dim_type degree, dim_type qdim=1, bool complete=false)
Gives the descriptor of a classical finite element method of degree K on mesh.
store a point and the associated index for the kdtree.
Definition: bgeot_kdtree.h:59