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(MMG5_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 if ( (!met) || (!met->m) ) {
245 /* the functions that computes the edge length cannot be called without an
246 * allocated metric */
247 return 0;
248 }
249
250 if ( !mesh->ne ) {
251 return 0;
252 }
253
254 /* Hash all edges in the mesh */
255 if ( !MMG5_hashNew(mesh,&hash,mesh->np,7*mesh->np) ) return 0;
256
257 for(k=1; k<=mesh->ne; k++) {
258 pt = &mesh->tetra[k];
259 if ( !MG_EOK(pt) ) continue;
260
261 for(ia=0; ia<6; ia++) {
262 i0 = MMG5_iare[ia][0];
263 i1 = MMG5_iare[ia][1];
264 np = pt->v[i0];
265 nq = pt->v[i1];
266
267 if(!MMG5_hashEdge(mesh,&hash,np,nq,0)){
268 fprintf(stderr," ## Error: %s: function MMG5_hashEdge return 0\n",
269 __func__);
270 return 0;
271 }
272 }
273 }
274
275 /* Pop edges from hash table, and analyze their length */
276 for(k=1; k<=mesh->ne; k++) {
277 pt = &mesh->tetra[k];
278 if ( !MG_EOK(pt) ) continue;
279 n = 0;
280 for(i=0 ; i<4 ; i++) {
281 ppt = &mesh->point[pt->v[i]];
282 if(!(MG_SIN(ppt->tag) || MG_NOM & ppt->tag) && (ppt->tag & MG_GEO)) continue;
283 n++;
284 }
285 if(!n) {
286 continue;
287 }
288 for(ia=0; ia<6; ia++) {
289 i0 = MMG5_iare[ia][0];
290 i1 = MMG5_iare[ia][1];
291 np = pt->v[i0];
292 nq = pt->v[i1];
293
294 /* Remove edge from hash ; ier = 1 if edge has been found */
295 ier = MMG5_hashPop(&hash,np,nq);
296 if( ier ) {
297 if ( (!metRidTyp) && met->size==6 && met->m ) {
298 // Warning: we may erroneously approximate the length of a curve
299 // boundary edge by the length of the straight edge if the "MG_BDY"
300 // tag is missing along the edge.
301 len = MMG5_lenedg33_ani(mesh,met,ia,pt);
302 }
303 else
304 // Warning: we may erroneously approximate the length of a curve
305 // boundary edge by the length of the straight edge if the "MG_BDY"
306 // tag is missing along the edge.
307 len = MMG5_lenedg(mesh,met,ia,pt);
308
309
310 if ( !len ) {
311 ++(*nullEdge);
312 }
313 else {
314 *avlen += len;
315 (*ned)++;
316
317 if( len < (*lmin) ) {
318 *lmin = len;
319 *amin = np;
320 *bmin = nq;
321 }
322
323 if ( len > (*lmax) ) {
324 *lmax = len;
325 *amax = np;
326 *bmax = nq;
327 }
328
329 /* Locate size of edge among given table */
330 for(i=0; i<8; i++) {
331 if ( bd[i] <= len && len < bd[i+1] ) {
332 hl[i]++;
333 break;
334 }
335 }
336 if( i == 8 ) hl[8]++;
337 }
338 }
339 }
340 }
341
342 MMG5_DEL_MEM(mesh,hash.item);
343 return 1;
344}
345
346
357int MMG3D_prilen(MMG5_pMesh mesh, MMG5_pSol met, int8_t metRidTyp) {
358 double avlen, lmin, lmax;
359 MMG5_int ned, nullEdge;
360 MMG5_int amin, bmin, amax, bmax, hl[9];
361 double *bd;
362
363 if (!MMG3D_computePrilen( mesh, met, &avlen, &lmin, &lmax, &ned, &amin,
364 &bmin, &amax, &bmax, &nullEdge, metRidTyp, &bd, hl ) )
365 return 0;
366
367 /* Display histogram */
368 MMG5_displayLengthHisto(mesh, ned, &avlen, amin, bmin, lmin,
369 amax, bmax, lmax,nullEdge, &bd[0], &hl[0],1);
370
371 return 1;
372}
373
374
392void MMG3D_computeLESqua(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *ne,double *max,double *avg,
393 double *min,MMG5_int *iel,MMG5_int *good,MMG5_int *med,MMG5_int his[5],int imprim) {
394 MMG5_pTetra pt;
395 double rap;
396 MMG5_int k,ok,nex;
397 static int8_t mmgWarn0=0;
398
399 /*compute tet quality*/
400 for (k=1; k<=mesh->ne; k++) {
401 pt = &mesh->tetra[k];
402 if( !MG_EOK(pt) ) continue;
403
404 pt->qual = MMG5_orcal(mesh,met,k);
405 }
406
407 if ( imprim <= 0 )
408 return;
409
410 (*min) = (*avg) = 0.0;
411 (*max) = 1.0;
412 (*iel) = 0;
413 (*med) = (*good) = 0;
414
415 for (k=0; k<5; k++) his[k] = 0;
416
417 nex = ok = 0;
418 for (k=1; k<=mesh->ne; k++) {
419 pt = &mesh->tetra[k];
420 if( !MG_EOK(pt) ) {
421 nex++;
422 continue;
423 }
424 ok++;
425 if ( (!mmgWarn0) && (MMG5_orvol(mesh->point,pt->v) < 0.0) ) {
426 mmgWarn0 = 1;
427 fprintf(stderr," ## Warning: %s: at least 1 negative volume.\n",
428 __func__);
429 }
430 rap = 1. - MMG3D_ALPHAD * pt->qual;
431 if ( rap > (*min) ) {
432 (*min) = rap;
433 (*iel) = ok;
434 }
435 if ( rap < 0.9 ) (*med)++;
436 if ( rap < 0.6 ) (*good)++;
437 // if ( rap < MMG3D_BADKAL ) mesh->info.badkal = 1;
438 (*avg) += rap;
439 (*max) = MG_MIN((*max),rap);
440 if(rap < 0.6)
441 his[0] += 1;
442 else if(rap < 0.9)
443 his[1] += 1;
444 else if(rap < 0.93)
445 his[2] += 1;
446 else if(rap < 0.99)
447 his[3] += 1;
448 else
449 his[4] += 1;
450 }
451
452 (*ne) = mesh->ne-nex;
453
454 return;
455}
456
476int MMG3D_displayQualHisto(MMG5_int ne,double max,double avg,double min,MMG5_int iel,
477 MMG5_int good,MMG5_int med,MMG5_int his[5],MMG5_int nrid,int optimLES,
478 int imprim) {
479
480 fprintf(stdout,"\n -- MESH QUALITY");
481 if ( optimLES )
482 fprintf(stdout," (LES)");
483 fprintf(stdout," %" MMG5_PRId "\n",ne);
484
485 fprintf(stdout," BEST %8.6f AVRG. %8.6f WRST. %8.6f (%" MMG5_PRId ")\n",
486 max,avg / ne,min,iel);
487
488 return ( MMG3D_displayQualHisto_internal(ne,max,avg,min,iel,good,med,his,
489 nrid,optimLES,imprim) );
490}
491
510int MMG3D_displayQualHisto_internal(MMG5_int ne,double max,double avg,double min,MMG5_int iel,
511 MMG5_int good,MMG5_int med,MMG5_int his[5],MMG5_int nrid,int optimLES,
512 int imprim)
513{
514 const double les_ticks[6] = {0,0.6,0.9,0.93,0.99,1};
515 int i,imax;
516
517 if ( abs(imprim) >= 3 ){
518 if ( optimLES ) {
519 /* print histo */
520 fprintf(stdout," HISTOGRAMM:");
521 fprintf(stdout," %6.2f %% < 0.6\n",100.0*((float)good/(float)ne));
522 if ( abs(imprim) > 3 ) {
523 fprintf(stdout," %6.2f %% < 0.9\n",100.0*( (float)med/(float)ne));
524
525 assert ( min >= max );
526 for ( i=0; i<5; ++i ) {
527 if ( max < les_ticks[i+1] && min >= les_ticks[i] ) {
528 fprintf(stdout," %5.2f < Q < %5.2f %7"MMG5_PRId" %6.2f %%\n",
529 les_ticks[i],les_ticks[i+1],his[i],
530 100.*((float)his[i]/(float)ne));
531 }
532 }
533 }
534 return 1;
535 }
536 else {
537 /* print histo */
538 fprintf(stdout," HISTOGRAMM:");
539 fprintf(stdout," %6.2f %% > 0.12\n",100.0*((float)good/(float)ne));
540 if ( abs(imprim) > 3 ) {
541 fprintf(stdout," %6.2f %% > 0.5\n",100.0*( (float)med/(float)ne));
542 imax = MG_MIN(4,(int)(5.*max));
543 for (i=imax; i>=(int)(5*min); i--) {
544 fprintf(stdout," %5.1f < Q < %5.1f %7"MMG5_PRId" %6.2f %%\n",
545 i/5.,i/5.+0.2,his[i],100.*((float)his[i]/(float)ne));
546 }
547 if ( nrid ) {
548 fprintf(stdout,"\n ## WARNING: %" MMG5_PRId " TETRA WITH 4 RIDGES POINTS:"
549 " UNABLE TO COMPUTE ANISO QUALITY.\n",nrid);
550 }
551 }
552 }
553 }
554
555 return MMG5_minQualCheck(iel,min,1.);
556}
557
575void MMG3D_computeInqua(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *ne,double *max,double *avg,
576 double *min,MMG5_int *iel,MMG5_int *good,MMG5_int *med,MMG5_int his[5],int imprim) {
577 MMG5_pTetra pt;
578 double rap;
579 MMG5_int k,ok,nex;
580 int ir;
581 static int8_t mmgWarn0 = 0;
582
583 /*compute tet quality*/
584 for (k=1; k<=mesh->ne; k++) {
585 pt = &mesh->tetra[k];
586 if( !MG_EOK(pt) ) continue;
587
588 if ( met->m ) {
589 if ( met->size == 6) {
590 pt->qual = MMG5_caltet33_ani(mesh,met,pt);
591 }
592 else
593 pt->qual = MMG5_orcal(mesh,met,k);
594 }
595 else // -A option
596 pt->qual = MMG5_caltet_iso(mesh,met,pt);
597 }
598 if ( imprim <= 0 ) return;
599
600 (*min) = 2.0;
601 (*max) = (*avg) = 0.0;
602 (*iel) = 0;
603 (*med) = (*good) = 0;
604
605 for (k=0; k<5; k++) his[k] = 0;
606
607 nex = ok = 0;
608 for (k=1; k<=mesh->ne; k++) {
609 pt = &mesh->tetra[k];
610 if( !MG_EOK(pt) ) {
611 nex++;
612 continue;
613 }
614 ok++;
615 if ( (!mmgWarn0) && (MMG5_orvol(mesh->point,pt->v) < 0.0) ) {
616 mmgWarn0 = 1;
617 fprintf(stderr," ## Warning: %s: at least 1 negative volume\n",
618 __func__);
619 }
620 rap = MMG3D_ALPHAD * pt->qual;
621 if ( rap < (*min) ) {
622 (*min) = rap;
623 (*iel) = ok;
624 }
625 if ( rap > 0.5 ) (*med)++;
626 if ( rap > 0.12 ) (*good)++;
627 if ( rap < MMG3D_BADKAL ) mesh->info.badkal = 1;
628 (*avg) += rap;
629 (*max) = MG_MAX((*max),rap);
630 ir = MG_MIN(4,(int)(5.0*rap));
631 his[ir] += 1;
632 }
633
634 (*ne) = mesh->ne-nex;
635
636 return;
637}
638
648 double rapmin,rapmax,rapavg;
649 int k;
650 MMG5_int med,good,iel,ne,his[5];
651
652 ne = iel = good = med = 0;
653 for ( k=0; k<5; ++k ) {
654 his[k] = 0;
655 }
656 rapmax = 0.;
657 rapmin = 2.;
658 rapavg = 2.;
659
660 if( mesh->info.optimLES ) {
661 MMG3D_computeLESqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
662 his,mesh->info.imprim);
663 }
664 else {
665 MMG3D_computeInqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
666 his,mesh->info.imprim);
667 }
668
669 if ( mesh->info.imprim <= 0 )
670 return 1;
671
672 return MMG3D_displayQualHisto(ne,rapmax,rapavg,rapmin,
673 iel,good,med,his,0,mesh->info.optimLES,
674 mesh->info.imprim);
675}
676
696void MMG3D_computeOutqua(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int *ne,double *max,double *avg,
697 double *min,MMG5_int *iel,MMG5_int *good,MMG5_int *med,MMG5_int his[5],
698 MMG5_int *nrid,int imprim) {
699 MMG5_pTetra pt;
700 MMG5_pPoint ppt;
701 double rap;
702 int i,ir,n;
703 MMG5_int k,ok,nex;
704 static int8_t mmgWarn0 = 0;
705
706 /*compute tet quality*/
707 for (k=1; k<=mesh->ne; k++) {
708 pt = &mesh->tetra[k];
709 if( !MG_EOK(pt) ) continue;
710 pt->qual = MMG5_orcal(mesh,met,k);
711 }
712
713 if ( imprim <= 0 )
714 return;
715
716 (*min) = 2.0;
717 (*max) = (*avg) = 0.0;
718 (*iel) = 0;
719 (*med) = (*good) = 0;
720
721 for (k=0; k<5; k++) his[k] = 0;
722
723 nex = ok = (*nrid) = 0;
724 for (k=1; k<=mesh->ne; k++) {
725 pt = &mesh->tetra[k];
726 if( !MG_EOK(pt) ) {
727 nex++;
728 continue;
729 }
730 ok++;
731 if ( (!mmgWarn0) && (MMG5_orvol(mesh->point,pt->v) < 0.0) ) {
732 mmgWarn0 = 1;
733 fprintf(stderr," ## Warning: %s: at least 1 negative volume\n",
734 __func__);
735 }
736
737 /* Count the number of tets with only ridge metric if special metric storage
738 * at ridge. */
739 if ( mesh->info.metRidTyp==1 ) {
740 n = 0;
741 for(i=0 ; i<4 ; i++) {
742 ppt = &mesh->point[pt->v[i]];
743 if(!(MG_SIN(ppt->tag) || MG_NOM & ppt->tag) && (ppt->tag & MG_GEO)) continue;
744 n++;
745 }
746 if(!n) {
747 (*nrid)++;
748 continue;
749 }
750 }
751
752 rap = MMG3D_ALPHAD * pt->qual;
753 if ( rap < (*min) ) {
754 (*min) = rap;
755 (*iel) = ok;
756 }
757 if ( rap > 0.5 ) (*med)++;
758 if ( rap > 0.12 ) (*good)++;
759 if ( rap < MMG3D_BADKAL ) mesh->info.badkal = 1;
760 (*avg) += rap;
761 (*max) = MG_MAX((*max),rap);
762 ir = MG_MIN(4,(int)(5.0*rap));
763 his[ir] += 1;
764 }
765
766 (*ne) = mesh->ne-nex;
767
768 return;
769}
770
781 double rapmin,rapmax,rapavg;
782 int k;
783 MMG5_int his[5];
784 MMG5_int med,good,iel,ne,nrid;
785
786 nrid = ne = iel = good = med = 0;
787 for ( k=0; k<5; ++k ) {
788 his[k] = 0;
789 }
790 rapmax = 0.;
791 rapmin = 2.;
792 rapavg = 2.;
793
794 if( mesh->info.optimLES ) {
795 MMG3D_computeLESqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
796 his,mesh->info.imprim);
797 }
798 else {
799 MMG3D_computeOutqua(mesh,met,&ne,&rapmax,&rapavg,&rapmin,&iel,&good,&med,
800 his,&nrid,mesh->info.imprim);
801 }
802
803 if ( mesh->info.imprim <= 0 )
804 return 1;
805
806 return MMG3D_displayQualHisto(ne,rapmax,rapavg,rapmin,
807 iel,good,med,his,nrid,mesh->info.optimLES,
808 mesh->info.imprim);
809}
810
824int MMG5_countelt(MMG5_pMesh mesh,MMG5_pSol sol, double *weightelt, long *npcible) {
825 MMG5_pTetra pt;
826 double len;
827 int ia,ipa,ipb,lon,l;
828 //int npbdry;
829 int lenint,loc,nedel,longen;
830 double dned,dnface,dnint/*,dnins*/,w,lenavg,lent[6];
831 double dnpdel,dnadd,leninv,dnaddloc,dnpdelloc;
832 int ddebug=0,ib,nv;
833 int64_t list[MMG3D_LMAX];
834 MMG5_int *pdel,k;
835 long nptot;
836 //FILE *inm;
837
838 pdel = (MMG5_int*) calloc(mesh->np+1,sizeof(MMG5_int));
839 nptot = (long) mesh->np;
840
841 // svg des poids
842 // npbdry = 0;
843 // inm = fopen("poid.sol","w");
844 // fprintf(inm,"MeshVersionFormatted 2\n Dimension 3 \n SolAtTetrahedra \n %" MMG5_PRId "\n 1 1 \n",mesh->ne);
845
846 // substraction of the half of the number of bdry vertex to avoid the surestimation due of the interface
847 // for (k=1; k<=mesh->np; k++) {
848 // if(mesh->point[k].tag & MG_BDY) npbdry++;
849 // }
850 // nptot -= 0.5*npbdry;
851
852 dnadd = dnpdel = 0;
853
854 for (k=1; k<=mesh->ne; k++) {
855 pt = &mesh->tetra[k];
856 if ( !MG_EOK(pt) ) continue;
857
858 /*longueur moyenne*/
859 lenavg = 0;
860 nv = 6;
861 for(ib=0 ; ib<6 ; ib++) {
862 ipa = MMG5_iare[ib][0];
863 ipb = MMG5_iare[ib][1];
864 lent[ib] = MMG5_lenedg(mesh,sol,ib,pt);
865 if ( lent[ib]==0 ) nv--;
866 lenavg+=lent[ib];
867 }
868 if ( nv )
869 lenavg /= (double)nv;
870 else
871 lenavg = 1; // Unable to treat this element
872
873 w = 0;
874 if(weightelt)
875 weightelt[k] = 0;
876 nedel = 0;
877
878 for (ia=0; ia<6; ia++) {
879 int8_t isbdy;
880 longen = MMG5_coquil(mesh,k,ia,list,&isbdy);
881 lon = longen/2;
882
883 if ( lon<=0 ) {
884 MMG5_SAFE_FREE(pdel);
885 return 0;
886 }
887 /* if ( isbdy ) { */
888 /* continue; */
889 /* } */
890 //assert(!(longen%2));
891 for (l=1; l<lon; l++)
892 if ( list[l] < 6*k ) break;
893
894 if ( l < lon ) {
895 loc = 1;
896 //continue;
897 } else {
898 loc = 0;
899 }
900
901 dnaddloc = 0;
902 //dnpdelloc = 0;
903
904 len = lent[ia];
905
906 if(ddebug) printf("len %e\n",len);
907 if(len > 3) {
908 loc = 0; //count all edges and divide by lon
909 len = lenavg; //if very long edge, take the mean
910 lenint = ((int) len);
911 if(fabs(lenint -len) > 0.5) lenint++;
912 //POURQUOI SURESTIMER ???lenint++;
913 //nb de point a inserer sur l'arete : longueur - 1
914 dned = lenint - 1;
915 //nb de point a l'interieur de la face si toutes les aretes sont coupees le meme nb de fois
916 dnface = (lenint+2)*(lenint+1) / 2. - 3 - 3*dned;
917 //nb de point a l'interieur du tetra si toutes les aretes sont coupees le meme nb de fois
918 dnint = (lenint+3)*(lenint+2)*(lenint+1) / 6. - 4 - 4*dnface - 6*dned;
919 //nb de point a inserer pour cette arete de ce tetra : on divise par lon
920 //dnins = dned*(1./lon) + (dnface/3. + dnint/6.);//(dnface/12. + dnint/6.);
921 //if(!isbdry) {
922 //nb points sur l'arete +
923 //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)
924 dnaddloc = dned + lon*(2*dnface/3. + dnint/6.);
925 //} else {
926 // dnaddloc = 0.5*(dned + lon*(2*dnface/3. + dnint/6.));
927 //}
928 dnaddloc *= 1./lon;
929 if(!loc) {
930 /*on ne compte les points internes que pour les (tres) bons tetras*/
931 if( MMG3D_ALPHAD * pt->qual < 0.5) {
932 if(MMG3D_ALPHAD * pt->qual >= 1./5.)
933 dnaddloc = dned / lon + 2*dnface/3.;
934 else
935 dnaddloc = dned / lon ;
936 }
937 //rajout de 30% parce que 1) on vise des longueurs de 0.7 et
938 //2) on ne tient pas compte du fait qu'on divise tjs par 2 dans la generation
939 if( (MMG3D_ALPHAD*pt->qual <= 1./50.) )
940 dnaddloc = 0;
941 else if((MMG3D_ALPHAD*pt->qual <= 1./10.) )
942 dnaddloc = 0.2*dnaddloc;
943 else if((len > 10) && (MMG3D_ALPHAD*pt->qual >= 1./1.5) ) //on sous-estime uniquement pour les tres bons
944 dnaddloc = dnaddloc*0.3 + dnaddloc;
945 else if(len < 6 && len>3)
946 dnaddloc = 0.7*dnaddloc;
947
948
949 dnadd += dnaddloc;
950 }
951 } else if(len > 2.8) {
952 //if(!isbdry) {
953 dnaddloc = 2.;
954 //} else {
955 // dnaddloc = 1;
956 //}
957 if(!loc){
958 // if(!isbdry) {
959 dnadd += 2.;
960 // } else {
961 // dnadd++;
962 // }
963 }
964 //dnins = 2;
965 } else if(len > 1.41) {
966 //if(!isbdry)
967 dnaddloc = 1;
968 if(!loc) {
969 //if(!isbdry)
970 dnadd += 1.;
971 }
972 //dnins = 1;
973 } else if(len < 0.6) {
974 nedel = 1;
975
976 leninv = 1./len;
977 if(pt->v[ipa]<pt->v[ipb]) {
978 if(!pdel[pt->v[ipa]]) {
979 // if(!isbdry) {
980 dnpdelloc = (leninv - 1.)/leninv;
981 // } else {
982 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
983 // }
984 if(!loc) {
985 dnpdel+=dnpdelloc;
986 pdel[pt->v[ipa]]=1;
987 }
988 } else if(!pdel[pt->v[ipb]]) {
989 // if(!isbdry) {
990 dnpdelloc = (leninv - 1.)/leninv;
991 // } else {
992 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
993 // }
994 if(!loc) {
995 dnpdel +=dnpdelloc;
996 pdel[pt->v[ipb]]=1;
997 }
998 }
999 } else {
1000 if(!pdel[pt->v[ipb]]) {
1001 // if(!isbdry) {
1002 dnpdelloc = (leninv - 1.)/leninv;
1003 // } else {
1004 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
1005 // }
1006 if(!loc) {
1007 dnpdel+=dnpdelloc;
1008 pdel[pt->v[ipb]]=1;
1009 }
1010 } else if(!pdel[pt->v[ipa]]) {
1011 // if(!isbdry) {
1012 dnpdelloc = (leninv - 1.)/leninv;
1013 // } else {
1014 // dnpdelloc = 0.5*(leninv - 1.)/leninv;
1015 // }
1016 if(!loc) {
1017 dnpdel+=dnpdelloc;
1018 pdel[pt->v[ipa]]=1;
1019 }
1020 }
1021 }
1022 //ndel++;
1023 }
1024
1025 //pour cette arete de ce tetra :
1026 //PHASE 1 = dnaddloc + nedel (on compte un si arete trop petite)
1027 //PHASE 2 = dnaddloc
1028 if(ddebug) printf("on ajoute %e\n",dnaddloc);
1029 w += (2*dnaddloc);//1./lon*(2*dnaddloc + dnpdelloc);
1030
1031 }/*for ia*/
1032 if(ddebug) printf("on soustrait %d\n",nedel);
1033
1034 w += 0.5*nedel;
1035
1036 //si l'elt ne doit pas etre ni splitte ni collapse est ce qu'on le compte ???
1037 //if(w==0) w+=1;
1038
1039 //fprintf(inm,"%e\n",w);
1040 if(weightelt)
1041 weightelt[k] = 10*w;
1042 } /*For k*/
1043
1044
1045 nptot += (long) dnadd - (long) dnpdel;
1046 *npcible = nptot;
1047 fprintf(stdout," ** ESTIMATION OF THE FINAL NUMBER OF NODES : %ld \n",nptot);
1048 if(mesh->info.imprim > 6)
1049 fprintf(stdout," ** %lf ADD DEL %lf\n",dnadd,dnpdel);
1050
1051 free(pdel);
1052
1053 //fclose(inm);
1054 return 1;
1055}
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:1406
int MMG5_hashNew(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int hsiz, MMG5_int hmax)
Definition: hash.c:532
int MMG5_hashEdge(MMG5_pMesh mesh, MMG5_Hash *hash, MMG5_int a, MMG5_int b, MMG5_int k)
Definition: hash.c:346
int MMG5_hashPop(MMG5_Hash *hash, MMG5_int a, MMG5_int b)
Definition: hash_3d.c:850
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 and documentation for the mmg3d library, for volumetric meshes in 3D.
#define MMG3D_LMAX
Definition: libmmg3d.h:130
#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:357
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:392
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:476
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:696
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:510
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:824
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:575
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:780
int8_t ddb
Definition: mmg3d1_delone.c:42
int MMG3D_inqua(MMG5_pMesh mesh, MMG5_pSol met)
Definition: quality_3d.c:647
Identic as MMG5_HGeom but use MMG5_hedge to store edges instead of MMG5_hgeom (memory economy).
Definition: libmmgtypes.h:603
MMG5_hedge * item
Definition: libmmgtypes.h:605
int8_t badkal
Definition: libmmgtypes.h:540
uint8_t metRidTyp
Definition: libmmgtypes.h:554
uint8_t optimLES
Definition: libmmgtypes.h:553
MMG mesh structure.
Definition: libmmgtypes.h:613
MMG5_Info info
Definition: libmmgtypes.h:659
MMG5_int ne
Definition: libmmgtypes.h:620
MMG5_pPoint point
Definition: libmmgtypes.h:649
MMG5_pTetra tetra
Definition: libmmgtypes.h:651
MMG5_int np
Definition: libmmgtypes.h:620
Structure to store vertices of an MMG mesh.
Definition: libmmgtypes.h:276
double c[3]
Definition: libmmgtypes.h:277
uint16_t tag
Definition: libmmgtypes.h:290
double * m
Definition: libmmgtypes.h:680
Structure to store tetrahedra of an MMG mesh.
Definition: libmmgtypes.h:407
MMG5_int v[4]
Definition: libmmgtypes.h:409
double qual
Definition: libmmgtypes.h:408