Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
quality_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
35#include "libmmg3d.h"
38
39extern int8_t ddb;
40
50int MMG3D_tetraQual(MMG5_pMesh mesh, MMG5_pSol met,int8_t metRidTyp) {
51 MMG5_pTetra pt;
52 double minqual;
53 MMG5_int k,iel;
54
55 minqual = 2./MMG3D_ALPHAD;
56
57 /* compute tet quality */
58 iel = 1;
59 for (k=1; k<=mesh->ne; k++) {
60 pt = &mesh->tetra[k];
61 if( !MG_EOK(pt) ) continue;
62
63 if ( !metRidTyp && met->size == 6 && met->m ) {
64 pt->qual = MMG5_caltet33_ani(mesh,met,pt);
65 }
66 else if ( !(met && met->m) ) {
67 pt->qual = MMG5_caltet_iso(mesh,NULL,pt);
68 }
69 else {
70 pt->qual = MMG5_orcal(mesh,met,k);
71 }
72
73 int i=0;
74 /* Once metric is stored using 'ridge' convention, a tetra with 4 ridge
75 * points has a 0 quality, ignore it for quality checks */
76 if ( metRidTyp ) {
77 for ( i=0; i<4; ++i ) {
78 MMG5_pPoint ppt = &mesh->point[pt->v[i]];
79 if ( (MG_SIN(ppt->tag) || MG_NOM & ppt->tag) || !(ppt->tag & MG_GEO) ) {
80 break;
81 }
82 }
83 }
84
85 /* Check quality on suitable elements */
86 if ( i < 4 && pt->qual < minqual ) {
87 minqual = pt->qual;
88 iel = k;
89 }
90 }
91
92 /* Here the quality is not normalized by alpha, thus we need to
93 * normalized it */
94 return MMG5_minQualCheck(iel,minqual,MMG3D_ALPHAD);
95}
96
110 double cal,abx,aby,abz,acx,acy,acz,adx,ady,adz;
111 double bcx,bcy,bcz,bdx,bdy,bdz,cdx,cdy,cdz;
112 double h1,h2,h3,h4,h5,h6,det,vol,rap,v1,v2,v3,num;
113 double *a,*b,*c,*d;
114 double mm[6];
115 int iad0,iad1,iad2,iad3;
116 MMG5_int ip[4],k;
117
118 ip[0] = pt->v[0];
119 ip[1] = pt->v[1];
120 ip[2] = pt->v[2];
121 ip[3] = pt->v[3];
122
123 iad0 = met->size * ip[0];
124 iad1 = met->size * ip[1];
125 iad2 = met->size * ip[2];
126 iad3 = met->size * ip[3];
127
128 /* average metric */
129 for (k=0; k<6; k++)
130 mm[k] = 0.25 * (met->m[iad0+k]+met->m[iad1+k]+met->m[iad2+k]+met->m[iad3+k]);
131
132 a = mesh->point[ip[0]].c;
133 b = mesh->point[ip[1]].c;
134 c = mesh->point[ip[2]].c;
135 d = mesh->point[ip[3]].c;
136
137 /* volume */
138 abx = b[0] - a[0];
139 aby = b[1] - a[1];
140 abz = b[2] - a[2];
141
142 acx = c[0] - a[0];
143 acy = c[1] - a[1];
144 acz = c[2] - a[2];
145
146 adx = d[0] - a[0];
147 ady = d[1] - a[1];
148 adz = d[2] - a[2];
149
150 bcx = c[0] - b[0];
151 bcy = c[1] - b[1];
152 bcz = c[2] - b[2];
153
154 bdx = d[0] - b[0];
155 bdy = d[1] - b[1];
156 bdz = d[2] - b[2];
157
158 cdx = d[0] - c[0];
159 cdy = d[1] - c[1];
160 cdz = d[2] - c[2];
161
162 v1 = acy*adz - acz*ady;
163 v2 = acz*adx - acx*adz;
164 v3 = acx*ady - acy*adx;
165 vol = abx * v1 + aby * v2 + abz * v3;
166 if ( vol <= 0. ) return 0.0;
167
168 det = mm[0] * ( mm[3]*mm[5] - mm[4]*mm[4]) \
169 - mm[1] * ( mm[1]*mm[5] - mm[2]*mm[4]) \
170 + mm[2] * ( mm[1]*mm[4] - mm[2]*mm[3]);
171 if ( det < MMG5_EPSD2 ) {
172 return 0.0;
173 }
174 det = sqrt(det) * vol;
175
176 /* edge lengths */
177 h1 = mm[0]*abx*abx + mm[3]*aby*aby + mm[5]*abz*abz
178 + 2.0*(mm[1]*abx*aby + mm[2]*abx*abz + mm[4]*aby*abz);
179 h2 = mm[0]*acx*acx + mm[3]*acy*acy + mm[5]*acz*acz
180 + 2.0*(mm[1]*acx*acy + mm[2]*acx*acz + mm[4]*acy*acz);
181 h3 = mm[0]*adx*adx + mm[3]*ady*ady + mm[5]*adz*adz
182 + 2.0*(mm[1]*adx*ady + mm[2]*adx*adz + mm[4]*ady*adz);
183 h4 = mm[0]*bcx*bcx + mm[3]*bcy*bcy + mm[5]*bcz*bcz
184 + 2.0*(mm[1]*bcx*bcy + mm[2]*bcx*bcz + mm[4]*bcy*bcz);
185 h5 = mm[0]*bdx*bdx + mm[3]*bdy*bdy + mm[5]*bdz*bdz
186 + 2.0*(mm[1]*bdx*bdy + mm[2]*bdx*bdz + mm[4]*bdy*bdz);
187 h6 = mm[0]*cdx*cdx + mm[3]*cdy*cdy + mm[5]*cdz*cdz
188 + 2.0*(mm[1]*cdx*cdy + mm[2]*cdx*cdz + mm[4]*cdy*cdz);
189
190 /* quality */
191 rap = h1 + h2 + h3 + h4 + h5 + h6;
192 num = sqrt(rap) * rap;
193
194 cal = det / num;
195
196 return cal;
197}
198
199
222 double* lmin, double* lmax, MMG5_int* ned, MMG5_int* amin,
223 MMG5_int* bmin, MMG5_int* amax,
224 MMG5_int* bmax, MMG5_int* nullEdge, int8_t metRidTyp,
225 double** bd_in, MMG5_int hl[9] )
226{
227 MMG5_pTetra pt;
228 MMG5_pPoint ppt;
229 MMG5_Hash hash;
230 double len;
231 MMG5_int k,np,nq,n;
232 int8_t ia,i0,i1,ier,i;
233 static double bd[9]= {0.0, 0.3, 0.6, 0.7071, 0.9, 1.3, 1.4142, 2.0, 5.0};
234
235 *bd_in = bd;
236 memset(hl,0,9*sizeof(int));
237 *ned = 0;
238 *avlen = 0.0;
239 *lmax = 0.0;
240 *lmin = 1.e30;
241 *amin = *amax = *bmin = *bmax = 0;
242 *nullEdge = 0;
243
244 /* Hash all edges in the mesh */
245 if ( !MMG5_hashNew(mesh,&hash,mesh->np,7*mesh->np) ) return 0;
246
247 for(k=1; k<=mesh->ne; k++) {
248 pt = &mesh->tetra[k];
249 if ( !MG_EOK(pt) ) continue;
250
251 for(ia=0; ia<6; ia++) {
252 i0 = MMG5_iare[ia][0];
253 i1 = MMG5_iare[ia][1];
254 np = pt->v[i0];
255 nq = pt->v[i1];
256
257 if(!MMG5_hashEdge(mesh,&hash,np,nq,0)){
258 fprintf(stderr," ## Error: %s: function MMG5_hashEdge return 0\n",
259 __func__);
260 return 0;
261 }
262 }
263 }
264
265 /* Pop edges from hash table, and analyze their length */
266 for(k=1; k<=mesh->ne; k++) {
267 pt = &mesh->tetra[k];
268 if ( !MG_EOK(pt) ) continue;
269 n = 0;
270 for(i=0 ; i<4 ; i++) {
271 ppt = &mesh->point[pt->v[i]];
272 if(!(MG_SIN(ppt->tag) || MG_NOM & ppt->tag) && (ppt->tag & MG_GEO)) continue;
273 n++;
274 }
275 if(!n) {
276 continue;
277 }
278 for(ia=0; ia<6; ia++) {
279 i0 = MMG5_iare[ia][0];
280 i1 = MMG5_iare[ia][1];
281 np = pt->v[i0];
282 nq = pt->v[i1];
283
284 /* Remove edge from hash ; ier = 1 if edge has been found */
285 ier = MMG5_hashPop(&hash,np,nq);
286 if( ier ) {
287 if ( (!metRidTyp) && met->size==6 && met->m ) {
288 len = MMG5_lenedg33_ani(mesh,met,ia,pt);
289 }
290 else
291 len = MMG5_lenedg(mesh,met,ia,pt);
292
293
294 if ( !len ) {
295 ++(*nullEdge);
296 }
297 else {
298 *avlen += len;
299 (*ned)++;
300
301 if( len < (*lmin) ) {
302 *lmin = len;
303 *amin = np;
304 *bmin = nq;
305 }
306
307 if ( len > (*lmax) ) {
308 *lmax = len;
309 *amax = np;
310 *bmax = nq;
311 }
312
313 /* Locate size of edge among given table */
314 for(i=0; i<8; i++) {
315 if ( bd[i] <= len && len < bd[i+1] ) {
316 hl[i]++;
317 break;
318 }
319 }
320 if( i == 8 ) hl[8]++;
321 }
322 }
323 }
324 }
325
326 MMG5_DEL_MEM(mesh,hash.item);
327 return 1;
328}
329
330
341int MMG3D_prilen(MMG5_pMesh mesh, MMG5_pSol met, int8_t metRidTyp) {
342 double avlen, lmin, lmax;
343 MMG5_int ned, nullEdge;
344 MMG5_int amin, bmin, amax, bmax, hl[9];
345 double *bd;
346
347 if (!MMG3D_computePrilen( mesh, met, &avlen, &lmin, &lmax, &ned, &amin,
348 &bmin, &amax, &bmax, &nullEdge, metRidTyp, &bd, hl ) )
349 return 0;
350
351 /* Display histogram */
352 MMG5_displayLengthHisto(mesh, ned, &avlen, amin, bmin, lmin,
353 amax, bmax, lmax,nullEdge, &bd[0], &hl[0],1);
354
355 return 1;
356}
357
358
376void MMG3D_computeLESqua(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *ne,double *max,double *avg,
377 double *min,MMG5_int *iel,MMG5_int *good,MMG5_int *med,MMG5_int his[5],int imprim) {
378 MMG5_pTetra pt;
379 double rap;
380 MMG5_int k,ok,nex;
381 static int8_t mmgWarn0=0;
382
383 /*compute tet quality*/
384 for (k=1; k<=mesh->ne; k++) {
385 pt = &mesh->tetra[k];
386 if( !MG_EOK(pt) ) continue;
387
388 pt->qual = MMG5_orcal(mesh,met,k);
389 }
390
391 if ( imprim <= 0 )
392 return;
393
394 (*min) = (*avg) = 0.0;
395 (*max) = 1.0;
396 (*iel) = 0;
397 (*med) = (*good) = 0;
398
399 for (k=0; k<5; k++) his[k] = 0;
400
401 nex = ok = 0;
402 for (k=1; k<=mesh->ne; k++) {
403 pt = &mesh->tetra[k];
404 if( !MG_EOK(pt) ) {
405 nex++;
406 continue;
407 }
408 ok++;
409 if ( (!mmgWarn0) && (MMG5_orvol(mesh->point,pt->v) < 0.0) ) {
410 mmgWarn0 = 1;
411 fprintf(stderr," ## Warning: %s: at least 1 negative volume.\n",
412 __func__);
413 }
414 rap = 1. - MMG3D_ALPHAD * pt->qual;
415 if ( rap > (*min) ) {
416 (*min) = rap;
417 (*iel) = ok;
418 }
419 if ( rap < 0.9 ) (*med)++;
420 if ( rap < 0.6 ) (*good)++;
421 // if ( rap < MMG3D_BADKAL ) mesh->info.badkal = 1;
422 (*avg) += rap;
423 (*max) = MG_MIN((*max),rap);
424 if(rap < 0.6)
425 his[0] += 1;
426 else if(rap < 0.9)
427 his[1] += 1;
428 else if(rap < 0.93)
429 his[2] += 1;
430 else if(rap < 0.99)
431 his[3] += 1;
432 else
433 his[4] += 1;
434 }
435
436 (*ne) = mesh->ne-nex;
437
438 return;
439}
440
460int MMG3D_displayQualHisto(MMG5_int ne,double max,double avg,double min,MMG5_int iel,
461 MMG5_int good,MMG5_int med,MMG5_int his[5],MMG5_int nrid,int optimLES,
462 int imprim) {
463
464 fprintf(stdout,"\n -- MESH QUALITY");
465 if ( optimLES )
466 fprintf(stdout," (LES)");
467 fprintf(stdout," %" MMG5_PRId "\n",ne);
468
469 fprintf(stdout," BEST %8.6f AVRG. %8.6f WRST. %8.6f (%" MMG5_PRId ")\n",
470 max,avg / ne,min,iel);
471
472 return ( MMG3D_displayQualHisto_internal(ne,max,avg,min,iel,good,med,his,
473 nrid,optimLES,imprim) );
474}
475
494int MMG3D_displayQualHisto_internal(MMG5_int ne,double max,double avg,double min,MMG5_int iel,
495 MMG5_int good,MMG5_int med,MMG5_int his[5],MMG5_int nrid,int optimLES,
496 int imprim)
497{
498 const double les_ticks[6] = {0,0.6,0.9,0.93,0.99,1};
499 int i,imax;
500
501 if ( abs(imprim) >= 3 ){
502 if ( optimLES ) {
503 /* print histo */
504 fprintf(stdout," HISTOGRAMM:");
505 fprintf(stdout," %6.2f %% < 0.6\n",100.0*((float)good/(float)ne));
506 if ( abs(imprim) > 3 ) {
507 fprintf(stdout," %6.2f %% < 0.9\n",100.0*( (float)med/(float)ne));
508
509 assert ( min >= max );
510 for ( i=0; i<5; ++i ) {
511 if ( max < les_ticks[i+1] && min >= les_ticks[i] ) {
512 fprintf(stdout," %5.2f < Q < %5.2f %7"MMG5_PRId" %6.2f %%\n",
513 les_ticks[i],les_ticks[i+1],his[i],
514 100.*((float)his[i]/(float)ne));
515 }
516 }
517 }
518 return 1;
519 }
520 else {
521 /* print histo */
522 fprintf(stdout," HISTOGRAMM:");
523 fprintf(stdout," %6.2f %% > 0.12\n",100.0*((float)good/(float)ne));
524 if ( abs(imprim) > 3 ) {
525 fprintf(stdout," %6.2f %% > 0.5\n",100.0*( (float)med/(float)ne));
526 imax = MG_MIN(4,(int)(5.*max));
527 for (i=imax; i>=(int)(5*min); i--) {
528 fprintf(stdout," %5.1f < Q < %5.1f %7"MMG5_PRId" %6.2f %%\n",
529 i/5.,i/5.+0.2,his[i],100.*((float)his[i]/(float)ne));
530 }
531 if ( nrid ) {
532 fprintf(stdout,"\n ## WARNING: %" MMG5_PRId " TETRA WITH 4 RIDGES POINTS:"
533 " UNABLE TO COMPUTE ANISO QUALITY.\n",nrid);
534 }
535 }
536 }
537 }
538
539 return MMG5_minQualCheck(iel,min,1.);
540}
541
559void MMG3D_computeInqua(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *ne,double *max,double *avg,
560 double *min,MMG5_int *iel,MMG5_int *good,MMG5_int *med,MMG5_int his[5],int imprim) {
561 MMG5_pTetra pt;
562 double rap;
563 MMG5_int k,ok,nex;
564 int ir;
565 static int8_t mmgWarn0 = 0;
566
567 /*compute tet quality*/
568 for (k=1; k<=mesh->ne; k++) {
569 pt = &mesh->tetra[k];
570 if( !MG_EOK(pt) ) continue;
571
572 if ( met->m ) {
573 if ( met->size == 6) {
574 pt->qual = MMG5_caltet33_ani(mesh,met,pt);
575 }
576 else
577 pt->qual = MMG5_orcal(mesh,met,k);
578 }
579 else // -A option
580 pt->qual = MMG5_caltet_iso(mesh,met,pt);
581 }
582 if ( imprim <= 0 ) return;
583
584 (*min) = 2.0;
585 (*max) = (*avg) = 0.0;
586 (*iel) = 0;
587 (*med) = (*good) = 0;
588
589 for (k=0; k<5; k++) his[k] = 0;
590
591 nex = ok = 0;
592 for (k=1; k<=mesh->ne; k++) {
593 pt = &mesh->tetra[k];
594 if( !MG_EOK(pt) ) {
595 nex++;
596 continue;
597 }
598 ok++;
599 if ( (!mmgWarn0) && (MMG5_orvol(mesh->point,pt->v) < 0.0) ) {
600 mmgWarn0 = 1;
601 fprintf(stderr," ## Warning: %s: at least 1 negative volume\n",
602 __func__);
603 }
604 rap = MMG3D_ALPHAD * pt->qual;
605 if ( rap < (*min) ) {
606 (*min) = rap;
607 (*iel) = ok;
608 }
609 if ( rap > 0.5 ) (*med)++;
610 if ( rap > 0.12 ) (*good)++;
611 if ( rap < MMG3D_BADKAL ) mesh->info.badkal = 1;
612 (*avg) += rap;
613 (*max) = MG_MAX((*max),rap);
614 ir = MG_MIN(4,(int)(5.0*rap));
615 his[ir] += 1;
616 }
617
618 (*ne) = mesh->ne-nex;
619
620 return;
621}
622
632 double rapmin,rapmax,rapavg;
633 int k;
634 MMG5_int med,good,iel,ne,his[5];
635
636 ne = iel = good = med = 0;
637 for ( k=0; k<5; ++k ) {
638 his[k] = 0;
639 }
640 rapmax = 0.;
641 rapmin = 2.;
642 rapavg = 2.;
643
644 if( mesh->info.optimLES ) {
645 MMG3D_computeLESqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
646 his,mesh->info.imprim);
647 }
648 else {
649 MMG3D_computeInqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
650 his,mesh->info.imprim);
651 }
652
653 if ( mesh->info.imprim <= 0 )
654 return 1;
655
656 return MMG3D_displayQualHisto(ne,rapmax,rapavg,rapmin,
657 iel,good,med,his,0,mesh->info.optimLES,
658 mesh->info.imprim);
659}
660
680void MMG3D_computeOutqua(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *ne,double *max,double *avg,
681 double *min,MMG5_int *iel,MMG5_int *good,MMG5_int *med,MMG5_int his[5],
682 MMG5_int *nrid,int imprim) {
683 MMG5_pTetra pt;
684 MMG5_pPoint ppt;
685 double rap;
686 int i,ir,n;
687 MMG5_int k,ok,nex;
688 static int8_t mmgWarn0 = 0;
689
690 /*compute tet quality*/
691 for (k=1; k<=mesh->ne; k++) {
692 pt = &mesh->tetra[k];
693 if( !MG_EOK(pt) ) continue;
694 pt->qual = MMG5_orcal(mesh,met,k);
695 }
696
697 if ( imprim <= 0 )
698 return;
699
700 (*min) = 2.0;
701 (*max) = (*avg) = 0.0;
702 (*iel) = 0;
703 (*med) = (*good) = 0;
704
705 for (k=0; k<5; k++) his[k] = 0;
706
707 nex = ok = (*nrid) = 0;
708 for (k=1; k<=mesh->ne; k++) {
709 pt = &mesh->tetra[k];
710 if( !MG_EOK(pt) ) {
711 nex++;
712 continue;
713 }
714 ok++;
715 if ( (!mmgWarn0) && (MMG5_orvol(mesh->point,pt->v) < 0.0) ) {
716 mmgWarn0 = 1;
717 fprintf(stderr," ## Warning: %s: at least 1 negative volume\n",
718 __func__);
719 }
720
721 /* Count the number of tets with only ridge metric if special metric storage
722 * at ridge. */
723 if ( mesh->info.metRidTyp==1 ) {
724 n = 0;
725 for(i=0 ; i<4 ; i++) {
726 ppt = &mesh->point[pt->v[i]];
727 if(!(MG_SIN(ppt->tag) || MG_NOM & ppt->tag) && (ppt->tag & MG_GEO)) continue;
728 n++;
729 }
730 if(!n) {
731 (*nrid)++;
732 continue;
733 }
734 }
735
736 rap = MMG3D_ALPHAD * pt->qual;
737 if ( rap < (*min) ) {
738 (*min) = rap;
739 (*iel) = ok;
740 }
741 if ( rap > 0.5 ) (*med)++;
742 if ( rap > 0.12 ) (*good)++;
743 if ( rap < MMG3D_BADKAL ) mesh->info.badkal = 1;
744 (*avg) += rap;
745 (*max) = MG_MAX((*max),rap);
746 ir = MG_MIN(4,(int)(5.0*rap));
747 his[ir] += 1;
748 }
749
750 (*ne) = mesh->ne-nex;
751
752 return;
753}
754
765 double rapmin,rapmax,rapavg;
766 int k;
767 MMG5_int his[5];
768 MMG5_int med,good,iel,ne,nrid;
769
770 nrid = ne = iel = good = med = 0;
771 for ( k=0; k<5; ++k ) {
772 his[k] = 0;
773 }
774 rapmax = 0.;
775 rapmin = 2.;
776 rapavg = 2.;
777
778 if( mesh->info.optimLES ) {
779 MMG3D_computeLESqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
780 his,mesh->info.imprim);
781 }
782 else {
783 MMG3D_computeOutqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
784 his,&nrid,mesh->info.imprim);
785 }
786
787 if ( mesh->info.imprim <= 0 )
788 return 1;
789
790 return MMG3D_displayQualHisto(ne,rapmax,rapavg,rapmin,
791 iel,good,med,his,nrid,mesh->info.optimLES,
792 mesh->info.imprim);
793}
794
808int MMG5_countelt(MMG5_pMesh mesh,MMG5_pSol sol, double *weightelt, long *npcible) {
809 MMG5_pTetra pt;
810 double len;
811 int ia,ipa,ipb,lon,l;
812 //int npbdry;
813 int lenint,loc,nedel,longen;
814 double dned,dnface,dnint/*,dnins*/,w,lenavg,lent[6];
815 double dnpdel,dnadd,leninv,dnaddloc,dnpdelloc;
816 int ddebug=0,ib,nv;
817 int64_t list[MMG3D_LMAX];
818 MMG5_int *pdel,k;
819 long nptot;
820 //FILE *inm;
821
822 pdel = (MMG5_int*) calloc(mesh->np+1,sizeof(MMG5_int));
823 nptot = (long) mesh->np;
824
825 // svg des poids
826 // npbdry = 0;
827 // inm = fopen("poid.sol","w");
828 // fprintf(inm,"MeshVersionFormatted 2\n Dimension 3 \n SolAtTetrahedra \n %" MMG5_PRId "\n 1 1 \n",mesh->ne);
829
830 // substraction of the half of the number of bdry vertex to avoid the surestimation due of the interface
831 // for (k=1; k<=mesh->np; k++) {
832 // if(mesh->point[k].tag & MG_BDY) npbdry++;
833 // }
834 // nptot -= 0.5*npbdry;
835
836 dnadd = dnpdel = 0;
837
838 for (k=1; k<=mesh->ne; k++) {
839 pt = &mesh->tetra[k];
840 if ( !MG_EOK(pt) ) continue;
841
842 /*longueur moyenne*/
843 lenavg = 0;
844 nv = 6;
845 for(ib=0 ; ib<6 ; ib++) {
846 ipa = MMG5_iare[ib][0];
847 ipb = MMG5_iare[ib][1];
848 lent[ib] = MMG5_lenedg(mesh,sol,ib,pt);
849 if ( lent[ib]==0 ) nv--;
850 lenavg+=lent[ib];
851 }
852 if ( nv )
853 lenavg /= (double)nv;
854 else
855 lenavg = 1; // Unable to treat this element
856
857 w = 0;
858 if(weightelt)
859 weightelt[k] = 0;
860 nedel = 0;
861
862 for (ia=0; ia<6; ia++) {
863 int8_t isbdy;
864 longen = MMG5_coquil(mesh,k,ia,list,&isbdy);
865 lon = longen/2;
866
867 if ( lon<=0 ) {
868 MMG5_SAFE_FREE(pdel);
869 return 0;
870 }
871 /* if ( isbdy ) { */
872 /* continue; */
873 /* } */
874 //assert(!(longen%2));
875 for (l=1; l<lon; l++)
876 if ( list[l] < 6*k ) break;
877
878 if ( l < lon ) {
879 loc = 1;
880 //continue;
881 } else {
882 loc = 0;
883 }
884
885 dnaddloc = 0;
886 //dnpdelloc = 0;
887
888 len = lent[ia];
889
890 if(ddebug) printf("len %e\n",len);
891 if(len > 3) {
892 loc = 0; //count all edges and divide by lon
893 len = lenavg; //if very long edge, take the mean
894 lenint = ((int) len);
895 if(fabs(lenint -len) > 0.5) lenint++;
896 //POURQUOI SURESTIMER ???lenint++;
897 //nb de point a inserer sur l'arete : longueur - 1
898 dned = lenint - 1;
899 //nb de point a l'interieur de la face si toutes les aretes sont coupees le meme nb de fois
900 dnface = (lenint+2)*(lenint+1) / 2. - 3 - 3*dned;
901 //nb de point a l'interieur du tetra si toutes les aretes sont coupees le meme nb de fois
902 dnint = (lenint+3)*(lenint+2)*(lenint+1) / 6. - 4 - 4*dnface - 6*dned;
903 //nb de point a inserer pour cette arete de ce tetra : on divise par lon
904 //dnins = dned*(1./lon) + (dnface/3. + dnint/6.);//(dnface/12. + dnint/6.);
905 //if(!isbdry) {
906 //nb points sur l'arete +
907 //lon*(2/3 nb point sur la face (ie 1/3 de face et 2 faces adj a l'arete) + 1/6 nb de point interne)
908 dnaddloc = dned + lon*(2*dnface/3. + dnint/6.);
909 //} else {
910 // dnaddloc = 0.5*(dned + lon*(2*dnface/3. + dnint/6.));
911 //}
912 dnaddloc *= 1./lon;
913 if(!loc) {
914 /*on ne compte les points internes que pour les (tres) bons tetras*/
915 if( MMG3D_ALPHAD * pt->qual < 0.5) {
916 if(MMG3D_ALPHAD * pt->qual >= 1./5.)
917 dnaddloc = dned / lon + 2*dnface/3.;
918 else
919 dnaddloc = dned / lon ;
920 }
921 //rajout de 30% parce que 1) on vise des longueurs de 0.7 et
922 //2) on ne tient pas compte du fait qu'on divise tjs par 2 dans la generation
923 if( (MMG3D_ALPHAD*pt->qual <= 1./50.) )
924 dnaddloc = 0;
925 else if((MMG3D_ALPHAD*pt->qual <= 1./10.) )
926 dnaddloc = 0.2*dnaddloc;
927 else if((len > 10) && (MMG3D_ALPHAD*pt->qual >= 1./1.5) ) //on sous-estime uniquement pour les tres bons
928 dnaddloc = dnaddloc*0.3 + dnaddloc;
929 else if(len < 6 && len>3)
930 dnaddloc = 0.7*dnaddloc;
931
932
933 dnadd += dnaddloc;
934 }
935 } else if(len > 2.8) {
936 //if(!isbdry) {
937 dnaddloc = 2.;
938 //} else {
939 // dnaddloc = 1;
940 //}
941 if(!loc){
942 // if(!isbdry) {
943 dnadd += 2.;
944 // } else {
945 // dnadd++;
946 // }
947 }
948 //dnins = 2;
949 } else if(len > 1.41) {
950 //if(!isbdry)
951 dnaddloc = 1;
952 if(!loc) {
953 //if(!isbdry)
954 dnadd += 1.;
955 }
956 //dnins = 1;
957 } else if(len < 0.6) {
958 nedel = 1;
959
960 leninv = 1./len;
961 if(pt->v[ipa]<pt->v[ipb]) {
962 if(!pdel[pt->v[ipa]]) {
963 // if(!isbdry) {
964 dnpdelloc = (leninv - 1.)/leninv;
965 // } else {
966 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
967 // }
968 if(!loc) {
969 dnpdel+=dnpdelloc;
970 pdel[pt->v[ipa]]=1;
971 }
972 } else if(!pdel[pt->v[ipb]]) {
973 // if(!isbdry) {
974 dnpdelloc = (leninv - 1.)/leninv;
975 // } else {
976 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
977 // }
978 if(!loc) {
979 dnpdel +=dnpdelloc;
980 pdel[pt->v[ipb]]=1;
981 }
982 }
983 } else {
984 if(!pdel[pt->v[ipb]]) {
985 // if(!isbdry) {
986 dnpdelloc = (leninv - 1.)/leninv;
987 // } else {
988 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
989 // }
990 if(!loc) {
991 dnpdel+=dnpdelloc;
992 pdel[pt->v[ipb]]=1;
993 }
994 } else if(!pdel[pt->v[ipa]]) {
995 // if(!isbdry) {
996 dnpdelloc = (leninv - 1.)/leninv;
997 // } else {
998 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
999 // }
1000 if(!loc) {
1001 dnpdel+=dnpdelloc;
1002 pdel[pt->v[ipa]]=1;
1003 }
1004 }
1005 }
1006 //ndel++;
1007 }
1008
1009 //pour cette arete de ce tetra :
1010 //PHASE 1 = dnaddloc + nedel (on compte un si arete trop petite)
1011 //PHASE 2 = dnaddloc
1012 if(ddebug) printf("on ajoute %e\n",dnaddloc);
1013 w += (2*dnaddloc);//1./lon*(2*dnaddloc + dnpdelloc);
1014
1015 }/*for ia*/
1016 if(ddebug) printf("on soustrait %d\n",nedel);
1017
1018 w += 0.5*nedel;
1019
1020 //si l'elt ne doit pas etre ni splitte ni collapse est ce qu'on le compte ???
1021 //if(w==0) w+=1;
1022
1023 //fprintf(inm,"%e\n",w);
1024 if(weightelt)
1025 weightelt[k] = 10*w;
1026 } /*For k*/
1027
1028
1029 nptot += (long) dnadd - (long) dnpdel;
1030 *npcible = nptot;
1031 fprintf(stdout," ** ESTIMATION OF THE FINAL NUMBER OF NODES : %ld \n",nptot);
1032 if(mesh->info.imprim > 6)
1033 fprintf(stdout," ** %lf ADD DEL %lf\n",dnadd,dnpdel);
1034
1035 free(pdel);
1036
1037 //fclose(inm);
1038 return 1;
1039}
int ier
MMG5_pMesh MMG5_pSol * sol
MMG5_pMesh * mesh
int MMG5_coquil(MMG5_pMesh mesh, MMG5_int start, int ia, int64_t *list, int8_t *isbdy)
Definition: boulep_3d.c:1403
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
int MMG5_hashPop(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition: hash_3d.c:761
static double MMG5_caltet_iso(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTetra pt)
static double MMG5_lenedg33_ani(MMG5_pMesh mesh, MMG5_pSol met, int ia, MMG5_pTetra pt)
static double MMG5_orcal(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int iel)
API headers for the mmg3d library.
#define MMG3D_LMAX
Definition: libmmg3d.h:58
#define MMG3D_ALPHAD
#define MMG3D_BADKAL
static const uint8_t MMG5_iare[6][2]
vertices of extremities of the edges of the tetra
#define MG_GEO
int MMG5_minQualCheck(MMG5_int iel, double minqual, double alpha)
Definition: quality.c:343
#define MG_EOK(pt)
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MG_SIN(tag)
void MMG5_displayLengthHisto(MMG5_pMesh, MMG5_int, double *, MMG5_int, MMG5_int, double, MMG5_int, MMG5_int, double, int, double *, MMG5_int *, int8_t)
Definition: quality.c:252
double MMG5_orvol(MMG5_pPoint point, MMG5_int *v)
Definition: tools.c:951
#define MG_NOM
#define MMG5_EPSD2
#define MMG5_SAFE_FREE(ptr)
#define MMG5_DEL_MEM(mesh, ptr)
int MMG3D_prilen(MMG5_pMesh mesh, MMG5_pSol met, int8_t metRidTyp)
Definition: quality_3d.c:341
void MMG3D_computeLESqua(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *ne, double *max, double *avg, double *min, MMG5_int *iel, MMG5_int *good, MMG5_int *med, MMG5_int his[5], int imprim)
Definition: quality_3d.c:376
int MMG3D_displayQualHisto(MMG5_int ne, double max, double avg, double min, MMG5_int iel, MMG5_int good, MMG5_int med, MMG5_int his[5], MMG5_int nrid, int optimLES, int imprim)
Definition: quality_3d.c:460
void MMG3D_computeOutqua(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *ne, double *max, double *avg, double *min, MMG5_int *iel, MMG5_int *good, MMG5_int *med, MMG5_int his[5], MMG5_int *nrid, int imprim)
Definition: quality_3d.c:680
int MMG3D_displayQualHisto_internal(MMG5_int ne, double max, double avg, double min, MMG5_int iel, MMG5_int good, MMG5_int med, MMG5_int his[5], MMG5_int nrid, int optimLES, int imprim)
Definition: quality_3d.c:494
int MMG3D_computePrilen(MMG5_pMesh mesh, MMG5_pSol met, double *avlen, double *lmin, double *lmax, MMG5_int *ned, MMG5_int *amin, MMG5_int *bmin, MMG5_int *amax, MMG5_int *bmax, MMG5_int *nullEdge, int8_t metRidTyp, double **bd_in, MMG5_int hl[9])
Definition: quality_3d.c:221
int MMG5_countelt(MMG5_pMesh mesh, MMG5_pSol sol, double *weightelt, long *npcible)
Definition: quality_3d.c:808
void MMG3D_computeInqua(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int *ne, double *max, double *avg, double *min, MMG5_int *iel, MMG5_int *good, MMG5_int *med, MMG5_int his[5], int imprim)
Definition: quality_3d.c:559
int MMG3D_tetraQual(MMG5_pMesh mesh, MMG5_pSol met, int8_t metRidTyp)
Definition: quality_3d.c:50
double MMG5_caltet33_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTetra pt)
Definition: quality_3d.c:109
int MMG3D_outqua(MMG5_pMesh mesh, MMG5_pSol met)
Definition: quality_3d.c:764
int8_t ddb
Definition: mmg3d1_delone.c:42
int MMG3D_inqua(MMG5_pMesh mesh, MMG5_pSol met)
Definition: quality_3d.c:631
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
int8_t badkal
Definition: libmmgtypes.h:533
uint8_t metRidTyp
Definition: libmmgtypes.h:547
uint8_t optimLES
Definition: libmmgtypes.h:546
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_pTetra tetra
Definition: libmmgtypes.h:643
MMG5_int np
Definition: libmmgtypes.h:612
Structure to store points of a MMG mesh.
Definition: libmmgtypes.h:270
int16_t tag
Definition: libmmgtypes.h:284
double c[3]
Definition: libmmgtypes.h:271
double * m
Definition: libmmgtypes.h:671
MMG5_int v[4]
Definition: libmmgtypes.h:403
double qual
Definition: libmmgtypes.h:402