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