GetFEM  5.5
getfem_mesh_fem.cc
1 /*===========================================================================
2 
3  Copyright (C) 1999-2026 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, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
21 
22 #include <queue>
23 #include "getfem/dal_singleton.h"
24 #include "getfem/getfem_mesh_fem.h"
25 #include "getfem/getfem_torus.h"
26 
27 namespace getfem {
28 
30  for (dal::bv_visitor cv(fe_convex); !cv.finished(); ++cv) {
31  if (linked_mesh_->convex_index().is_in(cv)) {
32  if (v_num_update < linked_mesh_->convex_version_number(cv)) {
33  if (auto_add_elt_pf != 0)
34  const_cast<mesh_fem *>(this)
35  ->set_finite_element(cv, auto_add_elt_pf);
36  else if (auto_add_elt_K != dim_type(-1)) {
37  if (auto_add_elt_disc)
38  const_cast<mesh_fem *>(this)
40  (cv, auto_add_elt_K, auto_add_elt_alpha,
41  auto_add_elt_complete);
42  else
43  const_cast<mesh_fem *>(this)
44  ->set_classical_finite_element(cv, auto_add_elt_K,
45  auto_add_elt_complete);
46  }
47  else
48  const_cast<mesh_fem *>(this)->set_finite_element(cv, 0);
49  }
50  }
51  else const_cast<mesh_fem *>(this)->set_finite_element(cv, 0);
52  }
53  for (dal::bv_visitor cv(linked_mesh_->convex_index());
54  !cv.finished(); ++cv) {
55  if (!fe_convex.is_in(cv)
56  && v_num_update < linked_mesh_->convex_version_number(cv)) {
57  if (auto_add_elt_pf != 0)
58  const_cast<mesh_fem *>(this)
59  ->set_finite_element(cv, auto_add_elt_pf);
60  else if (auto_add_elt_K != dim_type(-1)) {
61  if (auto_add_elt_disc)
62  const_cast<mesh_fem *>(this)
64  (cv, auto_add_elt_K, auto_add_elt_alpha, auto_add_elt_complete);
65  else
66  const_cast<mesh_fem *>(this)
67  ->set_classical_finite_element(cv, auto_add_elt_K,
68  auto_add_elt_complete);
69  }
70  }
71  }
72  if (!dof_enumeration_made) enumerate_dof();
73  v_num = v_num_update = act_counter();
74  }
75 
76  dal::bit_vector mesh_fem::basic_dof_on_region(const mesh_region &b) const {
77  context_check(); if (!dof_enumeration_made) this->enumerate_dof();
78  dal::bit_vector res;
79  for (getfem::mr_visitor v(b,linked_mesh()); !v.finished(); ++v) {
80  size_type cv = v.cv();
81  if (convex_index().is_in(cv)) {
82  if (v.is_face()) {
83  short_type f = short_type(v.f());
84  size_type nbb =
85  dof_structure.structure_of_convex(cv)->nb_points_of_face(f);
86  for (size_type i = 0; i < nbb; ++i) {
87  size_type n = Qdim/fem_of_element(cv)->target_dim();
88  for (size_type ll = 0; ll < n; ++ll)
89  res.add(dof_structure.ind_points_of_face_of_convex(cv,f)[i]+ll);
90  }
91  } else {
92  size_type nbb =
93  dof_structure.structure_of_convex(cv)->nb_points();
94  for (size_type i = 0; i < nbb; ++i) {
95  size_type n = Qdim/fem_of_element(cv)->target_dim();
96  for (size_type ll = 0; ll < n; ++ll)
97  res.add(dof_structure.ind_points_of_convex(cv)[i]+ll);
98  }
99  }
100  }
101  }
102  return res;
103  }
104 
105  template <typename V>
106  static void add_e_line__(const V &v, dal::bit_vector &r) {
107  typedef typename gmm::linalg_traits<V>::value_type T;
108  typename gmm::linalg_traits<V>::const_iterator it = gmm::vect_begin(v);
109  typename gmm::linalg_traits<V>::const_iterator ite = gmm::vect_end(v);
110  for (; it != ite; ++it) if (*it != T(0)) r.add(it.index());
111  }
112 
113  dal::bit_vector mesh_fem::dof_on_region(const mesh_region &b) const {
114  dal::bit_vector res = basic_dof_on_region(b);
115  if (is_reduced()) {
116  if (nb_dof() == 0) return dal::bit_vector();
117  dal::bit_vector basic = res;
118  res.clear();
119  for (dal::bv_visitor i(basic); !i.finished(); ++i)
120  add_e_line__(gmm::mat_row(E_, i), res);
121  }
122  return res;
123  }
124 
125 
127  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
128  context_check();
129  if (pf == 0) {
130  if (fe_convex.is_in(cv)) {
131  fe_convex.sup(cv);
132  dof_enumeration_made = false;
133  touch(); v_num = act_counter();
134  }
135  }
136  else {
137  GMM_ASSERT1(basic_structure(linked_mesh_->structure_of_convex(cv))
138  == pf->basic_structure(cv),
139  "Incompatibility between fem " << name_of_fem(pf) <<
140  " and mesh element " <<
141  name_of_geometric_trans(linked_mesh_->trans_of_convex(cv)));
142  GMM_ASSERT1((Qdim % pf->target_dim()) == 0 || pf->target_dim() == 1,
143  "Incompatibility between Qdim=" << int(Qdim) <<
144  " and target_dim " << int(pf->target_dim()) << " of " <<
145  name_of_fem(pf));
146 
147 
148  if (cv == f_elems.size()) {
149  f_elems.push_back(pf);
150  fe_convex.add(cv);
151  dof_enumeration_made = false;
152  touch(); v_num = act_counter();
153  } else {
154  if (cv > f_elems.size()) f_elems.resize(cv+1);
155  if (!fe_convex.is_in(cv) || f_elems[cv] != pf) {
156  fe_convex.add(cv);
157  f_elems[cv] = pf;
158  dof_enumeration_made = false;
159  touch(); v_num = act_counter();
160  }
161  }
162  }
163  }
164 
165  void mesh_fem::set_finite_element(const dal::bit_vector &cvs, pfem ppf) {
166  for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv)
167  set_finite_element(cv, ppf);
168  }
169 
172 
174  dim_type fem_degree,
175  bool complete) {
176  pfem pf = getfem::classical_fem(linked_mesh().trans_of_convex(cv),
177  fem_degree, complete);
178  set_finite_element(cv, pf);
179  }
180 
181  void mesh_fem::set_classical_finite_element(const dal::bit_vector &cvs,
182  dim_type fem_degree,
183  bool complete) {
184  for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
185  pfem pf = getfem::classical_fem(linked_mesh().trans_of_convex(cv),
186  fem_degree, complete);
187  set_finite_element(cv, pf);
188  }
189  }
190 
191  void mesh_fem::set_classical_finite_element(dim_type fem_degree,
192  bool complete) {
194  complete);
195  set_auto_add(fem_degree, false);
196  }
197 
199  (size_type cv, dim_type fem_degree, scalar_type alpha, bool complete) {
201  (linked_mesh().trans_of_convex(cv), fem_degree, alpha, complete);
202  set_finite_element(cv, pf);
203  }
204 
206  (const dal::bit_vector &cvs, dim_type fem_degree, scalar_type alpha,
207  bool complete) {
208  for (dal::bv_visitor cv(cvs); !cv.finished(); ++cv) {
210  (linked_mesh().trans_of_convex(cv), fem_degree, alpha, complete);
211  set_finite_element(cv, pf);
212  }
213  }
214 
216  (dim_type fem_degree, scalar_type alpha, bool complete) {
218  (linked_mesh().convex_index(), fem_degree, alpha, complete);
219  set_auto_add(fem_degree, true, alpha);
220  }
221 
223  context_check(); if (!dof_enumeration_made) enumerate_dof();
224  pfem pf = f_elems[cv];
225  return linked_mesh().trans_of_convex(cv)->transform
226  (pf->node_of_dof(cv, i * pf->target_dim() / Qdim),
227  linked_mesh().points_of_convex(cv));
228  }
229 
231  context_check(); if (!dof_enumeration_made) enumerate_dof();
232  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
233  size_type cv = dof_structure.first_convex_of_point(i);
234  if (cv != size_type(-1)) {
235  pfem pf = f_elems[cv];
236  return linked_mesh().trans_of_convex(cv)->transform
237  (pf->node_of_dof(cv, dof_structure.ind_in_convex_of_point(cv, i)),
238  linked_mesh().points_of_convex(cv));
239  }
240  }
241  GMM_ASSERT1(false, "Inexistent dof");
242  }
243 
245  context_check(); if (!dof_enumeration_made) enumerate_dof();
246  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
247  size_type cv = dof_structure.first_convex_of_point(i);
248  if (cv != size_type(-1)) {
249  size_type tdim = f_elems[cv]->target_dim();
250  return dim_type((d-i) / tdim);
251  }
252  }
253  GMM_ASSERT1(false, "Inexistent dof");
254  return 0;
255  }
256 
258  context_check(); if (!dof_enumeration_made) enumerate_dof();
259  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
260  size_type cv = dof_structure.first_convex_of_point(i);
261  if (cv != size_type(-1)) return cv;
262  }
263  return size_type(-1);
264  }
265 
266  const mesh::ind_cv_ct &mesh_fem::convex_to_basic_dof(size_type d) const {
267  context_check(); if (!dof_enumeration_made) enumerate_dof();
268  for (size_type i = d; i != d - Qdim && i != size_type(-1); --i) {
269  size_type cv = dof_structure.first_convex_of_point(i);
270  if (cv != size_type(-1)) return dof_structure.convex_to_point(i);
271  }
272  GMM_ASSERT1(false, "Inexistent dof");
273  }
274 
275  struct fem_dof {
276  size_type ind_node;
277  pdof_description pnd;
278  size_type part;
279  };
280 
281  struct dof_comp_ {
282  bool operator()(const fem_dof& m, const fem_dof& n) const {
283  if (m.ind_node < n.ind_node) return true;
284  if (m.ind_node > n.ind_node) return false;
285  if (m.part == n.part)
286  return dof_description_compare(m.pnd, n.pnd) < 0;
287  else if (m.part < n.part) return true;
288  else /*if (m.part > n.part)*/ return false;
289  }
290  };
291 
292  void mesh_fem::get_global_dof_index(std::vector<size_type> &ind) const {
293  context_check(); if (!dof_enumeration_made) enumerate_dof();
294  ind.resize(nb_total_dof);
295  gmm::fill(ind, size_type(-1));
296  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
297  pfem pf = fem_of_element(cv);
298  for (size_type j=0; j < pf->nb_dof(cv); j++) {
299  size_type gid = pf->index_of_global_dof(cv,j);
300  if (gid != size_type(-1)) {
301  size_type dof = dof_structure.ind_points_of_convex(cv)[j];
302  for (size_type i=0; i < Qdim/pf->target_dim(); ++i)
303  ind[dof+i] = gid;
304  }
305  }
306  }
307  }
308 
309  bool mesh_fem::is_uniform() const {
310  context_check(); if (!dof_enumeration_made) enumerate_dof();
311  return is_uniform_;
312  }
313 
314  bool mesh_fem::is_uniformly_vectorized() const {
315  context_check(); if (!dof_enumeration_made) enumerate_dof();
316  return is_uniformly_vectorized_;
317  }
318 
319  /// Enumeration of dofs
320  void mesh_fem::enumerate_dof() const {
322  is_uniform_ = true;
323  is_uniformly_vectorized_ = (get_qdim() > 1);
324  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
325  context_check();
326  if (fe_convex.card() == 0)
327  { dof_enumeration_made = true; nb_total_dof = 0; return; }
328  pfem first_pf = f_elems[fe_convex.first_true()];
329  if (first_pf && first_pf->is_on_real_element()) is_uniform_ = false;
330  if (first_pf && first_pf->target_dim() > 1) is_uniformly_vectorized_=false;
331 
332  // Dof counter
333  size_type nbdof = 0;
334 
335  // Information stored per element
336  size_type nb_max_cv = linked_mesh().nb_allocated_convex();
337  std::vector<bgeot::kdtree> dof_nodes(nb_max_cv);
338  std::vector<scalar_type> elt_car_sizes(nb_max_cv);
339  std::vector<std::map<fem_dof, size_type, dof_comp_>> dof_sorts(nb_max_cv);
340 
341  // Information for global dof
342  dal::bit_vector encountered_global_dof, processed_elt;
343  dal::dynamic_array<size_type> ind_global_dof;
344 
345  // Auxilliary variables
346  std::vector<size_type> itab;
347  base_node P(linked_mesh().dim());
348  base_node bmin(linked_mesh().dim()), bmax(linked_mesh().dim());
349  fem_dof fd;
350  bgeot::mesh_structure::ind_set s;
351 
352  dof_structure.clear();
353  bgeot::pstored_point_tab pspt_old = 0;
354  bgeot::pgeometric_trans pgt_old = 0;
355  bgeot::pgeotrans_precomp pgp = 0;
356 
357  for (dal::bv_visitor cv(linked_mesh().convex_index());
358  !cv.finished(); ++cv) {
359  if (fe_convex.is_in(cv)) {
360  gmm::copy(linked_mesh().points_of_convex(cv)[0], bmin);
361  gmm::copy(bmin, bmax);
362  for (const base_node &pt : linked_mesh().points_of_convex(cv)) {
363  for (size_type d = 1; d < bmin.size(); ++d) {
364  bmin[d] = std::min(bmin[d], pt[d]);
365  bmax[d] = std::max(bmax[d], pt[d]);
366  }
367  }
368  elt_car_sizes[cv] = gmm::vect_dist2_sqr(bmin, bmax);
369  }
370  }
371 
372  dal::bit_vector cv_done;
373 
374  for (dal::bv_visitor cv(linked_mesh().convex_index());
375  !cv.finished(); ++cv) { // Loop on elements
376  if (!fe_convex.is_in(cv)) continue;
377  pfem pf = fem_of_element(cv);
378  if (pf != first_pf) is_uniform_ = false;
379  if (pf->target_dim() > 1) is_uniformly_vectorized_ = false;
380  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
381  bgeot::pstored_point_tab pspt = pf->node_tab(cv);
382  if (pgt != pgt_old || pspt != pspt_old)
383  pgp = bgeot::geotrans_precomp(pgt, pspt, pf);
384  pgt_old = pgt; pspt_old = pspt;
385  size_type nbd = pf->nb_dof(cv);
386  pdof_description andof = global_dof(pf->dim());
387  itab.resize(nbd);
388 
389  for (size_type i = 0; i < nbd; i++) { // Loop on dofs
390  fd.pnd = pf->dof_types()[i];
391  fd.part = get_dof_partition(cv);
392 
393  if (fd.pnd == andof) { // If the dof is a global one
394  size_type num = pf->index_of_global_dof(cv, i);
395  if (!(encountered_global_dof[num])) {
396  ind_global_dof[num] = nbdof;
397  nbdof += Qdim / pf->target_dim();
398  encountered_global_dof[num] = true;
399  }
400  itab[i] = ind_global_dof[num];
401  } else if (!dof_linkable(fd.pnd)) { // If the dof is not linkable
402  itab[i] = nbdof;
403  nbdof += Qdim / pf->target_dim();
404  } else { // For a standard linkable dof
405  pgp->transform(linked_mesh().points_of_convex(cv), i, P);
406  size_type idof = nbdof;
407 
408  if (dof_nodes[cv].nb_points() > 0) {
409  scalar_type dist = dof_nodes[cv].nearest_neighbor(ipt, P);
410  if (gmm::abs(dist) <= 1e-6*elt_car_sizes[cv]) {
411  fd.ind_node=ipt.i;
412  auto it = dof_sorts[cv].find(fd);
413  if (it != dof_sorts[cv].end()) idof = it->second;
414  }
415  }
416 
417  if (idof == nbdof) {
418  nbdof += Qdim / pf->target_dim();
419 
420  linked_mesh().neighbors_of_convex(cv, pf->faces_of_dof(cv, i), s);
421  for (size_type ncv : s) { // For each unscanned neighbor
422  if (!cv_done[ncv] && fe_convex.is_in(ncv)) { // add the dof
423 
424  fd.ind_node = size_type(-1);
425  if (dof_nodes[ncv].nb_points() > 0) {
426  scalar_type dist = dof_nodes[ncv].nearest_neighbor(ipt, P);
427  if (gmm::abs(dist) <= 1e-6*elt_car_sizes[ncv])
428  fd.ind_node=ipt.i;
429  }
430  if (fd.ind_node == size_type(-1))
431  fd.ind_node = dof_nodes[ncv].add_point(P);
432  dof_sorts[ncv][fd] = idof;
433  }
434  }
435  }
436  itab[i] = idof;
437  }
438  }
439  cv_done.add(cv);
440  dof_sorts[cv].clear(); dof_nodes[cv].clear();
441  dof_structure.add_convex_noverif(pf->structure(cv), itab.begin(), cv);
442  }
443 
444  dof_enumeration_made = true;
445  nb_total_dof = nbdof;
446  }
447 
448  void mesh_fem::reduce_to_basic_dof(const dal::bit_vector &kept_dof) {
449  gmm::row_matrix<gmm::rsvector<scalar_type> >
450  RR(kept_dof.card(), nb_basic_dof());
451  size_type j = 0;
452  for (dal::bv_visitor i(kept_dof); !i.finished(); ++i, ++j)
453  RR(j, i) = scalar_type(1);
454  set_reduction_matrices(RR, gmm::transposed(RR));
455  }
456 
457  void mesh_fem::reduce_to_basic_dof(const std::set<size_type> &kept_dof) {
458  gmm::row_matrix<gmm::rsvector<scalar_type> >
459  RR(kept_dof.size(), nb_basic_dof());
460  size_type j = 0;
461  for (std::set<size_type>::const_iterator it = kept_dof.begin();
462  it != kept_dof.end(); ++it, ++j)
463  RR(j, *it) = scalar_type(1);
464  set_reduction_matrices(RR, gmm::transposed(RR));
465  }
466 
467  void mesh_fem::clear() {
468  fe_convex.clear();
469  dof_enumeration_made = false;
470  is_uniform_ = true;
471  touch(); v_num = act_counter();
472  dof_structure.clear();
473  use_reduction = false;
474  R_ = REDUCTION_MATRIX();
475  E_ = EXTENSION_MATRIX();
476  }
477 
478  void mesh_fem::init_with_mesh(const mesh &me, dim_type Q) {
479  GMM_ASSERT1(linked_mesh_ == 0, "Mesh level set already initialized");
480  dof_enumeration_made = false;
481  is_uniform_ = false;
482  auto_add_elt_pf = 0;
483  auto_add_elt_K = dim_type(-1);
484  Qdim = Q;
485  mi.resize(1); mi[0] = Q;
486  linked_mesh_ = &me;
487  use_reduction = false;
488  this->add_dependency(me);
489  v_num = v_num_update = act_counter();
490  }
491 
492  void mesh_fem::copy_from(const mesh_fem &mf) {
493  clear_dependencies();
494  linked_mesh_ = 0;
495  init_with_mesh(*mf.linked_mesh_, mf.get_qdim());
496 
497  f_elems = mf.f_elems;
498  fe_convex = mf.fe_convex;
499  R_ = mf.R_;
500  E_ = mf.E_;
501  dof_structure = mf.dof_structure;
502  dof_enumeration_made = mf.dof_enumeration_made;
503  is_uniform_ = mf.is_uniform_;
504  nb_total_dof = mf.nb_total_dof;
505  auto_add_elt_pf = mf.auto_add_elt_pf;
506  auto_add_elt_K = mf.auto_add_elt_K;
507  auto_add_elt_disc = mf.auto_add_elt_disc;
508  auto_add_elt_complete = mf.auto_add_elt_complete;
509  auto_add_elt_alpha = mf.auto_add_elt_alpha;
510  mi = mf.mi;
511  dof_partition = mf.dof_partition;
512  v_num_update = mf.v_num_update;
513  v_num = mf.v_num;
514  use_reduction = mf.use_reduction;
515  }
516 
517  mesh_fem::mesh_fem(const mesh_fem &mf) : context_dependencies() {
518  linked_mesh_ = 0; copy_from(mf);
519  }
520 
521  mesh_fem &mesh_fem::operator=(const mesh_fem &mf) {
522  copy_from(mf);
523  return *this;
524  }
525 
526  mesh_fem::mesh_fem(const mesh &me, dim_type Q)
527  { linked_mesh_ = 0; init_with_mesh(me, Q); }
528 
529  mesh_fem::mesh_fem() {
530  linked_mesh_ = 0;
531  dof_enumeration_made = false;
532  is_uniform_ = true;
533  set_qdim(1);
534  }
535 
536  mesh_fem::~mesh_fem() { }
537 
538  void mesh_fem::read_from_file(std::istream &ist) {
539  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_fem");
540  gmm::stream_standard_locale sl(ist);
541  dal::bit_vector npt;
543  std::string tmp("nop"), tmp2("nop"); tmp.clear(); tmp2.clear();
544  bool dof_read = false;
545  gmm::col_matrix< gmm::wsvector<scalar_type> > RR, EE;
546  ist.precision(16);
547  clear();
548  ist.seekg(0);ist.clear();
549  bgeot::read_until(ist, "BEGIN MESH_FEM");
550 
551  while (true) {
552  ist >> std::ws; bgeot::get_token(ist, tmp);
553  if (bgeot::casecmp(tmp, "END")==0) {
554  break;
555  } else if (bgeot::casecmp(tmp, "CONVEX")==0) {
556  bgeot::get_token(ist, tmp);
557  size_type ic = atoi(tmp.c_str());
558  GMM_ASSERT1(linked_mesh().convex_index().is_in(ic), "Convex " << ic <<
559  " does not exist, are you sure "
560  "that the mesh attached to this object is right one ?");
561 
562  int rgt = bgeot::get_token(ist, tmp);
563  if (rgt != 3) { // for backward compatibility
564  char c; ist.get(c);
565  while (!isspace(c)) { tmp.push_back(c); ist.get(c); }
566  }
568  GMM_ASSERT1(fem, "could not create the FEM '" << tmp << "'");
569  set_finite_element(ic, fem);
570  } else if (bgeot::casecmp(tmp, "BEGIN")==0) {
571  bgeot::get_token(ist, tmp);
572  if (bgeot::casecmp(tmp, "DOF_PARTITION") == 0) {
573  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
574  size_type d; ist >> d; set_dof_partition(cv, unsigned(d));
575  }
576  ist >> bgeot::skip("END DOF_PARTITION");
577  } else if (bgeot::casecmp(tmp, "DOF_ENUMERATION") == 0) {
578  dal::bit_vector doflst;
579  dof_structure.clear(); dof_enumeration_made = false;
580  is_uniform_ = true;
581  size_type nbdof_unif = size_type(-1);
582  touch(); v_num = act_counter();
583  while (true) {
584  bgeot::get_token(ist, tmp);
585  if (bgeot::casecmp(tmp, "END")==0) {
586  break;
587  }
588  bgeot::get_token(ist, tmp2);
589 
590  size_type ic = atoi(tmp.c_str());
591  std::vector<size_type> tab;
592  if (convex_index().is_in(ic) && tmp.size() &&
593  isdigit(tmp[0]) && tmp2 == ":") {
595  if (nbdof_unif == size_type(-1))
596  nbdof_unif = nbd;
597  else if (nbdof_unif != nbd)
598  is_uniform_ = false;
599  tab.resize(nb_basic_dof_of_element(ic));
600  for (size_type i=0; i < fem_of_element(ic)->nb_dof(ic);
601  i++) {
602  ist >> tab[i];
603  for (size_type q=0; q < size_type(get_qdim())
604  / fem_of_element(ic)->target_dim(); ++q)
605  doflst.add(tab[i]+q);
606  }
607  dof_structure.add_convex_noverif
608  (fem_of_element(ic)->structure(ic), tab.begin(), ic);
609  } else GMM_ASSERT1(false, "Missing convex or wrong number "
610  << "in dof enumeration: '"
611  << tmp << "' [pos="
612  << std::streamoff(ist.tellg())<<"]");
613  /*bgeot::get_token(ist, tmp);
614  cerr << " tok: '" << tmp << "'\n";*/
615  }
616  dof_read = true;
617  this->dof_enumeration_made = true;
618  touch(); v_num = act_counter();
619  this->nb_total_dof = doflst.card();
620  ist >> bgeot::skip("DOF_ENUMERATION");
621  } else if (bgeot::casecmp(tmp, "REDUCTION_MATRIX")==0) {
622  bgeot::get_token(ist, tmp);
623  GMM_ASSERT1(bgeot::casecmp(tmp, "NROWS")==0,
624  "Missing number of rows");
625  size_type nrows; ist >> nrows;
626  bgeot::get_token(ist, tmp);
627  GMM_ASSERT1(bgeot::casecmp(tmp, "NCOLS")==0,
628  "Missing number of columns");
629  size_type ncols; ist >> ncols;
630  bgeot::get_token(ist, tmp);
631  GMM_ASSERT1(bgeot::casecmp(tmp, "NNZ")==0,
632  "Missing number of nonzero elements");
633  size_type nnz; ist >> nnz;
634  gmm::clear(RR); gmm::resize(RR, nrows, ncols);
635  for (size_type i = 0; i < ncols; ++i) {
636  bgeot::get_token(ist, tmp);
637  GMM_ASSERT1(bgeot::casecmp(tmp, "COL")==0,
638  "Missing some columns");
639  size_type nnz_col; ist >> nnz_col;
640  for (size_type j=0; j<nnz_col; ++j) {
641  size_type ind; ist >> ind;
642  scalar_type val; ist >> val;
643  RR(ind, i) = val; // can be optimized using a csc matrix
644  }
645  }
646  R_ = REDUCTION_MATRIX(nrows, ncols);
647  gmm::copy(RR, R_);
648  use_reduction = true;
649  ist >> bgeot::skip("END");
650  ist >> bgeot::skip("REDUCTION_MATRIX");
651  } else if (bgeot::casecmp(tmp, "EXTENSION_MATRIX")==0) {
652  bgeot::get_token(ist, tmp);
653  GMM_ASSERT1(bgeot::casecmp(tmp, "NROWS")==0,
654  "Missing number of rows");
655  size_type nrows; ist >> nrows;
656  bgeot::get_token(ist, tmp);
657  GMM_ASSERT1(bgeot::casecmp(tmp, "NCOLS")==0,
658  "Missing number of columns");
659  size_type ncols; ist >> ncols;
660  bgeot::get_token(ist, tmp);
661  GMM_ASSERT1(bgeot::casecmp(tmp, "NNZ")==0,
662  "Missing number of nonzero elements");
663  size_type nnz; ist >> nnz;
664  gmm::clear(EE); gmm::resize(EE, nrows, ncols);
665  for (size_type i = 0; i < nrows; ++i) {
666  bgeot::get_token(ist, tmp);
667  GMM_ASSERT1(bgeot::casecmp(tmp, "ROW")==0,
668  "Missing some rows");
669  size_type nnz_row; ist >> nnz_row;
670  for (size_type j=0; j < nnz_row; ++j) {
671  size_type ind; ist >> ind;
672  scalar_type val; ist >> val;
673  EE(i, ind) = val; // can be optimized using a csc matrix
674  }
675  }
676  E_ = EXTENSION_MATRIX(nrows, ncols);
677  gmm::copy(EE, E_);
678  use_reduction = true;
679  ist >> bgeot::skip("END");
680  ist >> bgeot::skip("EXTENSION_MATRIX");
681  }
682  else if (tmp.size())
683  GMM_ASSERT1(false, "Syntax error in file at token '"
684  << tmp << "' [pos=" << std::streamoff(ist.tellg())
685  << "]");
686  } else if (bgeot::casecmp(tmp, "QDIM")==0) {
687  GMM_ASSERT1(!dof_read, "Can't change QDIM after dof enumeration");
688  bgeot::get_token(ist, tmp);
689  int q = atoi(tmp.c_str());
690  GMM_ASSERT1(q > 0 && q <= 250, "invalid qdim: " << q);
691  set_qdim(dim_type(q));
692  } else if (tmp.size()) {
693  GMM_ASSERT1(false, "Unexpected token '" << tmp <<
694  "' [pos=" << std::streamoff(ist.tellg()) << "]");
695  } else if (ist.eof()) {
696  GMM_ASSERT1(false, "Unexpected end of stream "
697  << "(missing BEGIN MESH_FEM/END MESH_FEM ?)");
698  }
699  }
700  }
701 
702  void mesh_fem::read_from_file(const std::string &name) {
703  std::ifstream o(name.c_str());
704  GMM_ASSERT1(o, "Mesh_fem file '" << name << "' does not exist");
705  read_from_file(o);
706  }
707 
708  template<typename VECT> static void
709  write_col(std::ostream &ost, const VECT &v) {
710  typename gmm::linalg_traits<VECT>::const_iterator it = v.begin();
711  ost << gmm::nnz(v);
712  for (; it != v.end(); ++it)
713  ost << " " << it.index() << " " << *it;
714  ost << "\n";
715  }
716 
717  void mesh_fem::write_reduction_matrices_to_file(std::ostream &ost) const {
718  if (use_reduction) {
719  ost.precision(16);
720  ost << " BEGIN REDUCTION_MATRIX " << '\n';
721  ost << " NROWS " << gmm::mat_nrows(R_) << '\n';
722  ost << " NCOLS " << gmm::mat_ncols(R_) << '\n';
723  ost << " NNZ " << gmm::nnz(R_) << '\n';
724  for (size_type i = 0; i < gmm::mat_ncols(R_); ++i) {
725  ost << " COL ";
726  write_col(ost, gmm::mat_col(R_, i));
727  }
728  ost << " END REDUCTION_MATRIX " << '\n';
729  ost << " BEGIN EXTENSION_MATRIX " << '\n';
730  ost << " NROWS " << gmm::mat_nrows(E_) << '\n';
731  ost << " NCOLS " << gmm::mat_ncols(E_) << '\n';
732  ost << " NNZ " << gmm::nnz(E_) << '\n';
733  for (size_type i = 0; i < gmm::mat_nrows(E_); ++i) {
734  ost << " ROW ";
735  write_col(ost, gmm::mat_row(E_, i));
736  }
737  ost << " END EXTENSION_MATRIX " << '\n';
738  }
739  }
740 
741  void mesh_fem::write_basic_to_file(std::ostream &ost) const {
742  ost << "QDIM " << size_type(get_qdim()) << '\n';
743  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
744  ost << " CONVEX " << cv;
745  ost << " \'" << name_of_fem(fem_of_element(cv));
746  ost << "\'\n";
747  }
748 
749  if (!dof_partition.empty()) {
750  ost << " BEGIN DOF_PARTITION\n";
751  unsigned i = 0;
752  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
753  ost << " " << get_dof_partition(cv); if ((++i % 20) == 0) ost << "\n";
754  }
755  ost << "\n";
756  ost << " END DOF_PARTITION\n";
757  }
758 
759  ost << " BEGIN DOF_ENUMERATION " << '\n';
760  for (dal::bv_visitor cv(convex_index()); !cv.finished(); ++cv) {
761  ost << " " << cv << ": ";
762  ind_dof_ct::const_iterator it = ind_basic_dof_of_element(cv).begin();
763  while (it != ind_basic_dof_of_element(cv).end()) {
764  ost << " " << *it;
765  // skip repeated dofs for "pseudo" vector elements
766  for (size_type i=0;
767  i < size_type(get_qdim())/fem_of_element(cv)->target_dim();
768  ++i) ++it;
769  }
770  ost << '\n';
771  }
772  ost << " END DOF_ENUMERATION " << '\n';
773  }
774 
775  void mesh_fem::write_to_file(std::ostream &ost) const {
776  context_check();
777  gmm::stream_standard_locale sl(ost);
778  ost << '\n' << "BEGIN MESH_FEM" << '\n' << '\n';
779  write_basic_to_file(ost);
780  write_reduction_matrices_to_file(ost);
781  ost << "END MESH_FEM" << '\n';
782  }
783 
784  void mesh_fem::write_to_file(const std::string &name, bool with_mesh) const {
785  std::ofstream o(name.c_str());
786  GMM_ASSERT1(o, "impossible to open file '" << name << "'");
787  o << "% GETFEM MESH_FEM FILE " << '\n';
788  o << "% GETFEM VERSION " << GETFEM_VERSION << '\n' << '\n' << '\n';
789  if (with_mesh) linked_mesh().write_to_file(o);
790  write_to_file(o);
791  }
792 
793  struct mf__key_ : public context_dependencies {
794  const mesh *pmsh;
795  dim_type order, qdim;
796  bool complete;
797  mf__key_(const mesh &msh, dim_type o, dim_type q, bool complete_)
798  : pmsh(&msh), order(o), qdim(q), complete(complete_)
799  { add_dependency(msh); }
800  bool operator <(const mf__key_ &a) const {
801  if (pmsh < a.pmsh) return true;
802  else if (pmsh > a.pmsh) return false;
803  else if (order < a.order) return true;
804  else if (order > a.order) return false;
805  else if (qdim < a.qdim) return true;
806  else if (qdim > a.qdim) return false;
807  else if (complete < a.complete) return true;
808  return false;
809  }
810  void update_from_context() const {}
811  mf__key_(const mf__key_ &mfk) : context_dependencies( ) {
812  pmsh = mfk.pmsh;
813  order = mfk.order;
814  qdim = mfk.qdim;
815  complete = mfk.complete;
816  add_dependency(*pmsh);
817  }
818  private :
819  mf__key_& operator=(const mf__key_ &mfk);
820  };
821 
822 
823  class classical_mesh_fem_pool {
824 
825  typedef std::shared_ptr<const mesh_fem> pmesh_fem;
826  typedef std::map<mf__key_, pmesh_fem> mesh_fem_tab;
827 
828  mesh_fem_tab mfs;
829 
830  public :
831 
832  const mesh_fem &operator()(const mesh &msh, dim_type o, dim_type qdim,
833  bool complete=false) {
834  mesh_fem_tab::iterator itt = mfs.begin(), itn = mfs.begin();
835  if (itn != mfs.end()) itn++;
836  while (itt != mfs.end()) {
837  if (!(itt->first.is_context_valid()))
838  { mfs.erase(itt); }
839  itt=itn;
840  if (itn != mfs.end()) itn++;
841  }
842 
843  mf__key_ key(msh, o, qdim, complete);
844  mesh_fem_tab::iterator it = mfs.find(key);
845  assert(it == mfs.end() || it->second->is_context_valid());
846 
847  if (it == mfs.end()) {
848  auto p_torus_mesh = dynamic_cast<const getfem::torus_mesh *>(&msh);
849  auto pmf = (p_torus_mesh) ? std::make_shared<torus_mesh_fem>(*p_torus_mesh, qdim)
850  : std::make_shared<mesh_fem>(msh, qdim);
851  pmf->set_classical_finite_element(o);
852  pmf->set_auto_add(o, false);
853  return *(mfs[key] = pmf);
854  }
855  else return *(it->second);
856  }
857 
858  };
859 
860  const mesh_fem &classical_mesh_fem(const mesh &msh,
861  dim_type order, dim_type qdim,
862  bool complete) {
863  classical_mesh_fem_pool &pool
865  return pool(msh, order, qdim, complete);
866  }
867 
868  struct dummy_mesh_fem_ {
869  mesh_fem mf;
870  dummy_mesh_fem_() : mf(dummy_mesh()) {}
871  };
872 
875 
876 
877  void vectorize_base_tensor(const base_tensor &t, base_matrix &vt,
878  size_type ndof, size_type qdim, size_type N) {
879  GMM_ASSERT1(qdim == N || qdim == 1, "mixed intrinsic vector and "
880  "tensorised fem is not supported");
881  gmm::resize(vt, ndof, N);
882  ndof = (ndof*qdim)/N;
883 
884  if (qdim == N) {
885  gmm::copy(t.as_vector(), vt.as_vector());
886  } else if (qdim == 1) {
887  gmm::clear(vt);
888  base_tensor::const_iterator it = t.begin();
889  for (size_type i = 0; i < ndof; ++i, ++it)
890  for (size_type j = 0; j < N; ++j) vt(i*N+j, j) = *it;
891  }
892  }
893 
894  void vectorize_grad_base_tensor(const base_tensor &t, base_tensor &vt,
895  size_type ndof, size_type qdim, size_type Q) {
896  size_type N = t.sizes()[2];
897  GMM_ASSERT1(qdim == Q || qdim == 1, "mixed intrinsic vector and "
898  "tensorised fem is not supported");
899  vt.adjust_sizes(bgeot::multi_index(ndof, Q, N));
900  ndof = (ndof*qdim)/Q;
901 
902  if (qdim == Q) {
903  gmm::copy(t.as_vector(), vt.as_vector());
904  } else if (qdim == 1) {
905  gmm::clear(vt.as_vector());
906  base_tensor::const_iterator it = t.begin();
907  for (size_type k = 0; k < N; ++k)
908  for (size_type i = 0; i < ndof; ++i, ++it)
909  for (size_type j = 0; j < Q; ++j) vt(i*Q+j, j, k) = *it;
910  }
911  }
912 
913 
914 
915 } /* end of namespace getfem. */
916 
917 
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:195
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:504
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:98
void write_to_file(const std::string &name) const
Write the mesh to a file.
Definition: getfem_mesh.cc:708
gmm::uint64_type convex_version_number(size_type ic) const
return the version number of the convex ic.
Definition: getfem_mesh.h:214
Copy an original 2D mesh to become a torus mesh with radial dimension.
Definition: getfem_torus.h:83
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:68
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
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:606
bool dof_linkable(pdof_description)
Says if the dof is linkable.
Definition: getfem_fem.cc:615
pdof_description global_dof(dim_type d)
Description of a global dof, i.e.
Definition: getfem_fem.cc:542
dof_description * pdof_description
Type representing a pointer on a dof_description.
Definition: getfem_fem.h:159
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:243
pfem fem_descriptor(const std::string &name)
get a fem descriptor from its string name.
Definition: getfem_fem.cc:4659
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:4571
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:4566
std::string name_of_fem(pfem p)
get the string name of a fem descriptor.
Definition: getfem_fem.cc:4668
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
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:49
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
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:58