GetFEM  5.5
getfem_mesh_level_set.cc
1 /*===========================================================================
2 
3  Copyright (C) 2005-2026 Julien Pommier
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 
22 
23 
24 namespace getfem {
25 
26  std::ostream &operator<<(std::ostream &os, const mesh_level_set::zone &z) {
27  os << "zone[";
28  for (mesh_level_set::zone::const_iterator it = z.begin();
29  it != z.end(); ++it) {
30  if (it != z.begin()) os << ", ";
31  os << **it;
32  }
33  os << "]";
34  return os;
35  }
36 
37  std::ostream &operator<<(std::ostream &os,const mesh_level_set::zoneset &zs) {
38  os << "zoneset[";
39  for (mesh_level_set::zoneset::const_iterator it = zs.begin();
40  it != zs.end(); ++it) {
41  if (it != zs.begin()) os << "; ";
42  os << **it;
43  }
44  os << "]";
45  return os;
46  }
47 
48 
49 #ifdef DEBUG_LS
50 #include <asm/msr.h>
51 struct Chrono {
52  unsigned long long tprev;
53  unsigned long long acc;
54  unsigned long long tmax;
55  bool running; unsigned cnt;
56  Chrono() : acc(0), tmax(0), running(false), cnt(0) {}
57  void tic() { rdtscll(tprev); running = true; ++cnt; }
58  double toc() {
59  if (!running) return 0.; running = false;
60  unsigned long long t; rdtscll(t);
61  t -= tprev;
62  acc += t; tmax = std::max(tmax, t);
63  return double(t)/2.8e9;
64  }
65  double total() { return double(acc) / 2.8e9; }
66  double max() { return double(tmax) / 2.8e9; }
67  double mean() { return cnt ? total() / cnt : 0.; }
68  unsigned count() { return cnt; }
69 };
70 
71  Chrono interpolate_face_chrono;
72 #endif
73 
74  static bool noisy = false;
75  void getfem_mesh_level_set_noisy(void) { noisy = true; }
76 
77  void mesh_level_set::clear(void) {
78  cut_cv.clear();
79  is_adapted_ = false; touch();
80  }
81 
82  const dal::bit_vector &mesh_level_set::crack_tip_convexes() const {
83  return crack_tip_convexes_;
84  }
85 
86  void mesh_level_set::init_with_mesh(mesh &me) {
87  GMM_ASSERT1(linked_mesh_ == 0, "mesh_level_set already initialized");
88  linked_mesh_ = &me;
89  this->add_dependency(me);
90  is_adapted_ = false;
91  }
92 
93  mesh_level_set::mesh_level_set(mesh &me)
94  { linked_mesh_ = 0; init_with_mesh(me); }
95 
96  mesh_level_set::mesh_level_set(void)
97  { linked_mesh_ = 0; is_adapted_ = false; }
98 
99 
100  mesh_level_set::~mesh_level_set() {}
101 
102  static void interpolate_face(const bgeot::pgeometric_trans &pgt,
103  mesh &m, dal::bit_vector& ptdone,
104  const std::vector<size_type>& ipts,
105  const bgeot::pconvex_structure &cvs,
106  size_type nb_vertices,
107  const std::vector<dal::bit_vector> &constraints,
108  const std::vector<const
109  mesher_signed_distance *> &list_constraints) {
110  if (cvs->dim() == 0) return;
111  else if (cvs->dim() > 1) {
112  std::vector<size_type> fpts;
113  for (short_type f=0; f < cvs->nb_faces(); ++f) {
114  fpts.resize(cvs->nb_points_of_face(f));
115  for (size_type k=0; k < fpts.size(); ++k)
116  fpts[k] = ipts[cvs->ind_points_of_face(f)[k]];
117  interpolate_face(pgt, m,ptdone,fpts,cvs->faces_structure()[f],
118  nb_vertices, constraints, list_constraints);
119  }
120  }
121 
122  if (noisy) {
123  cout << "ipts.size() = " << ipts.size() << endl;
124  cout << " nb_vertices = " << nb_vertices << endl;
125  }
126 
127  dal::bit_vector cts; size_type cnt = 0;
128  for (size_type i=0; i < ipts.size(); ++i) {
129  // cout << "ipts[i] = " << ipts[i] << endl;
130  if (ipts[i] < nb_vertices) {
131  if (noisy)
132  cout << "point " << i << " coordinates "
133  << m.points()[ipts[i]] << " constraints[ipts[i]] = "
134  << constraints[ipts[i]] << endl;
135  if (cnt == 0) cts = constraints[ipts[i]];
136  else cts &= constraints[ipts[i]];
137  ++cnt;
138  }
139  }
140 
141  if (noisy) cout << "cts = " << cts << endl;
142 
143  if (cts.card()) {
144  // dal::bit_vector new_cts;
145  for (size_type i=0; i < ipts.size(); ++i) {
146  if (ipts[i] >= nb_vertices && !ptdone[ipts[i]]) {
147  base_node P = m.points()[ipts[i]];
148  // if (cts.card() > 1)
149  // cout << "WARNING, projection sur " << cts << endl;
150  if (!pure_multi_constraint_projection(list_constraints, P, cts)) {
151  GMM_WARNING1("Pure multi has failed in interpolate_face !! "
152  "Original point " << m.points()[ipts[i]]
153  << " projection " << P);
154  } else {
155  if (pgt->convex_ref()->is_in(P) > 1E-8) {
156  GMM_WARNING1("Projected point outside the reference convex ! "
157  "Projection canceled. P = " << P);
158  } else m.points()[ipts[i]] = P;
159  }
160  ptdone[ipts[i]] = true;
161  // dist(P, new_cts);
162  }
163  }
164  }
165  }
166 
167 
168  struct point_stock {
169 
170  bgeot::node_tab points;
171  std::vector<dal::bit_vector> constraints_;
172  std::vector<scalar_type> radius_;
173  const std::vector<const mesher_signed_distance*> &list_constraints;
174  scalar_type radius_cv;
175 
176  void clear(void) { points.clear(); constraints_.clear();radius_.clear(); }
177  scalar_type radius(size_type i) const { return radius_[i]; }
178  const dal::bit_vector &constraints(size_type i) const
179  { return constraints_[i]; }
180  size_type size(void) const { return points.size(); }
181  const base_node &operator[](size_type i) const { return points[i]; }
182 
183  size_type add(const base_node &pt, const dal::bit_vector &bv,
184  scalar_type r) {
185  size_type j = points.search_node(pt);
186  if (j == size_type(-1)) {
187  j = points.add_node(pt);
188  constraints_.push_back(bv);
189  radius_.push_back(r);
190  }
191  return j;
192  }
193  size_type add(const base_node &pt, scalar_type r) {
194  size_type j = points.search_node(pt);
195  if (j == size_type(-1)) {
196  dal::bit_vector bv;
197  for (size_type i = 0; i < list_constraints.size(); ++i)
198  if (gmm::abs((*(list_constraints[i]))(pt)) < 1E-8*radius_cv)
199  bv.add(i);
200  j = points.add_node(pt);
201  constraints_.push_back(bv);
202  radius_.push_back(r);
203  }
204  return j;
205  }
206  size_type add(const base_node &pt) {
207  size_type j = points.search_node(pt);
208  if (j == size_type(-1)) {
209  dal::bit_vector bv;
210  for (size_type i = 0; i < list_constraints.size(); ++i)
211  if (gmm::abs((*(list_constraints[i]))(pt)) < 1E-8*radius_cv)
212  bv.add(i);
213  j = points.add_node(pt);
214  constraints_.push_back(bv);
215  scalar_type r = min_curvature_radius_estimate(list_constraints,pt,bv);
216  radius_.push_back(r);
217  }
218  return j;
219  }
220 
221  dal::bit_vector decimate(const mesher_signed_distance &ref_element,
222  scalar_type dmin) const {
223  dal::bit_vector retained_points;
224  if (size() != 0) {
225  size_type n = points[0].size();
226 
227  bgeot::kdtree points_tree;
228  points_tree.reserve(size());
229  for (size_type i = 0; i < size(); ++i)
230  points_tree.add_point_with_id(points[i], i);
231 
232  for (size_type nb_co = n; nb_co != size_type(-1); nb_co --) {
233  for (size_type i = 0; i < size(); ++i) {
234  if (!(retained_points.is_in(i)) &&
235  (constraints(i).card() == nb_co ||
236  (nb_co == n && constraints(i).card() > n)) &&
237  ref_element(points[i]) < 1E-8) {
238  bool kept = true;
239  scalar_type d = (nb_co == 0) ? (dmin * 1.5)
240  : std::min(radius(i)*0.25, dmin);
241  base_node min = points[i], max = min;
242  for (size_type m = 0; m < n; ++m) { min[m]-=d; max[m]+=d; }
244  points_tree.points_in_box(inpts, min, max);
245  for (size_type j = 0; j < inpts.size(); ++j)
246  if (retained_points.is_in(inpts[j].i) &&
247  constraints(inpts[j].i).contains(constraints(i))
248  && gmm::vect_dist2(points[i], points[inpts[j].i]) < d)
249  { kept = false; break; }
250  if (kept) {
251  if (noisy) cout << "kept point : " << points[i] << " co = "
252  << constraints(i) << endl;
253  retained_points.add(i);
254  }
255  }
256  }
257  }
258  }
259  return retained_points;
260  }
261 
262  point_stock(const std::vector<const mesher_signed_distance*> &ls,
263  scalar_type rcv)
264  : points(scalar_type(10000000)), list_constraints(ls),
265  radius_cv(rcv) {}
266  };
267 
268 
269  static pmesher_signed_distance new_ref_element(bgeot::pgeometric_trans pgt) {
270  dim_type n = pgt->structure()->dim();
271  size_type nbp = pgt->basic_structure()->nb_points();
272  /* Identifying simplexes. */
273  if (nbp == size_type(n+1) &&
274  pgt->basic_structure() == bgeot::simplex_structure(n)) {
275  return new_mesher_simplex_ref(n);
276  }
277 
278  /* Identifying parallelepiped. */
279  if (nbp == (size_type(1) << n) &&
280  pgt->basic_structure() == bgeot::parallelepiped_structure(n)) {
281  base_node rmin(n), rmax(n);
282  std::fill(rmax.begin(), rmax.end(), scalar_type(1));
283  return new_mesher_rectangle(rmin, rmax);
284  }
285 
286  /* Identifying prisms. */
287  if (nbp == size_type(2 * n) &&
288  pgt->basic_structure() == bgeot::prism_P1_structure(n)) {
289  return new_mesher_prism_ref(n);
290  }
291 
292  GMM_ASSERT1(false, "This element is not taken into account. Contact us");
293  }
294 
295 
296  struct global_mesh_for_mesh_level_set : public mesh {};
297  static mesh& global_mesh() {
299  }
300 
301  void mesh_level_set::run_delaunay(std::vector<base_node> &fixed_points,
302  gmm::dense_matrix<size_type> &simplexes,
303  std::vector<dal::bit_vector> &
304  /* fixed_points_constraints */) {
305  double t0=gmm::uclock_sec();
306  if (noisy) cout << "running delaunay with " << fixed_points.size()
307  << " points.." << std::flush;
308  bgeot::qhull_delaunay(fixed_points, simplexes);
309  if (noisy) cout << " -> " << gmm::mat_ncols(simplexes)
310  << " simplexes [" << gmm::uclock_sec()-t0 << "sec]\n";
311  }
312 
313  static bool intersects(const mesh_level_set::zone &z1,
314  const mesh_level_set::zone &z2) {
315  for (std::set<const std::string *>::const_iterator it = z1.begin(); it != z1.end();
316  ++it)
317  if (z2.find(*it) != z2.end()) return true;
318  return false;
319  }
320 
321  void mesh_level_set::merge_zoneset(zoneset &zones1,
322  const zoneset &zones2) const {
323  for (std::set<const zone *>::const_iterator it2 = zones2.begin();
324  it2 != zones2.end(); ++it2) {
325  zone z = *(*it2);
326  for (std::set<const zone *>::iterator it1 = zones1.begin();
327  it1 != zones1.end(); ) {
328  if (intersects(z, *(*it1))) {
329  z.insert((*it1)->begin(), (*it1)->end());
330  zones1.erase(it1++);
331  }
332  else ++it1;
333  }
334  zones1.insert(&(*(allzones.insert(z).first)));
335  }
336  }
337 
338  /* recursively replace '0' by '+' and '-', and the add the new zones */
339  static void add_sub_zones_no_zero(std::string &s,
340  mesh_level_set::zone &z,
341  std::set<std::string> &allsubzones) {
342  size_t i = s.find('0');
343  if (i != size_t(-1)) {
344  s[i] = '+'; add_sub_zones_no_zero(s, z, allsubzones);
345  s[i] = '-'; add_sub_zones_no_zero(s, z, allsubzones);
346  } else {
347  z.insert(&(*(allsubzones.insert(s).first)));
348  }
349  }
350 
351  void mesh_level_set::merge_zoneset(zoneset &zones1,
352  const std::string &subz) const {
353  // very sub-optimal
354  zone z; std::string s(subz);
355  add_sub_zones_no_zero(s, z, allsubzones);
356  zoneset zs;
357  zs.insert(&(*(allzones.insert(z).first)));
358  merge_zoneset(zones1, zs);
359  }
360 
361  /* prezone was filled for the whole convex by find_crossing_level_set.
362  This information is now refined for each sub-convex.
363  */
364  void mesh_level_set::find_zones_of_element(size_type cv,
365  std::string &prezone,
366  scalar_type radius) {
367  convex_info &cvi = cut_cv[cv];
368  cvi.zones.clear();
369  for (dal::bv_visitor i(cvi.pmsh->convex_index()); !i.finished();++i) {
370  // If the sub element is too small, the zone is not taken into account
371  if (cvi.pmsh->convex_area_estimate(i) > 1e-8) {
372  std::string subz = prezone;
373  //cout << "prezone for convex " << cv << " : " << subz << endl;
374  for (size_type j = 0; j < level_sets.size(); ++j) {
375  if (subz[j] == '*' || subz[j] == '0') {
376  int s = sub_simplex_is_not_crossed_by(cv, level_sets[j], i,radius);
377  // cout << "sub_simplex_is_not_crossed_by = " << s << endl;
378  subz[j] = (s < 0) ? '-' : ((s > 0) ? '+' : '0');
379  }
380  }
381  merge_zoneset(cvi.zones, subz);
382  }
383  }
384  if (noisy) cout << "Number of zones for convex " << cv << " : "
385  << cvi.zones.size() << endl;
386  }
387 
388 
389  void mesh_level_set::cut_element(size_type cv,
390  const dal::bit_vector &primary,
391  const dal::bit_vector &secondary,
392  scalar_type radius_cv) {
393 
394  cut_cv[cv] = convex_info();
395  cut_cv[cv].pmsh = std::make_shared<mesh>();
396  if (noisy) cout << "cutting element " << cv << endl;
397  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
398  pmesher_signed_distance ref_element = new_ref_element(pgt);
399  std::vector<pmesher_signed_distance> mesher_level_sets;
400 
401  size_type n = pgt->structure()->dim();
402  size_type nbtotls = primary.card() + secondary.card();
403  pintegration_method exactint = classical_exact_im(pgt);
404  GMM_ASSERT1(nbtotls <= 16,
405  "An element is cut by more than 16 level_set, aborting");
406 
407  /*
408  * Step 1 : build the signed distances, estimate the curvature radius
409  * and the degree K.
410  */
411  dim_type K = 0; // Max. degree of the level sets.
412  scalar_type r0 = 1E+10; // min curvature radius
413  std::vector<const mesher_signed_distance*> list_constraints;
414  point_stock mesh_points(list_constraints, radius_cv);
415 
416  ref_element->register_constraints(list_constraints);
417  size_type nbeltconstraints = list_constraints.size();
418  mesher_level_sets.reserve(nbtotls);
419  for (size_type ll = 0; ll < level_sets.size(); ++ll) {
420  if (primary[ll]) {
421  base_node X(n); gmm::fill_random(X);
422  K = std::max(K, (level_sets[ll])->degree());
423  mesher_level_sets.push_back(level_sets[ll]->mls_of_convex(cv, 0));
424  pmesher_signed_distance mls(mesher_level_sets.back());
425  list_constraints.push_back(mesher_level_sets.back().get());
426  r0 = std::min(r0, curvature_radius_estimate(*mls, X, true));
427  GMM_ASSERT1(gmm::abs(r0) >= 1e-13, "Something wrong in your level "
428  "set ... curvature radius = " << r0);
429  if (secondary[ll]) {
430  mesher_level_sets.push_back(level_sets[ll]->mls_of_convex(cv, 1));
431  pmesher_signed_distance mls2(mesher_level_sets.back());
432  list_constraints.push_back(mesher_level_sets.back().get());
433  r0 = std::min(r0, curvature_radius_estimate(*mls2, X, true));
434  }
435  }
436  }
437 
438  /*
439  * Step 2 : projection of points of a grid on each signed distance.
440  */
441  scalar_type h0 = std::min(1./(K+1), 0.2 * r0), dmin = 0.55;
442  bool h0_is_ok = true;
443 
444  do {
445 
446  h0_is_ok = true;
447  mesh_points.clear();
448  scalar_type geps = .001*h0;
449  size_type nbpt = 1;
450  std::vector<size_type> gridnx(n);
451  for (size_type i=0; i < n; ++i)
452  { gridnx[i]=1+(size_type)(1./h0); nbpt *= gridnx[i]; }
453  base_node P(n), Q(n), V(n);
454  dal::bit_vector co;
455  std::vector<size_type> co_v;
456 
457  for (size_type i=0; i < nbpt; ++i) {
458  for (size_type k=0, r = i; k < n; ++k) { // building grid point
459  unsigned p = unsigned(r % gridnx[k]);
460  P[k] = p * scalar_type(1) / scalar_type(gridnx[k]-1);
461  r /= gridnx[k];
462  }
463  co.clear(); co_v.resize(0);
464  if ((*ref_element)(P) < geps) {
465  bool kept = false;
466  for (size_type k=list_constraints.size()-1; k!=size_type(-1); --k) {
467  // for (size_type k=0; k < list_constraints.size(); ++k) {
468  // Rerversed to project on level set before on convex boundaries
469  gmm::copy(P, Q);
470  scalar_type d = list_constraints[k]->grad(P, V);
471  if (gmm::vect_norm2(V)*h0*7 > gmm::abs(d))
472  if (try_projection(*(list_constraints[k]), Q, true)) {
473  if (k >= nbeltconstraints
474  && gmm::vect_dist2(P, Q) < h0 * 3.5) kept = true;
475  if (gmm::vect_dist2(P, Q) < h0 / 1.5) {
476  co.add(k); co_v.push_back(k);
477  if ((*ref_element)(Q) < 1E-8) {
478  scalar_type r =
479  curvature_radius_estimate(*(list_constraints[k]), Q);
480  r0 = std::min(r0, r);
481  if (r0 < 4.*h0) { h0 = 0.2 * r0; h0_is_ok = false; break; }
482  if (k >= nbeltconstraints || kept) mesh_points.add(Q, r);
483  }
484  }
485  }
486  }
487  if (kept) mesh_points.add(P, 1.E10);
488  }
489  size_type nb_co = co.card();
490  dal::bit_vector nn;
491  if (h0_is_ok)
492  for (size_type count = 0; count < (size_type(1) << nb_co); ++count) {
493  nn.clear();
494  for (size_type j = 0; j < nb_co; ++j)
495  if (count & (size_type(1) << j)) nn.add(co_v[j]);
496  if (nn.card() > 1 && nn.card() <= n) {
497  if (noisy) cout << "trying set of constraints" << nn << endl;
498  gmm::copy(P, Q);
499  bool ok=pure_multi_constraint_projection(list_constraints,Q,nn);
500  if (ok && (*ref_element)(Q) < 1E-9) {
501  if (noisy) cout << "Intersection point found " << Q << " with "
502  << nn << endl;
503  mesh_points.add(Q);
504  }
505  }
506  }
507  }
508 
509  if (!h0_is_ok) continue;
510 
511  /*
512  * Step 3 : Delaunay, test if a simplex cut a level set and adapt
513  * the mesh to the curved level sets.
514  */
515 
516  dmin = h0;
517  if (noisy) cout << "dmin = " << dmin << " h0 = " << h0 << endl;
518  if (noisy) cout << "convex " << cv << endl;
519 
520  dal::bit_vector retained_points
521  = mesh_points.decimate(*ref_element, dmin);
522 
523  bool delaunay_again = true;
524 
525  std::vector<base_node> fixed_points;
526  std::vector<dal::bit_vector> fixed_points_constraints;
527  mesh &msh(*(cut_cv[cv].pmsh));
528 
529  mesh_region &ls_border_faces(cut_cv[cv].ls_border_faces);
530  std::vector<base_node> cvpts;
531 
532  size_type nb_delaunay = 0;
533 
534  while (delaunay_again) {
535  if (++nb_delaunay > 15)
536  { h0_is_ok = false; h0 /= 2.0; dmin = 2.*h0; break; }
537 
538  fixed_points.resize(0);
539  fixed_points_constraints.resize(0);
540  // std::vector<base_node> fixed_points;
541  // std::vector<dal::bit_vector> fixed_points_constraints;
542  fixed_points.reserve(retained_points.card());
543  fixed_points_constraints.reserve(retained_points.card());
544  for (dal::bv_visitor i(retained_points); !i.finished(); ++i) {
545  fixed_points.push_back(mesh_points[i]);
546  fixed_points_constraints.push_back(mesh_points.constraints(i));
547  }
548 
549  gmm::dense_matrix<size_type> simplexes;
550  run_delaunay(fixed_points, simplexes, fixed_points_constraints);
551  delaunay_again = false;
552 
553  msh.clear();
554 
555  for (size_type i = 0; i < fixed_points.size(); ++i) {
556  size_type j = msh.add_point(fixed_points[i]);
557  assert(j == i);
558  }
559 
560  cvpts.resize(0);
561  for (size_type i = 0; i < gmm::mat_ncols(simplexes); ++i) {
562  size_type j = msh.add_convex(bgeot::simplex_geotrans(n,1),
563  gmm::vect_const_begin(gmm::mat_col(simplexes, i)));
564  /* remove flat convexes => beware the final mesh may not be conformal ! */
565  if (msh.convex_quality_estimate(j) < 1E-10) msh.sup_convex(j);
566  else {
567  std::vector<scalar_type> signs(list_constraints.size());
568  std::vector<size_type> prev_point(list_constraints.size());
569  for (size_type ii = 0; ii <= n; ++ii) {
570  for (size_type jj = 0; jj < list_constraints.size(); ++jj) {
571  scalar_type dd =
572  (*(list_constraints[jj]))(msh.points_of_convex(j)[ii]);
573  if (gmm::abs(dd) > radius_cv * 1E-7) {
574  if (dd * signs[jj] < 0.0) {
575  if (noisy) cout << "Intersection found ... " << jj
576  << " dd = " << dd << " convex quality = "
577  << msh.convex_quality_estimate(j) << "\n";
578  // calcul d'intersection
579  base_node X = msh.points_of_convex(j)[ii], G;
580  base_node VV = msh.points_of_convex(j)[prev_point[jj]] - X;
581  if (dd > 0.) gmm::scale(VV, -1.);
582  dd = (*(list_constraints[jj])).grad(X, G);
583  size_type nbit = 0;
584  while (gmm::abs(dd) > 1e-16*radius_cv && (++nbit < 20)) { // Newton
585  scalar_type nG = gmm::vect_sp(G, VV);
586  if (gmm::abs(nG) < 1E-8) nG = 1E-8;
587  if (nG < 0) nG = 1.0;
588  gmm::add(gmm::scaled(VV, -dd / nG), X);
589  dd = (*(list_constraints[jj])).grad(X, G);
590  }
591  if (gmm::abs(dd) > 1e-16*radius_cv) { // brute force dychotomy
592  base_node X1 = msh.points_of_convex(j)[ii];
593  base_node X2 = msh.points_of_convex(j)[prev_point[jj]], X3;
594  scalar_type dd1 = (*(list_constraints[jj]))(X1);
595  scalar_type dd2 = (*(list_constraints[jj]))(X2);
596  if (dd1 > dd2) { std::swap(dd1, dd2); std::swap(X1, X2); }
597  while (gmm::abs(dd1) > 1e-15*radius_cv) {
598  X3 = (X1 + X2) / 2.0;
599  scalar_type dd3 = (*(list_constraints[jj]))(X3);
600  if (dd3 == dd1 || dd3 == dd2) break;
601  if (dd3 > 0) { dd2 = dd3; X2 = X3; }
602  else { dd1 = dd3; X1 = X3; }
603  }
604  X = X1;
605  }
606 
607  size_type kk = mesh_points.add(X);
608  if (!(retained_points[kk])) {
609  retained_points.add(kk);
610  delaunay_again = true;
611  break;
612  // goto delaunay_fin;
613  }
614  }
615  if (signs[jj] == 0.0) { signs[jj] = dd; prev_point[jj] = ii; }
616  }
617  }
618  }
619  }
620  }
621 
622  // delaunay_fin :;
623 
624  }
625  if (!h0_is_ok) continue;
626 
627  // Produces an order K mesh for K > 1 (with affine element for the moment)
628  if (K>1) {
629  for (dal::bv_visitor_c j(msh.convex_index()); !j.finished(); ++j) {
630  bgeot::pgeometric_trans pgt2 = bgeot::simplex_geotrans(n, K);
631  cvpts.resize(pgt2->nb_points());
632  for (size_type k=0; k < pgt2->nb_points(); ++k) {
633  cvpts[k] = bgeot::simplex_geotrans(n,1)->transform
634  (pgt2->convex_ref()->points()[k], msh.points_of_convex(j));
635  }
636  msh.sup_convex(j);
637  /* some new point will be added to the mesh, but the initial ones
638  (those on the convex vertices) are kepts */
639  size_type jj = msh.add_convex_by_points(pgt2, cvpts.begin());
640  assert(jj == j);
641  }
642  }
643 
644  if (noisy) {
646  sl.build(msh, getfem::slicer_none(), 1);
647  char s[512]; snprintf(s, 511, "totobefore%d.dx", int(cv));
648  getfem::dx_export exp(s);
649  exp.exporting(sl);
650  exp.exporting_mesh_edges();
651  exp.write_mesh();
652  }
653 
654  /* detect the faces lying on level_set boundaries
655  (not exact, some other faces maybe be found, use this only for vizualistion) */
656  for (dal::bv_visitor i(msh.convex_index()); !i.finished(); ++i) {
657  for (short_type f = 0; f <= n; ++f) {
658  const mesh::ind_pt_face_ct &fpts
659  = msh.ind_points_of_face_of_convex(i, f);
660 
661  dal::bit_vector cts; bool first = true;
662  for (unsigned k=0; k < fpts.size(); ++k) {
663  if (fpts[k] >= fixed_points_constraints.size()) {
664  assert(K>1);
665  continue; /* ignore additional point inserted when K>1 */
666  }
667  if (first) { cts = fixed_points_constraints[fpts[k]]; first=false; }
668  else cts &= fixed_points_constraints[fpts[k]];
669  }
670  for (dal::bv_visitor ii(cts); !ii.finished(); ++ii) {
671  if (ii >= nbeltconstraints)
672  ls_border_faces.add(i, f);
673  }
674  }
675  }
676 
677 
678  if (K > 1) { // To be done only on the level-set ...
679  dal::bit_vector ptdone;
680  std::vector<size_type> ipts;
681  // for (mr_visitor icv(ls_border_faces); !icv.finished(); ++icv) {
682  // size_type i = icv.cv();
683  // short_type f = icv.f();
684  for (dal::bv_visitor i(msh.convex_index()); !i.finished(); ++i) {
685  for (short_type f = 0; f <= n; ++f) {
686  const mesh::ind_pt_face_ct &fpts
687  = msh.ind_points_of_face_of_convex(i, f);
688  ipts.assign(fpts.begin(), fpts.end());
689 #ifdef DEBUG_LS
690  interpolate_face_chrono.tic();
691 #endif
692 
693  interpolate_face(pgt, msh, ptdone, ipts,
694  msh.trans_of_convex(i)->structure()
695  ->faces_structure()[f], fixed_points.size(),
696  fixed_points_constraints, list_constraints);
697 #ifdef DEBUG_LS
698  interpolate_face_chrono.toc();
699 #endif
700  }
701  }
702  }
703 
704  if (noisy) {
706  sl.build(msh, getfem::slicer_none(), 12);
707  char s[512]; snprintf(s, 511, "toto%d.dx", int(cv));
708  getfem::dx_export exp(s);
709  exp.exporting(sl);
710  exp.exporting_mesh_edges();
711  exp.write_mesh();
712  }
713 
714  /*
715  * Step 4 : Building the new integration method.
716  */
717  base_matrix G;
718  bgeot::pgeometric_trans pgt2 = bgeot::simplex_geotrans(n, K);
719  papprox_integration
720  pai = classical_approx_im(pgt2,dim_type(2*K))->approx_method();
721  auto new_approx = std::make_shared<approx_integration>(pgt->convex_ref());
722  base_matrix KK(n,n), CS(n,n);
723  base_matrix pc(pgt2->nb_points(), n);
724  for (dal::bv_visitor i(msh.convex_index()); !i.finished(); ++i) {
725  vectors_to_base_matrix(G, msh.points_of_convex(i));
726  bgeot::geotrans_interpolation_context c(msh.trans_of_convex(i),
727  pai->point(0), G);
728  scalar_type sign = 0.0;
729  for (size_type j = 0; j < pai->nb_points_on_convex(); ++j) {
730  c.set_xref(pai->point(j));
731  pgt2->poly_vector_grad(pai->point(j), pc);
732  gmm::mult(G,pc,KK);
733  scalar_type J = gmm::lu_det(KK);
734  if (noisy && J * sign < 0) {
735  cout << "CAUTION reversal situation in convex " << i
736  << "sign = " << sign << " J = " << J << endl;
737  for (size_type nip = 0; nip < msh.nb_points_of_convex(i); ++nip)
738  cout << "Point " << nip << "=" << msh.points_of_convex(i)[nip]
739  << " ";
740  cout << endl;
741  }
742  if (sign == 0 && gmm::abs(J) > 1E-14) sign = J;
743  new_approx->add_point(c.xreal(), pai->coeff(j) * gmm::abs(J));
744  }
745  }
746 
747  getfem::mesh_region border_faces;
748  getfem::outer_faces_of_mesh(msh, border_faces);
749  for (getfem::mr_visitor it(border_faces); !it.finished(); ++it) {
750  vectors_to_base_matrix(G, msh.points_of_convex(it.cv()));
751  bgeot::geotrans_interpolation_context c(msh.trans_of_convex(it.cv()),
752  pai->point(0), G);
753  for (size_type j = 0; j < pai->nb_points_on_face(it.f()); ++j) {
754  c.set_xref(pai->point_on_face(it.f(), j));
755  new_approx->add_point(c.xreal(), pai->coeff_on_face(it.f(), j)
756  * gmm::abs(c.J()), it.f() /* faux */);
757  }
758  }
759  new_approx->valid_method();
760 
761  /*
762  * Step 5 : Test the validity of produced integration method.
763  */
764 
765  scalar_type error = test_integration_error(new_approx, 1);
766  if (noisy) cout << " max monomial integration err: " << error << "\n";
767  if (error > 1e-5) {
768  if (noisy) cout << "Not Good ! Let us make a finer cut.\n";
769  if (dmin > 3*h0) { dmin /= 2.; }
770  else { h0 /= 2.0; dmin = 2.*h0; }
771  h0_is_ok = false;
772  }
773 
774 
775  if (h0_is_ok && noisy) { // ajout dans global mesh pour visu
776  vectors_to_base_matrix(G, linked_mesh().points_of_convex(cv));
777  std::vector<size_type> pts(msh.nb_points());
778  for (size_type i = 0; i < msh.nb_points(); ++i)
779  pts[i] = global_mesh().add_point(pgt->transform(msh.points()[i], G));
780 
781  for (dal::bv_visitor i(msh.convex_index()); !i.finished(); ++i)
782  global_mesh().add_convex(msh.trans_of_convex(i),
783  gmm::index_ref_iterator(pts.begin(),
784  msh.ind_points_of_convex(i).begin()));
785  }
786 
787  } while (!h0_is_ok);
788 
789 #ifdef DEBUG_LS
790  cout << "Interpolate face: " << interpolate_face_chrono.total()
791  << " moyenne: " << interpolate_face_chrono.mean() << "\n";
792 #endif
793  }
794 
795 
797  m.clear();
798  base_matrix G;
799  for (dal::bv_visitor cv(linked_mesh().convex_index());
800  !cv.finished(); ++cv) {
801  if (is_convex_cut(cv)) {
802  const convex_info &ci = (cut_cv.find(cv))->second;
803  mesh &msh = *(ci.pmsh);
804  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
805  vectors_to_base_matrix(G, linked_mesh().points_of_convex(cv));
806  std::vector<size_type> pts(msh.nb_points());
807  for (size_type i = 0; i < msh.nb_points(); ++i)
808  pts[i] = m.add_point(pgt->transform(msh.points()[i], G));
809 
810  std::vector<size_type> ic2(msh.nb_allocated_convex());
811 
812  for (dal::bv_visitor i(msh.convex_index()); !i.finished(); ++i) {
813  ic2[i] = m.add_convex(msh.trans_of_convex(i),
814  gmm::index_ref_iterator(pts.begin(),
815  msh.ind_points_of_convex(i).begin()));
816 
817  }
818  for (mr_visitor i(ci.ls_border_faces); !i.finished(); ++i) {
819  m.region(0).add(ic2[i.cv()], i.f());
820  }
821 
822  } else {
823  m.add_convex_by_points(linked_mesh().trans_of_convex(cv),
824  linked_mesh().points_of_convex(cv).begin());
825  }
826  }
827 
828 
829  }
830 
831  void mesh_level_set::update_crack_tip_convexes() {
832  crack_tip_convexes_.clear();
833 
834  for (std::map<size_type, convex_info>::const_iterator it = cut_cv.begin();
835  it != cut_cv.end(); ++it) {
836  size_type cv = it->first;
837  mesh &msh = *(it->second.pmsh);
838  for (unsigned ils = 0; ils < nb_level_sets(); ++ils) {
839  if (get_level_set(ils)->has_secondary()) {
840  pmesher_signed_distance
841  mesherls0 = get_level_set(ils)->mls_of_convex(cv, 0, false);
842  pmesher_signed_distance
843  mesherls1 = get_level_set(ils)->mls_of_convex(cv, 1, false);
844  for (dal::bv_visitor ii(msh.convex_index()); !ii.finished(); ++ii) {
845  for (unsigned ipt = 0; ipt < msh.nb_points_of_convex(ii); ++ipt) {
846  if (gmm::abs((*mesherls0)(msh.points_of_convex(ii)[ipt])) < 1E-10
847  && gmm::abs((*mesherls1)(msh.points_of_convex(ii)[ipt])) < 1E-10) {
848  crack_tip_convexes_.add(cv);
849  goto next_convex;
850  }
851  }
852  }
853  }
854  }
855  next_convex:
856  ;
857  }
858  }
859 
861 
862  // compute the elements touched by each level set
863  // for each element touched, compute the sub mesh
864  // then compute the adapted integration method
865  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_level_set");
866  cut_cv.clear();
867  allsubzones.clear();
868  zones_of_convexes.clear();
869  allzones.clear();
870 
871  // noisy = true;
872 
873  std::string z;
874  for (dal::bv_visitor cv(linked_mesh().convex_index());
875  !cv.finished(); ++cv) {
876  scalar_type radius = linked_mesh().convex_radius_estimate(cv);
877  dal::bit_vector prim, sec;
878  find_crossing_level_set(cv, prim, sec, z, radius);
879  zones_of_convexes[cv] = &(*(allsubzones.insert(z).first));
880  if (noisy) cout << "element " << cv << " cut level sets : "
881  << prim << " zone : " << z << endl;
882  if (prim.card()) {
883  cut_element(cv, prim, sec, radius);
884  find_zones_of_element(cv, z, radius);
885  }
886  }
887  if (noisy) {
889  sl.build(global_mesh(), getfem::slicer_none(), 6);
890  getfem::dx_export exp("totoglob.dx");
891  exp.exporting(sl);
892  exp.exporting_mesh_edges();
893  exp.write_mesh();
894  }
895 
896  update_crack_tip_convexes();
897  is_adapted_ = true;
898  }
899 
900  // detect the intersection of two or more level sets and the convexes
901  // where the intersection occurs. To be alled after adapt.
902  void mesh_level_set::find_level_set_potential_intersections
903  (std::vector<size_type> &icv, std::vector<dal::bit_vector> &ils) {
904 
905  GMM_ASSERT1(linked_mesh_ != 0, "Uninitialized mesh_level_set");
906  std::string z;
907  for (dal::bv_visitor cv(linked_mesh().convex_index());
908  !cv.finished(); ++cv)
909  if (is_convex_cut(cv)) {
910  scalar_type radius = linked_mesh().convex_radius_estimate(cv);
911  dal::bit_vector prim, sec;
912  find_crossing_level_set(cv, prim, sec, z, radius);
913  if (prim.card() > 1) {
914  icv.push_back(cv);
915  ils.push_back(prim);
916  }
917  }
918  }
919 
920  // return +1 if the sub-element is on the one side of the level-set
921  // -1 if the sub-element is on the other side of the level-set
922  // 0 if the sub-element is one the positive part of the secundary
923  // level-set if any.
924  int mesh_level_set::sub_simplex_is_not_crossed_by(size_type cv,
925  plevel_set ls,
926  size_type sub_cv,
927  scalar_type radius) {
928  scalar_type EPS = 1e-7 * radius;
929  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
930  convex_info &cvi = cut_cv[cv];
931  bgeot::pgeometric_trans pgt2 = cvi.pmsh->trans_of_convex(sub_cv);
932 
933  // cout << "cv " << cv << " radius = " << radius << endl;
934 
935  pmesher_signed_distance mls0 = ls->mls_of_convex(cv, 0), mls1(mls0);
936  if (ls->has_secondary()) mls1 = ls->mls_of_convex(cv, 1);
937  int p = 0;
938  bool is_cut = false;
939  scalar_type d2 = 0, d1 = 1, d0 = 0, d0min = 0;
940  for (size_type i = 0; i < pgt2->nb_points(); ++i) {
941  d0 = (*mls0)(cvi.pmsh->points_of_convex(sub_cv)[i]);
942  if (i == 0) d0min = gmm::abs(d0);
943  else d0min = std::min(d0min, gmm::abs(d0));
944  if (ls->has_secondary())
945  d1 = std::min(d1, (*mls1)(cvi.pmsh->points_of_convex(sub_cv)[i]));
946 
947  int p2 = ( (d0 < -EPS) ? -1 : ((d0 > EPS) ? +1 : 0));
948  if (p == 0) p = p2;
949  if (gmm::abs(d0) > gmm::abs(d2)) d2 = d0;
950  if (!p2 || p*p2 < 0) is_cut = true;
951  }
952  // cout << "d0min = " << d0min << " d1 = " << d1 << " iscut = "
953  // << is_cut << endl;
954  if (is_cut && ls->has_secondary() && d1 >= -radius*0.0001) return 0;
955  // if (d0min < EPS && ls->has_secondary() && d1 >= -EPS) return 0;
956  return (d2 < 0.) ? -1 : 1;
957  }
958 
959  int mesh_level_set::is_not_crossed_by(size_type cv, plevel_set ls,
960  unsigned lsnum, scalar_type radius) {
961  const mesh_fem &mf = ls->get_mesh_fem();
962  GMM_ASSERT1(!mf.is_reduced(), "Internal error");
963  const mesh_fem::ind_dof_ct &dofs = mf.ind_basic_dof_of_element(cv);
964  pfem pf = mf.fem_of_element(cv);
965  int p = -2;
966  scalar_type EPS = 1e-8 * radius;
967 
968  /* easy cases:
969  - different sign on the dof nodes => intersection for sure
970  - min value of the levelset greater than the radius of the convex
971  => no intersection
972  */
973  for (mesh_fem::ind_dof_ct::const_iterator it=dofs.begin();
974  it != dofs.end(); ++it) {
975  scalar_type v = ls->values(lsnum)[*it];
976  int p2 = ( (v < -EPS) ? -1 : ((v > EPS) ? +1 : 0));
977  if (p == -2) p=p2;
978  if (!p2 || p*p2 < 0) return 0;
979  }
980 
981  pmesher_signed_distance mls1 = ls->mls_of_convex(cv, lsnum, false);
982  base_node X(pf->dim()), G(pf->dim());
983  gmm::fill_random(X); X *= 1E-2;
984  scalar_type d = mls1->grad(X, G);
985  if (gmm::vect_norm2(G)*2.5 < gmm::abs(d)) return p;
986 
987  bgeot::pgeometric_trans pgt = linked_mesh().trans_of_convex(cv);
988  pmesher_signed_distance ref_element = new_ref_element(pgt);
989 
990  gmm::fill_random(X); X *= 1E-2;
991  mesher_intersection mi1(ref_element, mls1);
992  if (!try_projection(mi1, X)) return p;
993  if ((*ref_element)(X) > 1E-8) return p;
994 
995  gmm::fill_random(X); X *= 1E-2;
996  pmesher_signed_distance mls2 = ls->mls_of_convex(cv, lsnum, true);
997  mesher_intersection mi2(ref_element, mls2);
998  if (!try_projection(mi2, X)) return p;
999  if ((*ref_element)(X) > 1E-8) return p;
1000 
1001  return 0;
1002  }
1003 
1004  void mesh_level_set::find_crossing_level_set(size_type cv,
1005  dal::bit_vector &prim,
1006  dal::bit_vector &sec,
1007  std::string &z,
1008  scalar_type radius) {
1009  prim.clear(); sec.clear();
1010  z = std::string(level_sets.size(), '*');
1011  unsigned lsnum = 0;
1012  for (size_type k = 0; k < level_sets.size(); ++k, ++lsnum) {
1013  if (noisy) cout << "testing cv " << cv << " with level set "
1014  << k << endl;
1015  int s = is_not_crossed_by(cv, level_sets[k], 0, radius);
1016  if (!s) {
1017  if (noisy) cout << "is cut \n";
1018  if (level_sets[k]->has_secondary()) {
1019  s = is_not_crossed_by(cv, level_sets[k], 1, radius);
1020  if (!s) { sec.add(lsnum); prim.add(lsnum); }
1021  else if (s < 0) prim.add(lsnum); else z[k] = '0';
1022  }
1023  else prim.add(lsnum);
1024  }
1025  else z[k] = (s < 0) ? '-' : '+';
1026  }
1027  }
1028 
1029 
1030 } /* end of namespace getfem. */
1031 
1032 
1033 
the geotrans_interpolation_context structure is passed as the argument of geometric transformation in...
Balanced tree over a set of points.
Definition: bgeot_kdtree.h:101
void add_point_with_id(const base_node &n, size_type i)
insert a new point, with an associated number.
Definition: bgeot_kdtree.h:119
short_type nb_points_of_convex(size_type ic) const
Return the number of points of convex ic.
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.
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.
Store a set of points, identifying points that are nearer than a certain very small distance.
void clear()
reset the array, remove all points
size_type search_node(const base_node &pt, const scalar_type radius=0) const
Search a node in the array.
size_type add_node(const base_node &pt, const scalar_type radius=0, bool remove_duplicated_nodes=true)
Add a point to the array or use an existing point, located within a distance smaller than radius.
void clear(void)
Clear and desallocate all the elements.
Definition: dal_basic.h:303
static T & instance()
Instance from the current thread.
A (quite large) class for exportation of data to IBM OpenDX.
void exporting_mesh_edges(bool with_slice_edge=true)
append edges information (if you want to draw the mesh and are using a refined slice.
void global_cut_mesh(mesh &m) const
fill m with the (non-conformal) "cut" mesh.
size_type nb_level_sets(void) const
Get number of level-sets referenced in this object.
void adapt(void)
do all the work (cut the convexes wrt the levelsets)
mesh & linked_mesh(void) const
Gives a reference to the linked mesh of type mesh.
"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
virtual scalar_type convex_radius_estimate(size_type ic) const
Return an estimate of the convex largest dimension.
Definition: getfem_mesh.cc:460
size_type nb_points() const
Give the number of geometrical nodes in the mesh.
Definition: getfem_mesh.h:193
const mesh_region region(size_type id) const
Return the region of index 'id'.
Definition: getfem_mesh.h:420
size_type add_convex(bgeot::pgeometric_trans pgt, ITER ipts)
Add a convex to the mesh.
Definition: getfem_mesh.h:225
void clear()
Erase the mesh.
Definition: getfem_mesh.cc:272
This slicer does nothing.
The output of a getfem::mesh_slicer which has been recorded.
void build(const getfem::mesh &m, const slicer_action &a, size_type nrefine=1)
Build the slice, by applying a slicer_action operation.
Keep informations about a mesh crossed by level-sets.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
void fill_random(L &l)
fill a vector or matrix with random value (uniform [-1,1]).
Definition: gmm_blas.h:129
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1663
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*‍/
Definition: gmm_blas.h:263
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1275
linalg_traits< DenseMatrixLU >::value_type lu_det(const DenseMatrixLU &LU, const Pvector &pvector)
Compute the matrix determinant (via a LU factorization)
Definition: gmm_dense_lu.h:240
size_type add_convex_by_points(bgeot::pgeometric_trans pgt, ITER ipts, const scalar_type tol=scalar_type(0))
Add a convex to the mesh, given a geometric transformation and a list of point coordinates.
Definition: getfem_mesh.h:557
void APIDECL outer_faces_of_mesh(const mesh &m, const dal::bit_vector &cvlst, convex_face_ct &flist)
returns a list of "exterior" faces of a mesh (i.e.
Definition: getfem_mesh.cc:821
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:243
std::vector< index_node_pair > kdtree_tab_type
store a set of points with associated indexes.
Definition: bgeot_kdtree.h:67
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
std::ostream & operator<<(std::ostream &o, const convex_structure &cv)
Print the details of the convex structure cvs to the output stream o.
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
pconvex_structure parallelepiped_structure(dim_type nc, dim_type k)
Give a pointer on the structures of a parallelepiped of dimension d.
pconvex_structure prism_P1_structure(dim_type nc)
Give a pointer on the structures of a prism of dimension d.
pconvex_structure simplex_structure(dim_type nc)
Give a pointer on the structures of a simplex of dimension d.
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.
pintegration_method classical_approx_im(bgeot::pgeometric_trans pgt, dim_type degree)
try to find an approximate integration method for the geometric transformation pgt which is able to i...
pintegration_method classical_exact_im(bgeot::pgeometric_trans pgt)
return an exact integration method for convex type handled by pgt.