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);
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);
45 scalar_type mesher_level_set::grad(
const base_node &P,
46 base_small_vector &G)
const {
47 if (initialized < 1) init_grad();
50 G[i] = bgeot::to_scalar(gradient[i].eval(P.begin()));
54 void mesher_level_set::hess(
const base_node &P, base_matrix &H)
const {
55 if (initialized < 2) init_hess();
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()));
68 bool try_projection(
const mesher_signed_distance& dist, base_node &X,
70 base_small_vector G; base_node Y = X;
71 scalar_type d = dist.grad(X, G), dmin = gmm::abs(d);
73 if (on_surface || d > 0.0)
74 while (iter == 0 || dmin > 1e-15 || gmm::vect_dist2(X, Y) > 1e-15 ) {
77 GMM_WARNING4(
"Try projection failed, 1000 iterations\n\n");
81 gmm::scale(G, -d / std::max(1E-8, gmm::vect_norm2_sqr(G)));
92 if (gmm::abs(d) >= dmin*0.95) ++count_falt;
93 else { count_falt = 0; dmin = gmm::abs(d); }
95 if (count_falt > 20)
return false;
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;
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);
119 scalar_type residual(0),
alpha(0), det(0);
123 try_projection(*(ls[0]), X,
true);
124 d[0] = -(ls[0]->grad(X, G[0]));
128 det = scalar_type(0); info = 1;
129 alpha = -scalar_type(1);
138 det = scalar_type(1);
139 for (i = 0; i < nbco; ++i) det *= H(i,i);
143 if (info || gmm::abs(det) < 1E-20) {
144 dal::bit_vector cts_red = cts;
147 for (dal::bv_visitor ic(cts); !ic.finished(); ++ic, ++i) {
149 gmm::add(gmm::scaled(G[j], -gmm::vect_sp(G[j], G[i])), G[i]);
153 { cts_red[ic] =
false; eliminated++; }
155 gmm::scale(G[i], scalar_type(1)/norm_gi);
158 if (eliminated >= 1) {
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]));
163 det = scalar_type(0); info = 1;
170 det = scalar_type(1);
171 for (i = 0; i < nbco; ++i) det *= H(i,i);
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]));
189 GMM_ASSERT1(nbco <= N,
"internal error");
191 for (i = 0; i < nbco; ++i) d[i] = -(ls[i]->grad(X, G[i]));
192 alpha = scalar_type(1);
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]));
199 if (alpha < 1E-15)
break;
207 }
while (residual > 1e-14 && (residual > 1e-11 || iter < 15)
211 for (i = 0; i < nbco; ++i)
if (gmm::abs(d[i]) > SEPS) {
223 static scalar_type max_vp(
const base_matrix& 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);
229 for (
size_type i = 0; i < m; ++i) emax = std::max(emax, gmm::abs(eig[i]));
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);
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) {
250 = curvature_radius_estimate(*(list_constraints[j]), X);
251 r0 = std::min(r, r0);
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;
268 gmm::dense_matrix<T> B(n,n), C(n,n);
271 bgeot::lu_inverse(&(*(B.begin())), n);
274 gmm::mult(gmm::scaled(M, T(-2)*trB), C, G);
275 gmm::add(gmm::scaled(M, T(2)*trBinv), G);
279 struct pt_attribute {
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;
286 if (constraints.last_true() > other.constraints.last_true())
288 else if (constraints.last_true() < other.constraints.last_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;
303 pmesher_signed_distance dist;
304 const mesher_virtual_function& edge_len;
305 scalar_type h0, dist_point_hull, boundary_threshold_flatness;
308 base_node bounding_box_min, bounding_box_max;
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;
316 scalar_type ptol, ttol, L0mult, deltat, geps, deps;
318 std::vector<const mesher_signed_distance*> constraints;
320 gmm::dense_matrix<scalar_type> W;
323 std::vector<size_type> attracted_points;
324 std::vector<base_node> attractor_points;
327 const pmesher_signed_distance &dist_,
328 const mesher_virtual_function &edge_len_,
330 mesh &m,
const std::vector<base_node> &fixed_points,
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),
336 if (noise == -1) noisy = gmm::traces_level::level() - 2;
340 dist->bounding_box(bounding_box_min,bounding_box_max);
341 N = bounding_box_min.size();
343 L0mult = 1.2; deltat = .2; geps = .001*h0;
345 L0mult=1+0.4/pow(scalar_type(2),scalar_type(N-1));
346 deltat=.1; geps=1e-1*h0;
349 dist->register_constraints(this->constraints);
353 base_matrix G(N,N+1);
354 vectors_to_base_matrix(G,
356 gmm::mult(G, bgeot::geotrans_precomp(pgt, pgt->convex_ref()->pspt(),
358 bgeot::lu_inverse(&(*(W.begin())), N);
359 do_build_mesh(m,fixed_points);
362 template<
class TAB> scalar_type simplex_quality(
const TAB &ppts) {
363 base_matrix G(N,N), GW(N, N);
365 base_node P = ppts[i+1] - ppts[0];
366 std::copy(P.const_begin(), P.const_begin()+N, G.begin()+i*N);
369 return gmm::abs(1./gmm::condition_number(GW));
372 scalar_type worst_element, best_element;
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) {
382 S(k,j) = c[t(j+1,i)*N+k] - c[t(0,i)*N+k];
386 if (bgeot::lu_det(&(*(SW.begin())), N) < 1E-16) cost += 1e30;
388 scalar_type qual = gmm::Frobenius_condition_number_sqr(SW);
390 worst_element = std::max(worst_element, qual / scalar_type(N*N));
391 best_element = std::min(best_element, qual / scalar_type(N*N));
394 return cost / scalar_type(N * N);
397 void fbcond_cost_function_derivative(
const base_vector& c,
400 base_matrix Dcond(N,N), G(N,N), S(N,N), SW(N,N);
401 unsigned nbt = unsigned(gmm::mat_ncols(t));
403 for (
unsigned i=0; i < nbt; ++i) {
406 S(k,j) = c[t(j+1,i)*N+k] - c[t(0,i)*N+k];
410 Frobenius_condition_number_sqr_gradient(SW,Dcond);
415 grad[t(j+1,i)*N+k] += G(k,j);
416 grad[t(0,i)*N+k] -= G(k,j);
420 for (
unsigned i=0; i < pts.size(); ++i) {
421 if (pts_attr[i]->constraints.card() || pts_attr[i]->fixed)
426 gmm::scale(grad, scalar_type(1) / scalar_type(N * N));
430 struct fbcond_cost_function_object {
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); }
437 struct fbcond_cost_function_derivative_object {
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); }
444 void optimize_quality() {
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);
453 base_matrix S(N,N), SW(N,N);
454 for (
unsigned i=0; i < nbt; ++i) {
457 S(k,j) = X[t(j+1,i)*N+k] - X[t(0,i)*N+k];
460 if (bgeot::lu_det(&(*(S.begin())), N) < 0) {
461 std::swap(t(0,i), t(1,i));
464 S(k,j) = X[t(j+1,i)*N+k] - X[t(0,i)*N+k];
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";
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;
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)));
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;
491 for (
unsigned i=0; i < pts.size(); ++i)
492 gmm::copy_n(X.begin() + i*N, N, pts[i].begin());
496 if (ic != gmm::mat_ncols(t)-1) {
498 std::swap(t(k,ic), t(k,gmm::mat_ncols(t)-1));
500 t.resize(N+1,gmm::mat_ncols(t)-1);
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()));
508 void control_mesh_surface(
void) {
511 dal::bit_vector ii = m.convex_index(), points_to_project;
513 for (ic << ii; ic !=
size_type(-1); ic << ii) {
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 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
527 if (points_to_project.card()) {
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);
537 void suppress_flat_boundary_elements(
void) {
542 std::vector<base_small_vector> normals;
543 dal::bit_vector ii = m.convex_index();
544 dal::bit_vector flat_bound_elemnts;
547 for (ic << ii; ic !=
size_type(-1); ic << ii) {
548 scalar_type max_flatness = -2.0;
551 if (!m.is_convex_having_neighbor(ic,f)) {
552 if (quality_of_element(ic) < 1E-8) max_flatness = 1E-8;
554 base_small_vector n = m.normal_of_face_of_convex(ic, f);
555 normals.push_back(n / gmm::vect_norm2(n));
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 <<
" : ";
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 <<
" ";
572 if (max_flatness < boundary_threshold_flatness
573 && max_flatness!=-2.0) {
574 flat_bound_elemnts.add(ic);
575 if (noisy > 1) cout <<
" -> deleting";
577 if ((normals.size() >= 2 || max_flatness != -2.0) && noisy > 1)
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())
584 }
while (nb_deleted > 0);
588 bool try_projection(base_node &X)
589 {
return getfem::try_projection(*dist, X); }
591 void projection(base_node &X) {
592 base_small_vector G(X.size());
593 scalar_type d = dist->grad(X, G);
596 while (gmm::abs(d) > 1e-10) {
598 GMM_ASSERT1(it <= 10000,
"Object empty, or bad signed distance");
601 gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
602 d = dist->grad(X, G);
606 void surface_projection(base_node &X) {
608 scalar_type d = dist->grad(X, G);
610 while (gmm::abs(d) > 1e-10) {
612 GMM_ASSERT1(it <= 10000,
"Object empty, or bad signed distance X="
613 << X <<
", G=" << G <<
" d = " << d);
617 gmm::add(gmm::scaled(G, -d / gmm::vect_norm2_sqr(G)), X);
618 d = dist->grad(X, G);
622 void projection(base_node &X, dal::bit_vector& bv)
623 { projection(X); bv.clear(); (*dist)(X,bv); }
625 void constraint_projection(base_node &X,
size_type cnum) {
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);
634 bool pure_multi_constraint_projection(base_node &X,
635 const dal::bit_vector &cts) {
636 getfem::pure_multi_constraint_projection(constraints, X, cts);
650 return ct2.contains(cts);
655 bool multi_constraint_projection(base_node &X,
656 const dal::bit_vector &cts) {
657 if (!(cts.card())) { projection(X);
return true; }
663 for (dal::bv_visitor ic(cts); !ic.finished(); ++ic)
664 constraint_projection(X,ic);
667 }
while (gmm::vect_dist2(oldX,X) > 1e-14 && cnt < 1000);
668 if (cnt >= 1000)
return false;
671 return ct2.contains(cts);
675 void tangential_displacement(base_small_vector &X,
676 const dal::bit_vector &cts) {
678 base_matrix normals(N, cts.card());
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));
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));
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);
698 const pt_attribute* get_attr(
bool fixed,
const dal::bit_vector &bv) {
702 return &(*attributes_set.insert(a).first);
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);
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;
721 else if (noisy > 1 && new_cts.card() > cts.card()) {
722 cout <<
"Point #" << ip <<
" has been upgraded from "
723 << cts <<
" to " << new_cts << endl;
725 if (new_cts != cts) {
726 pts_attr[ip] = get_attr(pts_attr[ip]->fixed, new_cts);
732 template <
class VECT>
void move_carefully(
size_type ip,
const VECT &VV) {
741 if (norm <= h0/scalar_type(4))
744 gmm::add(gmm::scaled(V, h0 / (scalar_type(4) * norm)), pts[ip]);
745 project_and_update_constraints(ip);
748 template <
class VECT>
void move_carefully(
const VECT &V) {
749 scalar_type norm_max(0), lambda(1);
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);
758 move_carefully(i, gmm::scaled(gmm::sub_vector
759 (V, gmm::sub_interval(i*N, N)),lambda));
762 void distribute_points_regularly(
const std::vector<base_node>
765 std::vector<size_type> gridnx(N);
767 base_node eff_boxmin(N), eff_boxmax(N);
768 bool eff_box_init =
false;
771 h0 = std::min(h0, bounding_box_max[i] - bounding_box_min[i]);
772 GMM_ASSERT1(h0 >= 1E-10,
"h0 = " << h0 <<
" too small, aborting.");
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);
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()));
790 cout <<
"Removed duplicate fixed point: "<<fixed_points[i]<<
"\n";
792 base_node P(N), Q(N);
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;
803 if ((prefind == 1 && (*dist)(P) < 0) || prefind == 2) {
804 for (
size_type k = 0; k < constraints.size() && co.card() < N; ++k) {
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);
815 bool ok = pure_multi_constraint_projection(Q, co);
816 if (!ok || gmm::abs((*dist)(Q)) > geps) {
gmm::copy(P, Q); co.clear(); }
823 if ((*dist)(Q) < geps) {
824 if (m.search_point(Q) ==
size_type(-1)) {
827 { eff_boxmin = eff_boxmax = Q; eff_box_init =
true; }
829 eff_boxmin[k] = std::min(eff_boxmin[k], Q[k]);
830 eff_boxmax[k] = std::max(eff_boxmax[k], Q[k]);
832 m.add_point(Q); pts.push_back(Q);
833 pts_attr.push_back(get_attr(
false, co));
837 if (noisy > 0) cout <<
"effective bounding box : " << eff_boxmin <<
" : " << eff_boxmax << endl;
839 h0 = std::min(h0, gmm::vect_dist2(eff_boxmin, eff_boxmax)
844 void add_point_hull(
void) {
845 if (dist_point_hull > 0) {
849 for (
unsigned i=0; i < nbpt; ++i) {
850 if (pts_attr[i]->constraints.card()) {
855 P += V * (dist_point_hull*h0/d);
856 if ((*dist)(P)*sqrt(scalar_type(N)) > dist_point_hull*h0) {
859 if (gmm::vect_dist2(P, Q) > dist_point_hull*h0/scalar_type(2))
860 { pts.push_back(P); ++nbadd; }
865 if (noisy > 1) cout <<
"point hull: " << nbadd <<
" points added\n";
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;
874 dist_max = std::max(dist_max, gmm::vect_dist2_sqr(A[i],B[i]));
875 return sqrt(dist_max);
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_) {}
885 if (attr[a] != attr[b])
return attr[a] < attr[b];
886 return pts[a] < pts[b];
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;
893 std::sort(idx.begin(), idx.end(), cleanup_points_compare(pts,pts_attr));
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]];
901 if (i == idx.size()-1 || a != pts_attr[idx[i+1]]) {
903 base_node bmin = P, bmax = P;
904 scalar_type h = h0*edge_len(P);
906 { bmin[k] -= h/20.; bmax[k] += h/20.; }
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)) {
913 cout <<
"point #" << i <<
" " << P
914 <<
" is too near from point #" << neighbors[k].i
915 << pts[idx[neighbors[k].i]] <<
" : will be removed\n";
924 pts_prev.resize(keep_pts.card());
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]];
931 pts_attr.swap(pts_attr2);
932 pts.resize(pts_prev.size());
933 std::copy(pts_prev.begin(), pts_prev.end(), pts.begin());
939 void select_elements(
int version) {
943 base_node weights(N+1);
944 for (
size_type i=0; i < gmm::mat_ncols(t); ) {
945 bool ext_simplex =
false;
947 bool on_boundary_simplex =
false;
948 bool is_bridge_simplex =
false;
949 scalar_type q(0), dG(0);
953 if (t(k, i) >= nbpt) ext_simplex =
true;
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));
962 q = quality_of_element(i);
965 if (!(pts_attr[t(k,i)]->constraints.card() == 0))
966 on_boundary_simplex =
true;
971 if (version == 1 && on_boundary_simplex)
974 dal::bit_vector all_cts = pts_attr[t(k,i)]->constraints
975 | pts_attr[t(l,i)]->constraints;
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;
983 if (ext_simplex || dG > 0 || is_bridge_simplex || q < 1e-14) {
989 worst_q_P = G*(scalar_type(1)/scalar_type(N+1));
996 void adapt_mesh(mesh &m,
size_type degree) {
997 std::vector<base_node> cvpts(N+1), cvpts2;
1000 for (
size_type ip=0; ip < pts.size(); ++ip) {
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);
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]];
1012 cvnum = m.add_convex(bgeot::simplex_geotrans(N,1), &t[i*(N+1)]);
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);
1022 cvnum = m.add_convex_by_points(pgt, cvpts2.begin());
1030 dal::bit_vector ptdone; ptdone.sup(0,m.points_index().last_true());
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()]);
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]);
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;
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);
1078 void special_constraints_management(
void) {
1082 bool tree_empty =
true;
1083 mesh::ind_set iAneighbors, iBneighbors, common_pts;
1085 attractor_points.resize(0); attracted_points.resize(0);
1088 !ie.finished(); ++ie) {
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)
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()) {
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;
1120 if (do_projection) {
1122 if (pts_attr[iA]->constraints.card()
1123 < pts_attr[iB]->constraints.card()) std::swap(iA,iB);
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);
1131 { std::swap(PA,PB); std::swap(iA,iB); std::swap(okB, okA); }
1133 if (okB && (gmm::vect_dist2(PA,pts[iA])
1134 > 1.1*gmm::vect_dist2(PB,pts[iB]))) {
1136 std::swap(iA,iB); std::swap(PA,PB);
1140 if (okA && gmm::vect_dist2(PA, pts[iA]) < h0*0.75) {
1143 for (
size_type i=0; i < pts.size(); ++i)
1148 base_node bmin = PA, bmax = PA;
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;
1157 if (do_projection) {
1158 attractor_points.push_back(PA);
1159 attracted_points.push_back(iA);
1168 void running_delaunay(
bool mct) {
1170 cout <<
"NEW DELAUNAY, running on " << pts.size() <<
" points\n";
1173 bgeot::qhull_delaunay(pts, t);
1175 if (noisy > 1) cout <<
"number of elements before selection = "
1176 << gmm::mat_ncols(t) <<
"\n";
1180 for (
size_type i=0; i < gmm::mat_ncols(t); ++i)
1183 edges_mesh.add_segment(t(j,i), t(k,i));
1184 special_constraints_management();
1187 if (noisy > 0) cout <<
"number of elements after selection = "
1188 << gmm::mat_ncols(t) <<
"\n";
1190 for (
size_type i=0; i < gmm::mat_ncols(t); ++i)
1193 edges_mesh.add_segment(t(j,i), t(k,i));
1196 void standard_move_strategy(base_vector &X) {
1198 !ie.finished(); ++ie) {
1201 base_node bar = pts[iB]-pts[iA];
1202 scalar_type F = std::max(L0[ie]-L[ie], 0.);
1205 base_node Fbar = (bar)*(F/L[ie]);
1207 if (!pts_attr[iA]->fixed)
1208 gmm::add(gmm::scaled(Fbar, -deltat),
1209 gmm::sub_vector(X, gmm::sub_interval(iA*N, N)));
1210 if (!pts_attr[iB]->fixed)
1211 gmm::add(gmm::scaled(Fbar, deltat),
1212 gmm::sub_vector(X, gmm::sub_interval(iB*N, N)));
1217 void do_build_mesh(mesh &m,
1218 const std::vector<base_node> &fixed_points) {
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;
1225 attracted_points.resize(0);
1226 attractor_points.resize(0);
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;
1236 if (count==0 || pts_prev.size() != pts.size()
1237 || (pts_dist_max(pts, pts_prev) > ttol*h0 && count_id >= 5)) {
1240 if (noisy == 1) cout <<
"Iter " << count <<
" ";
1242 if (count_ct >= 20 || pt_changed) {
1246 running_delaunay(mct);
1247 pt_changed = nbpt != pts.size();
1250 ++count_id; ++count_ct;
1255 GMM_ASSERT1(nbcv != 0,
"no more edges!");
1256 L.resize(nbcv); L0.resize(nbcv);
1257 scalar_type sL = 0, sL0 = 0;
1259 !ie.finished(); ++ie) {
1262 base_node C(A); C+=B; C /= scalar_type(2);
1264 L0[ie] = edge_len(C);
1265 sL += pow(L[ie],scalar_type(N));
1266 sL0 += pow(L0[ie],scalar_type(N));
1268 gmm::scale(L0, L0mult * pow(sL/sL0, scalar_type(1)/scalar_type(N)));
1271 base_vector X(pts.size() * N);
1272 standard_move_strategy(X);
1273 for (
size_type i = 0; i < attracted_points.size(); ++i) {
1275 gmm::copy(attractor_points[i] - pts[npt],
1276 gmm::sub_vector(X, gmm::sub_interval(npt*N, N)));
1281 scalar_type maxdp = pts_dist_max(pts,pts2);
1283 cout <<
", maxdp = " << maxdp <<
", ptol = "
1284 << ptol <<
" CV=" << sqrt(maxdp)*deltat/h0 <<
"\n";
1285 ++count; ++iter_wtcc;
1287 if (iter_wtcc == 100) control_mesh_surface();
1296 if ( (count > 40 && sqrt(maxdp)*deltat < ptol * h0)
1297 || iter_wtcc>iter_max || count > 10000) {
1308 control_mesh_surface();
1311 bgeot::qhull_delaunay(pts, t);
1313 select_elements((prefind == 3) ? 0 : 1);
1314 suppress_flat_boundary_elements();
1325 if (prefind != 3) optimize_quality();
1330 for (
unsigned cv = 0; cv < gmm::mat_ncols(t); ++cv) {
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));
1337 pts_attr.push_back(get_attr(
false, dal::bit_vector()));
1341 if (pts.size() != nbpt) {
1342 control_mesh_surface();
1345 bgeot::qhull_delaunay(pts, t);
1347 select_elements((prefind == 3) ? 0 : 1);
1348 suppress_flat_boundary_elements();
1359 if (prefind != 3) optimize_quality();
1370 m.optimize_structure();
1419 void build_mesh(mesh &m,
const pmesher_signed_distance& dist,
1420 scalar_type h0,
const std::vector<base_node> &fixed_points,
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);
Balanced tree over a set of points.
void add_point_with_id(const base_node &n, size_type i)
insert a new point, with an associated number.
void clear()
reset the tree, remove all points
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,...
void copy(const L1 &l1, L2 &l2)
*/
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
void fill_random(L &l)
fill a vector or matrix with random value (uniform [-1,1]).
linalg_traits< M >::value_type mat_trace(const M &m)
Trace of a matrix.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
void resize(V &v, size_type n)
*/
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
bool is_hermitian(const MAT &A, magnitude_of_linalg(MAT) tol=magnitude_of_linalg(MAT)(-1))
*/
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*/
void add(const L1 &l1, L2 &l2)
*/
size_type lu_factor(DenseMatrix &A, Pvector &ipvt)
LU Factorization of a general (dense) matrix (real or complex).
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.
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.
std::vector< index_node_pair > kdtree_tab_type
store a set of points with associated indexes.
gmm::uint16_type short_type
used as the common short type integer in the library
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
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 .
GEneric Tool for Finite Element Methods.