Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
anisosiz_3d.c
Go to the documentation of this file.
1/* =============================================================================
2** This file is part of the mmg software package for the tetrahedral
3** mesh modification.
4** Copyright (c) Bx INP/CNRS/Inria/UBordeaux/UPMC, 2004-
5**
6** mmg is free software: you can redistribute it and/or modify it
7** under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation, either version 3 of the License, or
9** (at your option) any later version.
10**
11** mmg is distributed in the hope that it will be useful, but WITHOUT
12** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14** License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public
17** License and of the GNU General Public License along with mmg (in
18** files COPYING.LESSER and COPYING). If not, see
19** <http://www.gnu.org/licenses/>. Please read their terms carefully and
20** use this copy of the mmg distribution only if you accept them.
21** =============================================================================
22*/
23
36#include "libmmg3d.h"
39#include "mmgexterns_private.h"
40
48int MMG3D_printEigenv(double dm[3],double vp[3][3]) {
49
50 printf("--- Eigenvalues:\n");
51 printf("%e %e %e\n",dm[0],dm[1],dm[2]);
52 printf("---Eigenvectors (visualization by columns):\n");
53 printf("%e %e %e\n",vp[0][0],vp[1][0],vp[2][0]);
54 printf("%e %e %e\n",vp[0][1],vp[1][1],vp[2][1]);
55 printf("%e %e %e\n",vp[0][2],vp[1][2],vp[2][2]);
56
57 return 1;
58}
59
67int MMG3D_printMat(int8_t symmat,double *m) {
68
69 if( symmat ) {
70 printf("%e %e %e\n",m[0],m[1],m[2]);
71 printf("%e %e %e\n",m[1],m[3],m[4]);
72 printf("%e %e %e\n",m[2],m[4],m[5]);
73 } else {
74 printf("%e %e %e\n",m[0],m[1],m[2]);
75 printf("%e %e %e\n",m[3],m[4],m[5]);
76 printf("%e %e %e\n",m[6],m[7],m[8]);
77 }
78
79 return 1;
80}
81
90int MMG3D_printErrorMat(int8_t symmat,double *m,double *mr) {
91 double dm[9],dd;
92 int i,dim;
93
94 if( symmat )
95 dim = 6;
96 else
97 dim = 9;
98
99 dd = 0.0;
100 for( i = 0; i < dim; i++ )
101 if( fabs(m[i]) > dd )
102 dd = fabs(m[i]);
103 dd = 1.0 / dd;
104
105 for( i = 0; i < dim; i++ )
106 dm[i] = (m[i]-mr[i])*dd;
107
108 if( !MMG3D_printMat(symmat,dm) ) return 0;
109
110 return 1;
111}
112
114 MMG5_pPoint ppt;
115 int i;
116 int n;
117
118 n = 0;
119 for(i=0 ; i<4 ; i++) {
120 ppt = &mesh->point[pt->v[i]];
121 if ( MG_RID(ppt->tag) ) continue;
122 n++;
123 }
124
125 if(!n) {
126 //fprintf(stderr,"\n ## Warning: 4 ridges points... Unable to compute metric.\n");
127 return 0;
128 }
129
130 return 1;
131}
132
144inline int MMG5_moymet(MMG5_pMesh mesh,MMG5_pSol met,MMG5_pTetra pt,double *m1) {
145 MMG5_pPoint ppt;
146 double mm[6],*mp;
147 double dd;
148 int i,k,n;
149 int8_t ddebug = 0;
150 static int8_t mmgWarn=0;
151
152 n = 0;
153 for (k=0; k<6; ++k) mm[k] = 0.;
154 for(i=0 ; i<4 ; i++) {
155 ppt = &mesh->point[pt->v[i]];
156 if ( MG_RID(ppt->tag) ) continue;
157 n++;
158 mp = &met->m[6*pt->v[i]];
159 for (k=0; k<6; ++k) {
160 mm[k] += mp[k];
161 }
162 }
163
164 if(!n) {
165 if ( ddebug && !mmgWarn ) {
166 mmgWarn=1;
167 fprintf(stderr,"\n ## Warning: %s: at least 1 tetra with 4 ridges vertices"
168 "... Unable to compute metric.\n",__func__);
169 }
170 return 0;
171 }
172 dd = 1./n;
173 for (k=0; k<6; ++k) m1[k] = mm[k]*dd;
174 return n;
175}
176
191static int MMG5_defmetsin(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int kel, int iface, int ip) {
192 MMG5_pTetra pt;
193 MMG5_pxTetra pxt;
194 MMG5_pPoint p0;
195 MMG5_pPar par;
196 double *m,n[3],isqhmin,isqhmax,b0[3],b1[3],ps1,tau[3];
197 double ntau2,gammasec[3];
198 double c[3],kappa,maxkappa,alpha, hausd,hausd_v;
199 MMG5_int lists[MMG3D_LMAX+2];
200 int64_t listv[MMG3D_LMAX+2];
201 int k,ilist,ifac,isloc,init_s,ilists,ilistv;
202 MMG5_int idp,iel;
203 uint8_t i,i0,i1,i2;
204 static int8_t mmgWarn = 0;
205
206 pt = &mesh->tetra[kel];
207 idp = pt->v[ip];
208 p0 = &mesh->point[idp];
209
210 /* local parameters at vertex: useless for now because new points are created
211 * without reference (inside the domain) */
212 hausd_v = mesh->info.hausd;
213 isqhmin = mesh->info.hmin;
214 isqhmax = mesh->info.hmax;
215 isloc = 0;
216
217 if ( mesh->adja[4*(kel-1)+iface+1] ) return 0;
218 ilist = MMG5_boulesurfvolp(mesh,kel,ip,iface,
219 listv,&ilistv,lists,&ilists,(p0->tag & MG_NOM));
220
221 if ( ilist!=1 ) {
222 if ( !mmgWarn ) {
223 fprintf(stderr,"\n ## Warning: %s: at least 1 metric not computed:"
224 " unable to compute the ball of point\n",__func__);
225 mmgWarn = 1;
226 }
227 return 0;
228 }
229
230
231 /* travel across the ball of ip to find the minimal local params imposed on
232 * tetras */
233 if ( mesh->info.parTyp & MG_Tetra ) {
234 i = 0;
235 do
236 {
237 if ( isloc ) break;
238
239 par = &mesh->info.par[i];
240 if ( par->elt != MMG5_Tetrahedron ) continue;
241
242 for ( k=0; k<ilistv; ++k ) {
243 pt = &mesh->tetra[listv[k]/4];
244 if ( par->ref == pt->ref ) {
245 hausd_v = par->hausd;
246 isqhmin = par->hmin;
247 isqhmax = par->hmax;
248 isloc = 1;
249 break;
250 }
251 }
252 } while ( ++i<mesh->info.npar );
253
254 for ( ; i<mesh->info.npar; ++i ) {
255 par = &mesh->info.par[i];
256 if ( par->elt != MMG5_Tetrahedron ) continue;
257
258 for ( k=0; k<ilistv; ++k ) {
259 pt = &mesh->tetra[listv[k]/4];
260 if ( par->ref == pt->ref ) {
261 hausd_v = MG_MIN(hausd_v,par->hausd);
262 isqhmin = MG_MAX(isqhmin,par->hmin);
263 isqhmax = MG_MIN(isqhmax,par->hmax);
264 break;
265 }
266 }
267 }
268 }
269
270
271 maxkappa = 0.0;
272 init_s = 0;
273
274 for (k=0; k<ilists; k++) {
275 iel = lists[k] / 4;
276 ifac = lists[k] % 4;
277 pt = &mesh->tetra[iel];
278 assert(pt->xt && (mesh->xtetra[pt->xt].ftag[ifac] & MG_BDY) );
279 pxt = &mesh->xtetra[pt->xt];
280
281 for ( i = 0; i < 3; i++ ) {
282 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
283 }
284 assert(i<3);
285
286 i0 = MMG5_idir[ifac][i];
287 i1 = MMG5_idir[ifac][MMG5_inxt2[i]];
288 i = MMG5_iprv2[i];
289 i2 = MMG5_idir[ifac][i];
290
291 /* Computation of the two control points associated to edge p0p1 with
292 * p1=mesh->point[pt->v[i1]]: p0 is singular */
293 MMG5_norpts(mesh,pt->v[i0],pt->v[i1],pt->v[i2],n);
294
295 MMG5_BezierEdge(mesh,idp,pt->v[i1],b0,b1,MG_EDG_OR_NOM(pxt->tag[MMG5_iarf[ifac][i]]),n);
296
297 /* tangent vector */
298 tau[0] = 3.0*(b0[0] - p0->c[0]);
299 tau[1] = 3.0*(b0[1] - p0->c[1]);
300 tau[2] = 3.0*(b0[2] - p0->c[2]);
301 ntau2 = tau[0]*tau[0] + tau[1]*tau[1] + tau[2]*tau[2];
302
303 /* 2nd order derivative */
304 gammasec[0] = 6.0*p0->c[0] - 12.0*b0[0] + 6.0*b1[0];
305 gammasec[1] = 6.0*p0->c[1] - 12.0*b0[1] + 6.0*b1[1];
306 gammasec[2] = 6.0*p0->c[2] - 12.0*b0[2] + 6.0*b1[2];
307 if ( ntau2 < MMG5_EPSD ) continue;
308 ntau2 = 1.0 / ntau2;
309
310 /* derivative via the normal parametrization */
311 ps1 = gammasec[0]*tau[0] + gammasec[1]*tau[1] + gammasec[2]*tau[2];
312 c[0] = gammasec[0] - ps1*tau[0]*ntau2;
313 c[1] = gammasec[1] - ps1*tau[1]*ntau2;
314 c[2] = gammasec[2] - ps1*tau[2]*ntau2;
315
316 kappa = ntau2 * sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]);
317
318 /* local parameters for triangle */
319 hausd = hausd_v;
320
321 if ( mesh->info.parTyp & MG_Tria ) {
322 if ( !isloc ) {
323 for ( i=0; i<mesh->info.npar; ++i ) {
324 par = &mesh->info.par[i];
325
326 if ( (par->elt != MMG5_Triangle) || (pxt->ref[ifac] != par->ref ) )
327 continue;
328
329 hausd = par->hausd;
330 if ( !init_s ) {
331 isqhmin = par->hmin;
332 isqhmax = par->hmax;
333 init_s = 1;
334 }
335 else {
336 isqhmin = MG_MAX(par->hmin,isqhmin);
337 isqhmax = MG_MIN(par->hmax,isqhmax);
338 }
339 break;
340 }
341 }
342 else {
343 for ( i=0 ; i<mesh->info.npar; ++i) {
344 par = &mesh->info.par[i];
345
346 if ( (par->elt != MMG5_Triangle) || (pxt->ref[ifac] != par->ref ) )
347 continue;
348
349 hausd = MG_MIN(par->hausd,hausd);
350 isqhmin = MG_MAX(par->hmin,isqhmin);
351 isqhmax = MG_MIN(par->hmax,isqhmax);
352 break;
353 }
354 }
355 }
356 maxkappa = MG_MAX(kappa/hausd,maxkappa);
357 }
358
359 isqhmin = 1.0 / (isqhmin*isqhmin);
360 isqhmax = 1.0 / (isqhmax*isqhmax);
361
362 alpha = 1.0 / 8.0 * maxkappa;
363 alpha = MG_MIN(alpha,isqhmin);
364 alpha = MG_MAX(alpha,isqhmax);
365
366 m = &met->m[6*idp];
367 memset(m,0,6*sizeof(double));
368 m[0] = m[3] = m[5] = alpha;
369
370 return 1;
371}
372
390static int MMG5_defmetrid(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int kel,
391 int iface, MMG5_int ip)
392{
393 MMG5_pTetra pt;
394 MMG5_pxTetra pxt;
395 MMG5_Tria ptt;
396 MMG5_pPoint p0,p1,p2;
397 MMG5_pPar par;
398 MMG5_Bezier b;
399 MMG5_int iel,idp,*list;
400 int k,ilist1,ilist2,ilist;
401 MMG5_int list1[MMG3D_LMAX+2],list2[MMG3D_LMAX+2],iprid[2],ier;
402 double *m,isqhmin,isqhmax,*n1,*n2,*n,*t;
403 double trot[2],u[2],ux,uy,uz,det,bcu[3];
404 double r[3][3],lispoi[3*MMG3D_LMAX+1];
405 double detg,detd;
406 int i,i0,i1,i2,ifac,isloc;
407 static int8_t mmgWarn = 0;
408
409 pt = &mesh->tetra[kel];
410 idp = pt->v[ip];
411 p0 = &mesh->point[idp];
412 pxt = &mesh->xtetra[pt->xt];
413
414 /* local parameters */
415 isqhmin = mesh->info.hmin;
416 isqhmax = mesh->info.hmax;
417
418 if ( mesh->info.parTyp ) {
419 isloc = 0;
420
421 i = 0;
422 do
423 {
424 if ( isloc ) break;
425
426 par = &mesh->info.par[i];
427 if ( ( (par->elt != MMG5_Triangle) || (pxt->ref[iface] != par->ref ) ) &&
428 ( (par->elt != MMG5_Tetrahedron) || (pt->ref != par->ref ) ) )
429 continue;
430
431 isqhmin = par->hmin;
432 isqhmax = par->hmax;
433 isloc = 1;
434 } while ( ++i<mesh->info.npar );
435
436 for ( ; i<mesh->info.npar; ++i) {
437 par = &mesh->info.par[i];
438
439 if ( ( (par->elt != MMG5_Triangle) || (pxt->ref[iface] != par->ref ) ) &&
440 ( (par->elt != MMG5_Tetrahedron) || (pt->ref != par->ref ) ) )
441 continue;
442
443 isqhmin = MG_MAX(isqhmin,par->hmin);
444 isqhmax = MG_MIN(isqhmax,par->hmax);
445 }
446 }
447
448 isqhmin = 1.0 / (isqhmin*isqhmin);
449 isqhmax = 1.0 / (isqhmax*isqhmax);
450
451 n1 = &mesh->xpoint[p0->xp].n1[0];
452 n2 = &mesh->xpoint[p0->xp].n2[0];
453 t = p0->n;
454
455 m = &met->m[6*idp];
456 memset(m,0,6*sizeof(double));
457 m[0] = isqhmax;
458 m[1] = isqhmax;
459 m[2] = isqhmax;
460 m[3] = isqhmax;
461 m[4] = isqhmax;
462
463 // Call bouletrid that construct the surfacic ball
464 ier = MMG5_bouletrid(mesh,kel,iface,ip,&ilist1,list1,&ilist2,list2,
465 &iprid[0],&iprid[1] );
466 if ( !ier ) {
467 if ( !mmgWarn ) {
468 fprintf(stderr,"\n ## Warning: %s: at least 1 metric not computed:"
469 " unable to compute the ball of point\n",__func__);
470 mmgWarn = 1;
471 }
472 }
473
474 /* Specific size in direction of t */
475 m[0] = MG_MAX(m[0],MMG5_ridSizeInTangentDir(mesh,p0,idp,iprid,isqhmin,isqhmax));
476
477 /* Characteristic sizes in directions u1 and u2 */
478 for (i=0; i<2; i++) {
479 if ( i==0 ) {
480 n = n1;
481 ilist = ilist1;
482 list = &list1[0];
483 }
484 else {
485 n = n2;
486 ilist = ilist2;
487 list = &(list2[0]);
488 }
489 MMG5_rotmatrix(n,r);
490
491 /* Apply rotation to the half-ball under consideration */
492 i1 = 0;
493 ifac = -1; // Remove uninitialized warning
494 for (k=0; k<ilist; k++) {
495 iel = list[k] / 4;
496 ifac = list[k] % 4;
497 pt = &mesh->tetra[iel];
498 for ( i0=0; i0!=3; ++i0 ) {
499 if ( pt->v[MMG5_idir[ifac][i0]]==idp ) break;
500 }
501 assert(i0!=3);
502 i1 = MMG5_inxt2[i0];
503 p1 = &mesh->point[pt->v[MMG5_idir[ifac][i1]]];
504
505 ux = p1->c[0] - p0->c[0];
506 uy = p1->c[1] - p0->c[1];
507 uz = p1->c[2] - p0->c[2];
508
509 lispoi[3*k+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
510 lispoi[3*k+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
511 lispoi[3*k+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
512 }
513
514 /* last point : the half-ball is open : ilist tria, and ilist +1 points ;
515 lists are enumerated in direct order */
516 i2 = MMG5_inxt2[i1];
517 p2 = &mesh->point[pt->v[MMG5_idir[ifac][i2]]];
518
519 ux = p2->c[0] - p0->c[0];
520 uy = p2->c[1] - p0->c[1];
521 uz = p2->c[2] - p0->c[2];
522
523 lispoi[3*ilist+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
524 lispoi[3*ilist+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
525 lispoi[3*ilist+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
526
527 /* At this point, lispoi contains all the points of the half-ball of p0, rotated
528 so that t_{p_0}S = [z = 0] */
529
530 /* Rotated tangent vector (trot[2] = 0), and third direction */
531 trot[0] = r[0][0]*t[0] + r[0][1]*t[1] + r[0][2]*t[2];
532 trot[1] = r[1][0]*t[0] + r[1][1]*t[1] + r[1][2]*t[2];
533
534 u[0] = -trot[1];
535 u[1] = trot[0];
536
537 /* Travel half-ball at p0 and stop at first triangle containing u */
538 for (k=0; k<ilist; k++) {
539 detg = lispoi[3*k+1]*u[1] - lispoi[3*k+2]*u[0];
540 detd = u[0]*lispoi[3*(k+1)+2] - u[1]*lispoi[3*(k+1)+1];
541 if ( detg > 0.0 && detd > 0.0 ) break;
542 }
543
544 /* If triangle not found, try with -u */
545 if ( k == ilist ) {
546 u[0] *= -1.0;
547 u[1] *= -1.0;
548
549 for (k=0; k<ilist; k++) {
550 detg = lispoi[3*k+1]*u[1] - lispoi[3*k+2]*u[0];
551 detd = u[0]*lispoi[3*(k+1)+2] - u[1]*lispoi[3*(k+1)+1];
552 if ( detg > 0.0 && detd > 0.0 ) break;
553 }
554 }
555 if ( k == ilist ) continue;
556
557 iel = list[k] / 4;
558 ifac = list[k] % 4;
559 pt = &mesh->tetra[iel];
560 for ( i0=0; i0!=3; ++i0 ) {
561 if ( pt->v[MMG5_idir[ifac][i0]]==idp ) break;
562 }
563 assert(i0!=3);
564
565 assert( 0<=ifac && ifac<4 && "unexpected local face idx");
566 MMG5_tet2tri(mesh,iel,ifac,&ptt);
567 assert(pt->xt);
568 pxt = &mesh->xtetra[pt->xt];
569 if ( !MMG5_bezierCP(mesh,&ptt,&b,MG_GET(pxt->ori,ifac)) ) continue;
570
571 /* Barycentric coordinates of vector u in tria iel */
572 detg = lispoi[3*k+1]*u[1] - lispoi[3*k+2]*u[0];
573 detd = u[0]*lispoi[3*(k+1)+2] - u[1]*lispoi[3*(k+1)+1];
574 det = detg + detd;
575 if ( det < MMG5_EPSD ) continue;
576
577 det = 1.0 / det;
578 bcu[0] = 0.0;
579 bcu[1] = u[0]*lispoi[3*(k+1)+2] - u[1]*lispoi[3*(k+1)+1];
580 bcu[1] *= det;
581 assert(bcu[1] <= 1.0);
582 bcu[2] = 1.0 - bcu[1];
583
584 /* Computation of tangent vector and second derivative of curve t \mapsto
585 b(tbcu) (not in rotated frame) */
586 m[i+1] = MG_MAX(m[i+1],
587 MMG5_ridSizeInNormalDir(mesh,i0,bcu,&b,isqhmin,isqhmax));
588 }
589
590 return 1;
591}
592
606static int MMG5_defmetref(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int kel, int iface, int ip) {
607 MMG5_pTetra pt;
608 MMG5_pxTetra pxt;
609 MMG5_Tria ptt;
610 MMG5_pPoint p0,p1;
611 MMG5_pxPoint px0;
612 MMG5_Bezier b;
613 MMG5_pPar par;
614 MMG5_int lists[MMG3D_LMAX+2];
615 int64_t listv[MMG3D_LMAX+2];
616 int k,ilists,ilistv,ilist;
617 MMG5_int iel,ipref[2],idp;
618 int ifac,isloc;
619 double *m,isqhmin,isqhmax,*n,r[3][3],lispoi[3*MMG3D_LMAX+1];
620 double ux,uy,uz,det2d,c[3];
621 double tAA[6],tAb[3], hausd;
622 uint8_t i1,i2,itri1,itri2,i;
623 static int8_t mmgWarn0=0,mmgWarn1=0;
624
625 ipref[0] = ipref[1] = 0;
626 pt = &mesh->tetra[kel];
627 idp = pt->v[ip];
628 p0 = &mesh->point[idp];
629
630 /* local parameters at vertex: useless for now because new points are created
631 * without reference (inside the domain) */
632 hausd = mesh->info.hausd;
633 isqhmin = mesh->info.hmin;
634 isqhmax = mesh->info.hmax;
635 isloc = 0;
636
637 ilist = MMG5_boulesurfvolp(mesh,kel,ip,iface,listv,&ilistv,lists,&ilists,0);
638
639 if ( ilist!=1 ) {
640 if ( !mmgWarn0 ) {
641 fprintf(stderr,"\n ## Warning: %s: at least 1 metric not computed:"
642 " unable to compute the ball of point\n",__func__);
643 mmgWarn0 = 1;
644 }
645 return 0;
646 }
647
648 /* travel across the ball of ip to find the minimal local params imposed on
649 * tetras */
650 if ( mesh->info.parTyp & MG_Tetra ) {
651 i = 0;
652 do
653 {
654 if ( isloc ) break;
655
656 par = &mesh->info.par[i];
657 if ( par->elt != MMG5_Tetrahedron ) continue;
658
659 for ( k=0; k<ilistv; ++k ) {
660 pt = &mesh->tetra[listv[k]/4];
661 if ( par->ref == pt->ref ) {
662 hausd = par->hausd;
663 isqhmin = par->hmin;
664 isqhmax = par->hmax;
665 isloc = 1;
666 break;
667 }
668 }
669 } while ( ++i<mesh->info.npar );
670
671 for ( ; i<mesh->info.npar; ++i ) {
672 par = &mesh->info.par[i];
673 if ( par->elt != MMG5_Tetrahedron ) continue;
674
675 for ( k=0; k<ilistv; ++k ) {
676 pt = &mesh->tetra[listv[k]/4];
677 if ( par->ref == pt->ref ) {
678 hausd = MG_MIN(hausd ,par->hausd);
679 isqhmin = MG_MAX(isqhmin,par->hmin);
680 isqhmax = MG_MIN(isqhmax,par->hmax);
681 break;
682 }
683 }
684 }
685 }
686
687 /* Computation of the rotation matrix T_p0 S -> [z = 0] */
688 assert( p0->xp && !MG_SIN(p0->tag) && MG_EDG(p0->tag) && !(MG_NOM & p0->tag) );
689
690 px0 = &mesh->xpoint[p0->xp];
691
692 n = &px0->n1[0];
693 assert ( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] > MMG5_EPSD2 );
694
695 MMG5_rotmatrix(n,r);
696 m = &met->m[6*idp];
697
698 /* Apply rotation \circ translation to the whole ball */
699 for (k=0; k<ilists; k++) {
700 iel = lists[k] / 4;
701 ifac = lists[k] % 4;
702 pt = &mesh->tetra[iel];
703 assert(pt->xt && (mesh->xtetra[pt->xt].ftag[ifac] & MG_BDY) );
704 pxt = &mesh->xtetra[pt->xt];
705
706 for ( i = 0; i < 3; i++ ) {
707 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
708 }
709 assert(i<3);
710
711 // i0 = MMG5_idir[ifac][i];
712 itri1 = MMG5_inxt2[i];
713 i1 = MMG5_idir[ifac][itri1];
714 itri2 = MMG5_iprv2[i];
715 i2 = MMG5_idir[ifac][itri2];
716 p1 = &mesh->point[pt->v[i1]];
717
718 /* Store the two ending points of ref curves */
719 if ( MG_REF & pxt->tag[MMG5_iarf[ifac][itri1]] ) {
720 if ( !ipref[0] ) {
721 ipref[0] = pt->v[i2];
722 }
723 else if ( !ipref[1] && (pt->v[i2] != ipref[0]) ) {
724 ipref[1] = pt->v[i2];
725 }
726 else if ( (pt->v[i2] != ipref[0]) && (pt->v[i2] != ipref[1]) ) {
727 if ( !mmgWarn1 ) {
728 fprintf(stderr,"\n ## Warning: %s: at least 1 metric not computed:"
729 " non singular point at intersection of 3 ref edges.\n",__func__);
730 mmgWarn1 = 1;
731 }
732 return 0;
733 }
734 }
735
736 if ( MG_REF & pxt->tag[MMG5_iarf[ifac][itri2]] ) {
737 if ( !ipref[0] ) {
738 ipref[0] = pt->v[i1];
739 }
740 else if ( !ipref[1] && (pt->v[i1] != ipref[0]) ) {
741 ipref[1] = pt->v[i1];
742 }
743 else if ( (pt->v[i1] != ipref[0]) && (pt->v[i1] != ipref[1]) ) {
744 if ( !mmgWarn1 ) {
745 fprintf(stderr,"\n ## Warning: %s: at least 1 metric not computed:"
746 " non singular point at intersection of 3 ref edges.\n",__func__);
747 mmgWarn1 = 1;
748 }
749 return 0;
750 }
751 }
752
753 ux = p1->c[0] - p0->c[0];
754 uy = p1->c[1] - p0->c[1];
755 uz = p1->c[2] - p0->c[2];
756
757 lispoi[3*k+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
758 lispoi[3*k+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
759 lispoi[3*k+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
760 }
761
762 /* list goes modulo ilist */
763 assert ( ilists >= 1 );
764 lispoi[3*ilists+1] = lispoi[1];
765 lispoi[3*ilists+2] = lispoi[2];
766 lispoi[3*ilists+3] = lispoi[3];
767
768 /* Check all projections over tangent plane. */
769 for (k=0; k<ilists-1; k++) {
770 det2d = lispoi[3*k+1]*lispoi[3*(k+1)+2] - lispoi[3*k+2]*lispoi[3*(k+1)+1];
771 assert(det2d);
772 if ( det2d <= 0.0 ) {
773 return 0;
774 }
775 }
776 det2d = lispoi[3*(ilists-1)+1]*lispoi[3*0+2] - lispoi[3*(ilists-1)+2]*lispoi[3*0+1];
777 assert(det2d);
778 if ( det2d <= 0.0 ) {
779 return 0;
780 }
781 assert(ipref[0] && ipref[1]);
782
783 /* At this point, lispoi contains all the points of the ball of p0, rotated so
784 that t_{p_0}S = [z = 0], ipref1 and ipref2 are the indices of other ref
785 points. */
786
787 /* Second step : reconstitution of the curvature tensor at p0 in the tangent
788 plane, with a quadric fitting approach */
789 memset(tAA,0x00,6*sizeof(double));
790 memset(tAb,0x00,3*sizeof(double));
791
792 for (k=0; k<ilists; k++) {
793 /* Approximation of the curvature in the normal section associated to tau :
794 by assumption, p1 is either regular, either on a ridge (or a
795 singularity), but p0p1 is not ridge*/
796 iel = lists[k] / 4;
797 ifac = lists[k] % 4;
798 pt = &mesh->tetra[iel];
799 assert(pt->xt);
800 pxt = &mesh->xtetra[pt->xt];
801
802 for ( i = 0; i < 3; i++ ) {
803 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
804 }
805 assert(i<3);
806
807 // i0 = MMG5_idir[ifac][i];
808 // i1 = MMG5_idir[ifac][MMG5_inxt2[i]];
809 assert( 0<=ifac && ifac<4 && "unexpected local face idx");
810 MMG5_tet2tri(mesh,iel,ifac,&ptt);
811
812 MMG5_bezierCP(mesh,&ptt,&b,MG_GET(pxt->ori,ifac));
813
814 /* 1. Fill matrice tAA and second member tAb with \f$A=(\sum X_{P_i}^2 \sum
815 * Y_{P_i}^2 \sum X_{P_i}Y_{P_i})\f$ and \f$b=\sum Z_{P_i}\f$ with \f$P_i\f$
816 * the physical points at edge [i0;i1] extremities and middle.
817 *
818 * 2. Compute the physical coor \a c of the curve edge's mid-point.
819 */
820 MMG5_fillDefmetregSys(k,p0,i,b,r,c,lispoi,tAA,tAb);
821
822 /* local parameters */
823 if ( mesh->info.parTyp & MG_Tria ) {
824 if ( isloc ) {
825 for ( i=0; i<mesh->info.npar; ++i ) {
826 par = &mesh->info.par[i];
827
828 if ( (par->elt != MMG5_Triangle) || (pxt->ref[ifac] != par->ref ) )
829 continue;
830
831 hausd = MG_MIN(par->hausd,hausd);
832 isqhmin = MG_MAX(par->hmin,isqhmin);
833 isqhmax = MG_MIN(par->hmax,isqhmax);
834 break;
835 }
836 }
837 else {
838 for ( i=0; i<mesh->info.npar; ++i ) {
839 par = &mesh->info.par[i];
840
841 if ( (par->elt != MMG5_Triangle) || (pxt->ref[ifac] != par->ref ) )
842 continue;
843
844 hausd = par->hausd;
845 isqhmin = par->hmin;
846 isqhmax = par->hmax;
847 isloc = 1;
848 break;
849 }
850 }
851 }
852 }
853
854 isqhmin = 1.0 / (isqhmin*isqhmin);
855 isqhmax = 1.0 / (isqhmax*isqhmax);
856
857 /* Solve tAA * tmp_m = tAb and fill m with tmp_m (after rotation) */
858 return MMG5_solveDefmetrefSys( mesh, p0, ipref, r, c, tAA, tAb, m,
859 isqhmin, isqhmax, hausd);
860}
861
875static int MMG5_defmetreg(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int kel,int iface, int ip) {
876 MMG5_pTetra pt;
877 MMG5_pxTetra pxt;
878 MMG5_Tria ptt;
879 MMG5_pPoint p0,p1;
880 MMG5_pxPoint px0;
881 MMG5_Bezier b;
882 MMG5_pPar par;
883 MMG5_int lists[MMG3D_LMAX+2];
884 int64_t listv[MMG3D_LMAX+2];
885 int k,ilist,ilists,ilistv;
886 int ifac,isloc;
887 MMG5_int iel,idp;
888 double *n,*m,r[3][3],ux,uy,uz,lispoi[3*MMG3D_LMAX+1];
889 double det2d,c[3],isqhmin,isqhmax;
890 double tAA[6],tAb[3],hausd;
891 uint8_t i1,i;
892 static int8_t mmgWarn = 0;
893
894 pt = &mesh->tetra[kel];
895 idp = pt->v[ip];
896 p0 = &mesh->point[idp];
897
898 /* local parameters at vertex */
899 hausd = mesh->info.hausd;
900 isqhmin = mesh->info.hmin;
901 isqhmax = mesh->info.hmax;
902 isloc = 0;
903
904 ilist = MMG5_boulesurfvolp(mesh,kel,ip,iface,listv,&ilistv,lists,&ilists,0);
905
906 if ( ilist!=1 ) {
907 if ( !mmgWarn ) {
908 fprintf(stderr,"\n ## Warning: %s: at least 1 metric not computed:"
909 " unable to compute the ball of point.\n",
910 __func__);
911 mmgWarn = 1;
912 }
913 return 0;
914 }
915
916 /* travel across the ball of ip to find the minimal local params imposed on
917 * tetras */
918 if ( mesh->info.parTyp & MG_Tetra ) {
919 i = 0;
920 do
921 {
922 if ( isloc ) break;
923
924 par = &mesh->info.par[i];
925 if ( par->elt != MMG5_Tetrahedron ) continue;
926
927 for ( k=0; k<ilistv; ++k ) {
928 pt = &mesh->tetra[listv[k]/4];
929 if ( par->ref == pt->ref ) {
930 hausd = par->hausd;
931 isqhmin = par->hmin;
932 isqhmax = par->hmax;
933 isloc = 1;
934 break;
935 }
936 }
937 } while ( ++i<mesh->info.npar );
938
939 for ( ; i<mesh->info.npar; ++i ) {
940 par = &mesh->info.par[i];
941 if ( par->elt != MMG5_Tetrahedron ) continue;
942
943 for ( k=0; k<ilistv; ++k ) {
944 pt = &mesh->tetra[listv[k]/4];
945 if ( par->ref == pt->ref ) {
946 hausd = MG_MIN(hausd ,par->hausd);
947 isqhmin = MG_MAX(isqhmin,par->hmin);
948 isqhmax = MG_MIN(isqhmax,par->hmax);
949 break;
950 }
951 }
952 }
953 }
954
955 /* Computation of the rotation matrix T_p0 S -> [z = 0] */
956 assert( !(p0->tag & MG_NOSURF) );
957 assert( p0->xp && !MG_SIN(p0->tag) && !MG_EDG(p0->tag) && !(MG_NOM & p0->tag) );
958 px0 = &mesh->xpoint[p0->xp];
959
960 n = &px0->n1[0];
961 assert ( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] > MMG5_EPSD2 );
962
963 MMG5_rotmatrix(n,r);
964 m = &met->m[6*idp];
965
966 /* Apply rotation \circ translation to the whole ball */
967 for (k=0; k<ilists; k++) {
968 iel = lists[k] / 4;
969 ifac = lists[k] % 4;
970 pt = &mesh->tetra[iel];
971 assert(pt->xt && (mesh->xtetra[pt->xt].ftag[ifac] & MG_BDY) );
972
973 for ( i = 0; i < 3; i++ ) {
974 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
975 }
976 assert(i<3);
977
978 // i0 = MMG5_idir[ifac][i];
979 i1 = MMG5_idir[ifac][MMG5_inxt2[i]];
980 p1 = &mesh->point[pt->v[i1]];
981
982 ux = p1->c[0] - p0->c[0];
983 uy = p1->c[1] - p0->c[1];
984 uz = p1->c[2] - p0->c[2];
985
986 lispoi[3*k+1] = r[0][0]*ux + r[0][1]*uy + r[0][2]*uz;
987 lispoi[3*k+2] = r[1][0]*ux + r[1][1]*uy + r[1][2]*uz;
988 lispoi[3*k+3] = r[2][0]*ux + r[2][1]*uy + r[2][2]*uz;
989 }
990
991 /* list goes modulo ilist */
992 assert ( ilists >= 1 );
993 lispoi[3*ilists+1] = lispoi[1];
994 lispoi[3*ilists+2] = lispoi[2];
995 lispoi[3*ilists+3] = lispoi[3];
996
997 /* Check all projections over tangent plane. */
998 for (k=0; k<ilists-1; k++) {
999 det2d = lispoi[3*k+1]*lispoi[3*(k+1)+2] - lispoi[3*k+2]*lispoi[3*(k+1)+1];
1000 assert(det2d);
1001 if ( det2d <= 0.0 ) {
1002 return 0;
1003 }
1004 }
1005 det2d = lispoi[3*(ilists-1)+1]*lispoi[3*0+2] - lispoi[3*(ilists-1)+2]*lispoi[3*0+1];
1006 assert(det2d);
1007 if ( det2d <= 0.0 ) {
1008 return 0;
1009 }
1010
1011 /* At this point, lispoi contains all the points of the ball of p0, rotated
1012 so that t_{p_0}S = [z = 0] */
1013
1014 /* Second step : reconstitution of the curvature tensor at p0 in the tangent
1015 plane, with a quadric fitting approach */
1016 memset(tAA,0x00,6*sizeof(double));
1017 memset(tAb,0x00,3*sizeof(double));
1018
1019 for (k=0; k<ilists; k++) {
1020 /* Approximation of the curvature in the normal section associated to tau :
1021 by assumption, p1 is either regular, either on a ridge (or a
1022 singularity), but p0p1 is not ridge*/
1023 iel = lists[k] / 4;
1024 ifac = lists[k] % 4;
1025 pt = &mesh->tetra[iel];
1026 assert(pt->xt);
1027 pxt = &mesh->xtetra[pt->xt];
1028
1029 for ( i = 0; i < 3; i++ ) {
1030 if ( pt->v[MMG5_idir[ifac][i]] == idp ) break;
1031 }
1032 assert(i<3);
1033
1034 // i0 = MMG5_idir[ifac][i];
1035 // i1 = MMG5_idir[ifac][MMG5_inxt2[i]];
1036 assert( 0<=ifac && iface<4 && "unexpected local face idx");
1037 MMG5_tet2tri(mesh,iel,ifac,&ptt);
1038
1039 MMG5_bezierCP(mesh,&ptt,&b,MG_GET(pxt->ori,ifac));
1040
1041 /* 1. Fill matrice tAA and second member tAb with \f$A=(\sum X_{P_i}^2 \sum
1042 * Y_{P_i}^2 \sum X_{P_i}Y_{P_i})\f$ and \f$b=\sum Z_{P_i}\f$ with P_i the
1043 * physical points at edge [i0;i1] extremities and middle.
1044 *
1045 * 2. Compute the physical coor \a c of the curve edge's mid-point.
1046 */
1047 MMG5_fillDefmetregSys(k,p0,i,b,r,c,lispoi,tAA,tAb);
1048
1049 /* local parameters */
1050 if ( mesh->info.parTyp & MG_Tria ) {
1051 if ( isloc ) {
1052 for ( i=0; i<mesh->info.npar; ++i ) {
1053 par = &mesh->info.par[i];
1054
1055 if ( (par->elt != MMG5_Triangle) || (pxt->ref[ifac] != par->ref ) )
1056 continue;
1057
1058 hausd = MG_MIN(par->hausd,hausd);
1059 isqhmin = MG_MAX(par->hmin,isqhmin);
1060 isqhmax = MG_MIN(par->hmax,isqhmax);
1061 break;
1062 }
1063 }
1064 else {
1065 for ( i=0; i<mesh->info.npar; ++i ) {
1066 par = &mesh->info.par[i];
1067
1068 if ( (par->elt != MMG5_Triangle) || (pxt->ref[ifac] != par->ref ) )
1069 continue;
1070
1071 hausd = par->hausd;
1072 isqhmin = par->hmin;
1073 isqhmax = par->hmax;
1074 isloc = 1;
1075 break;
1076 }
1077 }
1078 }
1079 }
1080
1081 isqhmin = 1.0 / (isqhmin*isqhmin);
1082 isqhmax = 1.0 / (isqhmax*isqhmax);
1083
1084 /* Solve tAA * tmp_m = tAb and fill m with tmp_m (after rotation) */
1085 return MMG5_solveDefmetregSys( mesh,r, c, tAA, tAb, m, isqhmin, isqhmax,
1086 hausd);
1087}
1088
1100static inline
1102 MMG5_pTetra pt,ptloc;
1103 MMG5_pPoint ppt;
1104 MMG5_pPar par;
1105 double isqhmax,isqhmin,*m;
1106 MMG5_int k,ip;
1107 int64_t list[MMG3D_LMAX+2];
1108 int l,i,j,isloc,ilist;
1109
1110 isqhmin = 1./(mesh->info.hmin*mesh->info.hmin);
1111 isqhmax = 1./(mesh->info.hmax*mesh->info.hmax);
1112
1113 if ( !ismet ) {
1114
1115 for (k=1; k<=mesh->ne; k++) {
1116 pt = &mesh->tetra[k];
1117 if ( !MG_EOK(pt) ) continue;
1118
1119 for ( l=0; l<4; ++l ) {
1120
1121 ip = pt->v[l];
1122 ppt = &mesh->point[ip];
1123 if ( ppt->flag || ppt->tag & MG_BDY || !MG_VOK(ppt) ) continue;
1124
1128 if ( mesh->info.parTyp ) {
1129 isqhmax = mesh->info.hmax;
1130 isloc = 0;
1131
1132 /* Local parameters at tetra */
1133 if ( mesh->info.parTyp & MG_Tetra ) {
1134 ilist = MMG5_boulevolp(mesh,k,l,list);
1135
1136 i = 0;
1137 do
1138 {
1139 if ( isloc ) break;
1140
1141 par = &mesh->info.par[i];
1142 if ( par->elt != MMG5_Tetrahedron ) continue;
1143
1144 for ( j=0; j<ilist; ++j ) {
1145 ptloc = &mesh->tetra[list[j]/4];
1146 if ( par->ref == ptloc->ref ) {
1147 isqhmax = par->hmax;
1148 isloc = 1;
1149 break;
1150 }
1151 }
1152 } while ( ++i<mesh->info.npar );
1153
1154 for ( ; i<mesh->info.npar; ++i ) {
1155 par = &mesh->info.par[i];
1156 if ( par->elt != MMG5_Tetrahedron ) continue;
1157
1158 for ( j=0; j<ilist; ++j ) {
1159 ptloc = &mesh->tetra[list[j]/4];
1160 if ( par->ref == ptloc->ref ) {
1161 isqhmax = MG_MIN(isqhmax,par->hmax);
1162 break;
1163 }
1164 }
1165 }
1166 }
1167 isqhmax = 1./(isqhmax*isqhmax);
1168 }
1169
1171 m = &met->m[met->size*ip];
1172 m[0] = isqhmax;
1173 m[1] = 0.;
1174 m[2] = 0.;
1175 m[3] = isqhmax;
1176 m[4] = 0.;
1177 m[5] = isqhmax;
1178 ppt->flag = 1;
1179 }
1180 }
1181 return 1;
1182 }
1183
1185 for (k=1; k<=mesh->ne; k++) {
1186 pt = &mesh->tetra[k];
1187 if ( !MG_EOK(pt) ) continue;
1188
1189 for ( l=0; l<4; ++l ) {
1190
1191 ip = pt->v[l];
1192 ppt = &mesh->point[ip];
1193 if ( ppt->flag || ppt->tag & MG_BDY || !MG_VOK(ppt) ) continue;
1194
1196 if ( mesh->info.parTyp ) {
1197 isqhmin = mesh->info.hmin;
1198 isqhmax = mesh->info.hmax;
1199 isloc = 0;
1200
1201 /* Local parameters at tetra */
1202 if ( mesh->info.parTyp & MG_Tetra ) {
1203 ilist = MMG5_boulevolp(mesh,k,l,list);
1204
1205 i = 0;
1206 do
1207 {
1208 if ( isloc ) break;
1209
1210 par = &mesh->info.par[i];
1211 if ( par->elt != MMG5_Tetrahedron ) continue;
1212
1213 for ( j=0; j<ilist; ++j ) {
1214 ptloc = &mesh->tetra[list[j]/4];
1215 if ( par->ref == ptloc->ref ) {
1216 isqhmin = par->hmin;
1217 isqhmax = par->hmax;
1218 isloc = 1;
1219 break;
1220 }
1221 }
1222 } while ( ++i<mesh->info.npar );
1223
1224 for ( ; i<mesh->info.npar; ++i ) {
1225 par = &mesh->info.par[i];
1226 if ( par->elt != MMG5_Tetrahedron ) continue;
1227
1228 for ( j=0; j<ilist; ++j ) {
1229 ptloc = &mesh->tetra[list[j]/4];
1230 if ( par->ref == ptloc->ref ) {
1231 isqhmin = MG_MAX(isqhmin,par->hmin);
1232 isqhmax = MG_MIN(isqhmax,par->hmax);
1233 break;
1234 }
1235 }
1236 }
1237 }
1238 isqhmin = 1./(isqhmin*isqhmin);
1239 isqhmax = 1./(isqhmax*isqhmax);
1240 }
1241
1242
1244 if ( !MMG5_truncate_met3d(met,ip,isqhmin,isqhmax) ) {
1245 return 0;
1246 }
1247 }
1248 }
1249
1250 return 1;
1251}
1252
1266static inline
1267int MMG3D_intextmet(MMG5_pMesh mesh,MMG5_pSol met,int np,double me[6]) {
1268 MMG5_pPoint p0;
1269 MMG5_pxPoint go;
1270 double *n;
1271 double dummy_n[3];
1272
1273 p0 = &mesh->point[np];
1274
1275 dummy_n[0] = dummy_n[1] = dummy_n[2] = 0.;
1276
1277 if ( MG_SIN(p0->tag) || (p0->tag & MG_NOM) ) {
1278 n = &dummy_n[0];
1279 }
1280 else if ( p0->tag & MG_GEO ) {
1281 /* Take the tangent at point */
1282 n = &p0->n[0];
1283 }
1284 else {
1285 /* Take the normal at point */
1286 assert(p0->xp);
1287 go = &mesh->xpoint[p0->xp];
1288 n = &go->n1[0];
1289 }
1290
1291 return MMG5_mmgIntextmet(mesh,met,np,me,n);
1292
1293}
1294
1311 MMG5_pTetra pt;
1312 MMG5_pxTetra pxt;
1313 MMG5_pPoint ppt;
1314 double mm[6];
1315 MMG5_int k,l;
1316 int iploc;
1317 int8_t ismet;
1318 int8_t i;
1319 static int8_t mmgErr = 0;
1320
1321 if ( !MMG5_defsiz_startingMessage (mesh,met,__func__) ) {
1322 return 0;
1323 }
1324
1325 for (k=1; k<=mesh->np; k++) {
1326 ppt = &mesh->point[k];
1327 ppt->flag = 0;
1328 ppt->s = 0;
1329 }
1330
1331 if ( !met->m ) {
1332 ismet = 0;
1333
1334 /* Allocate and store the header informations for each solution */
1335 if ( !MMG3D_Set_solSize(mesh,met,MMG5_Vertex,mesh->np,3) ) {
1336 return 0;
1337 }
1338
1339 MMG5_caltet = MMG5_caltet_ani;
1340 MMG5_caltri = MMG5_caltri_ani;
1341 MMG5_lenedg = MMG5_lenedg_ani;
1343 MMG5_lenSurfEdg = MMG5_lenSurfEdg_ani;
1344 }
1345 else {
1346 ismet = 1;
1347 }
1348
1352 if ( !mesh->info.nosizreq ) {
1353 if ( !MMG3D_set_metricAtPointsOnReqEdges ( mesh,met,ismet ) ) {
1354 return 0;
1355 }
1356 }
1357
1358 /* Step 2: metric definition at internal points */
1359 if ( !MMG5_defmetvol(mesh,met,ismet) ) return 0;
1360
1361 /* Step 3: metric definition at boundary points */
1362 for (k=1; k<=mesh->ne; k++) {
1363 pt = &mesh->tetra[k];
1364 // Warning: why are we skipped the tetra with negative refs ?
1365 if ( !MG_EOK(pt) || pt->ref < 0 || (pt->tag & MG_REQ) ) continue;
1366 else if ( !pt->xt ) continue;
1367
1368 pxt = &mesh->xtetra[pt->xt];
1369 for (l=0; l<4; l++) {
1370 if ( !(pxt->ftag[l] & MG_BDY) ) continue;
1371 // In multidomain case, acces the face through a tetra for which it is
1372 // well oriented.
1373 if ( !(MG_GET(pxt->ori,l)) ) continue;
1374
1375 for (i=0; i<3; i++) {
1376 iploc = MMG5_idir[l][i];
1377 ppt = &mesh->point[pt->v[iploc]];
1378
1379 if ( !MG_VOK(ppt) ) continue;
1380
1381 if ( ppt->flag > 1 ) continue;
1382
1383 if ( ismet ) memcpy(mm,&met->m[6*(pt->v[iploc])],6*sizeof(double));
1384
1385 if ( MG_SIN_OR_NOM(ppt->tag) ) {
1386 if ( !MMG5_defmetsin(mesh,met,k,l,iploc) ) continue;
1387 }
1388 else if ( ppt->tag & MG_GEO ) {
1389 if ( !MMG5_defmetrid(mesh,met,k,l,iploc)) continue;
1390 }
1391 else if ( ppt->tag & MG_REF ) {
1392 if ( !MMG5_defmetref(mesh,met,k,l,iploc) ) continue;
1393 } else {
1394 if ( !MMG5_defmetreg(mesh,met,k,l,iploc) ) continue;
1395 }
1396 if ( ismet ) {
1397 if ( !MMG3D_intextmet(mesh,met,pt->v[iploc],mm) ) {
1398 if ( !mmgErr ) {
1399 fprintf(stderr,"\n ## Error: %s: unable to intersect metrics"
1400 " at point %" MMG5_PRId ".\n",__func__,
1401 MMG3D_indPt(mesh,pt->v[iploc]));
1402 mmgErr = 1;
1403 }
1404 return 0;
1405 }
1406 }
1407 ppt->flag = 2;
1408 }
1409 }
1410 }
1411 /* Now the metric storage at ridges is the "mmg" one. */
1412 mesh->info.metRidTyp = 1;
1413
1414 /* search for unintialized metric */
1415 MMG5_defUninitSize(mesh,met,ismet);
1416
1417 return 1;
1418}
1419
1438static inline
1439int MMG5_grad2metVol_getmet(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int ip,double ux,double uy,double uz,double *m,int8_t *ridgedir) {
1440 MMG5_pPoint ppt;
1441 MMG5_pxPoint pxp;
1442 double *mm,*nn1,*nn2,rbasis[3][3],ps1,ps2;
1443
1444 ppt = &mesh->point[ip];
1445 mm = &met->m[6*ip];
1446
1447
1448 if( MG_SIN_OR_NOM(ppt->tag) ){
1449
1450 /* no normal, no tangent plane */
1451 memcpy(m,mm,6*sizeof(double));
1452
1453 }
1454 else if( ppt->tag & MG_GEO ) {
1455
1456 /* Recover normal and metric */
1457 pxp = &mesh->xpoint[ppt->xp];
1458 nn1 = pxp->n1;
1459 nn2 = pxp->n2;
1460 ps1 = ux*nn1[0] + uy*nn1[1] + uz*nn1[2];
1461 ps2 = ux*nn2[0] + uy*nn2[1] + uz*nn2[2];
1462 if ( fabs(ps2)<fabs(ps1) ) {
1463 *ridgedir = 1;
1464 }
1465 else{
1466 *ridgedir = 0;
1467 }
1468 /* Note that rbasis is not used in this function */
1469 if( !MMG5_buildridmet(mesh,met,ip,ux,uy,uz,m,rbasis) )
1470 return 0;
1471
1472 }
1473 else if( ppt->tag & MG_BDY ) {
1474 memcpy(m,mm,6*sizeof(double));
1475 }
1476 else {
1477
1478 /* internal point */
1479 memcpy(m,mm,6*sizeof(double));
1480
1481 }
1482
1483 return 1;
1484}
1485
1497static inline
1498void MMG5_grad2metVol_extmet(MMG5_pMesh mesh,MMG5_pPoint ppt,double l,double *m,double *mext) {
1499 double lambda[3],vp[3][3];
1500
1501 MMG5_eigenv3d(1,m,lambda,vp);
1502 for( int8_t i = 0; i < 3; i++ ) {
1503 double hext = 1./sqrt(lambda[i]) + mesh->info.hgrad*l + MMG5_EPSOK;
1504 lambda[i] = 1./(hext*hext);
1505 }
1506 MMG5_eigenvmatsym3d(mesh,mext,lambda,vp);
1507
1508}
1509
1533static inline
1534void MMG3D_gradSimred(MMG5_pMesh mesh,MMG5_pPoint ppt,double m[6],double mext[6],int8_t ridgedir,int8_t iloc,int *ier) {
1535 double tol = MMG5_EPS;
1536
1537 if ( MG_SIN_OR_NOM(ppt->tag) ) {
1538 double dm[3],dmext[3],vp[3][3],beta;
1539
1540 /* Simultaneous reduction basis */
1541 if( !MMG5_simred3d(mesh,m,mext,dm,dmext,vp) ) {
1542 *ier = -1;
1543 return;
1544 }
1545 beta = 1.0;
1546 /* Compute maximum size variation */
1547 for( int8_t i = 0; i < 3; i++ ) {
1548 beta = MG_MAX(beta,dmext[i]/dm[i]);
1549 }
1550 if( beta > 1.0 + tol ) {
1551 (*ier) = (*ier) | iloc;
1552 }
1553 if( (*ier) & iloc ) {
1554 /* You have to homothetically scale the metric in order to make it
1555 * consistent with the above check and for the gradation loop to converge.
1556 * Change the gradation law in the metric extension in
1557 * MMG5_grad2metVol_extmet if you want to restrict the influence of
1558 * singular points. */
1559 m[0] *= beta;
1560 m[3] *= beta;
1561 m[5] *= beta;
1562 }
1563
1564 }
1565 else if ( ppt->tag & MG_GEO ) {
1566 MMG5_pxPoint pxp;
1567 double mr[6],mrext[6],dm[3],dmext[3];
1568 double u[3],r[3][3],*t,*n;
1569
1570 /* Compute ridge orthonormal basis (t, n x t, n) */
1571 t = ppt->n;
1572 pxp = &mesh->xpoint[ppt->xp];
1573 if( ridgedir )
1574 n = pxp->n2;
1575 else
1576 n = pxp->n1;
1577 MMG5_crossprod3d(n,t,u);
1578 /* Store basis in rotation matrix */
1579 for( int8_t i = 0; i < 3; i++ ) {
1580 r[0][i] = t[i];
1581 r[1][i] = u[i];
1582 r[2][i] = n[i];
1583 }
1584 /* Rotate matrices to the ridge reference system */
1585 MMG5_rmtr(r,m,mr);
1586 dm[0] = mr[0];
1587 dm[1] = mr[3];
1588 dm[2] = mr[5];
1589 MMG5_rmtr(r,mext,mrext);
1590 dmext[0] = mrext[0];
1591 dmext[1] = mrext[3];
1592 dmext[2] = mrext[5];
1593 /* The ridge metrics is diagonal and must remain diagonal, while the
1594 * extended metric from the other point is not necessarily diagonal in the
1595 * ridge basis. Do not perform intersection, but simply evaluate lengths on
1596 * the ridge basis and truncate sizes. */
1597 for( int8_t i = 0; i < 3; i++ ) {
1598 if( dmext[i] > dm[i]*(1.0 + tol) ) {
1599 dm[i] = dmext[i];
1600 (*ier) = (*ier) | iloc;
1601 }
1602 }
1603 /* Update metric */
1604 if( (*ier) & iloc ) {
1605 /* Re-build matrix */
1606 MMG5_eigenvmatsym3d(mesh,m,dm,r);
1607 }
1608
1609 }
1610 else if( ppt->tag & MG_BDY ) {
1611 MMG5_pxPoint pxp;
1612 double mr[6],mrext[6],mtan[3],mtanext[3],r[3][3];
1613 double dm[3],dmext[3],vp[2][2];
1614
1615 /* Rotation matrices mapping n to e_3 */
1616 pxp = &mesh->xpoint[ppt->xp];
1617 MMG5_rotmatrix(pxp->n1,r);
1618
1619 /* Rotate metrics to the tangent plane */
1620 MMG5_rmtr(r,m,mr);
1621 mtan[0] = mr[0];
1622 mtan[1] = mr[1];
1623 mtan[2] = mr[3];
1624 MMG5_rmtr(r,mext,mrext);
1625 mtanext[0] = mrext[0];
1626 mtanext[1] = mrext[1];
1627 mtanext[2] = mrext[3];
1628 /* The current point metric is aligned with the surface normal direction,
1629 * while the extended metric from the other point need not.
1630 * Perform intersection only in the tangent plane, while simply truncate
1631 * sizes in the normal direction.
1632 *
1633 * Simultaneous reduction basis */
1634 if( !MMG5_simred2d(mesh,mtan,mtanext,dm,dmext,vp) ) {
1635 *ier = -1;
1636 return;
1637 }
1638 /* Intersection in the tangent plane */
1639 for( int8_t i = 0; i < 2; i++ ) {
1640 if( dmext[i] > dm[i]*(1.0 + tol) ) {
1641 dm[i] = dmext[i];
1642 (*ier) = (*ier) | iloc;
1643 }
1644 }
1645 /* The current point metric is aligned with the surface normal direction,
1646 * while the extended metric from the other point need not.
1647 * Simply evaluate lengths in the normal direction and truncate sizes. */
1648 dm[2] = mr[5];
1649 dmext[2] = mrext[5];
1650 if( dmext[2] > dm[2]*(1.0 + tol) ) {
1651 dm[2] = dmext[2];
1652 (*ier) = (*ier) | iloc;
1653 }
1654 /* Update metric */
1655 if( (*ier) & iloc ) {
1656 /* Simultaneous reduction basis is non-orthogonal, so invert it for the
1657 * inverse transformation for the tangent-plane metric. */
1658 double ivp[2][2];
1659 if( !MMG5_invmat22(vp,ivp) ) {
1660 *ier = -1;
1661 return;
1662 }
1663 MMG5_simredmat(2,mtan,dm,(double *)ivp);
1664 /* Re-assemble 3D metric: use the intersected metrics in the tangent
1665 * plane, and the truncated size in the normal direction. */
1666 mr[0] = mtan[0];
1667 mr[1] = mtan[1];
1668 mr[3] = mtan[2];
1669 mr[2] = mr[4] = 0.0;
1670 mr[5] = dm[2];
1671 /* Transpose rotation matrix and rotate back into the point metric*/
1673 MMG5_rmtr(r,mr,m);
1674 }
1675
1676 }
1677 else { /* internal point */
1678 double dm[3],dmext[3],vp[3][3];
1679
1680 /* Simultaneous reduction basis */
1681 if( !MMG5_simred3d(mesh,m,mext,dm,dmext,vp) ) {
1682 *ier = -1;
1683 return;
1684 }
1685
1686 /* Gradation of sizes in the simultaneous reduction basis */
1687 for( int8_t i = 0; i< 3; i++ ) {
1688 if( dmext[i] > dm[i]*(1.0 + tol) ) {
1689 dm[i] = dmext[i];
1690 (*ier) = (*ier) | iloc;
1691 }
1692 }
1693 /* Update metric */
1694 if( (*ier) & iloc ) {
1695 /* Simultaneous reduction basis is non-orthogonal, so invert it for the
1696 * inverse transformation */
1697 double ivp[3][3];
1698 if( !MMG5_invmat33(vp,ivp) ) {
1699 *ier = -1;
1700 return;
1701 }
1702 MMG5_simredmat(3,m,dm,(double *)ivp);
1703 }
1704
1705 }
1706
1707}
1708
1721static inline
1722void MMG5_grad2metVol_setmet(MMG5_pMesh mesh,MMG5_pSol met,int ip,double *m,int8_t ridgedir) {
1723 MMG5_pPoint ppt;
1724 double *mm;
1725
1726 ppt = &mesh->point[ip];
1727 mm = &met->m[6*ip];
1728
1729 if ( MG_RID(ppt->tag) ) {
1730 double mr[6];
1731 double u[3],r[3][3],*t,*n;
1732
1733 /* Compute ridge orthonormal basis (t, n x t, n) */
1734 t = ppt->n;
1735 MMG5_pxPoint pxp = &mesh->xpoint[ppt->xp];
1736 if( ridgedir )
1737 n = pxp->n2;
1738 else
1739 n = pxp->n1;
1740 MMG5_crossprod3d(n,t,u);
1741 /* Store basis in rotation matrix */
1742 for( int8_t i = 0; i < 3; i++ ) {
1743 r[0][i] = t[i];
1744 r[1][i] = u[i];
1745 r[2][i] = n[i];
1746 }
1747 /* Rotate matrices to the ridge reference system */
1748 MMG5_rmtr(r,m,mr);
1749 /* Store matrix in ridge format */
1750 mm[0] = mr[0];
1751 mm[1+ridgedir] = mr[3];
1752 mm[3+ridgedir] = mr[5];
1753
1754 } else {
1755
1756 memcpy(mm,m,6*sizeof(double));
1757
1758 }
1759
1760 return;
1761}
1762
1778static inline
1779int MMG5_grad2metVol(MMG5_pMesh mesh,MMG5_pSol met,int np1,int np2) {
1780 MMG5_pPoint p1,p2;
1781 double m1[6],m2[6],mext1[6],mext2[6];
1782 double ux,uy,uz,l;
1783 int8_t ridgedir1,ridgedir2;
1784 int ier = 0;
1785
1786 p1 = &mesh->point[np1];
1787 p2 = &mesh->point[np2];
1788
1789 ux = p2->c[0] - p1->c[0];
1790 uy = p2->c[1] - p1->c[1];
1791 uz = p2->c[2] - p1->c[2];
1792 l = sqrt(ux*ux+uy*uy+uz*uz);
1793
1794
1797 if( !MMG5_grad2metVol_getmet(mesh,met,np1,ux,uy,uz,m1,&ridgedir1) ) {
1798 return -1;
1799 }
1800 if( !MMG5_grad2metVol_getmet(mesh,met,np2,ux,uy,uz,m2,&ridgedir2) ) {
1801 return -1;
1802 }
1803 /* (metric now follows standard 3D storage) */
1804
1805
1807 if( p2->flag >= mesh->base-1 ) {
1808 /* Extend p2 metrics */
1809 MMG5_grad2metVol_extmet(mesh,p2,l,m2,mext2);
1810
1811 /* Gradate p1 metrics */
1812 MMG3D_gradSimred(mesh,p1,m1,mext2,ridgedir1,1,&ier);
1813 if( ier == -1 )
1814 return ier;
1815#ifndef NDEBUG
1816 double mtmp[6];
1817 int iertmp = 0;
1818 memcpy(mtmp,m1,6*sizeof(double));
1819 MMG3D_gradSimred(mesh,p1,mtmp,mext2,ridgedir1,1,&iertmp);
1820 if( iertmp & 1 )
1821 ier |= 4;
1822#endif
1823 }
1824
1825
1827 if( p1->flag >= mesh->base-1 ) {
1828 /* Expand p1 metrics */
1829 MMG5_grad2metVol_extmet(mesh,p1,l,m1,mext1);
1830
1831 /* Gradate p2 metrics */
1832 MMG3D_gradSimred(mesh,p2,m2,mext1,ridgedir2,2,&ier);
1833 if( ier == -1 )
1834 return ier;
1835#ifndef NDEBUG
1836 double mtmp[6];
1837 int iertmp = 0;
1838 memcpy(mtmp,m2,6*sizeof(double));
1839 MMG3D_gradSimred(mesh,p2,mtmp,mext1,ridgedir2,2,&iertmp);
1840 if( iertmp & 2 )
1841 ier |= 4;
1842#endif
1843 }
1844
1845
1846 /* Set metrics to the met structure, back to ridge storage */
1847 if( ier & 1 )
1848 MMG5_grad2metVol_setmet(mesh,met,np1,m1,ridgedir1);
1849 if( ier & 2 )
1850 MMG5_grad2metVol_setmet(mesh,met,np2,m2,ridgedir2);
1851
1852 return ier;
1853}
1854
1855
1867int MMG3D_updatemetreq_ani(double *n,double dn[3],double vp[3][3]) {
1868 double ip[3][3];
1869
1870 /* P^-1 */
1871 if ( !MMG5_invmat33(vp,ip) ) {
1872 return 0;
1873 }
1874
1875 /* tp^-1 * dn * P^-1 */
1876 n[0] = dn[0]*ip[0][0]*ip[0][0] + dn[1]*ip[1][0]*ip[1][0] + dn[2]*ip[2][0]*ip[2][0];
1877 n[1] = dn[0]*ip[0][0]*ip[0][1] + dn[1]*ip[1][0]*ip[1][1] + dn[2]*ip[2][0]*ip[2][1];
1878 n[2] = dn[0]*ip[0][0]*ip[0][2] + dn[1]*ip[1][0]*ip[1][2] + dn[2]*ip[2][0]*ip[2][2];
1879
1880 n[3] = dn[0]*ip[0][1]*ip[0][1] + dn[1]*ip[1][1]*ip[1][1] + dn[2]*ip[2][1]*ip[2][1];
1881 n[4] = dn[0]*ip[0][1]*ip[0][2] + dn[1]*ip[1][1]*ip[1][2] + dn[2]*ip[2][1]*ip[2][2];
1882
1883 n[5] = dn[0]*ip[0][2]*ip[0][2] + dn[1]*ip[1][2]*ip[1][2] + dn[2]*ip[2][2]*ip[2][2];
1884
1885 return 1;
1886}
1887
1902static inline
1904 MMG5_int npslave) {
1905 MMG5_pPoint p1,p2;
1906 double *mm1,*mm2,m1[6],m2[6],ux,uy,uz;
1907 double l,difsiz,rbasis1[3][3],rbasis2[3][3];
1908 double lambda[3],vp[3][3],beta,mu[3];
1909 int cfg_m2;
1910 int8_t ier;
1911
1912 p1 = &mesh->point[npmaster];
1913 p2 = &mesh->point[npslave];
1914
1915 ux = p2->c[0] - p1->c[0];
1916 uy = p2->c[1] - p1->c[1];
1917 uz = p2->c[2] - p1->c[2];
1918
1919 mm1 = &met->m[6*npmaster];
1920 mm2 = &met->m[6*npslave];
1921
1922 cfg_m2 = 0;
1923 ier = 0;
1924
1925 if ( MG_RID(p1->tag) ) {
1926 if ( MG_RID(p2->tag) ) {
1927 // The volume gradation from ridge point toward another ridge point is
1928 // bugged...
1929 return 0;
1930 }
1931
1932 /* Recover normal and metric associated to p1 */
1933 if( !MMG5_buildridmet(mesh,met,npmaster,ux,uy,uz,m1,rbasis1) ) { return 0; }
1934 }
1935 else {
1936 memcpy(m1,mm1,6*sizeof(double));
1937 }
1938
1939 if ( MG_RID(p2->tag) ) {
1940 /* Recover normal and metric associated to p2 */
1941 cfg_m2 = MMG5_buildridmet(mesh,met,npslave,ux,uy,uz,m2,rbasis2);
1942 if( !cfg_m2 ) { return 0; }
1943 }
1944 else {
1945 memcpy(m2,mm2,6*sizeof(double));
1946 }
1947
1948 l = sqrt(ux*ux+uy*uy+uz*uz);
1949
1950 difsiz = mesh->info.hgradreq*l;
1951
1952 /* Simultaneous reduction of mtan1 and mtan2 */
1953 if ( !MMG5_simred3d(mesh,m1,m2,lambda,mu,vp) ) {
1954 return 0;
1955 }
1956
1957 /* Gradation of sizes = 1/sqrt(eigenv of the tensors) in the first direction */
1958 MMG5_gradEigenvreq(lambda,mu,difsiz,0,&ier);
1959
1960 /* Gradation of sizes = 1/sqrt(eigenv of the tensors) in the second direction */
1961 MMG5_gradEigenvreq(lambda,mu,difsiz,1,&ier);
1962
1963 /* Gradation of sizes = 1/sqrt(eigenv of the tensors) in the third direction */
1964 MMG5_gradEigenvreq(lambda,mu,difsiz,2,&ier);
1965
1966 if ( !ier ) {
1967 return 0;
1968 }
1969
1970 /* Metric update using the simultaneous reduction technique */
1971 if( MG_SIN_OR_NOM(p2->tag) ) {
1972 /* We choose to not respect the gradation in order to restrict the influence
1973 * of the singular points. Thus:
1974 * lambda_new = = 0.5 lambda_1 + 0.5 lambda_new = lambda_1 + 0.5 beta.
1975 * with beta the smallest variation of the eigenvalues (lambda_new-lambda_1). */
1976
1977 /* This point can have an anisotropic metric if a user-provided metric is
1978 * found. So, compute the eigenvalues. */
1979 double ll[3],rr[3][3],llmin;
1980 int i;
1981 if( !MMG5_eigenv3d(1,mm2,ll, rr) )
1982 return 0;
1983 llmin = DBL_MAX;
1984 for( i = 0; i < 3; i++ )
1985 if( ll[i] < llmin )
1986 llmin = ll[i];
1987
1988
1989 beta = mu[0] - llmin;
1990
1991 if ( fabs(beta) < fabs(llmin-mu[1]) ) {
1992 beta = mu[1] - llmin;
1993 }
1994 ll[0] += 0.5*beta;
1995 ll[1] += 0.5*beta;
1996 ll[2] += 0.5*beta;
1997 assert ( ll[0]>0. && ll[1]>0. && ll[2]>0. );
1998 mm2[0] = ll[0]*rr[0][0]*rr[0][0] + ll[1]*rr[1][0]*rr[1][0] + ll[2]*rr[2][0]*rr[2][0];
1999 mm2[1] = ll[0]*rr[0][0]*rr[0][1] + ll[1]*rr[1][0]*rr[1][1] + ll[2]*rr[2][0]*rr[2][1];
2000 mm2[2] = ll[0]*rr[0][0]*rr[0][2] + ll[1]*rr[1][0]*rr[1][2] + ll[2]*rr[2][0]*rr[2][2];
2001 mm2[3] = ll[0]*rr[0][1]*rr[0][1] + ll[1]*rr[1][1]*rr[1][1] + ll[2]*rr[2][1]*rr[2][1];
2002 mm2[4] = ll[0]*rr[0][1]*rr[0][2] + ll[1]*rr[1][1]*rr[1][2] + ll[2]*rr[2][1]*rr[2][2];
2003 mm2[5] = ll[0]*rr[0][2]*rr[0][2] + ll[1]*rr[1][2]*rr[1][2] + ll[2]*rr[2][2]*rr[2][2];
2004 }
2005 else if( p2->tag & MG_GEO ){
2006
2007 if ( !MMG3D_updatemetreq_ani(m2,mu,vp) ) { return 0; }
2008
2009 /* Here mtan2 contains the gradated metric in the coreduction basis: compute
2010 * the sizes in the directions (t,u=t^n,n) */
2011 mu[0] = m2[0]*rbasis2[0][0]*rbasis2[0][0] + 2. * m2[1]*rbasis2[1][0]*rbasis2[0][0]
2012 + 2. * m2[2]*rbasis2[2][0]*rbasis2[0][0]
2013 + m2[3]*rbasis2[1][0]*rbasis2[1][0] + 2. * m2[4]*rbasis2[2][0]*rbasis2[1][0]
2014 + m2[5]*rbasis2[2][0]*rbasis2[2][0];
2015
2016 /* h = 1/sqrt(t_e M e) */
2017 assert ( mu[0] > MMG5_EPSD2 );
2018
2019 mu[1] = m2[0]*rbasis2[0][1]*rbasis2[0][1] + 2. * m2[1]*rbasis2[1][1]*rbasis2[0][1]
2020 + 2. * m2[2]*rbasis2[2][1]*rbasis2[0][1]
2021 + m2[3]*rbasis2[1][1]*rbasis2[1][1] + 2. * m2[4]*rbasis2[2][1]*rbasis2[1][1]
2022 + m2[5]*rbasis2[2][1]*rbasis2[2][1];
2023
2024 /* h = 1/sqrt(t_e M e) */
2025 assert ( mu[1] > MMG5_EPSD2 );
2026
2027 mu[2] = m2[0]*rbasis2[0][2]*rbasis2[0][2] + 2. * m2[1]*rbasis2[1][2]*rbasis2[0][2]
2028 + 2. * m2[2]*rbasis2[2][2]*rbasis2[0][2]
2029 + m2[3]*rbasis2[1][2]*rbasis2[1][2] + 2. * m2[4]*rbasis2[2][2]*rbasis2[1][2]
2030 + m2[5]*rbasis2[2][2]*rbasis2[2][2];
2031
2032 /* h = 1/sqrt(t_e M e) */
2033 assert ( mu[2] > MMG5_EPSD2 );
2034
2035 /* Update the ridge metric */
2036 mm2[0] = mu[0];
2037
2038 assert ( cfg_m2 );
2039
2040 mm2[cfg_m2] = mu[1];
2041 mm2[cfg_m2+2] = mu[2];
2042 }
2043 else{
2044
2045 if ( !MMG3D_updatemetreq_ani(m2,mu,vp) ) { return 0; }
2046 memcpy(mm2,m2,6*sizeof(double));
2047 }
2048
2049 return 1;
2050}
2051
2052
2074 MMG5_Hash edgeTable;
2075 MMG5_hedge *pht;
2076 MMG5_pTetra pt;
2077 MMG5_pPoint p0,p1;
2078 double *m,mv;
2079 int i,itv,maxit,ier;
2080 MMG5_int k,np0,np1,nu,nupv;
2081 static int mmgWarn = 0;
2082
2083 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug )
2084 fprintf(stdout," ** Anisotropic mesh gradation\n");
2085
2086 /* First step : make ridges iso in each apairing direction */
2087 for (k=1; k<= mesh->np; k++) {
2088 p1 = &mesh->point[k];
2089 if ( !MG_VOK(p1) ) continue;
2090 if ( MG_SIN_OR_NOM(p1->tag) ) continue;
2091 if ( !(p1->tag & MG_GEO) ) continue;
2092
2093 m = &met->m[6*k];
2094 mv = MG_MAX(m[1],m[2]);
2095 m[1] = mv;
2096 m[2] = mv;
2097 mv = MG_MAX(m[3],m[4]);
2098 m[3] = mv;
2099 m[4] = mv;
2100 }
2101
2104
2105
2106 /* alloc hashtable */
2107 if ( !MMG5_hashNew(mesh,&edgeTable,mesh->nemax,3*mesh->nemax) ) {
2108 fprintf(stderr,"\n ## Error: %s: unable to allocate hash table.\n",__func__);
2109 return 0;
2110 }
2111
2112 /* build edge table */
2113 for(k=1 ; k<=mesh->ne ; k++) {
2114 pt = &mesh->tetra[k];
2115 if ( !MG_EOK(pt) ) {
2116 continue;
2117 }
2118 for(i=0 ; i<6 ; i++) {
2119 np0 = pt->v[MMG5_iare[i][0]];
2120 np1 = pt->v[MMG5_iare[i][1]];
2121
2122 ier = MMG5_hashEdge(mesh,&edgeTable,np0,np1,k);
2123 if ( !ier ) {
2124 if ( !mmgWarn ) {
2125 mmgWarn = 1;
2126 fprintf(stderr,"\n ## Warning: %s: unable to hash at least one edge"
2127 " (tria %" MMG5_PRId ", edge %d).\n",__func__,MMG3D_indElt(mesh,k),i);
2128 }
2129 }
2130 }
2131 }
2132
2133 for (k=1; k<=mesh->np; k++)
2134 mesh->point[k].flag = mesh->base;
2135
2136 nupv = itv = 0;
2137 maxit = 500;
2138 mmgWarn = 0;
2139
2140 /* analyze mesh edges via hash table */
2141 do {
2142 ++mesh->base;
2143 nu = 0;
2144 for (k=0; k<edgeTable.siz; k++) {
2145 pht = &edgeTable.item[k];
2146 /* analyze linked list */
2147 while ( pht ) {
2148 if ( !pht->a ) break;
2149 np0 = pht->a;
2150 np1 = pht->b;
2151 p0 = &mesh->point[np0];
2152 p1 = &mesh->point[np1];
2153
2154 /* Skip edge if both nodes have been updated more than 1 iteration ago */
2155 if ( (p0->flag < mesh->base-1) && (p1->flag < mesh->base-1) ) {
2156 pht = pht->nxt ? &edgeTable.item[pht->nxt] : 0;
2157 continue;
2158 }
2159
2160 /* Skip points belonging to a required edge */
2161 if ( p0->s || p1->s ) {
2162 pht = pht->nxt ? &edgeTable.item[pht->nxt] : 0;
2163 continue;
2164 }
2165
2166 ier = MMG5_grad2metVol(mesh,met,np0,np1);
2167 if( ier == -1 ) {
2168 break;
2169 } else {
2170 if ( ier & 1 ) {
2171 p0->flag = mesh->base;
2172 nu++;
2173 }
2174 if ( ier & 2 ) {
2175 p1->flag = mesh->base;
2176 nu++;
2177 }
2178 if ( !mmgWarn && (ier & 4) ) {
2179 mmgWarn = itv;
2180 }
2181 }
2182
2183 /* next edge */
2184 pht = pht->nxt ? &edgeTable.item[pht->nxt] : 0;
2185 }
2186 }
2187 nupv += nu;
2188 } while ( ++itv < maxit && nu > 0 );
2189 MMG5_SAFE_FREE(edgeTable.item);
2190
2191 if ( abs(mesh->info.imprim) > 3 ) {
2192 if( mmgWarn ) {
2193 fprintf(stderr,"\n ## Warning: %s: Non-idempotent metric"
2194 " intersections since iteration %d.\n",__func__,mmgWarn);
2195 }
2196
2197 fprintf(stdout," gradation: %7" MMG5_PRId " updated, %d iter\n",nupv,itv);
2198 }
2199 return 1;
2200}
2201
2211 MMG5_pTetra pt;
2212 MMG5_pxTetra pxt;
2213 MMG5_Tria ptt;
2214 MMG5_pPoint p0,p1;
2215 int it,itv,maxit;
2216 int i,j,ier;
2217 MMG5_int nup,nu,nupv,k,np0,np1,npmaster,npslave;
2218
2219 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug ) {
2220 fprintf(stdout," ** Grading required points.\n");
2221 }
2222
2223 if ( mesh->info.hgrad < 0. ) {
2227 }
2228
2229 it = nup = 0;
2230 maxit = 100;
2231 do {
2232 nu = 0;
2233 for (k=1; k<=mesh->ne; k++) {
2234 pt = &mesh->tetra[k];
2235 if ( !MG_EOK(pt) ) continue;
2236 pxt = pt->xt ? &mesh->xtetra[pt->xt] : 0;
2237
2238 if ( pxt ) {
2239 for (i=0; i<4; i++) {
2240 if ( pxt->ftag[i] & MG_BDY) {
2241 /* Gradation along a surface edge */
2242 /* virtual triangle */
2243 MMG5_tet2tri(mesh,k,i,&ptt);
2244 for (j=0; j<3; j++) {
2245 np0 = ptt.v[MMG5_inxt2[j]];
2246 np1 = ptt.v[MMG5_iprv2[j]];
2247 p0 = &mesh->point[np0];
2248 p1 = &mesh->point[np1];
2249
2250 if ( MMG5_abs ( p0->s - p1->s ) < 2 ) {
2251 /* No size to propagate */
2252 continue;
2253 }
2254 else if ( p0->s > p1->s ) {
2255 npmaster = np0;
2256 npslave = np1;
2257 }
2258 else {
2259 assert ( p1->s > p0->s );
2260 npmaster = np1;
2261 npslave = np0;
2262 }
2263
2264 /* Impose the gradation to npslave from npmaster */
2265 /* gradation along the tangent plane */
2266 ier = MMG5_grad2metSurfreq(mesh,met,&ptt,npmaster,npslave);
2267 if ( ier ) {
2268 mesh->point[npslave].s = mesh->point[npmaster].s - 1;
2269 nu++;
2270 }
2271 }
2272 }
2273
2274 else continue;
2275 }
2276 }
2277 }
2278 nup += nu;
2279 }
2280 while( ++it < maxit && nu > 0 );
2281
2282 nupv = itv = 0;
2283 maxit = 500;
2284
2285 do {
2286 nu = 0;
2287 for (k=1; k<=mesh->ne; k++) {
2288 pt = &mesh->tetra[k];
2289 if ( !MG_EOK(pt) ) continue;
2290 for (i=0; i<4; i++) {
2291 /* Gradation along a volume edge */
2292 np0 = pt->v[MMG5_iare[i][0]];
2293 np1 = pt->v[MMG5_iare[i][1]];
2294 p0 = &mesh->point[np0];
2295 p1 = &mesh->point[np1];
2296
2297 if ( MMG5_abs ( p0->s - p1->s ) < 2 ) {
2298 /* No size to propagate */
2299 continue;
2300 }
2301 else if ( p0->s > p1->s ) {
2302 npmaster = np0;
2303 npslave = np1;
2304 }
2305 else {
2306 assert ( p1->s > p0->s );
2307 npmaster = np1;
2308 npslave = np0;
2309 }
2310
2311 /* Impose the gradation to npslave from npmaster */
2312 ier = MMG5_grad2metVolreq(mesh,met,pt,npmaster,npslave);
2313 if ( ier ) {
2314 mesh->point[npslave].s = mesh->point[npmaster].s - 1;
2315
2316 nu++;
2317 }
2318 }
2319 }
2320 nupv += nu;
2321 }
2322 while( ++itv < maxit && nu > 0 );
2323
2324 if ( abs(mesh->info.imprim) > 3 ) {
2325 if ( abs(mesh->info.imprim) < 5 && !mesh->info.ddebug ) {
2326 fprintf(stdout," gradation: %7" MMG5_PRId " updated, %d iter\n",nup+nupv,it+itv);
2327 }
2328 else {
2329 fprintf(stdout," surface gradation: %7" MMG5_PRId " updated, %d iter\n"
2330 " volume gradation: %7" MMG5_PRId " updated, %d iter\n",nup,it,nupv,itv);
2331 }
2332 }
2333
2334 return 1;
2335}
int MMG3D_Set_solSize(MMG5_pMesh mesh, MMG5_pSol sol, int typEntity, MMG5_int np, int typSol)
int ier
MMG5_pMesh * mesh
void MMG5_fillDefmetregSys(MMG5_int k, MMG5_pPoint p0, int i0, MMG5_Bezier b, double r[3][3], double c[3], double *lispoi, double tAA[6], double tAb[3])
Definition: anisosiz.c:290
int MMG5_solveDefmetregSys(MMG5_pMesh mesh, double r[3][3], double c[3], double tAA[6], double tAb[3], double *m, double isqhmin, double isqhmax, double hausd)
Definition: anisosiz.c:436
int MMG5_simred3d(MMG5_pMesh mesh, double *m, double *n, double dm[3], double dn[3], double vp[3][3])
Definition: anisosiz.c:1416
void MMG5_gradEigenvreq(double *dm, double *dn, double difsiz, int8_t dir, int8_t *ier)
Definition: anisosiz.c:1883
void MMG5_defUninitSize(MMG5_pMesh mesh, MMG5_pSol met, int8_t ismet)
Definition: anisosiz.c:228
double MMG5_ridSizeInNormalDir(MMG5_pMesh mesh, int i0, double *bcu, MMG5_Bezier *b, double isqhmin, double isqhmax)
Definition: anisosiz.c:836
int MMG5_grad2metSurfreq(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria pt, MMG5_int npmaster, MMG5_int npslave)
Definition: anisosiz.c:1951
int MMG5_simred2d(MMG5_pMesh mesh, double *m, double *n, double dm[2], double dn[2], double vp[2][2])
Definition: anisosiz.c:1326
int MMG5_solveDefmetrefSys(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int ipref[2], double r[3][3], double c[3], double tAA[6], double tAb[3], double *m, double isqhmin, double isqhmax, double hausd)
Definition: anisosiz.c:538
double MMG5_ridSizeInTangentDir(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int idp, MMG5_int *iprid, double isqhmin, double isqhmax)
Definition: anisosiz.c:764
static int MMG3D_intextmet(MMG5_pMesh mesh, MMG5_pSol met, int np, double me[6])
Definition: anisosiz_3d.c:1267
int MMG5_moymet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTetra pt, double *m1)
Definition: anisosiz_3d.c:144
int MMG3D_chk4ridVertices(MMG5_pMesh mesh, MMG5_pTetra pt)
Definition: anisosiz_3d.c:113
int MMG3D_gradsiz_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz_3d.c:2073
int MMG3D_printErrorMat(int8_t symmat, double *m, double *mr)
Definition: anisosiz_3d.c:90
int MMG3D_printEigenv(double dm[3], double vp[3][3])
Definition: anisosiz_3d.c:48
static int MMG5_defmetreg(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int kel, int iface, int ip)
Definition: anisosiz_3d.c:875
static int MMG5_grad2metVol(MMG5_pMesh mesh, MMG5_pSol met, int np1, int np2)
Definition: anisosiz_3d.c:1779
static void MMG5_grad2metVol_setmet(MMG5_pMesh mesh, MMG5_pSol met, int ip, double *m, int8_t ridgedir)
Definition: anisosiz_3d.c:1722
int MMG3D_printMat(int8_t symmat, double *m)
Definition: anisosiz_3d.c:67
static int MMG5_defmetsin(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int kel, int iface, int ip)
Definition: anisosiz_3d.c:191
int MMG3D_updatemetreq_ani(double *n, double dn[3], double vp[3][3])
Definition: anisosiz_3d.c:1867
static int MMG5_grad2metVol_getmet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int ip, double ux, double uy, double uz, double *m, int8_t *ridgedir)
Definition: anisosiz_3d.c:1439
static void MMG3D_gradSimred(MMG5_pMesh mesh, MMG5_pPoint ppt, double m[6], double mext[6], int8_t ridgedir, int8_t iloc, int *ier)
Definition: anisosiz_3d.c:1534
static int MMG5_defmetref(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int kel, int iface, int ip)
Definition: anisosiz_3d.c:606
int MMG3D_defsiz_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz_3d.c:1310
static void MMG5_grad2metVol_extmet(MMG5_pMesh mesh, MMG5_pPoint ppt, double l, double *m, double *mext)
Definition: anisosiz_3d.c:1498
static int MMG5_defmetvol(MMG5_pMesh mesh, MMG5_pSol met, int8_t ismet)
Definition: anisosiz_3d.c:1101
int MMG3D_gradsizreq_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz_3d.c:2210
static int MMG5_grad2metVolreq(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTetra pt, MMG5_int npmaster, MMG5_int npslave)
Definition: anisosiz_3d.c:1903
static int MMG5_defmetrid(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int kel, int iface, MMG5_int ip)
Definition: anisosiz_3d.c:390
int MMG5_BezierEdge(MMG5_pMesh mesh, MMG5_int ip0, MMG5_int ip1, double b0[3], double b1[3], int8_t ised, double v[3])
Definition: bezier_3d.c:152
MMG5_Info info
int MMG5_boulevolp(MMG5_pMesh mesh, MMG5_int start, int ip, int64_t *list)
Definition: boulep_3d.c:54
int MMG5_boulesurfvolp(MMG5_pMesh mesh, MMG5_int start, int ip, int iface, int64_t *listv, int *ilistv, MMG5_int *lists, int *ilists, int isnm)
Definition: boulep_3d.c:607
int MMG5_bouletrid(MMG5_pMesh mesh, MMG5_int start, int iface, int ip, int *il1, MMG5_int *l1, int *il2, MMG5_int *l2, MMG5_int *ip0, MMG5_int *ip1)
Definition: boulep_3d.c:952
int MMG5_eigenv3d(int symmat, double *mat, double lambda[3], double v[3][3])
Find eigenvalues and vectors of a 3x3 matrix.
Definition: eigenv.c:385
#define MMG5_EPSD
#define MMG5_EPS
int MMG5_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:526
int MMG5_hashEdge(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:345
static double MMG5_caltet_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTetra pt)
static double MMG5_lenedg_ani(MMG5_pMesh mesh, MMG5_pSol met, int ia, MMG5_pTetra pt)
static double MMG5_lenedgCoor_ani(double *ca, double *cb, double *sa, double *sb)
inlined Functions
static void MMG5_simredmat(int8_t dim, double *m, double *dm, double *iv)
static double MMG5_lenSurfEdg_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np0, MMG5_int np1, int8_t isedg)
int MMG5_defsiz_startingMessage(MMG5_pMesh mesh, MMG5_pSol met, const char *funcname)
Definition: isosiz.c:77
int MMG3D_set_metricAtPointsOnReqEdges(MMG5_pMesh mesh, MMG5_pSol met, int8_t ismet)
Definition: isosiz_3d.c:564
void MMG3D_mark_pointsOnReqEdge_fromTetra(MMG5_pMesh mesh)
Definition: isosiz_3d.c:1048
API headers for the mmg3d library.
LIBMMG3D_EXPORT double(* MMG3D_lenedgCoor)(double *ca, double *cb, double *sa, double *sb)
Definition: mmg3dexterns.c:10
#define MMG3D_LMAX
Definition: libmmg3d.h:58
MMG5_int MMG3D_indPt(MMG5_pMesh mesh, MMG5_int kp)
Definition: tools_3d.c:916
static const int8_t MMG5_iarf[4][3]
iarf[i]: edges of face opposite to vertex i
static const uint8_t MMG5_iare[6][2]
vertices of extremities of the edges of the tetra
void MMG5_tet2tri(MMG5_pMesh mesh, MMG5_int k, int8_t ie, MMG5_Tria *ptt)
Definition: mmg3d1.c:102
static const uint8_t MMG5_idir[4][3]
idir[i]: vertices of face opposite to vertex i
MMG5_int MMG3D_indElt(MMG5_pMesh mesh, MMG5_int kel)
Definition: tools_3d.c:860
@ MMG5_Vertex
Definition: libmmgtypes.h:224
@ MMG5_Tetrahedron
Definition: libmmgtypes.h:227
@ MMG5_Triangle
Definition: libmmgtypes.h:226
int MMG5_eigenvmatsym3d(MMG5_pMesh mesh, double m[], double lambda[], double v[][3])
Definition: mettools.c:164
int MMG5_buildridmet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np0, double ux, double uy, double uz, double mr[6], double r[3][3])
Definition: mettools.c:676
int MMG5_mmgIntextmet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np, double me[6], double n[3])
Definition: mettools.c:1139
#define MG_Tria
#define MG_REQ
#define MG_GEO
#define MMG5_EPSOK
double MMG5_caltri_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria ptt)
Definition: quality.c:115
#define MG_EOK(pt)
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MG_EDG(tag)
static const uint8_t MMG5_iprv2[3]
int MMG5_truncate_met3d(MMG5_pSol met, MMG5_int ip, double isqhmin, double isqhmax)
Definition: scalem.c:148
#define MG_EDG_OR_NOM(tag)
#define MG_SIN(tag)
int MMG5_rmtr(double r[3][3], double m[6], double mr[6])
Definition: tools.c:405
int MMG5_invmat33(double m[3][3], double mi[3][3])
Definition: tools.c:653
#define MG_Tetra
#define MG_GET(flag, bit)
#define MG_RID(tag)
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
int MMG5_rotmatrix(double n[3], double r[3][3])
Definition: tools.c:467
#define MG_BDY
void MMG5_transpose3d(double m[3][3])
Definition: tools.c:220
#define MG_NOSURF
#define MG_NOM
#define MG_SIN_OR_NOM(tag)
void MMG5_crossprod3d(double *a, double *b, double *result)
Definition: tools.c:300
int MMG5_norpts(MMG5_pMesh, MMG5_int, MMG5_int, MMG5_int, double *)
Definition: tools.c:183
#define MMG5_EPSD2
#define MG_REF
int MMG5_invmat22(double m[2][2], double mi[2][2])
Definition: tools.c:745
#define MMG5_SAFE_FREE(ptr)
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:595
MMG5_hedge * item
Definition: libmmgtypes.h:597
MMG5_int siz
Definition: libmmgtypes.h:596
int8_t parTyp
Definition: libmmgtypes.h:541
int8_t ddebug
Definition: libmmgtypes.h:532
double hmin
Definition: libmmgtypes.h:518
double hgrad
Definition: libmmgtypes.h:518
uint8_t metRidTyp
Definition: libmmgtypes.h:547
double hmax
Definition: libmmgtypes.h:518
uint8_t nosizreq
Definition: libmmgtypes.h:546
MMG5_pPar par
Definition: libmmgtypes.h:517
double hgradreq
Definition: libmmgtypes.h:518
double hausd
Definition: libmmgtypes.h:518
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_int ne
Definition: libmmgtypes.h:612
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_int * adja
Definition: libmmgtypes.h:624
MMG5_int nemax
Definition: libmmgtypes.h:612
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_int base
Definition: libmmgtypes.h:616
MMG5_pTetra tetra
Definition: libmmgtypes.h:643
MMG5_int np
Definition: libmmgtypes.h:612
MMG5_pxTetra xtetra
Definition: libmmgtypes.h:644
double hmin
Definition: libmmgtypes.h:258
double hmax
Definition: libmmgtypes.h:259
double hausd
Definition: libmmgtypes.h:260
MMG5_int ref
Definition: libmmgtypes.h:261
int8_t elt
Definition: libmmgtypes.h:262
Structure to store points of a MMG mesh.
Definition: libmmgtypes.h:270
double n[3]
Definition: libmmgtypes.h:272
int16_t tag
Definition: libmmgtypes.h:284
double c[3]
Definition: libmmgtypes.h:271
MMG5_int xp
Definition: libmmgtypes.h:279
MMG5_int s
Definition: libmmgtypes.h:283
MMG5_int flag
Definition: libmmgtypes.h:282
double * m
Definition: libmmgtypes.h:671
MMG5_int v[4]
Definition: libmmgtypes.h:403
MMG5_int xt
Definition: libmmgtypes.h:407
MMG5_int ref
Definition: libmmgtypes.h:404
int16_t tag
Definition: libmmgtypes.h:410
MMG5_int v[3]
Definition: libmmgtypes.h:334
Used to hash edges (memory economy compared to MMG5_hgeom).
Definition: libmmgtypes.h:584
MMG5_int b
Definition: libmmgtypes.h:585
MMG5_int a
Definition: libmmgtypes.h:585
MMG5_int nxt
Definition: libmmgtypes.h:585
Structure to store surface points of a MMG mesh.
Definition: libmmgtypes.h:294
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295
Structure to store the surface tetrahedra of a MMG mesh.
Definition: libmmgtypes.h:418
int16_t ftag[4]
Definition: libmmgtypes.h:423
int16_t tag[6]
Definition: libmmgtypes.h:425
int8_t ori
Definition: libmmgtypes.h:427
MMG5_int ref[4]
Definition: libmmgtypes.h:419