GetFEM++  5.3
getfem_mesh_fem.cc
1 /*===========================================================================
2 
3  Copyright (C) 1999-2017 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 (size_type i = 0; i < linked_mesh().nb_points_of_convex(cv); ++i) {
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]);
368  }
369  }
370  elt_car_sizes[cv] = gmm::vect_dist2_sqr(bmin, bmax);
371  }
372  }
373 
374  dal::bit_vector cv_done;
375 
376  for (dal::bv_visitor cv(linked_mesh().convex_index());
377  !cv.finished(); ++cv) { // Loop on elements
378  if (!fe_convex.is_in(cv)) continue;
379  pfem pf = fem_of_element(cv);
380  if (pf != first_pf) is_uniform_ = false;
381  if (pf->target_dim() > 1) is_uniformly_vectorized_ = false;
382  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
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;
387  size_type nbd = pf->nb_dof(cv);
388  pdof_description andof = global_dof(pf->dim());
389  itab.resize(nbd);
390 
391  for (size_type i = 0; i < nbd; i++) { // Loop on dofs
392  fd.pnd = pf->dof_types()[i];
393  fd.part = get_dof_partition(cv);
394 
395  if (fd.pnd == andof) { // If the dof is a global one
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;
401  }
402  itab[i] = ind_global_dof[num];
403  } else if (!dof_linkable(fd.pnd)) { // If the dof is not linkable
404  itab[i] = nbdof;
405  nbdof += Qdim / pf->target_dim();
406  } else { // For a standard linkable dof
407  pgp->transform(linked_mesh().points_of_convex(cv), i, P);
408  size_type idof = nbdof;
409 
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]) {
413  fd.ind_node=ipt.i;
414  auto it = dof_sorts[cv].find(fd);
415  if (it != dof_sorts[cv].end()) idof = it->second;
416  }
417  }
418 
419  if (idof == nbdof) {
420  nbdof += Qdim / pf->target_dim();
421 
422  linked_mesh().neighbours_of_convex(cv, pf->faces_of_dof(cv, i), s);
423  for (size_type ncv : s) { // For each unscanned neighbour
424  if (!cv_done[ncv] && fe_convex.is_in(ncv)) { // add the dof
425 
426  fd.ind_node = size_type(-1);
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])
430  fd.ind_node=ipt.i;
431  }
432  if (fd.ind_node == size_type(-1))
433  fd.ind_node = dof_nodes[ncv].add_point(P);
434  dof_sorts[ncv][fd] = idof;
435  }
436  }
437  }
438  itab[i] = idof;
439  }
440  }
441  cv_done.add(cv);
442  dof_sorts[cv].clear(); dof_nodes[cv].clear();
443  dof_structure.add_convex_noverif(pf->structure(cv), itab.begin(), cv);
444  }
445 
446  dof_enumeration_made = true;
447  nb_total_dof = nbdof;
448  }
449 
450  void mesh_fem::reduce_to_basic_dof(const dal::bit_vector &kept_dof) {
451  gmm::row_matrix<gmm::rsvector<scalar_type> >
452  RR(kept_dof.card(), nb_basic_dof());
453  size_type j = 0;
454  for (dal::bv_visitor i(kept_dof); !i.finished(); ++i, ++j)
455  RR(j, i) = scalar_type(1);
456  set_reduction_matrices(RR, gmm::transposed(RR));
457  }
458 
459  void mesh_fem::reduce_to_basic_dof(const std::set<size_type> &kept_dof) {
460  gmm::row_matrix<gmm::rsvector<scalar_type> >
461  RR(kept_dof.size(), nb_basic_dof());
462  size_type j = 0;
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);
466  set_reduction_matrices(RR, gmm::transposed(RR));
467  }
468 
469  void mesh_fem::clear() {
470  fe_convex.clear();
471  dof_enumeration_made = false;
472  is_uniform_ = true;
473  touch(); v_num = act_counter();
474  dof_structure.clear();
475  use_reduction = false;
476  R_ = REDUCTION_MATRIX();
477  E_ = EXTENSION_MATRIX();
478  }
479 
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;
483  is_uniform_ = false;
484  auto_add_elt_pf = 0;
485  auto_add_elt_K = dim_type(-1);
486  Qdim = Q;
487  mi.resize(1); mi[0] = Q;
488  linked_mesh_ = &me;
489  use_reduction = false;
490  this->add_dependency(me);
491  v_num = v_num_update = act_counter();
492  }
493 
494  void mesh_fem::copy_from(const mesh_fem &mf) {
495  clear_dependencies();
496  linked_mesh_ = 0;
497  init_with_mesh(*mf.linked_mesh_, mf.get_qdim());
498 
499  f_elems = mf.f_elems;
500  fe_convex = mf.fe_convex;
501  R_ = mf.R_;
502  E_ = mf.E_;
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;
512  mi = mf.mi;
513  dof_partition = mf.dof_partition;
514  v_num_update = mf.v_num_update;
515  v_num = mf.v_num;
516  use_reduction = mf.use_reduction;
517  }
518 
519  mesh_fem::mesh_fem(const mesh_fem &mf) : context_dependencies() {
520  linked_mesh_ = 0; copy_from(mf);
521  }
522 
523  mesh_fem &mesh_fem::operator=(const mesh_fem &mf) {
524  copy_from(mf);
525  return *this;
526  }
527 
528  mesh_fem::mesh_fem(const mesh &me, dim_type Q)
529  { linked_mesh_ = 0; init_with_mesh(me, Q); }
530 
531  mesh_fem::mesh_fem() {
532  linked_mesh_ = 0;
533  dof_enumeration_made = false;
534  is_uniform_ = true;
535  set_qdim(1);
536  }
537 
538  mesh_fem::~mesh_fem() { }
539 
540  void mesh_fem::read_from_file(std::istream &ist) {
541  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
542  gmm::stream_standard_locale sl(ist);
543  dal::bit_vector npt;
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;
548  ist.precision(16);
549  clear();
550  ist.seekg(0);ist.clear();
551  bgeot::read_until(ist, "BEGIN MESH_FEM");
552 
553  while (true) {
554  ist >> std::ws; bgeot::get_token(ist, tmp);
555  if (bgeot::casecmp(tmp, "END")==0) {
556  break;
557  } else if (bgeot::casecmp(tmp, "CONVEX")==0) {
558  bgeot::get_token(ist, tmp);
559  size_type ic = atoi(tmp.c_str());
560  GMM_ASSERT1(linked_mesh().convex_index().is_in(ic), "Convex " << ic <<
561  " does not exist, are you sure "
562  "that the mesh attached to this object is right one ?");
563 
564  int rgt = bgeot::get_token(ist, tmp);
565  if (rgt != 3) { // for backward compatibility
566  char c; ist.get(c);
567  while (!isspace(c)) { tmp.push_back(c); ist.get(c); }
568  }
570  GMM_ASSERT1(fem, "could not create the FEM '" << tmp << "'");
571  set_finite_element(ic, fem);
572  } else if (bgeot::casecmp(tmp, "BEGIN")==0) {
573  bgeot::get_token(ist, tmp);
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));
577  }
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;
582  is_uniform_ = true;
583  size_type nbdof_unif = size_type(-1);
584  touch(); v_num = act_counter();
585  while (true) {
586  bgeot::get_token(ist, tmp);
587  if (bgeot::casecmp(tmp, "END")==0) {
588  break;
589  }
590  bgeot::get_token(ist, tmp2);
591 
592  size_type ic = atoi(tmp.c_str());
593  std::vector<size_type> tab;
594  if (convex_index().is_in(ic) && tmp.size() &&
595  isdigit(tmp[0]) && tmp2 == ":") {
597  if (nbdof_unif == size_type(-1))
598  nbdof_unif = nbd;
599  else if (nbdof_unif != nbd)
600  is_uniform_ = false;
601  tab.resize(nb_basic_dof_of_element(ic));
602  for (size_type i=0; i < fem_of_element(ic)->nb_dof(ic);
603  i++) {
604  ist >> tab[i];
605  for (size_type q=0; q < size_type(get_qdim())
606  / fem_of_element(ic)->target_dim(); ++q)
607  doflst.add(tab[i]+q);
608  }
609  dof_structure.add_convex_noverif
610  (fem_of_element(ic)->structure(ic), tab.begin(), ic);
611  } else GMM_ASSERT1(false, "Missing convex or wrong number "
612  << "in dof enumeration: '"
613  << tmp << "' [pos="
614  << std::streamoff(ist.tellg())<<"]");
615  /*bgeot::get_token(ist, tmp);
616  cerr << " tok: '" << tmp << "'\n";*/
617  }
618  dof_read = true;
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) {
624  bgeot::get_token(ist, tmp);
625  GMM_ASSERT1(bgeot::casecmp(tmp, "NROWS")==0,
626  "Missing number of rows");
627  size_type nrows; ist >> nrows;
628  bgeot::get_token(ist, tmp);
629  GMM_ASSERT1(bgeot::casecmp(tmp, "NCOLS")==0,
630  "Missing number of columns");
631  size_type ncols; ist >> ncols;
632  bgeot::get_token(ist, tmp);
633  GMM_ASSERT1(bgeot::casecmp(tmp, "NNZ")==0,
634  "Missing number of nonzero elements");
635  size_type nnz; ist >> nnz;
636  gmm::clear(RR); gmm::resize(RR, nrows, ncols);
637  for (size_type i = 0; i < ncols; ++i) {
638  bgeot::get_token(ist, tmp);
639  GMM_ASSERT1(bgeot::casecmp(tmp, "COL")==0,
640  "Missing some columns");
641  size_type nnz_col; ist >> nnz_col;
642  for (size_type j=0; j<nnz_col; ++j) {
643  size_type ind; ist >> ind;
644  scalar_type val; ist >> val;
645  RR(ind, i) = val; // can be optimized using a csc matrix
646  }
647  }
648  R_ = REDUCTION_MATRIX(nrows, ncols);
649  gmm::copy(RR, R_);
650  use_reduction = true;
651  ist >> bgeot::skip("END");
652  ist >> bgeot::skip("REDUCTION_MATRIX");
653  } else if (bgeot::casecmp(tmp, "EXTENSION_MATRIX")==0) {
654  bgeot::get_token(ist, tmp);
655  GMM_ASSERT1(bgeot::casecmp(tmp, "NROWS")==0,
656  "Missing number of rows");
657  size_type nrows; ist >> nrows;
658  bgeot::get_token(ist, tmp);
659  GMM_ASSERT1(bgeot::casecmp(tmp, "NCOLS")==0,
660  "Missing number of columns");
661  size_type ncols; ist >> ncols;
662  bgeot::get_token(ist, tmp);
663  GMM_ASSERT1(bgeot::casecmp(tmp, "NNZ")==0,
664  "Missing number of nonzero elements");
665  size_type nnz; ist >> nnz;
666  gmm::clear(EE); gmm::resize(EE, nrows, ncols);
667  for (size_type i = 0; i < nrows; ++i) {
668  bgeot::get_token(ist, tmp);
669  GMM_ASSERT1(bgeot::casecmp(tmp, "ROW")==0,
670  "Missing some rows");
671  size_type nnz_row; ist >> nnz_row;
672  for (size_type j=0; j < nnz_row; ++j) {
673  size_type ind; ist >> ind;
674  scalar_type val; ist >> val;
675  EE(i, ind) = val; // can be optimized using a csc matrix
676  }
677  }
678  E_ = EXTENSION_MATRIX(nrows, ncols);
679  gmm::copy(EE, E_);
680  use_reduction = true;
681  ist >> bgeot::skip("END");
682  ist >> bgeot::skip("EXTENSION_MATRIX");
683  }
684  else if (tmp.size())
685  GMM_ASSERT1(false, "Syntax error in file at token '"
686  << tmp << "' [pos=" << std::streamoff(ist.tellg())
687  << "]");
688  } else if (bgeot::casecmp(tmp, "QDIM")==0) {
689  GMM_ASSERT1(!dof_read, "Can't change QDIM after dof enumeration");
690  bgeot::get_token(ist, tmp);
691  int q = atoi(tmp.c_str());
692  GMM_ASSERT1(q > 0 && q <= 250, "invalid qdim: " << q);
693  set_qdim(dim_type(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 ?)");
700  }
701  }
702  }
703 
704  void mesh_fem::read_from_file(const std::string &name) {
705  std::ifstream o(name.c_str());
706  GMM_ASSERT1(o, "Mesh_fem file '" << name << "' does not exist");
707  read_from_file(o);
708  }
709 
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();
713  ost << gmm::nnz(v);
714  for (; it != v.end(); ++it)
715  ost << " " << it.index() << " " << *it;
716  ost << "\n";
717  }
718 
719  void mesh_fem::write_reduction_matrices_to_file(std::ostream &ost) const {
720  if (use_reduction) {
721  ost.precision(16);
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) {
727  ost << " COL ";
728  write_col(ost, gmm::mat_col(R_, i));
729  }
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) {
736  ost << " ROW ";
737  write_col(ost, gmm::mat_row(E_, i));
738  }
739  ost << " END EXTENSION_MATRIX " << '\n';
740  }
741  }
742 
743  void mesh_fem::write_basic_to_file(std::ostream &ost) const {
744  ost << "QDIM " << size_type(get_qdim()) << '\n';
745  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
746  ost << " CONVEX " << cv;
747  ost << " \'" << name_of_fem(fem_of_element(cv));
748  ost << "\'\n";
749  }
750 
751  if (!dof_partition.empty()) {
752  ost << " BEGIN DOF_PARTITION\n";
753  unsigned i = 0;
754  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
755  ost << " " << get_dof_partition(cv); if ((++i % 20) == 0) ost << "\n";
756  }
757  ost << "\n";
758  ost << " END DOF_PARTITION\n";
759  }
760 
761  ost << " BEGIN DOF_ENUMERATION " << '\n';
762  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
763  ost << " " << cv << ": ";
764  ind_dof_ct::const_iterator it = ind_basic_dof_of_element(cv).begin();
765  while (it != ind_basic_dof_of_element(cv).end()) {
766  ost << " " << *it;
767  // skip repeated dofs for "pseudo" vector elements
768  for (size_type i=0;
769  i < size_type(get_qdim())/fem_of_element(cv)->target_dim();
770  ++i) ++it;
771  }
772  ost << '\n';
773  }
774  ost << " END DOF_ENUMERATION " << '\n';
775  }
776 
777  void mesh_fem::write_to_file(std::ostream &ost) const {
778  context_check();
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';
784  }
785 
786  void mesh_fem::write_to_file(const std::string &name, bool with_mesh) const {
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';
791  if (with_mesh) linked_mesh().write_to_file(o);
792  write_to_file(o);
793  }
794 
795  struct mf__key_ : public context_dependencies {
796  const mesh *pmsh;
797  dim_type order, qdim;
798  bool complete;
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;
810  return false;
811  }
812  void update_from_context() const {}
813  mf__key_(const mf__key_ &mfk) : context_dependencies( ) {
814  pmsh = mfk.pmsh;
815  order = mfk.order;
816  qdim = mfk.qdim;
817  complete = mfk.complete;
818  add_dependency(*pmsh);
819  }
820  private :
821  mf__key_& operator=(const mf__key_ &mfk);
822  };
823 
824 
825  class classical_mesh_fem_pool {
826 
827  typedef std::shared_ptr<const mesh_fem> pmesh_fem;
828  typedef std::map<mf__key_, pmesh_fem> mesh_fem_tab;
829 
830  mesh_fem_tab mfs;
831 
832  public :
833 
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()))
840  { mfs.erase(itt); }
841  itt=itn;
842  if (itn != mfs.end()) itn++;
843  }
844 
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());
848 
849  if (it == mfs.end()) {
850  auto p_torus_mesh = dynamic_cast<const getfem::torus_mesh *>(&msh);
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);
856  }
857  else return *(it->second);
858  }
859 
860  };
861 
862  const mesh_fem &classical_mesh_fem(const mesh &msh,
863  dim_type order, dim_type qdim,
864  bool complete) {
865  classical_mesh_fem_pool &pool
867  return pool(msh, order, qdim, complete);
868  }
869 
870  struct dummy_mesh_fem_ {
871  mesh_fem mf;
872  dummy_mesh_fem_() : mf(dummy_mesh()) {}
873  };
874 
877 
878 
879  void vectorize_base_tensor(const base_tensor &t, base_matrix &vt,
880  size_type ndof, size_type qdim, size_type N) {
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;
885  if (qdim == 1) {
886  gmm::clear(vt);
887  base_tensor::const_iterator it = t.begin();
888  for (size_type i = 0; i < ndof; ++i, ++it)
889  for (size_type j = 0; j < N; ++j) vt(i*N+j, j) = *it;
890  } else if (qdim == N) {
891  gmm::copy(t.as_vector(), vt.as_vector());
892  }
893  }
894 
895  void vectorize_grad_base_tensor(const base_tensor &t, base_tensor &vt,
896  size_type ndof, size_type qdim,
897  size_type N) {
898  GMM_ASSERT1(qdim == N || qdim == 1, "mixed intrinsic vector and "
899  "tensorised fem is not supported");
900  vt.adjust_sizes(bgeot::multi_index(ndof, N, N));
901  ndof = (ndof*qdim)/N;
902  if (qdim == 1) {
903  gmm::clear(vt.as_vector());
904  base_tensor::const_iterator it = t.begin();
905  for (size_type k = 0; k < N; ++k)
906  for (size_type i = 0; i < ndof; ++i, ++it)
907  for (size_type j = 0; j < N; ++j) vt(i*N+j, j, k) = *it;
908  } else if (qdim == N) {
909  gmm::copy(t.as_vector(), vt.as_vector());
910  }
911  }
912 
913 
914 
915 } /* end of namespace getfem. */
916 
917 
virtual size_type nb_basic_dof_of_element(size_type cv) const
Return the number of degrees of freedom attached to a given convex.
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
structure used to hold a set of convexes and/or convex faces.
dof_description * pdof_description
Type representing a pointer on a dof_description.
Definition: getfem_fem.h:155
void write_to_file(const std::string &name) const
Write the mesh to a file.
Definition: getfem_mesh.cc:667
short_type nb_points_of_convex(size_type ic) const
Return the number of points of convex ic.
const mesh_fem & dummy_mesh_fem()
Dummy mesh_fem for default parameter of functions.
void set_reduction_matrices(const MATR &RR, const MATE &EE)
Allows to set the reduction and the extension matrices.
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 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...
pfem fem_descriptor(const std::string &name)
get a fem descriptor from its string name.
Definition: getfem_fem.cc:3950
virtual dim_type basic_dof_qdim(size_type d) const
Return the dof component number (0<= x <Qdim)
Define the getfem::mesh_fem class.
Provides mesh and mesh fem of torus.
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! us...
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:95
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:3872
pconvex_structure structure_of_convex(size_type ic) const
Return the pconvex_structure of the convex ic.
dal::bit_vector dof_on_region(const mesh_region &b) const
Get a list of dof lying on a given mesh_region.
virtual_fem implementation as a vector of generic functions.
Definition: getfem_fem.h:500
const ind_cv_ct & convex_to_point(size_type ip) const
Return a container of the convexes attached to point ip.
static T & instance()
Instance from the current thread.
virtual const mesh::ind_cv_ct & convex_to_basic_dof(size_type d) const
Return the list of convexes attached to the specified dof.
virtual void read_from_file(std::istream &ist)
Read the mesh_fem from a stream.
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 langages with a "MATLAB like" synt...
Definition: bgeot_ftool.cc:49
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
virtual size_type nb_basic_dof() const
Return the total number of basic degrees of freedom (before the optional reduction).
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...
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.
void set_finite_element(size_type cv, pfem pf)
Set the finite element method of a convex.
Copy an original 2D mesh to become a torus mesh with radial dimension.
Definition: getfem_torus.h:83
Dynamic Array.
Definition: dal_basic.h:47
virtual dim_type get_qdim() const
Return the Q dimension.
std::string name_of_fem(pfem p)
get the string name of a fem descriptor.
Definition: getfem_fem.cc:3959
A simple singleton implementation.
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.
"iterator" class for regions.
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.
bool is_reduced() const
Return true if a reduction matrix is applied to the dofs.
Deal with interdependencies of objects.
void update_from_context() const
this function has to be defined and should update the object when the context is modified.
GEneric Tool for Finite Element Methods.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:239
bool dof_linkable(pdof_description)
Says if the dof is linkable.
Definition: getfem_fem.cc:594
Describe a finite element method linked to a mesh.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:79
virtual void write_to_file(std::ostream &ost) const
Write the mesh_fem to a stream.
virtual size_type first_convex_of_basic_dof(size_type d) const
Shortcut for convex_to_dof(d)[0].
size_type nb_allocated_convex() const
The number of convex indexes from 0 to the index of the last convex.
size_type first_convex_of_point(size_type ip) const
Convex ID of the first convex attached to the point ip.
pconvex_structure basic_structure(pconvex_structure cv)
Original structure (if concerned)
store a point and the associated index for the kdtree.
Definition: bgeot_kdtree.h:59
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:3867
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 mesh & linked_mesh() const
Return a reference to the underlying mesh.
bool context_check() const
return true if update_from_context was called
const ind_cv_ct & ind_points_of_convex(size_type ic) const
Return a container to the list of points attached to convex ic.
const dal::bit_vector & convex_index() const
Get the set of convexes where a finite element has been assigned.
gmm::uint64_type convex_version_number(size_type ic) const
return the version number of the convex ic.
Definition: getfem_mesh.h:215
void neighbours_of_convex(size_type ic, short_type f, ind_set &s) const
Return in s a list of neighbours of a given convex face.
virtual void set_qdim(dim_type q)
Change the Q dimension.
virtual void enumerate_dof() const
Renumber the degrees of freedom.
pdof_description global_dof(dim_type d)
Description of a global dof, i.e.
Definition: getfem_fem.cc:521
virtual ind_dof_ct ind_basic_dof_of_element(size_type cv) const
Give an array of the dof numbers a of convex.
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
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.
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.
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:585