GetFEM  5.4.3
getfem_mesh_slicers.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2004-2020 Julien Pommier
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program; if not, write to the Free Software Foundation,
19  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21  As a special exception, you may use this file as it is a part of a free
22  software library without restriction. Specifically, if other files
23  instantiate templates or use macros or inline functions from this file,
24  or you compile this file and link it with other files to produce an
25  executable, this file does not by itself cause the resulting executable
26  to be covered by the GNU Lesser General Public License. This exception
27  does not however invalidate any other reasons why the executable file
28  might be covered by the GNU Lesser General Public License.
29 
30 ===========================================================================*/
31 
32 /**@file getfem_mesh_slicers.h
33  @author Julien Pommier <[email protected]>
34  @date February 2004.
35  @brief Define various mesh slicers.
36 
37  Mesh slices are analogous to a refined P1-discontinuous mesh_fem, a
38  list of nodes/simplexes on which the interpolation is very fast.
39 
40  A slice is built from a mesh, by applying some slicing operations
41  (cut the mesh with a plane, intersect with a sphere, take the
42  boundary faces, etc..).
43 
44  They are used for post-treatment (exportation of results to VTK or OpenDX,
45  etc.)
46 */
47 
48 #ifndef GETFEM_MESH_SLICERS_H
49 #define GETFEM_MESH_SLICERS_H
50 
51 #include <bitset>
52 #include <memory>
53 #include "gmm/gmm_kernel.h"
54 #include "getfem_mesh_fem.h"
55 #include "bgeot_rtree.h"
56 
57 namespace getfem {
58  /** @internal @brief node data in a slice.
59 
60  Contains both real position, and position in the reference
61  convex
62  */
63  struct slice_node {
64  typedef std::bitset<32> faces_ct; /** broken for convexes with more
65  * than 32 faces. */
66  base_node pt, pt_ref;
67  faces_ct faces;
68  slice_node() {}
69  slice_node(const base_node& pt_, const base_node& pt_ref_)
70  : pt(pt_), pt_ref(pt_ref_) {}
71  void swap(slice_node &other) {
72  std::swap(faces,other.faces); pt.swap(other.pt);
73  pt_ref.swap(other.pt_ref);
74  }
75  };
76 
77 
78  /** @internal @brief simplex data in a slice.
79 
80  Just a list of slice_node ids.
81  */
82  struct slice_simplex {
83  std::vector<size_type> inodes;
84  size_type dim() const { return inodes.size()-1; }
85  slice_simplex(size_type n) : inodes(n) {}
86  slice_simplex() : inodes(4) {}
87  bool operator==(const slice_simplex& o) const
88  { return inodes == o.inodes; }
89  bool operator!=(const slice_simplex& o) const
90  { return inodes != o.inodes; }
91  };
92 
93  class slicer_action;
94  class stored_mesh_slice;
95  class mesh_level_set;
96 
97  /** @brief Apply a serie a slicing operations to a mesh.
98 
99  No output is produced by this object, the real output obtained
100  with the side-effect of certain getfem::mesh_slicer objects
101  (such as getfem::slicer_build_stored_mesh_slice).
102  */
103  class mesh_slicer {
104  std::deque<slicer_action*> action; /* pointed actions are not deleted */
105  public:
106  typedef std::vector<slice_node> cs_nodes_ct;
107  typedef std::vector<slice_simplex> cs_simplexes_ct;
108  const mesh& m;
109  const mesh_level_set *mls; // optional
110  size_type cv;
111  short_type face, cv_nbfaces;
112  dim_type cv_dim;
114  /* list of nodes and simplexes for the current convex
115  (including those who are outside of the slice) */
116  cs_nodes_ct nodes;
117  cs_simplexes_ct simplexes;
118  /* indexes of used simplexes and nodes,
119  and index of simplexes who are considered to be in
120  the slice */
121  dal::bit_vector simplex_index, nodes_index, splx_in;
122  size_type fcnt;
123  bgeot::pconvex_ref cvr, prev_cvr;
124  bool discont; // true when mls->is_convex_cut(cv) == true
125 
126  mesh tmp_mesh; // used only when mls != 0
127  bgeot::mesh_structure tmp_mesh_struct; // used only when mls != 0
128  // for faces structure.
129 
130  void pack(); /* not used, indeed */
131  void update_nodes_index();
132  /** mesh_slicer constructor. Use mesh_slicer::exec to build the slice.
133  @param m_ the mesh that is going to be sliced.
134  */
135  mesh_slicer(const mesh& m_);
136  mesh_slicer(const mesh_level_set &mls_);
137  void using_mesh_level_set(const mesh_level_set &mls_);
138  void push_back_action(slicer_action &a) { action.push_back(&a); }
139  void push_front_action(slicer_action &a) { action.push_front(&a); }
140 
141  size_type add_simplex(const slice_simplex& s, bool isin) {
142  size_type i = simplexes.size();
143  simplexes.push_back(s); splx_in[i] = isin; simplex_index.add(i);
144  return i;
145  }
146  void sup_simplex(size_type i) {
147  splx_in.sup(i); simplex_index.sup(i);
148  }
149  size_type dim() {
150  if (nodes.size()) return nodes[0].pt.size();
151  else GMM_ASSERT1(false, "internal_error");
152  }
153  void simplex_orientation(slice_simplex& s);
154  /**@brief build a new mesh_slice.
155  @param nrefine number of refinments for each convex of the original
156  mesh (size_type or a vector indexed by the convex number)
157  @param cvlst the list of convex numbers (or convex faces) of m that
158  will be taken into account for the slice
159  */
160  void exec(size_type nrefine, const mesh_region& cvlst);
161  void exec(const std::vector<short_type> &nrefine,const mesh_region& cvlst);
162  void exec(size_type nrefine = 1);
163  /**
164  @brief build a new mesh slice.
165  @param sms an initial stored_mesh_slice
166  */
167  void exec(const stored_mesh_slice& sms);
168  /**
169  @brief build a new mesh_slice than can be used to interpolate a field
170  on a fixed set of points.
171  @param pts the list of points
172  */
173  void exec(const std::vector<base_node>& pts);
174  private:
175  void exec_(const short_type *pnrefine,
176  int nref_stride,
177  const mesh_region& cvlst);
178  const mesh& refined_simplex_mesh_for_convex_cut_by_level_set
179  (const mesh &cvm, unsigned nrefine);
180  const bgeot::mesh_structure &
181  refined_simplex_mesh_for_convex_faces_cut_by_level_set(short_type f);
182 
183  void update_cv_data(size_type cv_, short_type f_ = short_type(-1));
184  void init_indexes();
185  void apply_slicers();
186  };
187 
188 
189  /* stupid class in order to use any vector type for field data associated
190  to mesh_fems in slices (used for slice deformation and isovalues) */
191  class mesh_slice_cv_dof_data_base {
192  public:
193  const mesh_fem *pmf;
194  virtual void copy(size_type cv, base_vector& coeff) const = 0;
195  virtual scalar_type maxval() const = 0;
196  virtual ~mesh_slice_cv_dof_data_base() {}
197  virtual std::unique_ptr<mesh_slice_cv_dof_data_base> clone() const = 0;
198  };
199 
200  /**
201  Use this structure to specify that the mesh must be deformed before
202  the slicing operation (with a mesh_fem and an associated field).
203  */
204  template<typename VEC> class mesh_slice_cv_dof_data
205  : public mesh_slice_cv_dof_data_base {
206  typedef typename gmm::linalg_traits<VEC>::value_type T;
207  std::vector<T> u;
208  public:
209  mesh_slice_cv_dof_data(const mesh_fem &mf_, const VEC &u_) {
210  pmf=&mf_;
211  gmm::resize(u, mf_.nb_basic_dof());
212  if (mf_.is_reduced())
213  gmm::mult(mf_.extension_matrix(), u_, u);
214  else
215  gmm::copy(u_, u);
216  }
217  virtual void copy(size_type cv, base_vector& coeff) const {
218  coeff.resize(pmf->nb_basic_dof_of_element(cv));
219  const mesh_fem::ind_dof_ct &dof = pmf->ind_basic_dof_of_element(cv);
220  base_vector::iterator out = coeff.begin();
221  for (mesh_fem::ind_dof_ct::iterator it=dof.begin(); it != dof.end();
222  ++it, ++out)
223  *out = u[*it];
224  }
225  scalar_type maxval() const { return gmm::vect_norminf(u); }
226  virtual std::unique_ptr<mesh_slice_cv_dof_data_base> clone() const
227  { return std::make_unique<mesh_slice_cv_dof_data<VEC>>(*this); }
228  };
229 
230 
231  /** @brief generic slicer class.
232 
233  Given a list of slice_simplex/slice_node, it build a news list of
234  slice_simplex/slice_node, indicating which ones are in the slice
235  with the bit_vector splx_in.
236  */
238  public:
239  static const float EPS;
240  virtual void exec(mesh_slicer &ms) = 0;
241  virtual ~slicer_action() {}
242  };
243 
244  /** This slicer does nothing. */
245  class slicer_none : public slicer_action {
246  public:
247  slicer_none() {}
248  void exec(mesh_slicer &/*ms*/) {}
249  static slicer_none& static_instance();
250  };
251 
252  /** Extraction of the boundary of a slice. */
254  slicer_action *A;
255  std::vector<slice_node::faces_ct> convex_faces;
256  bool test_bound(const slice_simplex& s, slice_node::faces_ct& fmask,
257  const mesh_slicer::cs_nodes_ct& nodes) const;
258  void build_from(const mesh& m, const mesh_region& cvflst);
259  public:
260  slicer_boundary(const mesh& m, slicer_action &sA,
261  const mesh_region& fbound);
262  slicer_boundary(const mesh& m,
263  slicer_action &sA = slicer_none::static_instance());
264  void exec(mesh_slicer &ms);
265  };
266 
267  /* Apply a precomputed deformation to the slice nodes */
268  class slicer_apply_deformation : public slicer_action {
269  mesh_slice_cv_dof_data_base *defdata;
270  pfem pf;
271  fem_precomp_pool fprecomp;
272  std::vector<base_node> ref_pts;
273  public:
274  slicer_apply_deformation(mesh_slice_cv_dof_data_base &defdata_)
275  : defdata(&defdata_), pf(0) {
276  if (defdata &&
277  defdata->pmf->get_qdim() != defdata->pmf->linked_mesh().dim())
278  GMM_ASSERT1(false, "wrong Q(=" << int(defdata->pmf->get_qdim())
279  << ") dimension for slice deformation: should be equal to "
280  "the mesh dimension which is "
281  << int(defdata->pmf->linked_mesh().dim()));
282  }
283  void exec(mesh_slicer &ms);
284  };
285 
286  /**
287  Base class for general slices of a mesh (planar, sphere,
288  cylinder,isosurface)
289  */
290  class slicer_volume : public slicer_action {
291  public:
292  enum {VOLIN=-1, VOLBOUND=0, VOLOUT=+1, VOLSPLIT=+2};
293  protected:
294  /**
295  orient defines the kind of slicing :
296  VOLIN -> keep the inside of the volume,
297  VOLBOUND -> its boundary,
298  VOLOUT -> its outside,
299  VOLSPLIT -> keep everything but make split simplexes
300  untils no simplex crosses the boundary
301  */
302  int orient;
303  dal::bit_vector pt_in, pt_bin;
304 
305  /** Overload either 'prepare' or 'test_point'.
306  */
307  virtual void prepare(size_type /*cv*/,
308  const mesh_slicer::cs_nodes_ct& nodes,
309  const dal::bit_vector& nodes_index) {
310  pt_in.clear(); pt_bin.clear();
311  for (dal::bv_visitor i(nodes_index); !i.finished(); ++i) {
312  bool in, bin; test_point(nodes[i].pt, in, bin);
313  if (bin || ((orient > 0) ? !in : in)) pt_in.add(i);
314  if (bin) pt_bin.add(i);
315  }
316  }
317  virtual void test_point(const base_node&, bool& in, bool& bound) const
318  { in=true; bound=true; }
319  /** edge_intersect should always be overloaded */
320  virtual scalar_type
322  const mesh_slicer::cs_nodes_ct& /*nodes*/) const = 0;
323 
324  slicer_volume(int orient_) : orient(orient_) {}
325 
326  /** Utility function */
327  static scalar_type trinom(scalar_type a, scalar_type b, scalar_type c);
328  void split_simplex(mesh_slicer &ms,
329  slice_simplex s, /* s is NOT a reference, it is on
330  * purpose(push_back in the function)*/
331  size_type sstart, std::bitset<32> spin,
332  std::bitset<32> spbin);
333  public:
334  void exec(mesh_slicer &ms);
335  };
336 
337  /**
338  Slice a mesh with a half-space (or its boundary).
339  */
341  const base_node x0, n; /* normal directed from inside toward outside */
342  void test_point(const base_node& P, bool& in, bool& bound) const;
343  scalar_type edge_intersect(size_type iA, size_type iB,
344  const mesh_slicer::cs_nodes_ct& nodes) const;
345  public:
346  slicer_half_space(base_node x0_, base_node n_, int orient_) :
347  slicer_volume(orient_), x0(x0_), n(n_/gmm::vect_norm2(n_)) {
348  //n *= (1./bgeot::vect_norm2(n));
349  }
350  };
351 
352  /**
353  Slices a mesh with a sphere (or its boundary).
354  */
355  class slicer_sphere : public slicer_volume {
356  base_node x0;
357  scalar_type R;
358  void test_point(const base_node& P, bool& in, bool& bound) const;
359  scalar_type edge_intersect(size_type iA, size_type iB,
360  const mesh_slicer::cs_nodes_ct& nodes) const;
361  public:
362  /* orient = -1 => select interior,
363  orient = 0 => select boundary
364  orient = +1 => select exterior */
365  slicer_sphere(base_node x0_, scalar_type R_, int orient_) :
366  slicer_volume(orient_), x0(x0_), R(R_) {}
367  //cerr << "slicer_volume, x0=" << x0 << ", R=" << R << endl; }
368  };
369 
370  /**
371  Slices a mesh with a cylinder (or its boundary).
372  */
374  base_node x0, d;
375  scalar_type R;
376  void test_point(const base_node& P, bool& in, bool& bound) const;
377  scalar_type edge_intersect(size_type iA, size_type iB,
378  const mesh_slicer::cs_nodes_ct& nodes) const;
379  public:
380  slicer_cylinder(base_node x0_, base_node x1_,scalar_type R_,int orient_) :
381  slicer_volume(orient_), x0(x0_), d(x1_-x0_), R(R_) {
382  d /= gmm::vect_norm2(d);
383  }
384  };
385 
386 
387  /**
388  Extract an isosurface.
389  */
391  std::unique_ptr<const mesh_slice_cv_dof_data_base> mfU;
392  scalar_type val;
393  scalar_type val_scaling; /* = max(abs(U)) */
394  std::vector<scalar_type> Uval;
395  void prepare(size_type cv, const mesh_slicer::cs_nodes_ct& nodes,
396  const dal::bit_vector& nodes_index);
397  scalar_type edge_intersect(size_type iA, size_type iB,
398  const mesh_slicer::cs_nodes_ct&) const;
399  public:
400  /* orient = -1: u(x) <= val, 0: u(x) == val, +1: u(x) >= val */
401  slicer_isovalues(const mesh_slice_cv_dof_data_base& mfU_,
402  scalar_type val_, int orient_) :
403  slicer_volume(orient_), mfU(mfU_.clone()), val(val_) {
404  GMM_ASSERT1(mfU->pmf->get_qdim() == 1,
405  "can't compute isovalues of a vector field !");
406  val_scaling = mfU->maxval();
407  }
408  };
409 
410  /**
411  Slices a mesh with another mesh. (of same dimension,
412  and whose convex are preferably linear). Note that slicing
413  a refined mesh with a rough mesh should be faster than slicing
414  a rough mesh with a refined mesh.
415  */
417  const mesh& slm;
418  bgeot::rtree tree; /* tree of bounding boxes for slm */
419  protected:
420  virtual void intersection_callback(mesh_slicer &/*ms*/,
421  size_type /*slmcv*/) {}
422  public:
423  slicer_mesh_with_mesh(const mesh&);
424  void exec(mesh_slicer &ms);
425  };
426 
427  /**
428  union of two slices
429  */
430  class slicer_union : public slicer_action {
431  slicer_action *A, *B;
432  public:
433  slicer_union(const slicer_action &sA, const slicer_action &sB) :
434  A(&const_cast<slicer_action&>(sA)), B(&const_cast<slicer_action&>(sB)) {}
435  void exec(mesh_slicer &ms);
436  };
437 
438  /**
439  Build the intersection of two slices
440  */
442  slicer_action *A, *B;
443  public:
444  slicer_intersect(slicer_action &sA, slicer_action &sB) : A(&sA), B(&sB) {}
445  void exec(mesh_slicer &ms);
446  };
447 
448  /**
449  Build the complementary of a slice
450  */
452  slicer_action *A;
453  public:
454  slicer_complementary(slicer_action &sA) : A(&sA) {}
455  void exec(mesh_slicer &ms);
456  };
457 
458  /**
459  Slicer whose side-effect is to compute the area of the
460  slice. Note that if the slice is composed of simplexes of many
461  dimensions, the resulting area is nonsense.
462  */
464  scalar_type a;
465  public:
466  slicer_compute_area() : a(0) {}
467  void exec(mesh_slicer &ms);
468  scalar_type area() const { return a; }
469  };
470 
471  /**
472  Slicer whose side-effect is to build the list of edges
473  (i.e. segments) and store them in a mesh object.
474 
475  Hence all common nodes/edges are eliminated. (this slicer
476  is not useful for anything but visualization of sliced meshes)
477  */
479  mesh& edges_m;
480  dal::bit_vector *pslice_edges;
481  public:
482  /** @param edges_m_ the mesh that will be filled with edges. */
484  : edges_m(edges_m_), pslice_edges(0) {}
485  /** @param edges_m_ the mesh that will be filled with edges.
486  @param bv will contain on output the list of edges numbers
487  (as convex numbers in edges_m_) which where not part of the
488  original mesh, but became apparent when some convex faces were
489  sliced.
490  */
491  slicer_build_edges_mesh(mesh& edges_m_, dal::bit_vector& bv)
492  : edges_m(edges_m_), pslice_edges(&bv) {}
493  void exec(mesh_slicer &ms);
494  };
495 
496  /**
497  Slicer whose side-effect is to build a mesh from the slice
498  simplexes. Hence using slices is a good way to simplexify a
499  mesh, however keep in mind that high order geometric
500  transformation will be simplexified with linear simplexes!
501  */
503  mesh& m;
504  public:
505  slicer_build_mesh(mesh& m_) : m(m_) {}
506  void exec(mesh_slicer &ms);
507  };
508 
509  /**
510  Contract or expand each convex with respect to its gravity center
511  */
512  class slicer_explode : public slicer_action {
513  scalar_type coef;
514  public:
515  /**
516  @param c < 1 => contraction, > 1 -> expansion.
517  */
518  slicer_explode(scalar_type c) : coef(c) {}
519  void exec(mesh_slicer &ms);
520  };
521 
522 }
523 
524 #endif /*GETFEM_MESH_SLICERS_H*/
region-tree for window/point search on a set of rectangles.
Mesh structure definition.
Balanced tree of n-dimensional rectangles.
Definition: bgeot_rtree.h:98
handle a pool (i.e.
Definition: getfem_fem.h:717
Describe a finite element method linked to a mesh.
const EXTENSION_MATRIX & extension_matrix() const
Return the extension matrix corresponding to reduction applied (RE=I).
virtual size_type nb_basic_dof() const
Return the total number of basic degrees of freedom (before the optional reduction).
bool is_reduced() const
Return true if a reduction matrix is applied to the dofs.
Keep informations about a mesh crossed by level-sets.
structure used to hold a set of convexes and/or convex faces.
Use this structure to specify that the mesh must be deformed before the slicing operation (with a mes...
Apply a serie a slicing operations to a mesh.
void exec(size_type nrefine, const mesh_region &cvlst)
build a new mesh_slice.
mesh_slicer(const mesh &m_)
mesh_slicer constructor.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:99
generic slicer class.
Extraction of the boundary of a slice.
Slicer whose side-effect is to build the list of edges (i.e.
slicer_build_edges_mesh(mesh &edges_m_, dal::bit_vector &bv)
Slicer whose side-effect is to build a mesh from the slice simplexes.
Build the complementary of a slice.
Slicer whose side-effect is to compute the area of the slice.
Slices a mesh with a cylinder (or its boundary).
Contract or expand each convex with respect to its gravity center.
Slice a mesh with a half-space (or its boundary).
Build the intersection of two slices.
Extract an isosurface.
Slices a mesh with another mesh.
This slicer does nothing.
Slices a mesh with a sphere (or its boundary).
union of two slices
Base class for general slices of a mesh (planar, sphere, cylinder,isosurface)
virtual void prepare(size_type, const mesh_slicer::cs_nodes_ct &nodes, const dal::bit_vector &nodes_index)
Overload either 'prepare' or 'test_point'.
int orient
orient defines the kind of slicing : VOLIN -> keep the inside of the volume, VOLBOUND -> its boundary...
virtual scalar_type edge_intersect(size_type, size_type, const mesh_slicer::cs_nodes_ct &) const =0
edge_intersect should always be overloaded
static scalar_type trinom(scalar_type a, scalar_type b, scalar_type c)
Utility function.
The output of a getfem::mesh_slicer which has been recorded.
Define the getfem::mesh_fem class.
Include the base gmm files.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:244
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:73
bool operator==(const pconvex_structure &p1, const pconvex_structure &p2)
Stored objects must be compared by keys, because there is a possibility that they are duplicated in s...
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
GEneric Tool for Finite Element Methods.