Welcome to the NetCologne GmbH open source mirroring service!

This machine mirrors various open-source projects. 20 Gbit/s uplink.

If there are any issues or you want another project mirrored, please contact mirror-service -=AT=- netcologne DOT de !

GetFEM: src/getfem_mesher.cc Source File
GetFEM  5.5
getfem_mesher.cc
1 /*===========================================================================
2 
3  Copyright (C) 2004-2026 Julien Pommier, Yves Renard
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program. If not, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
21 #include "getfem/getfem_mesher.h"
22 
23 namespace getfem {
24 
25  void mesher_level_set::init_grad(void) const {
26  gradient.resize(base.dim());
27  for (dim_type d=0; d < base.dim(); ++d) {
28  gradient[d] = base; gradient[d].derivative(d);
29  }
30  initialized = 1;
31  }
32 
33  void mesher_level_set::init_hess(void) const {
34  if (initialized < 1) init_grad();
35  hessian.resize(base.dim()*base.dim());
36  for (dim_type d=0; d < base.dim(); ++d) {
37  for (dim_type e=0; e < base.dim(); ++e) {
38  hessian[d*base.dim()+e] = gradient[d];
39  hessian[d*base.dim()+e].derivative(e);
40  }
41  }
42  initialized = 2;
43  }
44 
45  scalar_type mesher_level_set::grad(const base_node &P,
46  base_small_vector &G) const {
47  if (initialized < 1) init_grad();
48  gmm::resize(G, P.size());
49  for (size_type i = 0; i < P.size(); ++i)
50  G[i] = bgeot::to_scalar(gradient[i].eval(P.begin()));
51  return (*this)(P);
52  }
53 
54  void mesher_level_set::hess(const base_node &P, base_matrix &H) const {
55  if (initialized < 2) init_hess();
56  gmm::resize(H, P.size(), P.size());
57  for (size_type i = 0; i < base.dim(); ++i)
58  for (size_type j = 0; j < base.dim(); ++j) {
59  H(i,j) = bgeot::to_scalar(hessian[i*P.size()+j].eval(P.begin()));
60  }
61  }
62 
63 
64  //
65  // Exported functions
66  //
67 
68  bool try_projection(const mesher_signed_distance& dist, base_node &X,
69  bool on_surface) {
70  base_small_vector G; base_node Y = X;
71  scalar_type d = dist.grad(X, G), dmin = gmm::abs(d);
72  size_type iter(0), count_falt(0);
73  if (on_surface || d > 0.0)
74  while (iter == 0 || dmin > 1e-15 || gmm::vect_dist2(X, Y) > 1e-15 ) {
75  gmm::copy(X, Y);
76  if (++iter > 1000) {
77  GMM_WARNING4("Try projection failed, 1000 iterations\n\n");
78  return false;
79  // return (gmm::abs(d) < 1E-10); // is there a possibility to detect
80  } // the impossibility without making 1000 iterations ?
81  gmm::scale(G, -d / std::max(1E-8, gmm::vect_norm2_sqr(G)));
82  gmm::add(G, X);
83 // scalar_type alpha(1);
84 // scalar_type dn = dist(X);
85 // while (0 && gmm::abs(dn) > 2. * gmm::abs(d) && alpha > 0.1) {
86 // alpha /= 2;
87 // gmm::add(gmm::scaled(G, -alpha), X);
88 // dn = dist(X);
89 // }
90 // if (gmm::abs(alpha) < 1E-15) return (gmm::abs(d) < 1E-10);
91  d = dist.grad(X, G);
92  if (gmm::abs(d) >= dmin*0.95) ++count_falt;
93  else { count_falt = 0; dmin = gmm::abs(d); }
94  // if (count_falt > 20) return (gmm::abs(d) < 1E-10);
95  if (count_falt > 20) return false;
96  }
97  return true;
98  }
99 
100  // Try to find an intersection of a set of signed distance d_i.
101  // Newton method on v solution to d_i(X+Gv) = 0, where the column of
102  // G are the gradients of d_i.
103  bool pure_multi_constraint_projection
104  (const std::vector<const mesher_signed_distance*> &list_constraints,
105  base_node &X, const dal::bit_vector &cts) {
106  size_type nbco = cts.card(), i(0), info, N = X.size();
107  if (!nbco) return true;
108  // cout << "nbco = " << nbco << endl;
109  std::vector<const mesher_signed_distance*> ls(nbco);
110  std::vector<scalar_type> d(nbco), v(nbco);
111  gmm::lapack_ipvt ipvt(nbco);
112  gmm::col_matrix<base_node> G(N, nbco);
113  gmm::dense_matrix<scalar_type> H(nbco, nbco);
114  base_small_vector dd(N);
115  for (dal::bv_visitor ic(cts); !ic.finished(); ++ic, ++i)
116  { ls[i] = list_constraints[ic]; d[i] = -(ls[i]->grad(X, G[i])); }
117  base_node oldX, aux(N);
118  size_type iter = 0;
119  scalar_type residual(0), alpha(0), det(0);
120 
121  if (nbco == 1) {
122  // cout << "one constraint" << endl;
123  try_projection(*(ls[0]), X, true);
124  d[0] = -(ls[0]->grad(X, G[0]));
125  } else {
126  do {
127  oldX = X;
128  det = scalar_type(0); info = 1;
129  alpha = -scalar_type(1);
130 
131  if (nbco <= N) {
132  if (nbco < N)
133  gmm::mult(gmm::transposed(G), G, H);
134  else
135  gmm::copy(gmm::transposed(G), H);
136  // cout << "H = " << H << endl;
137  info = gmm::lu_factor(H, ipvt);
138  det = scalar_type(1);
139  for (i = 0; i < nbco; ++i) det *= H(i,i);
140  }
141  // cout << "G = " << G << endl;
142 
143  if (info || gmm::abs(det) < 1E-20) {
144  dal::bit_vector cts_red = cts;
145  int eliminated = 0;
146  i = 0;
147  for (dal::bv_visitor ic(cts); !ic.finished(); ++ic, ++i) {
148  for (size_type j = 0; j < i; ++j)
149  gmm::add(gmm::scaled(G[j], -gmm::vect_sp(G[j], G[i])), G[i]);
150  scalar_type norm_gi = gmm::vect_norm2(G[i]);
151  // cout << "norm_gi = " << norm_gi << endl;
152  if (norm_gi < 1E-10)
153  { cts_red[ic] = false; eliminated++; }
154  else
155  gmm::scale(G[i], scalar_type(1)/norm_gi);
156  }
157  // cout << "G after = " << G << endl;
158  if (eliminated >= 1) {
159  // cout << "rec call with " << eliminated << " eliminated constraints" << endl;
160  pure_multi_constraint_projection(list_constraints, X, cts_red);
161  for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
162 
163  det = scalar_type(0); info = 1;
164  if (nbco <= N) {
165  if (nbco < N)
166  gmm::mult(gmm::transposed(G), G, H);
167  else
168  gmm::copy(G, H);
169  info = gmm::lu_factor(H, ipvt);
170  det = scalar_type(1);
171  for (i = 0; i < nbco; ++i) det *= H(i,i);
172  }
173 
174  }
175  }
176 
177  if (gmm::vect_norm2(d) > 1e-11) {
178  if (info || gmm::abs(det) < 1E-20) {
179  for (i = 0; i < nbco; ++i)
180  try_projection(*(ls[i]), X, true);
181  for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
182  }
183  else {
184  gmm::lu_solve(H, ipvt, v, d);
185  if (nbco < N)
186  gmm::mult(G, v, dd);
187  else
188  gmm::copy(v, dd);
189  GMM_ASSERT1(nbco <= N, "internal error");
190  gmm::add(dd, X);
191  for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
192  alpha = scalar_type(1);
193  if (iter > 0)
194  while (gmm::vect_norm2(d) > residual && alpha > 1E-10) {
195  alpha /= scalar_type(2);
196  gmm::add(gmm::scaled(dd, -alpha), X);
197  for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
198  }
199  if (alpha < 1E-15) break;
200  }
201  }
202 
203  ++iter;
204  residual = gmm::vect_norm2(d);
205  // cout << "residual = " << residual << " alpha = " << alpha;
206  // cout << " gmm::vect_dist2(oldX,X) = " << gmm::vect_dist2(oldX,X) << endl;
207  } while (residual > 1e-14 && (residual > 1e-11 || iter < 15)
208  && iter < 200);
209  // cout << "final residual = " << residual << endl;
210  }
211  for (i = 0; i < nbco; ++i) if (gmm::abs(d[i]) > SEPS) {
212  //cout << "PURE MULTI HAS FAILED for " << cts << " nb iter = " << iter << endl;
213  return false;
214  }
215  return true;
216  }
217 
218 
219 
220 
221  // return the eigenvalue of maximal abolute value for a
222  // symmetric base_matrix
223  static scalar_type max_vp(const base_matrix& M) {
224  size_type m = mat_nrows(M);
225  GMM_ASSERT1(is_hermitian(M), "Matrix is not symmetric");
226  std::vector<scalar_type> eig(m);
227  gmm::symmetric_qr_algorithm(M, eig);
228  scalar_type emax(0);
229  for (size_type i = 0; i < m; ++i) emax = std::max(emax, gmm::abs(eig[i]));
230  return emax;
231  }
232 
233  scalar_type curvature_radius_estimate(const mesher_signed_distance &dist,
234  base_node X, bool proj) {
235  if (proj) try_projection(dist, X, true);
236  base_small_vector V;
237  base_matrix H;
238  dist.grad(X, V);
239  dist.hess(X, H);
240  return gmm::vect_norm2(V) / std::max(1E-10, max_vp(H));
241  }
242 
243  scalar_type min_curvature_radius_estimate
244  (const std::vector<const mesher_signed_distance*> &list_constraints,
245  const base_node &X, const dal::bit_vector &cts, size_type hide_first) {
246  scalar_type r0 = 1E+10;
247  for (dal::bv_visitor j(cts); !j.finished(); ++j)
248  if (j >= hide_first) {
249  scalar_type r
250  = curvature_radius_estimate(*(list_constraints[j]), X);
251  r0 = std::min(r, r0);
252  }
253  return r0;
254  }
255 
256 
257  //
258  // local functions
259  //
260 
261 
262  template <typename MAT, typename MAT2> void
263  Frobenius_condition_number_sqr_gradient(const MAT& M, MAT2& G) {
264  typedef typename gmm::linalg_traits<MAT>::value_type T;
265  typedef typename gmm::number_traits<T>::magnitude_type R;
266 
267  size_type n = mat_ncols(M);
268  gmm::dense_matrix<T> B(n,n), C(n,n);
269  gmm::mult(gmm::transposed(M), M, B);
270  R trB = gmm::mat_trace(B);
271  bgeot::lu_inverse(&(*(B.begin())), n);
272  R trBinv = gmm::mat_trace(B);
273  gmm::mult(B,B,C);
274  gmm::mult(gmm::scaled(M, T(-2)*trB), C, G);
275  gmm::add(gmm::scaled(M, T(2)*trBinv), G);
276  }
277 
278 
279  struct pt_attribute {
280  bool fixed;
281  dal::bit_vector constraints;
282  bool operator<(const pt_attribute &other) const {
283  if (fixed && !other.fixed) return true;
284  else if (!fixed && other.fixed) return false;
285  else {
286  if (constraints.last_true() > other.constraints.last_true())
287  return false;
288  else if (constraints.last_true() < other.constraints.last_true())
289  return true;
290  else if (constraints.card() > other.constraints.card()) return true;
291  else if (constraints.card() < other.constraints.card()) return false;
292  else for (dal::bv_visitor i1(constraints), i2(other.constraints);
293  !i1.finished(); ++i1, ++i2) {
294  if (i1 < i2) return true;
295  else if (i2 > i1) return false;
296  }
297  }
298  return false;
299  }
300  };
301 
302  struct mesher {
303  pmesher_signed_distance dist;
304  const mesher_virtual_function& edge_len;
305  scalar_type h0, dist_point_hull, boundary_threshold_flatness;
306  size_type N, K, iter_max, iter_wtcc;
307  int prefind, noisy;
308  base_node bounding_box_min, bounding_box_max;
309  base_vector L, L0;
310 
311  std::vector<base_node> pts, pts_prev;
312  std::vector<const pt_attribute*> pts_attr;
313  std::set<pt_attribute> attributes_set;
314  gmm::dense_matrix<size_type> t;
315 
316  scalar_type ptol, ttol, L0mult, deltat, geps, deps;
317 
318  std::vector<const mesher_signed_distance*> constraints;
319 
320  gmm::dense_matrix<scalar_type> W;
321  bgeot::mesh_structure edges_mesh;
322 
323  std::vector<size_type> attracted_points;
324  std::vector<base_node> attractor_points;
325 
326  mesher(size_type K_,
327  const pmesher_signed_distance &dist_,
328  const mesher_virtual_function &edge_len_,
329  scalar_type h0_,
330  mesh &m, const std::vector<base_node> &fixed_points,
331  int noise, size_type itm, int pref,
332  scalar_type dph, scalar_type btf)
333  : dist(dist_), edge_len(edge_len_), dist_point_hull(dph),
334  boundary_threshold_flatness(btf), iter_max(itm), prefind(pref),
335  noisy(noise) {
336  if (noise == -1) noisy = gmm::traces_level::level() - 2;
337  K=K_; h0=h0_;
338  ptol = 0.0025;
339  ttol = .1;
340  dist->bounding_box(bounding_box_min,bounding_box_max);
341  N = bounding_box_min.size();
342  if (N == 2) {
343  L0mult = 1.2; deltat = .2; geps = .001*h0;
344  } else {
345  L0mult=1+0.4/pow(scalar_type(2),scalar_type(N-1));
346  deltat=.1; geps=1e-1*h0;
347  }
348  deps=sqrt(1e-8)*h0;
349  dist->register_constraints(this->constraints);
350 
351  bgeot::pgeometric_trans pgt = bgeot::simplex_geotrans(N,1);
352  gmm::resize(W,N,N);
353  base_matrix G(N,N+1);
354  vectors_to_base_matrix(G,
355  bgeot::equilateral_simplex_of_reference(dim_type(N))->points());
356  gmm::mult(G, bgeot::geotrans_precomp(pgt, pgt->convex_ref()->pspt(),
357  0)->grad(0), W);
358  bgeot::lu_inverse(&(*(W.begin())), N);
359  do_build_mesh(m,fixed_points);
360  }
361 
362  template<class TAB> scalar_type simplex_quality(const TAB &ppts) {
363  base_matrix G(N,N), GW(N, N);
364  for (size_type i=0; i < N; ++i) {
365  base_node P = ppts[i+1] - ppts[0];
366  std::copy(P.const_begin(), P.const_begin()+N, G.begin()+i*N);
367  }
368  gmm::mult(G, W, GW);
369  return gmm::abs(1./gmm::condition_number(GW));
370  }
371 
372  scalar_type worst_element, best_element;
373 
374  scalar_type fbcond_cost_function(const base_vector &c) {
375  unsigned nbt = unsigned(gmm::mat_ncols(t));
376  scalar_type cost = 0;
377  base_matrix S(N,N), SW(N,N);
378  worst_element = 1.; best_element = 1E40;
379  for (unsigned i=0; i < nbt; ++i) {
380  for (size_type j=0; j < N; ++j) {
381  for (size_type k=0; k < N; ++k) {
382  S(k,j) = c[t(j+1,i)*N+k] - c[t(0,i)*N+k];
383  }
384  }
385  gmm::mult(S,W,SW);
386  if (bgeot::lu_det(&(*(SW.begin())), N) < 1E-16) cost += 1e30;
387  else {
388  scalar_type qual = gmm::Frobenius_condition_number_sqr(SW);
389  cost += qual;
390  worst_element = std::max(worst_element, qual / scalar_type(N*N));
391  best_element = std::min(best_element, qual / scalar_type(N*N));
392  }
393  }
394  return cost / scalar_type(N * N);
395  }
396 
397  void fbcond_cost_function_derivative(const base_vector& c,
398  base_vector &grad) {
399  gmm::clear(grad);
400  base_matrix Dcond(N,N), G(N,N), S(N,N), SW(N,N);
401  unsigned nbt = unsigned(gmm::mat_ncols(t));
402 
403  for (unsigned i=0; i < nbt; ++i) {
404  for (size_type j=0; j < N; ++j) {
405  for (size_type k=0; k < N; ++k) {
406  S(k,j) = c[t(j+1,i)*N+k] - c[t(0,i)*N+k];
407  }
408  }
409  gmm::mult(S,W,SW);
410  Frobenius_condition_number_sqr_gradient(SW,Dcond);
411  gmm::mult(Dcond, gmm::transposed(W), G);
412  // gmm::mult(W, gmm::transposed(Dcond), G);
413  for (size_type j=0; j < N; ++j) {
414  for (size_type k=0; k < N; ++k) {
415  grad[t(j+1,i)*N+k] += G(k,j);
416  grad[t(0,i)*N+k] -= G(k,j);
417  }
418  }
419  }
420  for (unsigned i=0; i < pts.size(); ++i) {
421  if (pts_attr[i]->constraints.card() || pts_attr[i]->fixed)
422  for (size_type k=0; k < N; ++k) {
423  grad[i*N+k] = 0;
424  }
425  }
426  gmm::scale(grad, scalar_type(1) / scalar_type(N * N));
427 
428  }
429 
430  struct fbcond_cost_function_object {
431  mesher &m;
432  fbcond_cost_function_object(mesher &m_) : m(m_) {}
433  scalar_type operator()(const base_vector& c) const
434  { return m.fbcond_cost_function(c); }
435  };
436 
437  struct fbcond_cost_function_derivative_object {
438  mesher &m;
439  fbcond_cost_function_derivative_object(mesher &m_) : m(m_) {}
440  void operator()(const base_vector& c, base_vector &grad) const
441  { m.fbcond_cost_function_derivative(c, grad); }
442  };
443 
444  void optimize_quality() {
445 
446  size_type nbt = gmm::mat_ncols(t);
447 
448  if (noisy > 0) cout << "Quality post-optimization\n";
449  base_vector X(pts.size() * N);
450  for (unsigned i=0; i < pts.size(); ++i)
451  gmm::copy_n(pts[i].const_begin(), N, X.begin() + i*N);
452 
453  base_matrix S(N,N), SW(N,N);
454  for (unsigned i=0; i < nbt; ++i) {
455  for (size_type j=0; j < N; ++j) {
456  for (size_type k=0; k < N; ++k) {
457  S(k,j) = X[t(j+1,i)*N+k] - X[t(0,i)*N+k];
458  }
459  }
460  if (bgeot::lu_det(&(*(S.begin())), N) < 0) {
461  std::swap(t(0,i), t(1,i));
462  for (size_type j=0; j < N; ++j) {
463  for (size_type k=0; k < N; ++k) {
464  S(k,j) = X[t(j+1,i)*N+k] - X[t(0,i)*N+k];
465  }
466  }
467  }
468  if (noisy > 0 && gmm::abs(bgeot::lu_det(&(*(S.begin())), N)) < 1e-10)
469  cout << "Element " << i << " is very bad, det = "
470  << gmm::abs(lu_det(S)) << "\n";
471  gmm::mult(S,W,SW);
472  }
473 
474  if (noisy > 0) {
475  cout << "Initial quality: "
476  << fbcond_cost_function(X)/scalar_type(nbt);
477  cout << ", best element: " << sqrt(best_element)
478  << " worst element: " << sqrt(worst_element) << endl;
479  }
480  gmm::iteration iter; iter.set_noisy(noisy-1); iter.set_maxiter(1000);
481  iter.set_resmax(5E-2*sqrt(scalar_type(nbt)));
482  gmm::bfgs(fbcond_cost_function_object(*this),
483  fbcond_cost_function_derivative_object(*this),
484  X, 10, iter, 0, 0.001, float(gmm::mat_ncols(t)));
485 
486  if (noisy > 0) cout << "Final quality: "
487  << fbcond_cost_function(X)/scalar_type(nbt)
488  << ", best element: " << sqrt(best_element)
489  << " worst element: " << sqrt(worst_element) << endl;
490 
491  for (unsigned i=0; i < pts.size(); ++i)
492  gmm::copy_n(X.begin() + i*N, N, pts[i].begin());
493  }
494 
495  void delete_element(size_type ic) {
496  if (ic != gmm::mat_ncols(t)-1) {
497  for (size_type k=0; k < N+1; ++k)
498  std::swap(t(k,ic), t(k,gmm::mat_ncols(t)-1));
499  }
500  t.resize(N+1,gmm::mat_ncols(t)-1);
501  }
502 
503  scalar_type quality_of_element(size_type i) {
504  return simplex_quality(gmm::index_ref_iterator
505  (pts.begin(), gmm::mat_col(t,i).begin()));
506  }
507 
508  void control_mesh_surface(void) {
509  mesh m;
510  adapt_mesh(m, 1);
511  dal::bit_vector ii = m.convex_index(), points_to_project;
512  size_type ic, ipt;
513  for (ic << ii; ic != size_type(-1); ic << ii) {
514  for (short_type f = 0; f <= N; ++f) {
515  if (!m.is_convex_having_neighbor(ic,f)) {
516  for (unsigned i = 0; i < N; ++i) {
517  ipt = m.ind_points_of_face_of_convex(ic, f)[i];
518  if (pts_attr[ipt]->constraints.card() == 0)
519  points_to_project.add(ipt);
520  else if ((*dist)(pts[ipt]) < -1e-2)
521  cout << "WARNING, point " << ipt
522  << " incoherent !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
523  }
524  }
525  }
526  }
527  if (points_to_project.card()) {
528  iter_wtcc = 0;
529  if (noisy > 1)
530  cout << "points to project : " << points_to_project << endl;
531  ii = points_to_project;
532  for (ipt << ii; ipt != size_type(-1); ipt << ii)
533  surface_projection_and_update_constraints(ipt);
534  }
535  }
536 
537  void suppress_flat_boundary_elements(void) {
538  size_type nb_deleted = 0;
539  do {
540  mesh m;
541  adapt_mesh(m, 1);
542  std::vector<base_small_vector> normals;
543  dal::bit_vector ii = m.convex_index();
544  dal::bit_vector flat_bound_elemnts;
545  size_type ic;
546 
547  for (ic << ii; ic != size_type(-1); ic << ii) {
548  scalar_type max_flatness = -2.0;
549  normals.resize(0);
550  for (short_type f = 0; f <= N; ++f) {
551  if (!m.is_convex_having_neighbor(ic,f)) {
552  if (quality_of_element(ic) < 1E-8) max_flatness = 1E-8;
553  else {
554  base_small_vector n = m.normal_of_face_of_convex(ic, f);
555  normals.push_back(n / gmm::vect_norm2(n));
556  }
557  }
558  }
559 
560  if (noisy > 1 && max_flatness != -2.0)
561  cout << "flatness of element " << ic << " : " << max_flatness;
562  if (normals.size() >= 2) {
563  if (noisy > 1) cout << "flatness of element " << ic << " : ";
564 
565  for (unsigned i = 1; i < normals.size(); ++i)
566  for (unsigned j = 0; j < i; ++j) {
567  scalar_type flatness=1.0-gmm::vect_sp(normals[i], normals[j]);
568  max_flatness = std::max(max_flatness, flatness);
569  if (noisy > 1) cout << flatness << " ";
570  }
571  }
572  if (max_flatness < boundary_threshold_flatness
573  && max_flatness!=-2.0) {
574  flat_bound_elemnts.add(ic);
575  if (noisy > 1) cout << " -> deleting";
576  }
577  if ((normals.size() >= 2 || max_flatness != -2.0) && noisy > 1)
578  cout << endl;
579 
580  }
581  ii = flat_bound_elemnts; nb_deleted = flat_bound_elemnts.card();
582  for (ic = ii.take_last(); ic != size_type(-1); ic = ii.take_last())
583  delete_element(ic);
584  } while (nb_deleted > 0);
585  }
586 
587 
588  bool try_projection(base_node &X)
589  { return getfem::try_projection(*dist, X); }
590 
591  void projection(base_node &X) {
592  base_small_vector G(X.size());
593  scalar_type d = dist->grad(X, G);
594  size_type it(0);
595  if (d > 0.0)
596  while (gmm::abs(d) > 1e-10) {
597  ++it;
598  GMM_ASSERT1(it <= 10000, "Object empty, or bad signed distance");
599 // cout << "iter " << it << " X = " << X << " dist = " << d <<
600 // " grad = " << G << endl;
601  gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
602  d = dist->grad(X, G);
603  }
604  }
605 
606  void surface_projection(base_node &X) {
607  base_small_vector G;
608  scalar_type d = dist->grad(X, G);
609  size_type it(0);
610  while (gmm::abs(d) > 1e-10) {
611  ++it;
612  GMM_ASSERT1(it <= 10000, "Object empty, or bad signed distance X="
613  << X << ", G=" << G << " d = " << d);
614 // if (it > 9980)
615 // cout << "iter " << it << " X = " << X << " dist = " << d <<
616 // " grad = " << G << endl;
617  gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
618  d = dist->grad(X, G);
619  }
620  }
621 
622  void projection(base_node &X, dal::bit_vector& bv)
623  { projection(X); bv.clear(); (*dist)(X,bv); }
624 
625  void constraint_projection(base_node &X, size_type cnum) {
626  base_small_vector G;
627  scalar_type d = constraints[cnum]->grad(X, G);
628  while (gmm::abs(d) > 1e-10) {
629  gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
630  d=constraints[cnum]->grad(X, G);
631  }
632  }
633 
634  bool pure_multi_constraint_projection(base_node &X,
635  const dal::bit_vector &cts) {
636  getfem::pure_multi_constraint_projection(constraints, X, cts);
637 
638 // base_node oldX;
639 // size_type cnt = 0;
640 // do {
641 // oldX = X;
642 // for (dal::bv_visitor ic(cts); !ic.finished(); ++ic)
643 // constraint_projection(X,ic);
644 // ++cnt;
645 // } while (cts.card() && gmm::vect_dist2(oldX,X) > 1e-14 && cnt < 1000);
646 // if (cnt >= 1000) return false;
647 // if (cts.card()) {
648  dal::bit_vector ct2;
649  (*dist)(X, ct2);
650  return ct2.contains(cts);
651 // }
652 // return true;
653  }
654 
655  bool multi_constraint_projection(base_node &X,
656  const dal::bit_vector &cts) {
657  if (!(cts.card())) { projection(X); return true; }
658  else {
659  base_node oldX;
660  size_type cnt = 0;
661  do {
662  oldX = X;
663  for (dal::bv_visitor ic(cts); !ic.finished(); ++ic)
664  constraint_projection(X,ic);
665  projection(X);
666  ++cnt;
667  } while (gmm::vect_dist2(oldX,X) > 1e-14 && cnt < 1000);
668  if (cnt >= 1000) return false;
669  dal::bit_vector ct2;
670  (*dist)(X, ct2);
671  return ct2.contains(cts);
672  }
673  }
674 
675  void tangential_displacement(base_small_vector &X,
676  const dal::bit_vector &cts) {
677  base_small_vector G;
678  base_matrix normals(N, cts.card());
679  size_type cnt = 0;
680  for (dal::bv_visitor ic(cts); !ic.finished(); ++ic) {
681  constraints[ic]->grad(X, G);
682  gmm::copy(G, gmm::mat_col(normals, cnt));
683  for (size_type k=0; k < cnt; ++k) {
684  gmm::add(gmm::scaled(gmm::mat_col(normals, k),
685  -gmm::vect_sp(gmm::mat_col(normals,k),
686  gmm::mat_col(normals,cnt))),
687  gmm::mat_col(normals,cnt));
688  scalar_type n = gmm::vect_norm2(gmm::mat_col(normals, cnt));
689  if (n < 1e-8) continue;
690  gmm::scale(gmm::mat_col(normals, cnt), 1./n);
691  gmm::add(gmm::scaled(gmm::mat_col(normals, cnt),
692  -gmm::vect_sp(X,gmm::mat_col(normals, cnt))),X);
693  ++cnt;
694  }
695  }
696  }
697 
698  const pt_attribute* get_attr(bool fixed, const dal::bit_vector &bv) {
699  pt_attribute a;
700  a.fixed = fixed;
701  a.constraints = bv;
702  return &(*attributes_set.insert(a).first);
703  }
704 
705  void surface_projection_and_update_constraints(size_type ip) {
706  surface_projection(pts[ip]);
707  dal::bit_vector new_cts;
708  (*dist)(pts[ip], new_cts);
709  pts_attr[ip] = get_attr(pts_attr[ip]->fixed, new_cts);
710  }
711 
712  void project_and_update_constraints(size_type ip) {
713  const dal::bit_vector& cts = pts_attr[ip]->constraints;
714  dal::bit_vector new_cts;
715  multi_constraint_projection(pts[ip], cts);
716  (*dist)(pts[ip], new_cts);
717  if (noisy > 1 && !new_cts.contains(cts)) {
718  cout << "Point #" << ip << " has been downgraded from "
719  << cts << " to " << new_cts << endl;
720  }
721  else if (noisy > 1 && new_cts.card() > cts.card()) {
722  cout << "Point #" << ip << " has been upgraded from "
723  << cts << " to " << new_cts << endl;
724  }
725  if (new_cts != cts) {
726  pts_attr[ip] = get_attr(pts_attr[ip]->fixed, new_cts);
727  iter_wtcc = 0;
728  }
729 
730  }
731 
732  template <class VECT> void move_carefully(size_type ip, const VECT &VV) {
733  base_node V(N); gmm::copy(VV, V);
734 // if (pts_attr[ip]->constraints.card() != 0) {
735 // base_small_vector grad;
736 // dist->grad(pts[ip], grad);
737 // scalar_type r = gmm::vect_norm2_sqr(grad);
738 // gmm::add(gmm::scaled(grad, -gmm::vect_sp(V, grad) / r), V);
739 // }
740  scalar_type norm = gmm::vect_norm2(V);
741  if (norm <= h0/scalar_type(4))
742  gmm::add(V, pts[ip]);
743  else
744  gmm::add(gmm::scaled(V, h0 / (scalar_type(4) * norm)), pts[ip]);
745  project_and_update_constraints(ip);
746  }
747 
748  template <class VECT> void move_carefully(const VECT &V) {
749  scalar_type norm_max(0), lambda(1);
750  size_type npt = gmm::vect_size(V) / N;
751  for (size_type i = 0; i < npt; ++i)
752  norm_max = std::max(norm_max, gmm::vect_norm2
753  (gmm::sub_vector(V, gmm::sub_interval(i*N, N))));
754  if (norm_max > h0/scalar_type(3.7))
755  lambda = h0 / (scalar_type(3.7) * norm_max);
756 
757  for (size_type i = 0; i < npt; ++i)
758  move_carefully(i, gmm::scaled(gmm::sub_vector
759  (V, gmm::sub_interval(i*N, N)),lambda));
760  }
761 
762  void distribute_points_regularly(const std::vector<base_node>
763  &fixed_points) {
764  size_type nbpt = 1;
765  std::vector<size_type> gridnx(N);
766  mesh m;
767  base_node eff_boxmin(N), eff_boxmax(N);
768  bool eff_box_init = false;
769 
770  for (size_type i=0; i < N; ++i)
771  h0 = std::min(h0, bounding_box_max[i] - bounding_box_min[i]);
772  GMM_ASSERT1(h0 >= 1E-10, "h0 = " << h0 << " too small, aborting.");
773 
774  for (size_type i=0; i < N; ++i) {
775  scalar_type h = h0;
776  if (N == 2 && i == 1) h = sqrt(3.)/2. * h0;
777  gridnx[i]=1+(size_type)((bounding_box_max[i]-bounding_box_min[i])/h);
778  nbpt *= gridnx[i];
779  }
780 
781  /* build the regular grid and filter points outside */
782  for (size_type i=0; i < fixed_points.size(); ++i) {
783  if ((*dist)(fixed_points[i]) < geps &&
784  m.search_point(fixed_points[i]) == size_type(-1)) {
785  m.add_point(fixed_points[i]);
786  pts.push_back(fixed_points[i]);
787  pts_attr.push_back(get_attr(true,dal::bit_vector()));
788  }
789  else if (noisy > 0)
790  cout << "Removed duplicate fixed point: "<<fixed_points[i]<<"\n";
791  }
792  base_node P(N), Q(N);
793  for (size_type i=0; i < nbpt; ++i) {
794  for (size_type k=0, r = i; k < N; ++k) {
795  unsigned p = unsigned(r % gridnx[k]);
796  P[k] = p * (bounding_box_max[k] - bounding_box_min[k]) /
797  scalar_type((gridnx[k]-1)) + bounding_box_min[k];
798  if (N==2 && k==0 && ((r/gridnx[0])&1)==1) P[k] += h0/2;
799  r /= gridnx[k];
800  }
801 
802  dal::bit_vector co;
803  if ((prefind == 1 && (*dist)(P) < 0) || prefind == 2) {
804  for (size_type k = 0; k < constraints.size() && co.card() < N; ++k) {
805  gmm::copy(P, Q);
806  if (gmm::abs((*(constraints[k]))(Q)) < h0) {
807  constraint_projection(Q, k);
808  if ((*dist)(Q) > -geps &&
809  (gmm::vect_dist2(P, Q) < h0 / scalar_type(2))) co.add(k);
810  }
811  }
812  }
813  gmm::copy(P, Q);
814  if (co.card() > 0) {
815  bool ok = pure_multi_constraint_projection(Q, co);
816  if (!ok || gmm::abs((*dist)(Q)) > geps) { gmm::copy(P, Q); co.clear(); }
817  }
818 
819  if (prefind == 3) {
820  try_projection(Q);
821  }
822 
823  if ((*dist)(Q) < geps) {
824  if (m.search_point(Q) == size_type(-1)) {
825  //cout << "adding point : " << Q << endl;
826  if (!eff_box_init)
827  { eff_boxmin = eff_boxmax = Q; eff_box_init = true; }
828  else for (size_type k = 0; k < N; ++k) {
829  eff_boxmin[k] = std::min(eff_boxmin[k], Q[k]);
830  eff_boxmax[k] = std::max(eff_boxmax[k], Q[k]);
831  }
832  m.add_point(Q); pts.push_back(Q);
833  pts_attr.push_back(get_attr(false, co));
834  }
835  }
836  }
837  if (noisy > 0) cout << "effective bounding box : " << eff_boxmin << " : " << eff_boxmax << endl;
838  if (prefind == 3) {
839  h0 = std::min(h0, gmm::vect_dist2(eff_boxmin, eff_boxmax)
840  / scalar_type(2));
841  }
842  }
843 
844  void add_point_hull(void) {
845  if (dist_point_hull > 0) {
846  size_type nbpt = pts.size(), nbadd(0);
847  base_node P, Q;
848  base_small_vector V;
849  for (unsigned i=0; i < nbpt; ++i) {
850  if (pts_attr[i]->constraints.card()) {
851  P = pts[i];
852  dist->grad(P, V);
853  scalar_type d = gmm::vect_norm2(V);
854  if (d > 0) {
855  P += V * (dist_point_hull*h0/d);
856  if ((*dist)(P)*sqrt(scalar_type(N)) > dist_point_hull*h0) {
857  Q = P;
858  projection(Q);
859  if (gmm::vect_dist2(P, Q) > dist_point_hull*h0/scalar_type(2))
860  { pts.push_back(P); ++nbadd; }
861  }
862  }
863  }
864  }
865  if (noisy > 1) cout << "point hull: " << nbadd << " points added\n";
866  }
867  }
868 
869 
870  scalar_type pts_dist_max(const std::vector<base_node> &A,
871  const std::vector<base_node> &B) {
872  scalar_type dist_max = 0;
873  for (size_type i=0; i < pts.size(); ++i)
874  dist_max = std::max(dist_max, gmm::vect_dist2_sqr(A[i],B[i]));
875  return sqrt(dist_max);
876  }
877 
878  struct cleanup_points_compare {
879  const std::vector<base_node> &pts;
880  const std::vector<const pt_attribute*> &attr;
881  cleanup_points_compare(const std::vector<base_node> &pts_,
882  const std::vector<const pt_attribute*> &attr_)
883  : pts(pts_), attr(attr_) {}
884  bool operator()(size_type a, size_type b) {
885  if (attr[a] != attr[b]) return attr[a] < attr[b];
886  return pts[a] < pts[b];
887  }
888  };
889  void cleanup_points() {
890  std::vector<size_type> idx(pts.size());
891  for (size_type i=0; i < idx.size(); ++i) idx[i] = i;
892 
893  std::sort(idx.begin(), idx.end(), cleanup_points_compare(pts,pts_attr));
894  bgeot::kdtree tree;
895  bgeot::kdtree_tab_type neighbors;
896  dal::bit_vector keep_pts; keep_pts.add(0,idx.size());
897  for (size_type i=0, i0=0; i < idx.size(); ++i) {
898  const base_node &P = pts[idx[i]];
899  const pt_attribute *a = pts_attr[idx[i]];
900  tree.add_point_with_id(P,i);
901  if (i == idx.size()-1 || a != pts_attr[idx[i+1]]) {
902  for (size_type j=i0; j < i+1; ++j) {
903  base_node bmin = P, bmax = P;
904  scalar_type h = h0*edge_len(P);
905  for (size_type k = 0; k < N; ++k)
906  { bmin[k] -= h/20.; bmax[k] += h/20.; }
907 
908  tree.points_in_box(neighbors, bmin, bmax);
909  for (size_type k=0; k < neighbors.size(); ++k) {
910  if (neighbors[k].i != i && keep_pts.is_in(neighbors[k].i)
911  && keep_pts.is_in(i)) {
912  if (noisy > 0)
913  cout << "point #" << i << " " << P
914  << " is too near from point #" << neighbors[k].i
915  << pts[idx[neighbors[k].i]] << " : will be removed\n";
916  keep_pts.sup(i);
917  }
918  }
919  }
920  tree.clear();
921  i0 = i+1;
922  }
923  }
924  pts_prev.resize(keep_pts.card());
925  size_type cnt = 0;
926  std::vector<const pt_attribute*> pts_attr2(keep_pts.card());
927  for (dal::bv_visitor i(keep_pts); !i.finished(); ++i, ++cnt) {
928  pts_prev[cnt].swap(pts[idx[i]]);
929  pts_attr2[cnt] = pts_attr[idx[i]];
930  }
931  pts_attr.swap(pts_attr2);
932  pts.resize(pts_prev.size());
933  std::copy(pts_prev.begin(), pts_prev.end(), pts.begin());
934  }
935 
936  scalar_type worst_q;
937  base_node worst_q_P;
938 
939  void select_elements(int version) {
940  size_type nbpt = pts.size();
941 
942  worst_q = 1.;
943  base_node weights(N+1);
944  for (size_type i=0; i < gmm::mat_ncols(t); ) {
945  bool ext_simplex = false;
946  // bool boundary_simplex = true;
947  bool on_boundary_simplex = false;
948  bool is_bridge_simplex = false;
949  scalar_type q(0), dG(0);
950  base_node G;
951 
952  for (size_type k=0; k <= N; ++k)
953  if (t(k, i) >= nbpt) ext_simplex = true;
954 
955  if (!ext_simplex) {
956  G = pts[t(0,i)];
957  for (size_type k=1; k <= N; ++k) G += pts[t(k,i)];
958  gmm::scale(G, scalar_type(1)/scalar_type(N+1));
959  dG = (*dist)(G);
960  gmm::clear(weights);
961 
962  q = quality_of_element(i);
963 
964  for (size_type k=0; k <= N; ++k) {
965  if (!(pts_attr[t(k,i)]->constraints.card() == 0))
966  on_boundary_simplex = true;
967  // else
968  // boundary_simplex = false;
969  }
970 
971  if (version == 1 && on_boundary_simplex)
972  for (size_type k=1; k < N+1; ++k)
973  for (size_type l=0; l < k; ++l) {
974  dal::bit_vector all_cts = pts_attr[t(k,i)]->constraints
975  | pts_attr[t(l,i)]->constraints;
976  if (/* gmm::vect_dist2(pts[t(k,i)], pts[t(l,i)]) > h0 && */
977  !(pts_attr[t(k,i)]->constraints.contains(all_cts))
978  && !(pts_attr[t(l,i)]->constraints.contains(all_cts))
979  && (*dist)(0.5*(pts[t(k,i)] + pts[t(l,i)])) > 0.)
980  is_bridge_simplex = true;
981  }
982  }
983  if (ext_simplex || dG > 0 || is_bridge_simplex || q < 1e-14) {
984  delete_element(i);
985  } else {
986  ++i;
987  if (q < worst_q) {
988  worst_q = q;
989  worst_q_P = G*(scalar_type(1)/scalar_type(N+1));
990  }
991  }
992  }
993 
994  }
995 
996  void adapt_mesh(mesh &m, size_type degree) {
997  std::vector<base_node> cvpts(N+1), cvpts2;
998  size_type cvnum;
999  m.clear();
1000  for (size_type ip=0; ip < pts.size(); ++ip) {
1001  size_type z;
1003  while ((z = m.add_point(P)) != ip) {
1004  if (noisy > 0) cout << "WARNING : points are too near ...\n";
1006  gmm::add(gmm::scaled(Z, h0/1000.0), P);
1007  }
1008  }
1009  for (size_type i=0; i < t.size()/(N+1); ++i) {
1010  for (size_type k=0; k < N+1; ++k) cvpts[k] = pts[t[i*(N+1)+k]];
1011  if (degree == 1) {
1012  cvnum = m.add_convex(bgeot::simplex_geotrans(N,1), &t[i*(N+1)]);
1013  assert(cvnum == i);
1014  } else {
1016  bgeot::simplex_geotrans(N,short_type(degree));
1017  cvpts2.resize(pgt->nb_points());
1018  for (size_type k=0; k < pgt->nb_points(); ++k) {
1019  cvpts2[k] = bgeot::simplex_geotrans(N,1)->transform
1020  (pgt->convex_ref()->points()[k], cvpts);
1021  }
1022  cvnum = m.add_convex_by_points(pgt, cvpts2.begin());
1023  assert(cvnum == i);
1024  }
1025  }
1026  if (degree>1) {
1027  //m.optimize_structure();
1028  getfem::mesh_region border_faces;
1029  getfem::outer_faces_of_mesh(m, border_faces);
1030  dal::bit_vector ptdone; ptdone.sup(0,m.points_index().last_true());
1031  for (getfem::mr_visitor it(border_faces); !it.finished(); ++it) {
1032  mesh::ind_pt_face_ct fpts_
1033  = m.ind_points_of_face_of_convex(it.cv(), it.f());
1034  std::vector<size_type> fpts(fpts_.size());
1035  std::copy(fpts_.begin(), fpts_.end(), fpts.begin());
1036  interpolate_face(m, ptdone, fpts,
1037  m.trans_of_convex(it.cv())->structure()
1038  ->faces_structure()[it.f()]);
1039  }
1040  }
1041  }
1042 
1043 
1044 
1045  void interpolate_face(mesh &m, dal::bit_vector& ptdone,
1046  const std::vector<size_type>& ipts,
1048  if (cvs->dim() == 0) return;
1049  else if (cvs->dim() > 1) {
1050  std::vector<size_type> fpts;
1051  for (short_type f=0; f < cvs->nb_faces(); ++f) {
1052  fpts.resize(cvs->nb_points_of_face(f));
1053  for (size_type k=0; k < fpts.size(); ++k)
1054  fpts[k] = ipts[cvs->ind_points_of_face(f)[k]];
1055  interpolate_face(m,ptdone,fpts,cvs->faces_structure()[f]);
1056  }
1057  }
1058  dal::bit_vector cts; size_type cnt = 0;
1059  for (size_type i=0; i < ipts.size(); ++i) {
1060  if (ipts[i] < pts.size()) {
1061  if (cnt == 0) cts = pts_attr[ipts[i]]->constraints;
1062  else cts &= pts_attr[ipts[i]]->constraints;
1063  ++cnt;
1064  }
1065  }
1066  if (cts.card()) {
1067  // dal::bit_vector new_cts;
1068  for (size_type i=0; i < ipts.size(); ++i) {
1069  if (ipts[i] >= pts.size() && !ptdone[ipts[i]]) {
1070  base_node &P = m.points()[ipts[i]];
1071  multi_constraint_projection(P, cts);
1072  // (*dist)(P, new_cts);
1073  }
1074  }
1075  }
1076  }
1077 
1078  void special_constraints_management(void) {
1079 
1080  bgeot::kdtree tree;
1081  bgeot::kdtree_tab_type neighbors;
1082  bool tree_empty = true;
1083  mesh::ind_set iAneighbors, iBneighbors, common_pts;
1084 
1085  attractor_points.resize(0); attracted_points.resize(0);
1086 
1087  for (dal::bv_visitor ie(edges_mesh.convex_index());
1088  !ie.finished(); ++ie) {
1089  size_type iA = edges_mesh.ind_points_of_convex(ie)[0];
1090  size_type iB = edges_mesh.ind_points_of_convex(ie)[1];
1091  // if (L[ie] > L0[ie]) continue;
1092  if (pts_attr[iA] == pts_attr[iB] ||
1093  pts_attr[iA]->constraints.card() == 0 ||
1094  pts_attr[iB]->constraints.card() == 0) continue;
1095  if (pts_attr[iA]->constraints == pts_attr[iB]->constraints)
1096  continue;
1097  dal::bit_vector bv1(pts_attr[iA]->constraints);
1098  bv1.setminus(pts_attr[iB]->constraints);
1099  dal::bit_vector bv2(pts_attr[iB]->constraints);
1100  bv2.setminus(pts_attr[iA]->constraints);
1101  if (bv1.card() && bv2.card()) {
1102  bv1 |= bv2;
1103  edges_mesh.ind_points_to_point(iA, iAneighbors);
1104  edges_mesh.ind_points_to_point(iB, iBneighbors);
1105  common_pts.resize(0);
1106  for (size_type i = 0; i < iAneighbors.size(); ++i)
1107  if (std::find(iBneighbors.begin(), iBneighbors.end(),
1108  iAneighbors[i]) != iBneighbors.end())
1109  common_pts.push_back(iAneighbors[i]);
1110  bool do_projection = true;
1111  if ((*dist)(.5*(pts[iA]+pts[iB])) < 0) {
1112  for (mesh::ind_set::iterator it = common_pts.begin();
1113  it != common_pts.end(); ++it) {
1114  if (pts_attr[*it]->constraints.contains(bv1)) {
1115  do_projection = false;
1116  break;
1117  }
1118  }
1119  }
1120  if (do_projection) {
1121 
1122  if (pts_attr[iA]->constraints.card()
1123  < pts_attr[iB]->constraints.card()) std::swap(iA,iB);
1124 
1125  base_node PA = pts[iA];
1126  bool okA = multi_constraint_projection(PA, bv1);
1127  base_node PB = pts[iB];
1128  bool okB = multi_constraint_projection(PB, bv1);
1129 
1130  if (okB && !okA)
1131  { std::swap(PA,PB); std::swap(iA,iB); std::swap(okB, okA); }
1132 
1133  if (okB && (gmm::vect_dist2(PA,pts[iA])
1134  > 1.1*gmm::vect_dist2(PB,pts[iB]))) {
1135  // 1.5 au lieu de 1.1 ?
1136  std::swap(iA,iB); std::swap(PA,PB);
1137  }
1138 
1139 
1140  if (okA && gmm::vect_dist2(PA, pts[iA]) < h0*0.75) {
1141 
1142  if (tree_empty) {
1143  for (size_type i=0; i < pts.size(); ++i)
1144  tree.add_point_with_id(pts[i],i);
1145  tree_empty = false;
1146  }
1147 
1148  base_node bmin = PA, bmax = PA;
1149  for (size_type k = 0; k < N; ++k)
1150  { bmin[k] -= h0/1.8; bmax[k] += h0/1.8; }
1151  tree.points_in_box(neighbors, bmin, bmax);
1152  for (size_type k=0; k < neighbors.size(); ++k) {
1153  if (neighbors[k].i != iA && neighbors[k].i != iB)
1154  do_projection = false;
1155  }
1156 
1157  if (do_projection) {
1158  attractor_points.push_back(PA);
1159  attracted_points.push_back(iA);
1160  }
1161  }
1162  }
1163  }
1164  }
1165  }
1166 
1167 
1168  void running_delaunay(bool mct) {
1169  if (noisy > 0)
1170  cout << "NEW DELAUNAY, running on " << pts.size() << " points\n";
1171  size_type nbpt = pts.size();
1172  add_point_hull();
1173  bgeot::qhull_delaunay(pts, t);
1174  pts.resize(nbpt);
1175  if (noisy > 1) cout << "number of elements before selection = "
1176  << gmm::mat_ncols(t) << "\n";
1177  if (mct) {
1178  select_elements(0);
1179  edges_mesh.clear();
1180  for (size_type i=0; i < gmm::mat_ncols(t); ++i)
1181  for (size_type j=0; j < N+1; ++j)
1182  for (size_type k=j+1; k < N+1; ++k)
1183  edges_mesh.add_segment(t(j,i), t(k,i));
1184  special_constraints_management();
1185  }
1186  select_elements(1);
1187  if (noisy > 0) cout << "number of elements after selection = "
1188  << gmm::mat_ncols(t) << "\n";
1189  edges_mesh.clear();
1190  for (size_type i=0; i < gmm::mat_ncols(t); ++i)
1191  for (size_type j=0; j < N+1; ++j)
1192  for (size_type k=j+1; k < N+1; ++k)
1193  edges_mesh.add_segment(t(j,i), t(k,i));
1194  }
1195 
1196  void standard_move_strategy(base_vector &X) {
1197  for (dal::bv_visitor ie(edges_mesh.convex_index());
1198  !ie.finished(); ++ie) {
1199  size_type iA = edges_mesh.ind_points_of_convex(ie)[0];
1200  size_type iB = edges_mesh.ind_points_of_convex(ie)[1];
1201  base_node bar = pts[iB]-pts[iA];
1202  scalar_type F = std::max(L0[ie]-L[ie], 0.);
1203 
1204  if (F) {
1205  base_node Fbar = (bar)*(F/L[ie]);
1206 
1207  if (!pts_attr[iA]->fixed) // pts[iA] -= deltat*Fbar;
1208  gmm::add(gmm::scaled(Fbar, -deltat),
1209  gmm::sub_vector(X, gmm::sub_interval(iA*N, N)));
1210  if (!pts_attr[iB]->fixed) // pts[iB] += deltat*Fbar;
1211  gmm::add(gmm::scaled(Fbar, deltat),
1212  gmm::sub_vector(X, gmm::sub_interval(iB*N, N)));
1213  }
1214  }
1215  }
1216 
1217  void do_build_mesh(mesh &m,
1218  const std::vector<base_node> &fixed_points) {
1219 
1220  distribute_points_regularly(fixed_points);
1221  std::vector<base_node> pts2(pts.size(),base_node(N));
1222  size_type count = 0, count_id = 0, count_ct = 0;
1223  bool pt_changed = false;
1224  iter_wtcc = 0;
1225  attracted_points.resize(0);
1226  attractor_points.resize(0);
1227 
1228  do {
1229  if (noisy > 1) {
1230  cout << "Iter " << count << " / " << count + iter_max - iter_wtcc;
1231  if (count && pts_prev.size() == pts.size())
1232  cout << ", dist_max since last delaunay ="
1233  << pts_dist_max(pts, pts_prev) << ", tol=" << ttol*h0;
1234  cout << endl;
1235  }
1236  if (count==0 || pts_prev.size() != pts.size()
1237  || (pts_dist_max(pts, pts_prev) > ttol*h0 && count_id >= 5)) {
1238  size_type nbpt = pts.size();
1239  cleanup_points(); /* and copy pts to pts_prev */
1240  if (noisy == 1) cout << "Iter " << count << " ";
1241  bool mct = false;
1242  if (count_ct >= 20 || pt_changed) {
1243  mct = true;
1244  count_ct = 0;
1245  }
1246  running_delaunay(mct);
1247  pt_changed = nbpt != pts.size();
1248  count_id = 0;
1249  }
1250  ++count_id; ++count_ct;
1251  pts2 = pts;
1252 
1253  // computation of L and L0.
1254  size_type nbcv = edges_mesh.convex_index().card();
1255  GMM_ASSERT1(nbcv != 0, "no more edges!");
1256  L.resize(nbcv); L0.resize(nbcv);
1257  scalar_type sL = 0, sL0 = 0;
1258  for (dal::bv_visitor ie(edges_mesh.convex_index());
1259  !ie.finished(); ++ie) {
1260  const base_node &A = pts[edges_mesh.ind_points_of_convex(ie)[0]];
1261  const base_node &B = pts[edges_mesh.ind_points_of_convex(ie)[1]];
1262  base_node C(A); C+=B; C /= scalar_type(2);
1263  L[ie] = gmm::vect_dist2(A, B);
1264  L0[ie] = edge_len(C);
1265  sL += pow(L[ie],scalar_type(N));
1266  sL0 += pow(L0[ie],scalar_type(N));
1267  }
1268  gmm::scale(L0, L0mult * pow(sL/sL0, scalar_type(1)/scalar_type(N)));
1269 
1270  // Moving the points with standard strategy
1271  base_vector X(pts.size() * N);
1272  standard_move_strategy(X);
1273  for (size_type i = 0; i < attracted_points.size(); ++i) {
1274  size_type npt = attracted_points[i];
1275  gmm::copy(attractor_points[i] - pts[npt],
1276  gmm::sub_vector(X, gmm::sub_interval(npt*N, N)));
1277  }
1278 
1279  move_carefully(X);
1280 
1281  scalar_type maxdp = pts_dist_max(pts,pts2);
1282  if (noisy > 1)
1283  cout << ", maxdp = " << maxdp << ", ptol = "
1284  << ptol << " CV=" << sqrt(maxdp)*deltat/h0 << "\n";
1285  ++count; ++iter_wtcc;
1286 
1287  if (iter_wtcc == 100) control_mesh_surface();
1288 
1289  // m.clear();
1290  // for (size_type i=0; i < t.size()/(N+1); ++i)
1291  // m.add_convex_by_points(bgeot::simplex_geotrans(N,1),
1292  // dal::index_ref_iterator(pts.begin(), &t[i*(N+1)]));
1293  // char s[50]; snprintf(s, 49, "toto%02d.mesh", count);
1294  // m.write_to_file(s);
1295 
1296  if ( (count > 40 && sqrt(maxdp)*deltat < ptol * h0)
1297  || iter_wtcc>iter_max || count > 10000) {
1298 
1299 // {
1300 // m.clear();
1301 // adapt_mesh(m,K);
1302 // m.optimize_structure();
1303 // getfem::vtk_export exp("toto1.vtk");
1304 // exp.exporting(m);
1305 // exp.write_mesh_quality(m);
1306 // }
1307 
1308  control_mesh_surface();
1309  size_type nbpt = pts.size();
1310  add_point_hull();
1311  bgeot::qhull_delaunay(pts, t);
1312  pts.resize(nbpt);
1313  select_elements((prefind == 3) ? 0 : 1);
1314  suppress_flat_boundary_elements();
1315 
1316 // {
1317 // m.clear();
1318 // adapt_mesh(m,K);
1319 // m.optimize_structure();
1320 // getfem::vtk_export exp("toto2.vtk");
1321 // exp.exporting(m);
1322 // exp.write_mesh_quality(m);
1323 // }
1324 
1325  if (prefind != 3) optimize_quality();
1326 
1327  // ajout d'un point au barycentre des elements trop plats :
1328 
1329  if (prefind != 3)
1330  for (unsigned cv = 0; cv < gmm::mat_ncols(t); ++cv) {
1331 
1332  if (quality_of_element(cv) < 0.05) {
1333  base_node G = pts[t(0,cv)];
1334  for (size_type k=1; k <= N; ++k) G += pts[t(k,cv)];
1335  gmm::scale(G, scalar_type(1)/scalar_type(N+1));
1336  pts.push_back(G);
1337  pts_attr.push_back(get_attr(false, dal::bit_vector()));
1338  }
1339  }
1340 
1341  if (pts.size() != nbpt) {
1342  control_mesh_surface();
1343  nbpt = pts.size();
1344  add_point_hull();
1345  bgeot::qhull_delaunay(pts, t);
1346  pts.resize(nbpt);
1347  select_elements((prefind == 3) ? 0 : 1);
1348  suppress_flat_boundary_elements();
1349 
1350 // {
1351 // m.clear();
1352 // adapt_mesh(m,K);
1353 // m.optimize_structure();
1354 // getfem::vtk_export exp("toto3.vtk");
1355 // exp.exporting(m);
1356 // exp.write_mesh_quality(m);
1357 // }
1358 
1359  if (prefind != 3) optimize_quality();
1360  }
1361  break;
1362  }
1363 
1364 
1365  } while (true);
1366 
1367  m.clear();
1368  adapt_mesh(m,K);
1369  // m.write_to_file("toto.mesh");
1370  m.optimize_structure();
1371 
1372 
1373 // getfem::vtk_export exp("toto4.vtk");
1374 // exp.exporting(m);
1375 // exp.write_mesh_quality(m);
1376 
1377 // getfem::stored_mesh_slice sl;
1378 // sl.build(m, getfem::slicer_explode(0.8), 8);
1379 // getfem::vtk_export exp2("totoq.vtk");
1380 // exp2.exporting(sl);
1381 // exp2.write_mesh();
1382 // exp2.write_mesh_quality(m);
1383 // getfem::dx_export exp3("totoq.dx");
1384 // exp3.exporting(sl);
1385 // exp3.write_mesh();
1386 
1387 
1388 
1389 
1390 // getfem::stored_mesh_slice slb; slb.build(m, getfem::slicer_boundary(m), 4);
1391 // getfem::stored_mesh_slice sl2;
1392 // getfem::mesh_slicer ms(m);
1393 
1394 
1395 // getfem::slicer_build_stored_mesh_slice bb(sl2);
1396 // ms.push_back_action(bb);
1397 // getfem::convex_face_ct cvlst;
1398 // for (dal::bv_visitor cv(m.convex_index()); !cv.finished(); ++cv) {
1399 // scalar_type q = m.convex_quality_estimate(cv);
1400 // if (q< 0.2)
1401 // cvlst.push_back(getfem::convex_face(cv));
1402 // //cout << "cv " << cv << ": q=" << q << "\n";
1403 // }
1404 // //ms.exec(3, cvlst);
1405 // sl2.merge(slb);
1406 
1407 
1408 // getfem::vtk_export exp3("totoq2.vtk");
1409 // exp3.exporting(sl2);
1410 // exp3.write_mesh();
1411 // exp3.write_mesh_quality(m);
1412  }
1413 
1414 
1415  };
1416 
1417 
1418 
1419  void build_mesh(mesh &m, const pmesher_signed_distance& dist,
1420  scalar_type h0, const std::vector<base_node> &fixed_points,
1421  size_type K, int noise, size_type iter_max, int prefind,
1422  scalar_type dist_point_hull,
1423  scalar_type boundary_threshold_flatness) {
1424  mesher mg(K, dist, getfem::mvf_constant(1), h0, m, fixed_points, noise,
1425  iter_max, prefind, dist_point_hull, boundary_threshold_flatness);
1426  }
1427 
1428 }
1429 
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
void clear()
reset the tree, remove all points
Definition: bgeot_kdtree.h:112
Mesh structure definition.
const dal::bit_vector & convex_index() const
Return the list of valid convex IDs.
void clear()
erase the mesh
void ind_points_to_point(size_type, ind_set &) const
Return a container of the points attached (via an edge) to point ip.
const ind_set & ind_points_of_convex(size_type ic) const
Return a container to the list of points attached to convex ic.
"iterator" class for regions.
structure used to hold a set of convexes and/or convex faces.
The Iteration object calculates whether the solution has reached the desired accuracy,...
Definition: gmm_iter.h:52
An experimental mesher.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:556
void fill_random(L &l)
fill a vector or matrix with random value (uniform [-1,1]).
Definition: gmm_blas.h:129
linalg_traits< M >::value_type mat_trace(const M &m)
Trace of a matrix.
Definition: gmm_blas.h:527
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:58
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
Definition: gmm_blas.h:596
void resize(V &v, size_type n)
*‍/
Definition: gmm_blas.h:209
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1663
bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol=magnitude_of_linalg(MAT)(-1))
*‍/
Definition: gmm_blas.h:2240
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
size_type lu_factor(DenseMatrix &A, Pvector &ipvt)
LU Factorization of a general (dense) matrix (real or complex).
Definition: gmm_dense_lu.h:92
void lu_solve(const DenseMatrix &LU, const Pvector &pvector, VectorX &x, const VectorB &b)
LU Solve : Solve equation Ax=b, given an LU factored matrix.
Definition: gmm_dense_lu.h:129
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::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
pconvex_ref equilateral_simplex_of_reference(dim_type nc)
equilateral simplex (degree 1).
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
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
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree .
Definition: bgeot_poly.cc:46
GEneric Tool for Finite Element Methods.