GetFEM++  5.3
getfem_mesh_region.cc
1 /*===========================================================================
2 
3  Copyright (C) 2005-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 
23 #include "getfem/getfem_mesh.h"
24 #include "getfem/getfem_omp.h"
25 
26 namespace getfem {
27  typedef mesh_region::face_bitset face_bitset;
28 
29  mesh_region::mesh_region(const mesh_region &other)
30  : p(std::make_shared<impl>()), id_(size_type(-2)), parent_mesh(0),
31  index_updated(false)
32  {
33  this->operator=(other);
34  }
35 
36 
37  mesh_region::mesh_region() : p(std::make_shared<impl>()), id_(size_type(-2)),
38  type_(size_type(-1)),
39  partitioning_allowed(true), parent_mesh(0), index_updated(false)
40  {
41  if (me_is_multithreaded_now()) prohibit_partitioning();
42  }
43 
44  mesh_region::mesh_region(size_type id__) : id_(id__), type_(size_type(-1)),
45  partitioning_allowed(true), parent_mesh(0), index_updated(false)
46  { }
47 
48  mesh_region::mesh_region(mesh& m, size_type id__, size_type type) :
49  p(std::make_shared<impl>()), id_(id__), type_(type), partitioning_allowed(true), parent_mesh(&m),
50  index_updated(false)
51  {
52  if (me_is_multithreaded_now()) prohibit_partitioning();
53  }
54 
55  mesh_region::mesh_region(const dal::bit_vector &bv) :
56  p(std::make_shared<impl>()), id_(size_type(-2)), type_(size_type(-1)),
57  partitioning_allowed(true), parent_mesh(0), index_updated(false)
58  {
59  if (me_is_multithreaded_now()) prohibit_partitioning();
60  add(bv);
61  }
62 
63  void mesh_region::touch_parent_mesh()
64  {
65  if (parent_mesh) parent_mesh->touch_from_region(id_);
66  }
67 
68  const mesh_region& mesh_region::from_mesh(const mesh &m) const
69  {
70  if (!p.get())
71  {
72  mesh_region *r = const_cast<mesh_region*>(this);
73  if (id_ == size_type(-1))
74  {
75  r->p = std::make_shared<impl>();
76  r->add(m.convex_index());
77  }
78  else if (id_ != size_type(-2))
79  {
80  *r = m.region(id_);
81  }
82  }
83  index_updated = false;
84  return *this;
85  }
86 
87  mesh_region& mesh_region::operator=(const mesh_region &from)
88  {
89  if (!this->parent_mesh && !from.parent_mesh)
90  {
91  this->id_ = from.id_;
92  this->type_ = from.type_;
93  this->partitioning_allowed = from.partitioning_allowed;
94  if (from.p.get()) {
95  if (!this->p.get()) this->p = std::make_shared<impl>();
96  this->wp() = from.rp();
97  }
98  else
99  this->p.reset();
100  }
101  else if (!this->parent_mesh) {
102  this->p = from.p;
103  this->id_ = from.id_;
104  this->type_ = from.type_;
105  this->parent_mesh = from.parent_mesh;
106  this->partitioning_allowed = from.partitioning_allowed;
107  }
108  else {
109  if (from.p.get())
110  {
111  this->wp() = from.rp();
112  this->type_= from.get_type();
113  this->partitioning_allowed = from.partitioning_allowed;
114  }
115  else if (from.id_ == size_type(-1)) {
116  this->clear();
117  this->add(this->parent_mesh->convex_index());
118  this->type_ = size_type(-1);
119  this->partitioning_allowed = true;
120  }
121  touch_parent_mesh();
122  }
123  index_updated = false;
124  return *this;
125  }
126 
127  bool mesh_region::compare(const mesh &m1, const mesh_region &mr,
128  const mesh &m2) const {
129  if (&m1 != &m2) return false;
130  if (!p.get() && !mr.p.get()) return (id_ == mr.id_);
131  this->from_mesh(m1);
132  mr.from_mesh(m2);
133  if (this->p.get() && !(mr.p.get())) return false;
134  if (!(this->p.get()) && (mr.p.get())) return false;
135  if (this->p.get())
136  if (this->p.get()->m != mr.p.get()->m) return false;
137  return true;
138  }
139 
140  face_bitset mesh_region::operator[](size_t cv) const
141  {
142  map_t::const_iterator it = rp().m.find(cv);
143  if (it != rp().m.end()) return (*it).second;
144  else return face_bitset();
145  }
146 
147  void mesh_region::update_partition_iterators() const
148  {
149  if (index_updated) return;
150  itbegin = partition_begin();
151  itend = partition_end ();
152  index_updated = true;
153  }
154  mesh_region::const_iterator
155  mesh_region::partition_begin( ) const
156  {
157  size_type region_size = rp().m.size();
158  if (region_size < num_threads())
159  { //for small regions: put the whole region into zero thread
160  if (this_thread() == 0) return rp().m.begin();
161  else return rp().m.end();
162  }
163  size_type partition_size = static_cast<size_type>
164  (std::ceil(static_cast<scalar_type>(region_size)/
165  static_cast<scalar_type >(num_threads())));
166  size_type index_begin = partition_size * this_thread();
167  if (index_begin >= region_size ) return rp().m.end();
168 
169  const_iterator it = rp().m.begin();
170  for (size_type i=0;i<index_begin;++i) ++it;
171  return it;
172  }
173 
174  mesh_region::const_iterator
175  mesh_region::partition_end( ) const
176  {
177  size_type region_size = rp().m.size();
178  if (region_size < num_threads()) return rp().m.end();
179 
180  size_type partition_size = static_cast<size_type>
181  (std::ceil(static_cast<scalar_type>(region_size)/
182  static_cast<scalar_type >(num_threads())));
183  size_type index_end = partition_size * (this_thread() + 1);
184  if (index_end >= region_size ) return rp().m.end();
185 
186  const_iterator it = rp().m.begin();
187  for (size_type i=0;i<index_end && it!=rp().m.end();++i) ++it;
188  return it;
189  }
190 
191  mesh_region::const_iterator mesh_region::begin( ) const
192  {
193  GMM_ASSERT1(p != 0, "Internal error");
194  if (me_is_multithreaded_now() && partitioning_allowed)
195  {
196  update_partition_iterators();
197  return itbegin;
198  }
199  else { return rp().m.begin(); }
200  }
201 
202  mesh_region::const_iterator mesh_region::end ( ) const
203  {
204  if (me_is_multithreaded_now() && partitioning_allowed)
205  {
206  update_partition_iterators();
207  return itend;
208  }
209  else return rp().m.end();
210  }
211 
213  {
214  if (me_is_multithreaded_now()) partitioning_allowed = true;
215  else partitioning_allowed.all_threads() = true;
216  }
217 
218  void mesh_region::bounding_box(base_node& Pmin, base_node& Pmax) const {
219  auto &mesh = *this->get_parent_mesh();
220  for (auto cv : dal::bv_iterable_c(index())) {
221  for (auto &&pt : mesh.points_of_convex(cv)) {
222  for (auto j = 0; j < Pmin.size(); j++){
223  Pmin[j] = std::min(Pmin[j], pt[j]);
224  Pmax[j] = std::max(Pmax[j], pt[j]);
225  }
226  }
227  }
228  }
229 
231  {
232  if (me_is_multithreaded_now()) partitioning_allowed = false;
233  else partitioning_allowed.all_threads() = false;
234  }
235 
236  bool mesh_region::is_partitioning_allowed() const
237  {
238  return partitioning_allowed;
239  }
240 
241  /* may be optimized .. */
242  const dal::bit_vector& mesh_region::index() const
243  {
244  dal::bit_vector& convex_index = rp().index_.thrd_cast();
245  convex_index.clear();
246  for (const_iterator it = begin(); it != end(); ++it)
247  {
248  if (it->second.any()) convex_index.add(it->first);
249  }
250  return convex_index;
251  }
252 
253  void mesh_region::add(const dal::bit_vector &bv)
254  {
255  for (dal::bv_visitor i(bv); !i.finished(); ++i)
256  {
257  wp().m[i].set(0,1);
258  }
259  touch_parent_mesh();
260  index_updated = false;
261  }
262 
263  void mesh_region::add(size_type cv, short_type f)
264  {
265  wp().m[cv].set(short_type(f+1),1);
266  touch_parent_mesh();
267  index_updated = false;
268  }
269 
270  void mesh_region::sup_all(size_type cv)
271  {
272  map_t::iterator it = wp().m.find(cv);
273  if (it != wp().m.end()) {
274  wp().m.erase(it);
275  touch_parent_mesh();
276  }
277  index_updated = false;
278  }
279 
280  void mesh_region::sup(size_type cv, short_type f)
281  {
282  map_t::iterator it = wp().m.find(cv);
283  if (it != wp().m.end()) {
284  (*it).second.set(short_type(f+1),0);
285  if ((*it).second.none()) wp().m.erase(it);
286  touch_parent_mesh();
287  }
288  index_updated = false;
289  }
290 
291  void mesh_region::clear()
292  {
293  wp().m.clear(); touch_parent_mesh();
294  index_updated = false;
295  }
296 
297  void mesh_region::clean()
298  {
299  for (map_t::iterator it = wp().m.begin(), itn;
300  it != wp().m.end(); it = itn)
301  {
302  itn = it;
303  ++itn;
304  if ( !(*it).second.any() ) wp().m.erase(it);
305  }
306  touch_parent_mesh();
307  index_updated = false;
308  }
309 
310 
311  void mesh_region::swap_convex(size_type cv1, size_type cv2)
312  {
313  map_t::iterator it1 = wp().m.find(cv1), it2 = wp().m.find(cv2),
314  ite = wp().m.end();
315  face_bitset f1, f2;
316 
317  if (it1 != ite) f1 = it1->second;
318  if (it2 != ite) f2 = it2->second;
319  if (!f1.none()) wp().m[cv2] = f1;
320  else if (it2 != ite) wp().m.erase(it2);
321  if (!f2.none()) wp().m[cv1] = f2;
322  else if (it1 != ite) wp().m.erase(it1);
323  touch_parent_mesh();
324  index_updated = false;
325  }
326 
327  bool mesh_region::is_in(size_type cv, short_type f) const
328  {
329  GMM_ASSERT1(p.get(), "Use from mesh on that region before");
330  map_t::const_iterator it = rp().m.find(cv);
331  if (it == rp().m.end() || short_type(f+1) >= MAX_FACES_PER_CV) return false;
332  return ((*it).second)[short_type(f+1)];
333  }
334 
335  bool mesh_region::is_in(size_type cv, short_type f, const mesh &m) const
336  {
337  if (p.get()) {
338  map_t::const_iterator it = rp().m.find(cv);
339  if (it == rp().m.end() || short_type(f+1) >= MAX_FACES_PER_CV)
340  return false;
341  return ((*it).second)[short_type(f+1)];
342  }
343  else
344  {
345  if (id() == size_type(-1)) return true;
346  else return m.region(id()).is_in(cv, f);
347  }
348  }
349 
350 
351 
352  bool mesh_region::is_empty() const
353  {
354  return rp().m.empty();
355  }
356 
358  {
359  return is_empty() ||
360  (or_mask()[0] == true && or_mask().count() == 1);
361  }
362 
364  {
365  return is_empty() || (and_mask()[0] == false);
366  }
367 
368  face_bitset mesh_region::faces_of_convex(size_type cv) const
369  {
370  map_t::const_iterator it = rp().m.find(cv);
371  if (it != rp().m.end()) return ((*it).second) >> 1;
372  else return face_bitset();
373  }
374 
375  face_bitset mesh_region::and_mask() const
376  {
377  face_bitset bs;
378  if (rp().m.empty()) return bs;
379  bs.set();
380  for (map_t::const_iterator it = rp().m.begin(); it != rp().m.end(); ++it)
381  if ( (*it).second.any() ) bs &= (*it).second;
382  return bs;
383  }
384 
385  face_bitset mesh_region::or_mask() const
386  {
387  face_bitset bs;
388  if (rp().m.empty()) return bs;
389  for (map_t::const_iterator it = rp().m.begin(); it != rp().m.end(); ++it)
390  if ( (*it).second.any() ) bs |= (*it).second;
391  return bs;
392  }
393 
395  {
396  size_type sz=0;
397  for (map_t::const_iterator it = begin(); it != end(); ++it)
398  sz += (*it).second.count();
399  return sz;
400  }
401 
402  size_type mesh_region::unpartitioned_size() const
403  {
404  size_type sz=0;
405  for (map_t::const_iterator it = rp().m.begin(); it != rp().m.end(); ++it)
406  sz += (*it).second.count();
407  return sz;
408  }
409 
410 
412  const mesh_region &b)
413  {
414  GMM_TRACE4("intersection of "<<a.id()<<" and "<<b.id());
415  mesh_region r;
416  /* we do not allow the "all_convexes" kind of regions
417  for these operations as there are not intended to be manipulated
418  (they only exist to provide a default argument to the mesh_region
419  parameters of assembly procedures etc. */
420  GMM_ASSERT1(a.id() != size_type(-1)||
421  b.id() != size_type(-1), "the 'all_convexes' regions "
422  "are not supported for set operations");
423  if (a.id() == size_type(-1))
424  {
425  for (const_iterator it = b.begin();it != b.end(); ++it) r.wp().m.insert(*it);
426  return r;
427  }
428  else if (b.id() == size_type(-1))
429  {
430  for (const_iterator it = a.begin();it != a.end(); ++it) r.wp().m.insert(*it);
431  return r;
432  }
433 
434  map_t::const_iterator
435  ita = a.begin(), enda = a.end(),
436  itb = b.begin(), endb = b.end();
437 
438  while (ita != enda && itb != endb) {
439  if (ita->first < itb->first) ++ita;
440  else if (ita->first > itb->first) ++itb;
441  else {
442  face_bitset maska = ita->second, maskb = itb->second, bs;
443  if (maska[0] && !maskb[0]) bs = maskb;
444  else if (maskb[0] && !maska[0]) bs = maska;
445  else bs = maska & maskb;
446  if (bs.any()) r.wp().m.insert(r.wp().m.end(), std::make_pair(ita->first,bs));
447  ++ita; ++itb;
448  }
449  }
450  return r;
451  }
452 
454  const mesh_region &b)
455  {
456  GMM_TRACE4("Merger of " << a.id() << " and " << b.id());
457  mesh_region r;
458  GMM_ASSERT1(a.id() != size_type(-1) &&
459  b.id() != size_type(-1), "the 'all_convexes' regions "
460  "are not supported for set operations");
461  for (const_iterator it = a.begin();it != a.end(); ++it)
462  {
463  r.wp().m.insert(*it);
464  }
465  for (const_iterator it = b.begin();it != b.end(); ++it)
466  {
467  r.wp().m[it->first] |= it->second;
468  }
469  return r;
470  }
471 
472 
474  const mesh_region &b)
475  {
476  GMM_TRACE4("subtraction of "<<a.id()<<" and "<<b.id());
477  mesh_region r;
478  GMM_ASSERT1(a.id() != size_type(-1) &&
479  b.id() != size_type(-1), "the 'all_convexes' regions "
480  "are not supported for set operations");
481  for (const_iterator ita = a.begin();ita != a.end(); ++ita)
482  r.wp().m.insert(*ita);
483 
484  for (const_iterator itb = b.begin();itb != b.end(); ++itb)
485  {
486  size_type cv = itb->first;
487  map_t::iterator it = r.wp().m.find(cv);
488  if (it != r.wp().m.end()){
489  it->second &= ~(itb->second);
490  if (it->second.none()) r.wp().m.erase(it);
491  }
492  }
493  return r;
494  }
495 
497  const mesh_region &rg2,
498  const getfem::mesh& m2) const {
499  if (&m1 != &m2) return 0;
500  int r = 1, partially = 0;
501  for (mr_visitor cv(*this, m1); !cv.finished(); cv.next())
502  if (cv.is_face() && rg2.is_in(cv.cv(),short_type(-1), m2))
503  partially = -1;
504  else
505  r = 0;
506  if (r == 1) return 1; else return partially;
507  }
508 
510  {
511  return m.regions_index().last_true()+1;
512  }
513 
514 
515  void mesh_region::error_if_not_faces() const
516  {
517  GMM_ASSERT1(is_only_faces(), "Expecting a set of faces, not convexes");
518  }
519 
520  void mesh_region::error_if_not_convexes() const
521  {
522  GMM_ASSERT1(is_only_convexes(), "Expecting a set of convexes, not faces");
523  }
524 
525  void mesh_region::error_if_not_homogeneous() const
526  {
527  GMM_ASSERT1(is_only_faces() || is_only_convexes(), "Expecting a set "
528  "of convexes or a set of faces, but not a mixed set");
529  }
530 
531 
532 
533 
534 #if GETFEM_PARA_LEVEL > 1
535 
536  mesh_region::visitor::visitor(const mesh_region &s, const mesh &m,
537  bool intersect_with_mpi) :
538  cv_(size_type(-1)), f_(short_type(-1)), finished_(false)
539  {
540  if ((me_is_multithreaded_now() && s.partitioning_allowed)) {
541  s.from_mesh(m);
542  init(s);
543  } else {
544  if (s.id() == size_type(-1)) {
545  if (intersect_with_mpi)
546  init(m.get_mpi_region());
547  else
548  init(m.convex_index());
549  } else if (s.p.get()) {
550  if (intersect_with_mpi) {
551  mpi_rg = std::make_unique<mesh_region>(s);
552  mpi_rg->from_mesh(m);
553  m.intersect_with_mpi_region(*mpi_rg);
554  init(*mpi_rg);
555  } else
556  init(s);
557  } else {
558  if (intersect_with_mpi)
559  init(m.get_mpi_sub_region(s.id()));
560  else
561  init(m.region(s.id()));
562  }
563  }
564  }
565 
566 #else
567 
568  mesh_region::visitor::visitor(const mesh_region &s, const mesh &m, bool)
569  :cv_(size_type(-1)), f_(short_type(-1)), finished_(false)
570  {
571  if ((me_is_multithreaded_now() && s.partitioning_allowed)) {
572  s.from_mesh(m);
573  init(s);
574  } else {
575  if (s.id() == size_type(-1)) {
576  init(m.convex_index());
577  } else if (s.p.get()) {
578  init(s);
579  } else {
580  init(m.region(s.id()));
581  }
582  }
583  }
584 
585 #endif
586 
587 
588  bool mesh_region::visitor::next()
589  {
590  if (whole_mesh) {
591  if (itb == iteb) { finished_ = true; return false; }
592  cv_ = itb.index();
593  c = 0;
594  f_ = 0;
595  ++itb; while (itb != iteb && !(*itb)) ++itb;
596  return true;
597  }
598  while (c.none())
599  {
600  if (it == ite) { finished_=true; return false; }
601  cv_ = it->first;
602  c = it->second;
603  f_ = short_type(-1);
604  ++it;
605  if (c.none()) continue;
606  }
607  next_face();
608  return true;
609  }
610 
611  mesh_region::visitor::visitor(const mesh_region &s) :
612  cv_(size_type(-1)), f_(short_type(-1)), finished_(false)
613  {
614  init(s);
615  }
616 
617  void mesh_region::visitor::init(const dal::bit_vector &bv)
618  {
619  whole_mesh = true;
620  itb = bv.begin(); iteb = bv.end();
621  while (itb != iteb && !(*itb)) ++itb;
622  next();
623  }
624 
625  void mesh_region::visitor::init(const mesh_region &s)
626  {
627  whole_mesh = false;
628  it = s.begin();
629  ite = s.end();
630  next();
631  }
632 
633  std::ostream & operator <<(std::ostream &os, const mesh_region &w)
634  {
635  if (w.id() == size_type(-1))
636  os << " ALL_CONVEXES";
637  else if (w.p.get())
638  {
639  for (mr_visitor cv(w); !cv.finished(); cv.next())
640  {
641  os << cv.cv();
642  if (cv.is_face()) os << "/" << cv.f();
643  os << " ";
644  }
645  }
646  else
647  {
648  os << " region " << w.id();
649  }
650  return os;
651  }
652 
653  struct dummy_mesh_region_ {
654  mesh_region mr;
655  dummy_mesh_region_() : mr() {}
656  };
657 
658  const mesh_region &dummy_mesh_region()
660 }
void allow_partitioning()
In multithreaded part of the program makes only a partition of the region visible in the index() and ...
structure used to hold a set of convexes and/or convex faces.
region objects (set of convexes and/or convex faces)
size_type size() const
Region size, or the size of the region partition on the current thread if the region is partitioned...
Define a getfem::getfem_mesh object.
const dal::bit_vector & index() const
Index of the region convexes, or the convexes from the partition on the current thread.
int region_is_faces_of(const getfem::mesh &m1, const mesh_region &rg2, const getfem::mesh &m2) const
Test if the region is a boundary of a list of faces of elements of region rg.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:95
Tools for multithreaded, OpenMP and Boost based parallelization.
static T & instance()
Instance from the current thread.
static size_type free_region_id(const getfem::mesh &m)
Extract the next region number that does not yet exists in the mesh.
const mesh_region & from_mesh(const mesh &m) const
For regions which have been built with just a number &#39;id&#39;, from_mesh(m) sets the current region to &#39;m...
void prohibit_partitioning()
Disregard partitioning, which means being able to see the whole region in multirheaded code...
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
static mesh_region subtract(const mesh_region &a, const mesh_region &b)
subtract the second region from the first one
bool is_only_faces() const
Return true if the region do contain only convex faces.
void bounding_box(base_node &Pmin, base_node &Pmax) const
Return the bounding box [Pmin - Pmax] of the mesh_region.
static mesh_region intersection(const mesh_region &a, const mesh_region &b)
return the intersection of two mesh regions
bool is_only_convexes() const
Return true if the region do not contain any convex face.
"iterator" class for regions.
GEneric Tool for Finite Element Methods.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:79
static mesh_region merge(const mesh_region &a, const mesh_region &b)
return the union of two mesh_regions
const mesh_region region(size_type id) const
Return the region of index &#39;id&#39;.
Definition: getfem_mesh.h:414
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.