26 void mesher_level_set::init_grad(
void)
const {
27 gradient.resize(base.dim());
28 for (dim_type d=0; d < base.dim(); ++d) {
29 gradient[d] = base; gradient[d].derivative(d);
34 void mesher_level_set::init_hess(
void)
const {
35 if (initialized < 1) init_grad();
36 hessian.resize(base.dim()*base.dim());
37 for (dim_type d=0; d < base.dim(); ++d) {
38 for (dim_type e=0; e < base.dim(); ++e) {
39 hessian[d*base.dim()+e] = gradient[d];
40 hessian[d*base.dim()+e].derivative(e);
46 scalar_type mesher_level_set::grad(
const base_node &P,
47 base_small_vector &G)
const {
48 if (initialized < 1) init_grad();
51 G[i] = bgeot::to_scalar(gradient[i].eval(P.begin()));
55 void mesher_level_set::hess(
const base_node &P, base_matrix &H)
const {
56 if (initialized < 2) init_hess();
58 for (
size_type i = 0; i < base.dim(); ++i)
59 for (
size_type j = 0; j < base.dim(); ++j) {
60 H(i,j) = bgeot::to_scalar(hessian[i*P.size()+j].eval(P.begin()));
69 bool try_projection(
const mesher_signed_distance& dist, base_node &X,
71 base_small_vector G; base_node Y = X;
72 scalar_type d = dist.grad(X, G), dmin = gmm::abs(d);
74 if (on_surface || d > 0.0)
75 while (iter == 0 || dmin > 1e-15 || gmm::vect_dist2(X, Y) > 1e-15 ) {
78 GMM_WARNING4(
"Try projection failed, 1000 iterations\n\n");
82 gmm::scale(G, -d / std::max(1E-8, gmm::vect_norm2_sqr(G)));
93 if (gmm::abs(d) >= dmin*0.95) ++count_falt;
94 else { count_falt = 0; dmin = gmm::abs(d); }
96 if (count_falt > 20)
return false;
104 bool pure_multi_constraint_projection
105 (
const std::vector<const mesher_signed_distance*> &list_constraints,
106 base_node &X,
const dal::bit_vector &cts) {
107 size_type nbco = cts.card(), i(0), info, N = X.size();
108 if (!nbco)
return true;
110 std::vector<const mesher_signed_distance*> ls(nbco);
111 std::vector<scalar_type> d(nbco), v(nbco);
112 gmm::lapack_ipvt ipvt(nbco);
113 gmm::col_matrix<base_node> G(N, nbco);
114 gmm::dense_matrix<scalar_type> H(nbco, nbco);
115 base_small_vector dd(N);
116 for (dal::bv_visitor ic(cts); !ic.finished(); ++ic, ++i)
117 { ls[i] = list_constraints[ic]; d[i] = -(ls[i]->grad(X, G[i])); }
118 base_node oldX, aux(N);
120 scalar_type residual(0),
alpha(0), det(0);
124 try_projection(*(ls[0]), X,
true);
125 d[0] = -(ls[0]->grad(X, G[0]));
129 det = scalar_type(0); info = 1;
130 alpha = -scalar_type(1);
134 gmm::mult(gmm::transposed(G), G, H);
136 gmm::copy(gmm::transposed(G), H);
139 det = scalar_type(1);
140 for (i = 0; i < nbco; ++i) det *= H(i,i);
144 if (info || gmm::abs(det) < 1E-20) {
145 dal::bit_vector cts_red = cts;
148 for (dal::bv_visitor ic(cts); !ic.finished(); ++ic, ++i) {
150 gmm::add(gmm::scaled(G[j], -gmm::vect_sp(G[j], G[i])), G[i]);
154 { cts_red[ic] =
false; eliminated++; }
156 gmm::scale(G[i], scalar_type(1)/norm_gi);
159 if (eliminated >= 1) {
161 pure_multi_constraint_projection(list_constraints, X, cts_red);
162 for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
164 det = scalar_type(0); info = 1;
167 gmm::mult(gmm::transposed(G), G, H);
171 det = scalar_type(1);
172 for (i = 0; i < nbco; ++i) det *= H(i,i);
178 if (gmm::vect_norm2(d) > 1e-11) {
179 if (info || gmm::abs(det) < 1E-20) {
180 for (i = 0; i < nbco; ++i)
181 try_projection(*(ls[i]), X,
true);
182 for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
185 gmm::lu_solve(H, ipvt, v, d);
190 GMM_ASSERT1(nbco <= N,
"internal error");
192 for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
193 alpha = scalar_type(1);
195 while (gmm::vect_norm2(d) > residual && alpha > 1E-10) {
196 alpha /= scalar_type(2);
197 gmm::add(gmm::scaled(dd, -alpha), X);
198 for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
200 if (alpha < 1E-15)
break;
208 }
while (residual > 1e-14 && (residual > 1e-11 || iter < 15)
212 for (i = 0; i < nbco; ++i)
if (gmm::abs(d[i]) > SEPS) {
224 static scalar_type max_vp(
const base_matrix& M) {
226 GMM_ASSERT1(
is_hermitian(M),
"Matrix is not symmetric");
227 std::vector<scalar_type> eig(m);
228 gmm::symmetric_qr_algorithm(M, eig);
230 for (
size_type i = 0; i < m; ++i) emax = std::max(emax, gmm::abs(eig[i]));
234 scalar_type curvature_radius_estimate(
const mesher_signed_distance &dist,
235 base_node X,
bool proj) {
236 if (proj) try_projection(dist, X,
true);
244 scalar_type min_curvature_radius_estimate
245 (
const std::vector<const mesher_signed_distance*> &list_constraints,
246 const base_node &X,
const dal::bit_vector &cts,
size_type hide_first) {
247 scalar_type r0 = 1E+10;
248 for (dal::bv_visitor j(cts); !j.finished(); ++j)
249 if (j >= hide_first) {
251 = curvature_radius_estimate(*(list_constraints[j]), X);
252 r0 = std::min(r, r0);
263 template <
typename MAT,
typename MAT2>
void
264 Frobenius_condition_number_sqr_gradient(
const MAT& M, MAT2& G) {
265 typedef typename gmm::linalg_traits<MAT>::value_type T;
266 typedef typename gmm::number_traits<T>::magnitude_type R;
269 gmm::dense_matrix<T> B(n,n), C(n,n);
270 gmm::mult(gmm::transposed(M), M, B);
272 bgeot::lu_inverse(&(*(B.begin())), n);
275 gmm::mult(gmm::scaled(M, T(-2)*trB), C, G);
276 gmm::add(gmm::scaled(M, T(2)*trBinv), G);
280 struct pt_attribute {
282 dal::bit_vector constraints;
283 bool operator<(
const pt_attribute &other)
const {
284 if (fixed && !other.fixed)
return true;
285 else if (!fixed && other.fixed)
return false;
287 if (constraints.last_true() > other.constraints.last_true())
289 else if (constraints.last_true() < other.constraints.last_true())
291 else if (constraints.card() > other.constraints.card())
return true;
292 else if (constraints.card() < other.constraints.card())
return false;
293 else for (dal::bv_visitor i1(constraints), i2(other.constraints);
294 !i1.finished(); ++i1, ++i2) {
295 if (i1 < i2)
return true;
296 else if (i2 > i1)
return false;
304 pmesher_signed_distance dist;
305 const mesher_virtual_function& edge_len;
306 scalar_type h0, dist_point_hull, boundary_threshold_flatness;
309 base_node bounding_box_min, bounding_box_max;
312 std::vector<base_node> pts, pts_prev;
313 std::vector<const pt_attribute*> pts_attr;
314 std::set<pt_attribute> attributes_set;
315 gmm::dense_matrix<size_type> t;
317 scalar_type ptol, ttol, L0mult, deltat, geps, deps;
319 std::vector<const mesher_signed_distance*> constraints;
321 gmm::dense_matrix<scalar_type> W;
324 std::vector<size_type> attracted_points;
325 std::vector<base_node> attractor_points;
328 const pmesher_signed_distance &dist_,
329 const mesher_virtual_function &edge_len_,
331 mesh &m,
const std::vector<base_node> &fixed_points,
333 scalar_type dph, scalar_type btf)
334 : dist(dist_), edge_len(edge_len_), dist_point_hull(dph),
335 boundary_threshold_flatness(btf), iter_max(itm), prefind(pref),
337 if (noise == -1) noisy = gmm::traces_level::level() - 2;
341 dist->bounding_box(bounding_box_min,bounding_box_max);
342 N = bounding_box_min.size();
344 L0mult = 1.2; deltat = .2; geps = .001*h0;
346 L0mult=1+0.4/pow(scalar_type(2),scalar_type(N-1));
347 deltat=.1; geps=1e-1*h0;
350 dist->register_constraints(this->constraints);
354 base_matrix G(N,N+1);
355 vectors_to_base_matrix(G,
357 gmm::mult(G, bgeot::geotrans_precomp(pgt, pgt->convex_ref()->pspt(),
359 bgeot::lu_inverse(&(*(W.begin())), N);
360 do_build_mesh(m,fixed_points);
363 template<
class TAB> scalar_type simplex_quality(
const TAB &ppts) {
364 base_matrix G(N,N), GW(N, N);
366 base_node P = ppts[i+1] - ppts[0];
367 std::copy(P.const_begin(), P.const_begin()+N, G.begin()+i*N);
370 return gmm::abs(1./gmm::condition_number(GW));
373 scalar_type worst_element, best_element;
375 scalar_type fbcond_cost_function(
const base_vector &c) {
376 unsigned nbt = unsigned(gmm::mat_ncols(t));
377 scalar_type cost = 0;
378 base_matrix S(N,N), SW(N,N);
379 worst_element = 1.; best_element = 1E40;
380 for (
unsigned i=0; i < nbt; ++i) {
383 S(k,j) = c[t(j+1,i)*N+k] - c[t(0,i)*N+k];
387 if (bgeot::lu_det(&(*(SW.begin())), N) < 1E-16) cost += 1e30;
389 scalar_type qual = gmm::Frobenius_condition_number_sqr(SW);
391 worst_element = std::max(worst_element, qual / scalar_type(N*N));
392 best_element = std::min(best_element, qual / scalar_type(N*N));
395 return cost / scalar_type(N * N);
398 void fbcond_cost_function_derivative(
const base_vector& c,
401 base_matrix Dcond(N,N), G(N,N), S(N,N), SW(N,N);
402 unsigned nbt = unsigned(gmm::mat_ncols(t));
404 for (
unsigned i=0; i < nbt; ++i) {
407 S(k,j) = c[t(j+1,i)*N+k] - c[t(0,i)*N+k];
411 Frobenius_condition_number_sqr_gradient(SW,Dcond);
412 gmm::mult(Dcond, gmm::transposed(W), G);
416 grad[t(j+1,i)*N+k] += G(k,j);
417 grad[t(0,i)*N+k] -= G(k,j);
421 for (
unsigned i=0; i < pts.size(); ++i) {
422 if (pts_attr[i]->constraints.card() || pts_attr[i]->fixed)
427 gmm::scale(grad, scalar_type(1) / scalar_type(N * N));
431 struct fbcond_cost_function_object {
433 fbcond_cost_function_object(mesher &m_) : m(m_) {}
434 scalar_type operator()(
const base_vector& c)
const
435 {
return m.fbcond_cost_function(c); }
438 struct fbcond_cost_function_derivative_object {
440 fbcond_cost_function_derivative_object(mesher &m_) : m(m_) {}
441 void operator()(
const base_vector& c, base_vector &grad)
const
442 { m.fbcond_cost_function_derivative(c, grad); }
445 void optimize_quality() {
449 if (noisy > 0) cout <<
"Quality post-optimization\n";
450 base_vector X(pts.size() * N);
451 for (
unsigned i=0; i < pts.size(); ++i)
452 gmm::copy_n(pts[i].const_begin(), N, X.begin() + i*N);
454 base_matrix S(N,N), SW(N,N);
455 for (
unsigned i=0; i < nbt; ++i) {
458 S(k,j) = X[t(j+1,i)*N+k] - X[t(0,i)*N+k];
461 if (bgeot::lu_det(&(*(S.begin())), N) < 0) {
462 std::swap(t(0,i), t(1,i));
465 S(k,j) = X[t(j+1,i)*N+k] - X[t(0,i)*N+k];
469 if (noisy > 0 && gmm::abs(bgeot::lu_det(&(*(S.begin())), N)) < 1e-10)
470 cout <<
"Element " << i <<
" is very bad, det = "
471 << gmm::abs(lu_det(S)) <<
"\n";
476 cout <<
"Initial quality: "
477 << fbcond_cost_function(X)/scalar_type(nbt);
478 cout <<
", best element: " << sqrt(best_element)
479 <<
" worst element: " << sqrt(worst_element) << endl;
481 gmm::iteration iter; iter.set_noisy(noisy-1); iter.set_maxiter(1000);
482 iter.set_resmax(5E-2*sqrt(scalar_type(nbt)));
483 gmm::bfgs(fbcond_cost_function_object(*
this),
484 fbcond_cost_function_derivative_object(*
this),
485 X, 10, iter, 0, 0.001,
float(gmm::mat_ncols(t)));
487 if (noisy > 0) cout <<
"Final quality: "
488 << fbcond_cost_function(X)/scalar_type(nbt)
489 <<
", best element: " << sqrt(best_element)
490 <<
" worst element: " << sqrt(worst_element) << endl;
492 for (
unsigned i=0; i < pts.size(); ++i)
493 gmm::copy_n(X.begin() + i*N, N, pts[i].begin());
497 if (ic != gmm::mat_ncols(t)-1) {
499 std::swap(t(k,ic), t(k,gmm::mat_ncols(t)-1));
501 t.resize(N+1,gmm::mat_ncols(t)-1);
504 scalar_type quality_of_element(
size_type i) {
505 return simplex_quality(gmm::index_ref_iterator
506 (pts.begin(), gmm::mat_col(t,i).begin()));
509 void control_mesh_surface(
void) {
512 dal::bit_vector ii = m.convex_index(), points_to_project;
514 for (ic << ii; ic !=
size_type(-1); ic << ii) {
516 if (!m.is_convex_having_neighbor(ic,f)) {
517 for (
unsigned i = 0; i < N; ++i) {
518 ipt = m.ind_points_of_face_of_convex(ic, f)[i];
519 if (pts_attr[ipt]->constraints.card() == 0)
520 points_to_project.add(ipt);
521 else if ((*dist)(pts[ipt]) < -1e-2)
522 cout <<
"WARNING, point " << ipt
523 <<
" incoherent !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
528 if (points_to_project.card()) {
531 cout <<
"points to project : " << points_to_project << endl;
532 ii = points_to_project;
533 for (ipt << ii; ipt !=
size_type(-1); ipt << ii)
534 surface_projection_and_update_constraints(ipt);
538 void suppress_flat_boundary_elements(
void) {
543 std::vector<base_small_vector> normals;
544 dal::bit_vector ii = m.convex_index();
545 dal::bit_vector flat_bound_elemnts;
548 for (ic << ii; ic !=
size_type(-1); ic << ii) {
549 scalar_type max_flatness = -2.0;
552 if (!m.is_convex_having_neighbor(ic,f)) {
553 if (quality_of_element(ic) < 1E-8) max_flatness = 1E-8;
555 base_small_vector n = m.normal_of_face_of_convex(ic, f);
556 normals.push_back(n / gmm::vect_norm2(n));
561 if (noisy > 1 && max_flatness != -2.0)
562 cout <<
"flatness of element " << ic <<
" : " << max_flatness;
563 if (normals.size() >= 2) {
564 if (noisy > 1) cout <<
"flatness of element " << ic <<
" : ";
566 for (
unsigned i = 1; i < normals.size(); ++i)
567 for (
unsigned j = 0; j < i; ++j) {
568 scalar_type flatness=1.0-gmm::vect_sp(normals[i], normals[j]);
569 max_flatness = std::max(max_flatness, flatness);
570 if (noisy > 1) cout << flatness <<
" ";
573 if (max_flatness < boundary_threshold_flatness
574 && max_flatness!=-2.0) {
575 flat_bound_elemnts.add(ic);
576 if (noisy > 1) cout <<
" -> deleting";
578 if ((normals.size() >= 2 || max_flatness != -2.0) && noisy > 1)
582 ii = flat_bound_elemnts; nb_deleted = flat_bound_elemnts.card();
583 for (ic = ii.take_last(); ic !=
size_type(-1); ic = ii.take_last())
585 }
while (nb_deleted > 0);
589 bool try_projection(base_node &X)
590 {
return getfem::try_projection(*dist, X); }
592 void projection(base_node &X) {
593 base_small_vector G(X.size());
594 scalar_type d = dist->grad(X, G);
597 while (gmm::abs(d) > 1e-10) {
599 GMM_ASSERT1(it <= 10000,
"Object empty, or bad signed distance");
602 gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
603 d = dist->grad(X, G);
607 void surface_projection(base_node &X) {
609 scalar_type d = dist->grad(X, G);
611 while (gmm::abs(d) > 1e-10) {
613 GMM_ASSERT1(it <= 10000,
"Object empty, or bad signed distance X="
614 << X <<
", G=" << G <<
" d = " << d);
618 gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
619 d = dist->grad(X, G);
623 void projection(base_node &X, dal::bit_vector& bv)
624 { projection(X); bv.clear(); (*dist)(X,bv); }
626 void constraint_projection(base_node &X,
size_type cnum) {
628 scalar_type d = constraints[cnum]->grad(X, G);
629 while (gmm::abs(d) > 1e-10) {
630 gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
631 d=constraints[cnum]->grad(X, G);
635 bool pure_multi_constraint_projection(base_node &X,
636 const dal::bit_vector &cts) {
637 getfem::pure_multi_constraint_projection(constraints, X, cts);
651 return ct2.contains(cts);
656 bool multi_constraint_projection(base_node &X,
657 const dal::bit_vector &cts) {
658 if (!(cts.card())) { projection(X);
return true; }
664 for (dal::bv_visitor ic(cts); !ic.finished(); ++ic)
665 constraint_projection(X,ic);
668 }
while (gmm::vect_dist2(oldX,X) > 1e-14 && cnt < 1000);
669 if (cnt >= 1000)
return false;
672 return ct2.contains(cts);
676 void tangential_displacement(base_small_vector &X,
677 const dal::bit_vector &cts) {
679 base_matrix normals(N, cts.card());
681 for (dal::bv_visitor ic(cts); !ic.finished(); ++ic) {
682 constraints[ic]->grad(X, G);
683 gmm::copy(G, gmm::mat_col(normals, cnt));
685 gmm::add(gmm::scaled(gmm::mat_col(normals, k),
686 -gmm::vect_sp(gmm::mat_col(normals,k),
687 gmm::mat_col(normals,cnt))),
688 gmm::mat_col(normals,cnt));
690 if (n < 1e-8)
continue;
691 gmm::scale(gmm::mat_col(normals, cnt), 1./n);
692 gmm::add(gmm::scaled(gmm::mat_col(normals, cnt),
693 -gmm::vect_sp(X,gmm::mat_col(normals, cnt))),X);
699 const pt_attribute* get_attr(
bool fixed,
const dal::bit_vector &bv) {
703 return &(*attributes_set.insert(a).first);
706 void surface_projection_and_update_constraints(
size_type ip) {
707 surface_projection(pts[ip]);
708 dal::bit_vector new_cts;
709 (*dist)(pts[ip], new_cts);
710 pts_attr[ip] = get_attr(pts_attr[ip]->fixed, new_cts);
713 void project_and_update_constraints(
size_type ip) {
714 const dal::bit_vector& cts = pts_attr[ip]->constraints;
715 dal::bit_vector new_cts;
716 multi_constraint_projection(pts[ip], cts);
717 (*dist)(pts[ip], new_cts);
718 if (noisy > 1 && !new_cts.contains(cts)) {
719 cout <<
"Point #" << ip <<
" has been downgraded from "
720 << cts <<
" to " << new_cts << endl;
722 else if (noisy > 1 && new_cts.card() > cts.card()) {
723 cout <<
"Point #" << ip <<
" has been upgraded from "
724 << cts <<
" to " << new_cts << endl;
726 if (new_cts != cts) {
727 pts_attr[ip] = get_attr(pts_attr[ip]->fixed, new_cts);
733 template <
class VECT>
void move_carefully(
size_type ip,
const VECT &VV) {
734 base_node V(N); gmm::copy(VV, V);
742 if (norm <= h0/scalar_type(4))
743 gmm::add(V, pts[ip]);
745 gmm::add(gmm::scaled(V, h0 / (scalar_type(4) * norm)), pts[ip]);
746 project_and_update_constraints(ip);
749 template <
class VECT>
void move_carefully(
const VECT &V) {
750 scalar_type norm_max(0), lambda(1);
753 norm_max = std::max(norm_max, gmm::vect_norm2
754 (gmm::sub_vector(V, gmm::sub_interval(i*N, N))));
755 if (norm_max > h0/scalar_type(3.7))
756 lambda = h0 / (scalar_type(3.7) * norm_max);
759 move_carefully(i, gmm::scaled(gmm::sub_vector
760 (V, gmm::sub_interval(i*N, N)),lambda));
763 void distribute_points_regularly(
const std::vector<base_node>
766 std::vector<size_type> gridnx(N);
768 base_node eff_boxmin(N), eff_boxmax(N);
769 bool eff_box_init =
false;
772 h0 = std::min(h0, bounding_box_max[i] - bounding_box_min[i]);
773 GMM_ASSERT1(h0 >= 1E-10,
"h0 = " << h0 <<
" too small, aborting.");
777 if (N == 2 && i == 1) h = sqrt(3.)/2. * h0;
778 gridnx[i]=1+(
size_type)((bounding_box_max[i]-bounding_box_min[i])/h);
783 for (
size_type i=0; i < fixed_points.size(); ++i) {
784 if ((*dist)(fixed_points[i]) < geps &&
785 m.search_point(fixed_points[i]) ==
size_type(-1)) {
786 m.add_point(fixed_points[i]);
787 pts.push_back(fixed_points[i]);
788 pts_attr.push_back(get_attr(
true,dal::bit_vector()));
791 cout <<
"Removed duplicate fixed point: "<<fixed_points[i]<<
"\n";
793 base_node P(N), Q(N);
796 unsigned p = unsigned(r % gridnx[k]);
797 P[k] = p * (bounding_box_max[k] - bounding_box_min[k]) /
798 scalar_type((gridnx[k]-1)) + bounding_box_min[k];
799 if (N==2 && k==0 && ((r/gridnx[0])&1)==1) P[k] += h0/2;
804 if ((prefind == 1 && (*dist)(P) < 0) || prefind == 2) {
805 for (
size_type k = 0; k < constraints.size() && co.card() < N; ++k) {
807 if (gmm::abs((*(constraints[k]))(Q)) < h0) {
808 constraint_projection(Q, k);
809 if ((*dist)(Q) > -geps &&
810 (gmm::vect_dist2(P, Q) < h0 / scalar_type(2))) co.add(k);
816 bool ok = pure_multi_constraint_projection(Q, co);
817 if (!ok || gmm::abs((*dist)(Q)) > geps) { gmm::copy(P, Q); co.clear(); }
824 if ((*dist)(Q) < geps) {
825 if (m.search_point(Q) ==
size_type(-1)) {
828 { eff_boxmin = eff_boxmax = Q; eff_box_init =
true; }
830 eff_boxmin[k] = std::min(eff_boxmin[k], Q[k]);
831 eff_boxmax[k] = std::max(eff_boxmax[k], Q[k]);
833 m.add_point(Q); pts.push_back(Q);
834 pts_attr.push_back(get_attr(
false, co));
838 if (noisy > 0) cout <<
"effective bounding box : " << eff_boxmin <<
" : " << eff_boxmax << endl;
840 h0 = std::min(h0, gmm::vect_dist2(eff_boxmin, eff_boxmax)
845 void add_point_hull(
void) {
846 if (dist_point_hull > 0) {
850 for (
unsigned i=0; i < nbpt; ++i) {
851 if (pts_attr[i]->constraints.card()) {
856 P += V * (dist_point_hull*h0/d);
857 if ((*dist)(P)*sqrt(scalar_type(N)) > dist_point_hull*h0) {
860 if (gmm::vect_dist2(P, Q) > dist_point_hull*h0/scalar_type(2))
861 { pts.push_back(P); ++nbadd; }
866 if (noisy > 1) cout <<
"point hull: " << nbadd <<
" points added\n";
871 scalar_type pts_dist_max(
const std::vector<base_node> &A,
872 const std::vector<base_node> &B) {
873 scalar_type dist_max = 0;
875 dist_max = std::max(dist_max, gmm::vect_dist2_sqr(A[i],B[i]));
876 return sqrt(dist_max);
879 struct cleanup_points_compare {
880 const std::vector<base_node> &pts;
881 const std::vector<const pt_attribute*> &attr;
882 cleanup_points_compare(
const std::vector<base_node> &pts_,
883 const std::vector<const pt_attribute*> &attr_)
884 : pts(pts_), attr(attr_) {}
886 if (attr[a] != attr[b])
return attr[a] < attr[b];
887 return pts[a] < pts[b];
890 void cleanup_points() {
891 std::vector<size_type> idx(pts.size());
892 for (
size_type i=0; i < idx.size(); ++i) idx[i] = i;
894 std::sort(idx.begin(), idx.end(), cleanup_points_compare(pts,pts_attr));
897 dal::bit_vector keep_pts; keep_pts.add(0,idx.size());
898 for (
size_type i=0, i0=0; i < idx.size(); ++i) {
899 const base_node &P = pts[idx[i]];
900 const pt_attribute *a = pts_attr[idx[i]];
902 if (i == idx.size()-1 || a != pts_attr[idx[i+1]]) {
904 base_node bmin = P, bmax = P;
905 scalar_type h = h0*edge_len(P);
907 { bmin[k] -= h/20.; bmax[k] += h/20.; }
909 tree.points_in_box(neighbors, bmin, bmax);
910 for (
size_type k=0; k < neighbors.size(); ++k) {
911 if (neighbors[k].i != i && keep_pts.is_in(neighbors[k].i)
912 && keep_pts.is_in(i)) {
914 cout <<
"point #" << i <<
" " << P
915 <<
" is too near from point #" << neighbors[k].i
916 << pts[idx[neighbors[k].i]] <<
" : will be removed\n";
925 pts_prev.resize(keep_pts.card());
927 std::vector<const pt_attribute*> pts_attr2(keep_pts.card());
928 for (dal::bv_visitor i(keep_pts); !i.finished(); ++i, ++cnt) {
929 pts_prev[cnt].swap(pts[idx[i]]);
930 pts_attr2[cnt] = pts_attr[idx[i]];
932 pts_attr.swap(pts_attr2);
933 pts.resize(pts_prev.size());
934 std::copy(pts_prev.begin(), pts_prev.end(), pts.begin());
940 void select_elements(
int version) {
944 base_node weights(N+1);
945 for (
size_type i=0; i < gmm::mat_ncols(t); ) {
946 bool ext_simplex =
false;
948 bool on_boundary_simplex =
false;
949 bool is_bridge_simplex =
false;
950 scalar_type q(0), dG(0);
954 if (t(k, i) >= nbpt) ext_simplex =
true;
958 for (
size_type k=1; k <= N; ++k) G += pts[t(k,i)];
959 gmm::scale(G, scalar_type(1)/scalar_type(N+1));
963 q = quality_of_element(i);
966 if (!(pts_attr[t(k,i)]->constraints.card() == 0))
967 on_boundary_simplex =
true;
972 if (version == 1 && on_boundary_simplex)
975 dal::bit_vector all_cts = pts_attr[t(k,i)]->constraints
976 | pts_attr[t(l,i)]->constraints;
978 !(pts_attr[t(k,i)]->constraints.contains(all_cts))
979 && !(pts_attr[t(l,i)]->constraints.contains(all_cts))
980 && (*dist)(0.5*(pts[t(k,i)] + pts[t(l,i)])) > 0.)
981 is_bridge_simplex =
true;
984 if (ext_simplex || dG > 0 || is_bridge_simplex || q < 1e-14) {
990 worst_q_P = G*(scalar_type(1)/scalar_type(N+1));
997 void adapt_mesh(mesh &m,
size_type degree) {
998 std::vector<base_node> cvpts(N+1), cvpts2;
1001 for (
size_type ip=0; ip < pts.size(); ++ip) {
1004 while ((z = m.add_point(P)) != ip) {
1005 if (noisy > 0) cout <<
"WARNING : points are too near ...\n";
1007 gmm::add(gmm::scaled(Z, h0/1000.0), P);
1010 for (
size_type i=0; i < t.size()/(N+1); ++i) {
1011 for (
size_type k=0; k < N+1; ++k) cvpts[k] = pts[t[i*(N+1)+k]];
1013 cvnum = m.add_convex(bgeot::simplex_geotrans(N,1), &t[i*(N+1)]);
1017 bgeot::simplex_geotrans(N,
short_type(degree));
1018 cvpts2.resize(pgt->nb_points());
1019 for (
size_type k=0; k < pgt->nb_points(); ++k) {
1020 cvpts2[k] = bgeot::simplex_geotrans(N,1)->transform
1021 (pgt->convex_ref()->points()[k], cvpts);
1023 cvnum = m.add_convex_by_points(pgt, cvpts2.begin());
1031 dal::bit_vector ptdone; ptdone.sup(0,m.points_index().last_true());
1033 mesh::ind_pt_face_ct fpts_
1034 = m.ind_points_of_face_of_convex(it.cv(), it.f());
1035 std::vector<size_type> fpts(fpts_.size());
1036 std::copy(fpts_.begin(), fpts_.end(), fpts.begin());
1037 interpolate_face(m, ptdone, fpts,
1038 m.trans_of_convex(it.cv())->structure()
1039 ->faces_structure()[it.f()]);
1046 void interpolate_face(mesh &m, dal::bit_vector& ptdone,
1047 const std::vector<size_type>& ipts,
1049 if (cvs->dim() == 0)
return;
1050 else if (cvs->dim() > 1) {
1051 std::vector<size_type> fpts;
1052 for (
short_type f=0; f < cvs->nb_faces(); ++f) {
1053 fpts.resize(cvs->nb_points_of_face(f));
1054 for (
size_type k=0; k < fpts.size(); ++k)
1055 fpts[k] = ipts[cvs->ind_points_of_face(f)[k]];
1056 interpolate_face(m,ptdone,fpts,cvs->faces_structure()[f]);
1060 for (
size_type i=0; i < ipts.size(); ++i) {
1061 if (ipts[i] < pts.size()) {
1062 if (cnt == 0) cts = pts_attr[ipts[i]]->constraints;
1063 else cts &= pts_attr[ipts[i]]->constraints;
1069 for (
size_type i=0; i < ipts.size(); ++i) {
1070 if (ipts[i] >= pts.size() && !ptdone[ipts[i]]) {
1071 base_node &P = m.points()[ipts[i]];
1072 multi_constraint_projection(P, cts);
1079 void special_constraints_management(
void) {
1083 bool tree_empty =
true;
1084 mesh::ind_set iAneighbors, iBneighbors, common_pts;
1086 attractor_points.resize(0); attracted_points.resize(0);
1089 !ie.finished(); ++ie) {
1093 if (pts_attr[iA] == pts_attr[iB] ||
1094 pts_attr[iA]->constraints.card() == 0 ||
1095 pts_attr[iB]->constraints.card() == 0)
continue;
1096 if (pts_attr[iA]->constraints == pts_attr[iB]->constraints)
1098 dal::bit_vector bv1(pts_attr[iA]->constraints);
1099 bv1.setminus(pts_attr[iB]->constraints);
1100 dal::bit_vector bv2(pts_attr[iB]->constraints);
1101 bv2.setminus(pts_attr[iA]->constraints);
1102 if (bv1.card() && bv2.card()) {
1106 common_pts.resize(0);
1107 for (
size_type i = 0; i < iAneighbors.size(); ++i)
1108 if (std::find(iBneighbors.begin(), iBneighbors.end(),
1109 iAneighbors[i]) != iBneighbors.end())
1110 common_pts.push_back(iAneighbors[i]);
1111 bool do_projection =
true;
1112 if ((*dist)(.5*(pts[iA]+pts[iB])) < 0) {
1113 for (mesh::ind_set::iterator it = common_pts.begin();
1114 it != common_pts.end(); ++it) {
1115 if (pts_attr[*it]->constraints.contains(bv1)) {
1116 do_projection =
false;
1121 if (do_projection) {
1123 if (pts_attr[iA]->constraints.card()
1124 < pts_attr[iB]->constraints.card()) std::swap(iA,iB);
1126 base_node PA = pts[iA];
1127 bool okA = multi_constraint_projection(PA, bv1);
1128 base_node PB = pts[iB];
1129 bool okB = multi_constraint_projection(PB, bv1);
1132 { std::swap(PA,PB); std::swap(iA,iB); std::swap(okB, okA); }
1134 if (okB && (gmm::vect_dist2(PA,pts[iA])
1135 > 1.1*gmm::vect_dist2(PB,pts[iB]))) {
1137 std::swap(iA,iB); std::swap(PA,PB);
1141 if (okA && gmm::vect_dist2(PA, pts[iA]) < h0*0.75) {
1144 for (
size_type i=0; i < pts.size(); ++i)
1149 base_node bmin = PA, bmax = PA;
1151 { bmin[k] -= h0/1.8; bmax[k] += h0/1.8; }
1152 tree.points_in_box(neighbors, bmin, bmax);
1153 for (
size_type k=0; k < neighbors.size(); ++k) {
1154 if (neighbors[k].i != iA && neighbors[k].i != iB)
1155 do_projection =
false;
1158 if (do_projection) {
1159 attractor_points.push_back(PA);
1160 attracted_points.push_back(iA);
1169 void running_delaunay(
bool mct) {
1171 cout <<
"NEW DELAUNAY, running on " << pts.size() <<
" points\n";
1174 bgeot::qhull_delaunay(pts, t);
1176 if (noisy > 1) cout <<
"number of elements before selection = "
1177 << gmm::mat_ncols(t) <<
"\n";
1181 for (
size_type i=0; i < gmm::mat_ncols(t); ++i)
1184 edges_mesh.add_segment(t(j,i), t(k,i));
1185 special_constraints_management();
1188 if (noisy > 0) cout <<
"number of elements after selection = "
1189 << gmm::mat_ncols(t) <<
"\n";
1191 for (
size_type i=0; i < gmm::mat_ncols(t); ++i)
1194 edges_mesh.add_segment(t(j,i), t(k,i));
1197 void standard_move_strategy(base_vector &X) {
1199 !ie.finished(); ++ie) {
1202 base_node bar = pts[iB]-pts[iA];
1203 scalar_type F = std::max(L0[ie]-L[ie], 0.);
1206 base_node Fbar = (bar)*(F/L[ie]);
1208 if (!pts_attr[iA]->fixed)
1209 gmm::add(gmm::scaled(Fbar, -deltat),
1210 gmm::sub_vector(X, gmm::sub_interval(iA*N, N)));
1211 if (!pts_attr[iB]->fixed)
1212 gmm::add(gmm::scaled(Fbar, deltat),
1213 gmm::sub_vector(X, gmm::sub_interval(iB*N, N)));
1218 void do_build_mesh(mesh &m,
1219 const std::vector<base_node> &fixed_points) {
1221 distribute_points_regularly(fixed_points);
1222 std::vector<base_node> pts2(pts.size(),base_node(N));
1223 size_type count = 0, count_id = 0, count_ct = 0;
1224 bool pt_changed =
false;
1226 attracted_points.resize(0);
1227 attractor_points.resize(0);
1231 cout <<
"Iter " << count <<
" / " << count + iter_max - iter_wtcc;
1232 if (count && pts_prev.size() == pts.size())
1233 cout <<
", dist_max since last delaunay ="
1234 << pts_dist_max(pts, pts_prev) <<
", tol=" << ttol*h0;
1237 if (count==0 || pts_prev.size() != pts.size()
1238 || (pts_dist_max(pts, pts_prev) > ttol*h0 && count_id >= 5)) {
1241 if (noisy == 1) cout <<
"Iter " << count <<
" ";
1243 if (count_ct >= 20 || pt_changed) {
1247 running_delaunay(mct);
1248 pt_changed = nbpt != pts.size();
1251 ++count_id; ++count_ct;
1256 GMM_ASSERT1(nbcv != 0,
"no more edges!");
1257 L.resize(nbcv); L0.resize(nbcv);
1258 scalar_type sL = 0, sL0 = 0;
1260 !ie.finished(); ++ie) {
1263 base_node C(A); C+=B; C /= scalar_type(2);
1265 L0[ie] = edge_len(C);
1266 sL += pow(L[ie],scalar_type(N));
1267 sL0 += pow(L0[ie],scalar_type(N));
1269 gmm::scale(L0, L0mult * pow(sL/sL0, scalar_type(1)/scalar_type(N)));
1272 base_vector X(pts.size() * N);
1273 standard_move_strategy(X);
1274 for (
size_type i = 0; i < attracted_points.size(); ++i) {
1276 gmm::copy(attractor_points[i] - pts[npt],
1277 gmm::sub_vector(X, gmm::sub_interval(npt*N, N)));
1282 scalar_type maxdp = pts_dist_max(pts,pts2);
1284 cout <<
", maxdp = " << maxdp <<
", ptol = "
1285 << ptol <<
" CV=" << sqrt(maxdp)*deltat/h0 <<
"\n";
1286 ++count; ++iter_wtcc;
1288 if (iter_wtcc == 100) control_mesh_surface();
1297 if ( (count > 40 && sqrt(maxdp)*deltat < ptol * h0)
1298 || iter_wtcc>iter_max || count > 10000) {
1309 control_mesh_surface();
1312 bgeot::qhull_delaunay(pts, t);
1314 select_elements((prefind == 3) ? 0 : 1);
1315 suppress_flat_boundary_elements();
1326 if (prefind != 3) optimize_quality();
1331 for (
unsigned cv = 0; cv < gmm::mat_ncols(t); ++cv) {
1333 if (quality_of_element(cv) < 0.05) {
1334 base_node G = pts[t(0,cv)];
1335 for (
size_type k=1; k <= N; ++k) G += pts[t(k,cv)];
1336 gmm::scale(G, scalar_type(1)/scalar_type(N+1));
1338 pts_attr.push_back(get_attr(
false, dal::bit_vector()));
1342 if (pts.size() != nbpt) {
1343 control_mesh_surface();
1346 bgeot::qhull_delaunay(pts, t);
1348 select_elements((prefind == 3) ? 0 : 1);
1349 suppress_flat_boundary_elements();
1360 if (prefind != 3) optimize_quality();
1371 m.optimize_structure();
1420 void build_mesh(mesh &m,
const pmesher_signed_distance& dist,
1421 scalar_type h0,
const std::vector<base_node> &fixed_points,
1423 scalar_type dist_point_hull,
1424 scalar_type boundary_threshold_flatness) {
1425 mesher mg(K, dist, getfem::mvf_constant(1), h0, m, fixed_points, noise,
1426 iter_max, prefind, dist_point_hull, boundary_threshold_flatness);