Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
tools.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 "mmgcommon_private.h"
37
49inline void MMG5_nsort(int8_t n,double *val,int8_t *perm){
50 int8_t i,j;
51 int8_t aux;
52
53 for (i=0; i<n; i++) perm[i] = i;
54
55 for (i=0; i<n; i++) {
56 for (j=i+1; j<n; j++) {
57 if ( val[perm[i]] > val[perm[j]] ) {
58 aux = perm[i];
59 perm[i] = perm[j];
60 perm[j] = aux;
61 }
62 }
63 }
64}
65
80inline void MMG5_nperm(int8_t n,int8_t shift,int8_t stride,double *val,double *oldval,int8_t *perm) {
81 int8_t i,k;
82
83 for( i = 0; i < n; i++ )
84 oldval[i] = val[shift+i*stride];
85
86 for( i = 0; i < n; i++ ) {
87 k = perm[i];
88 val[shift+i*stride] = oldval[k];
89 }
90}
91
103int MMG5_devangle(double* n1, double *n2, double crit)
104{
105 double dev;
106
107 dev = n1[0]*n2[0] + n1[1]*n2[1] + n1[2]*n2[2];
108
109 if ( dev < crit ) {
110 return 0;
111 }
112
113 return 1;
114}
115
128 MMG5_int ip1,MMG5_int ip2, MMG5_int ip3,double *n) {
129 MMG5_pPoint p1,p2,p3;
130 double abx,aby,abz,acx,acy,acz;
131
132 p1 = &mesh->point[ip1];
133 p2 = &mesh->point[ip2];
134 p3 = &mesh->point[ip3];
135
136 /* area */
137 abx = p2->c[0] - p1->c[0];
138 aby = p2->c[1] - p1->c[1];
139 abz = p2->c[2] - p1->c[2];
140
141 acx = p3->c[0] - p1->c[0];
142 acy = p3->c[1] - p1->c[1];
143 acz = p3->c[2] - p1->c[2];
144
145 n[0] = aby*acz - abz*acy;
146 n[1] = abz*acx - abx*acz;
147 n[2] = abx*acy - aby*acx;
148
149 return 1;
150}
151
161 double n[3];
162 MMG5_int ip1, ip2, ip3;
163
164 ip1 = pt->v[0];
165 ip2 = pt->v[1];
166 ip3 = pt->v[2];
167
168 MMG5_nonUnitNorPts(mesh,ip1,ip2,ip3,n);
169
170 return n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
171}
183inline int MMG5_norpts(MMG5_pMesh mesh,MMG5_int ip1,MMG5_int ip2, MMG5_int ip3,double *n) {
184 double dd,det;
185
186 MMG5_nonUnitNorPts(mesh,ip1,ip2,ip3,n);
187
188 det = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
189
190 if ( det < MMG5_EPSD2 ) return 0;
191
192 dd = 1.0 / sqrt(det);
193 n[0] *= dd;
194 n[1] *= dd;
195 n[2] *= dd;
196
197 return 1;
198}
199
209inline int MMG5_nortri(MMG5_pMesh mesh,MMG5_pTria pt,double *n) {
210
211 return MMG5_norpts(mesh,pt->v[0],pt->v[1],pt->v[2],n);
212
213}
214
220void MMG5_transpose3d(double m[3][3]) {
221 double swp;
222 for( int8_t i = 0; i < 2; i++ ) {
223 for( int8_t j = i+1; j < 3; j++ ) {
224 swp = m[i][j];
225 m[i][j] = m[j][i];
226 m[j][i] = swp;
227 }
228 }
229}
230
237 double a[3][3] = {{1.,2.,3.},
238 {4.,5.,6.},
239 {7.,8.,9.}};
240 double b[3][3] = {{1.,4.,7.},
241 {2.,5.,8.},
242 {3.,6.,9.}};
243 double maxerr;
244
246
247 maxerr = MMG5_test_mat_error(9,(double *)a,(double *)b);
248 if( maxerr > MMG5_EPSD ) {
249 fprintf(stderr," ## Error matrix transposition: in function %s, max error %e\n",
250 __func__,maxerr);
251 return 0;
252 }
253
254 return 1;
255}
256
265void MMG5_dotprod(int8_t dim,double *a,double *b,double *result) {
266 *result = 0.0;
267 for( int8_t i = 0; i < dim; i++ )
268 *result += a[i]*b[i];
269}
270
277 double a[4] = {1.0, 2.0, 3.0, 4.0};
278 double b[4] = {1.0, 0.5, 1./3., 0.25};
279 double cex = 4.0;
280 double cnum,err;
281
282 MMG5_dotprod(4,a,b,&cnum);
283 err = fabs(cex-cnum);
284 if( err > MMG5_EPSD ) {
285 fprintf(stderr," ## Error scalar product: in function %s, error %e\n",
286 __func__,err);
287 return 0;
288 }
289
290 return 1;
291}
292
300void MMG5_crossprod3d(double *a,double *b,double *result) {
301 result[0] = a[1]*b[2] - a[2]*b[1];
302 result[1] = a[2]*b[0] - a[0]*b[2];
303 result[2] = a[0]*b[1] - a[1]*b[0];
304}
305
312 double a[3] = {1., 0., 0.};
313 double b[3] = {1./sqrt(2.),1./sqrt(2.),0.};
314 double cex[3] = {0.,0.,1./sqrt(2.)};
315 double cnum[3],maxerr;
316
317 MMG5_crossprod3d(a,b,cnum);
318
319 maxerr = MMG5_test_mat_error(3,cex,cnum);
320 if( maxerr > MMG5_EPSD ) {
321 fprintf(stderr," ## Error 3D cross product: in function %s, max error %e\n",
322 __func__,maxerr);
323 return 0;
324 }
325
326 return 1;
327}
328
337void MMG5_mn(double m[6], double n[6], double mn[9] ){
338
339 mn[0] = m[0]*n[0] + m[1]*n[1] + m[2]*n[2];
340 mn[1] = m[0]*n[1] + m[1]*n[3] + m[2]*n[4];
341 mn[2] = m[0]*n[2] + m[1]*n[4] + m[2]*n[5];
342 mn[3] = m[1]*n[0] + m[3]*n[1] + m[4]*n[2];
343 mn[4] = m[1]*n[1] + m[3]*n[3] + m[4]*n[4];
344 mn[5] = m[1]*n[2] + m[3]*n[4] + m[4]*n[5];
345 mn[6] = m[2]*n[0] + m[4]*n[1] + m[5]*n[2];
346 mn[7] = m[2]*n[1] + m[4]*n[3] + m[5]*n[4];
347 mn[8] = m[2]*n[2] + m[4]*n[4] + m[5]*n[5];
348
349 return;
350}
351
358 double m[6] = {1.,2.,3.,4.,5.,6.}; /* Test matrix 1 */
359 double n[6] = {2.,3.,4.,5.,6.,7.}; /* Test matrix 2 */
360 double mnex[9] = {20., 31., 37.,
361 36., 56., 67.,
362 45., 70., 84.}; /* Exact m*n product */
363 double nmex[9] = {20., 36., 45.,
364 31., 56., 70.,
365 37., 67., 84.}; /* Exact n*m product */
366 double prodnum[9],maxerr; /* Numerical approximation */
367
369 MMG5_mn(m,n,prodnum);
370
371 /* Check error in norm inf */
372 maxerr = MMG5_test_mat_error(9,mnex,prodnum);
373 if( maxerr > MMG5_EPSD ) {
374 fprintf(stderr," ## Error 3x3 symmetric matrix product m*n: in function %s, max error %e\n",
375 __func__,maxerr);
376 return 0;
377 }
378
379
381 MMG5_mn(n,m,prodnum);
382
383 /* Check error in norm inf */
384 maxerr = MMG5_test_mat_error(9,nmex,prodnum);
385 if( maxerr > MMG5_EPSD ) {
386 fprintf(stderr," ## Error 3x3 symmetric matrix product n*m: in function %s, max error %e\n",
387 __func__,maxerr);
388 return 0;
389 }
390
391 return 1;
392}
393
394
405inline int MMG5_rmtr(double r[3][3],double m[6], double mr[6]){
406 double n[3][3];
407
408 n[0][0] = m[0]*r[0][0] + m[1]*r[0][1] + m[2]*r[0][2];
409 n[1][0] = m[1]*r[0][0] + m[3]*r[0][1] + m[4]*r[0][2];
410 n[2][0] = m[2]*r[0][0] + m[4]*r[0][1] + m[5]*r[0][2];
411
412 n[0][1] = m[0]*r[1][0] + m[1]*r[1][1] + m[2]*r[1][2];
413 n[1][1] = m[1]*r[1][0] + m[3]*r[1][1] + m[4]*r[1][2];
414 n[2][1] = m[2]*r[1][0] + m[4]*r[1][1] + m[5]*r[1][2];
415
416 n[0][2] = m[0]*r[2][0] + m[1]*r[2][1] + m[2]*r[2][2];
417 n[1][2] = m[1]*r[2][0] + m[3]*r[2][1] + m[4]*r[2][2];
418 n[2][2] = m[2]*r[2][0] + m[4]*r[2][1] + m[5]*r[2][2];
419
420 mr[0] = r[0][0]*n[0][0] + r[0][1]*n[1][0] + r[0][2]*n[2][0];
421 mr[1] = r[0][0]*n[0][1] + r[0][1]*n[1][1] + r[0][2]*n[2][1];
422 mr[2] = r[0][0]*n[0][2] + r[0][1]*n[1][2] + r[0][2]*n[2][2];
423 mr[3] = r[1][0]*n[0][1] + r[1][1]*n[1][1] + r[1][2]*n[2][1];
424 mr[4] = r[1][0]*n[0][2] + r[1][1]*n[1][2] + r[1][2]*n[2][2];
425 mr[5] = r[2][0]*n[0][2] + r[2][1]*n[1][2] + r[2][2]*n[2][2];
426
427 return 1;
428}
429
435inline int MMG5_test_rmtr() {
436 double m[6] = {111./2.,-109./2., 89./2.,111./2.,-91./2.,111./2.}; /* Test matrix */
437 double r[3][3] = {{1./sqrt(2.),1./sqrt(2.), 0.},
438 { 0.,1./sqrt(2.),1./sqrt(2.)},
439 {1./sqrt(2.), 0.,1./sqrt(2.)}}; /* Test transformation */
440 double outex[6] = {1., 0., 0., 10., 0., 100.}; /* Exact result */
441 double outnum[6],maxerr; /* Numerical result */
442
444 if( !MMG5_rmtr(r,m,outnum) )
445 return 0;
446
447 /* Check error in norm inf */
448 maxerr = MMG5_test_mat_error(6,outex,outnum);
449 if( maxerr > 10.*MMG5_EPSOK ) {
450 fprintf(stderr," ## Error linear transformation of symmetric matrix: in function %s, max error %e\n",
451 __func__,maxerr);
452 return 0;
453 }
454
455 return 1;
456}
457
467inline int MMG5_rotmatrix(double n[3],double r[3][3]) {
468 double aa,bb,ab,ll,l,cosalpha,sinalpha;
469
470 aa = n[0]*n[0];
471 bb = n[1]*n[1];
472 ab = n[0]*n[1];
473 ll = aa+bb;
474 cosalpha = n[2];
475 sinalpha = sqrt(1.0- MG_MIN(1.0,cosalpha*cosalpha));
476
477 /* No rotation needed in this case */
478 if ( ll < MMG5_EPS ) {
479 if ( n[2] > 0.0 ) {
480 r[0][0] = 1.0 ; r[0][1] = 0.0 ; r[0][2] = 0.0;
481 r[1][0] = 0.0 ; r[1][1] = 1.0 ; r[1][2] = 0.0;
482 r[2][0] = 0.0 ; r[2][1] = 0.0 ; r[2][2] = 1.0;
483 }
484 else {
485 r[0][0] = -1.0 ; r[0][1] = 0.0 ; r[0][2] = 0.0;
486 r[1][0] = 0.0 ; r[1][1] = 1.0 ; r[1][2] = 0.0;
487 r[2][0] = 0.0 ; r[2][1] = 0.0 ; r[2][2] = -1.0;
488 }
489 }
490 else {
491 l = sqrt(ll);
492
493 r[0][0] = (aa*cosalpha + bb)/ll;
494 r[0][1] = ab*(cosalpha-1)/ll;
495 r[0][2] = -n[0]*sinalpha/l;
496 r[1][0] = r[0][1];
497 r[1][1] = (bb*cosalpha + aa)/ll;
498 r[1][2] = -n[1]*sinalpha/l;
499 r[2][0] = n[0]*sinalpha/l;
500 r[2][1] = n[1]*sinalpha/l;
501 r[2][2] = cosalpha;
502 }
503 return 1;
504}
505
513 double n[3] = {1./sqrt(1000101.),1000./sqrt(1000101.),10./sqrt(1000101.)}; /* Test unit vector */
514 double idex[6] = {1.,0.,0.,1.,0.,1.}; /*Exact identity matrix */
515 double ezex [3] = {0.,0.,1.}; /* Exact z-unit vector */
516 double R[3][3],idnum[6],eznum[3],maxerr; /* Numerical quantities */
517
520 if( !MMG5_rotmatrix(n,R) )
521 return 0;
522
523
525 for( int8_t i = 0; i < 3; i++ ) {
526 eznum[i] = 0.;
527 for( int8_t j = 0; j < 3; j++ )
528 eznum[i] += R[i][j]*n[j];
529 }
530
531 /* Check error in norm inf */
532 maxerr = MMG5_test_mat_error(3,ezex,eznum);
533 if( maxerr > 10.*MMG5_EPSOK ) {
534 fprintf(stderr," ## Error vector rotation: in function %s, max error %e\n",
535 __func__,maxerr);
536 return 0;
537 }
538
539
541 if( !MMG5_rmtr(R,idex,idnum) )
542 return 0;
543
544 /* Check error in norm inf */
545 maxerr = MMG5_test_mat_error(6,idex,idnum);
546 if( maxerr > MMG5_EPSOK ) {
547 fprintf(stderr," ## Error rotation matrix orthonormality: in function %s, max error %e\n",
548 __func__,maxerr);
549 return 0;
550 }
551
552 return 1;
553}
554
562int MMG5_invmat(double *m,double *mi) {
563 double aa,bb,cc,det,vmax,maxx;
564 int k;
565
566 /* check diagonal matrices */
567 vmax = fabs(m[1]);
568 maxx = fabs(m[2]);
569 if( maxx > vmax ) vmax = maxx;
570 maxx = fabs(m[4]);
571 if( maxx > vmax ) vmax = maxx;
572 if ( vmax < MMG5_EPS ) {
573 mi[0] = 1./m[0];
574 mi[3] = 1./m[3];
575 mi[5] = 1./m[5];
576 mi[1] = mi[2] = mi[4] = 0.0;
577 return 1;
578 }
579
580 /* check ill-conditionned matrix */
581 vmax = fabs(m[0]);
582 for (k=1; k<6; k++) {
583 maxx = fabs(m[k]);
584 if ( maxx > vmax ) vmax = maxx;
585 }
586 if ( vmax == 0.0 ) return 0;
587
588 /* compute sub-dets */
589 aa = m[3]*m[5] - m[4]*m[4];
590 bb = m[4]*m[2] - m[1]*m[5];
591 cc = m[1]*m[4] - m[2]*m[3];
592 det = m[0]*aa + m[1]*bb + m[2]*cc;
593 if ( fabs(det) < MMG5_EPSD2 ) return 0;
594 det = 1.0 / det;
595
596 mi[0] = aa*det;
597 mi[1] = bb*det;
598 mi[2] = cc*det;
599 mi[3] = (m[0]*m[5] - m[2]*m[2])*det;
600 mi[4] = (m[1]*m[2] - m[0]*m[4])*det;
601 mi[5] = (m[0]*m[3] - m[1]*m[1])*det;
602
603 return 1;
604}
605
613int MMG5_invmatg(double m[9],double mi[9]) {
614 double aa,bb,cc,det,vmax,maxx;
615 int k;
616
617 /* check ill-conditionned matrix */
618 vmax = fabs(m[0]);
619 for (k=1; k<9; k++) {
620 maxx = fabs(m[k]);
621 if ( maxx > vmax ) vmax = maxx;
622 }
623 if ( vmax == 0.0 ) return 0;
624
625 /* compute sub-dets */
626 aa = m[4]*m[8] - m[5]*m[7];
627 bb = m[5]*m[6] - m[3]*m[8];
628 cc = m[3]*m[7] - m[4]*m[6];
629 det = m[0]*aa + m[1]*bb + m[2]*cc;
630 if ( fabs(det) < MMG5_EPSD ) return 0;
631 det = 1.0 / det;
632
633 mi[0] = aa*det;
634 mi[3] = bb*det;
635 mi[6] = cc*det;
636 mi[1] = (m[2]*m[7] - m[1]*m[8])*det;
637 mi[4] = (m[0]*m[8] - m[2]*m[6])*det;
638 mi[7] = (m[1]*m[6] - m[0]*m[7])*det;
639 mi[2] = (m[1]*m[5] - m[2]*m[4])*det;
640 mi[5] = (m[2]*m[3] - m[0]*m[5])*det;
641 mi[8] = (m[0]*m[4] - m[1]*m[3])*det;
642
643 return 1;
644}
645
653int MMG5_invmat33(double m[3][3],double mi[3][3]) {
654 double aa,bb,cc,det,vmax,maxx;
655 int k,l;
656
657 /* check ill-conditionned matrix */
658 vmax = fabs(m[0][0]);
659 for (k=0; k<3; k++) {
660 for (l=0; l<3; l++) {
661 maxx = fabs(m[k][l]);
662 if ( maxx > vmax ) vmax = maxx;
663 }
664 }
665 if ( vmax == 0.0 ) return 0;
666
667 /* check diagonal matrices */
668 /* lower */
669 vmax = fabs(m[1][0]);
670 maxx = fabs(m[2][0]);
671 if( maxx > vmax ) vmax = maxx;
672 maxx = fabs(m[2][1]);
673 if( maxx > vmax ) vmax = maxx;
674 /* upper */
675 maxx = fabs(m[0][1]);
676 if( maxx > vmax ) vmax = maxx;
677 maxx = fabs(m[0][2]);
678 if( maxx > vmax ) vmax = maxx;
679 maxx = fabs(m[1][2]);
680 if( maxx > vmax ) vmax = maxx;
681
682 if ( vmax < MMG5_EPS ) {
683 mi[0][0] = 1./m[0][0];
684 mi[1][1] = 1./m[1][1];
685 mi[2][2] = 1./m[2][2];
686 mi[1][0] = mi[0][1] = mi[2][0] = mi[0][2] = mi[1][2] = mi[2][1] = 0.0;
687 return 1;
688 }
689
690 /* compute sub-dets */
691 aa = m[1][1]*m[2][2] - m[2][1]*m[1][2];
692 bb = m[2][1]*m[0][2] - m[0][1]*m[2][2];
693 cc = m[0][1]*m[1][2] - m[1][1]*m[0][2];
694 det = m[0][0]*aa + m[1][0]*bb + m[2][0]*cc;
695 if ( fabs(det) < MMG5_EPSD ) return 0;
696 det = 1.0 / det;
697
698 mi[0][0] = aa*det;
699 mi[0][1] = bb*det;
700 mi[0][2] = cc*det;
701 mi[1][0] = (m[2][0]*m[1][2] - m[1][0]*m[2][2])*det;
702 mi[1][1] = (m[0][0]*m[2][2] - m[2][0]*m[0][2])*det;
703 mi[1][2] = (m[1][0]*m[0][2] - m[0][0]*m[1][2])*det;
704 mi[2][0] = (m[1][0]*m[2][1] - m[2][0]*m[1][1])*det;
705 mi[2][1] = (m[2][0]*m[0][1] - m[0][0]*m[2][1])*det;
706 mi[2][2] = (m[0][0]*m[1][1] - m[1][0]*m[0][1])*det;
707
708 /* Check results */
709#ifndef NDEBUG
710 double res[3][3];
711
712 res[0][0] = m[0][0] * mi[0][0] + m[0][1] * mi[1][0] + m[0][2] * mi[2][0];
713 res[0][1] = m[0][0] * mi[0][1] + m[0][1] * mi[1][1] + m[0][2] * mi[2][1];
714 res[0][2] = m[0][0] * mi[0][2] + m[0][1] * mi[1][2] + m[0][2] * mi[2][2];
715
716 res[1][0] = m[1][0] * mi[0][0] + m[1][1] * mi[1][0] + m[1][2] * mi[2][0];
717 res[1][1] = m[1][0] * mi[0][1] + m[1][1] * mi[1][1] + m[1][2] * mi[2][1];
718 res[1][2] = m[1][0] * mi[0][2] + m[1][1] * mi[1][2] + m[1][2] * mi[2][2];
719
720 res[2][0] = m[2][0] * mi[0][0] + m[2][1] * mi[1][0] + m[2][2] * mi[2][0];
721 res[2][1] = m[2][0] * mi[0][1] + m[2][1] * mi[1][1] + m[2][2] * mi[2][1];
722 res[2][2] = m[2][0] * mi[0][2] + m[2][1] * mi[1][2] + m[2][2] * mi[2][2];
723
724
725 assert ( ( fabs(res[0][0]-1.) < MMG5_EPS ) &&
726 ( fabs(res[1][1]-1.) < MMG5_EPS ) &&
727 ( fabs(res[2][2]-1.) < MMG5_EPS ) &&
728 ( fabs(res[0][1]) < MMG5_EPS ) && ( fabs(res[0][2]) < MMG5_EPS ) &&
729 ( fabs(res[1][2]) < MMG5_EPS ) &&
730 ( fabs(res[1][0]) < MMG5_EPS ) && ( fabs(res[2][0]) < MMG5_EPS ) &&
731 ( fabs(res[2][1]) < MMG5_EPS ) && "Matrix inversion" );
732
733#endif
734
735 return 1;
736}
737
745int MMG5_invmat22(double m[2][2],double mi[2][2]) {
746 double det;
747
748 det = m[0][0]*m[1][1] - m[0][1]*m[1][0];
749 if ( fabs(det) < MMG5_EPS ) return 0;
750 det = 1.0 / det;
751
752 mi[0][0] = m[1][1]*det;
753 mi[0][1] = -m[0][1]*det;
754 mi[1][0] = -m[1][0]*det;
755 mi[1][1] = m[0][0]*det;
756
757 return 1;
758}
759
769inline int MMG5_sys33sym(double a[6], double b[3], double r[3]){
770 double ia[6],as[6],det,m;
771 int i;
772
773 /* If possible : multiply matrix by a constant coefficient for stability
774 purpose */
775 m = fabs(a[0]);
776 m = MG_MIN ( fabs(a[3]), m );
777 m = MG_MIN ( fabs(a[5]), m );
778
779 if ( m >= MMG5_EPSD ) {
780 /* Normalization */
781 m = 1.0/m;
782 }
783 else {
784 /* Unable to normalized */
785 m = 1.;
786 }
787
788 for(i=0;i<6;i++){
789 as[i] = a[i]*m;
790 }
791
792 det = as[0]*(as[3]*as[5]-as[4]*as[4]) - as[1]*(as[1]*as[5]-as[2]*as[4]) \
793 + as[2]*(as[1]*as[4]-as[2]*as[3]);
794
795 if(fabs(det) < MMG5_EPSD)
796 return 0;
797
798 det = 1.0/det;
799
800 ia[0] = (as[3]*as[5]-as[4]*as[4]);
801 ia[1] = - (as[1]*as[5]-as[2]*as[4]);
802 ia[2] = (as[1]*as[4]-as[2]*as[3]);
803 ia[3] = (as[0]*as[5]-as[2]*as[2]);
804 ia[4] = -(as[0]*as[4]-as[2]*as[1]);
805 ia[5] = (as[0]*as[3]-as[1]*as[1]);
806
807 r[0] = ia[0]*b[0] + ia[1]*b[1] + ia[2]*b[2];
808 r[1] = ia[1]*b[0] + ia[3]*b[1] + ia[4]*b[2];
809 r[2] = ia[2]*b[0] + ia[4]*b[1] + ia[5]*b[2];
810
811 r[0] *= (det*m);
812 r[1] *= (det*m);
813 r[2] *= (det*m);
814
815 return 1;
816}
817
825void MMG5_printTria(MMG5_pMesh mesh,char* fileName) {
826 MMG5_pTria ptt;
827 MMG5_int k;
828 FILE *inm;
829
830 inm = fopen(fileName,"w");
831
832 fprintf(inm,"----------> %" MMG5_PRId " TRIANGLES <----------\n",mesh->nt);
833 for(k=1; k<=mesh->nt; k++) {
834 ptt = &mesh->tria[k];
835 fprintf(inm,"num %" MMG5_PRId " -> %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId "\n",k,ptt->v[0],ptt->v[1],
836 ptt->v[2]);
837 fprintf(inm,"ref -> %" MMG5_PRId "\n",ptt->ref);
838 fprintf(inm,"tag -> %d %d %d\n",ptt->tag[0],ptt->tag[1],ptt->tag[2]);
839 fprintf(inm,"edg -> %" MMG5_PRId " %" MMG5_PRId " %" MMG5_PRId "\n",ptt->edg[0],ptt->edg[1],ptt->edg[2]);
840 fprintf(inm,"\n");
841 }
842 fprintf(inm,"---------> END TRIANGLES <--------\n");
843 fclose(inm);
844}
845
852size_t MMG5_memSize (void) {
853 size_t mem;
854
855#if (defined(__APPLE__) && defined(__MACH__))
856 size_t size;
857
858 size = sizeof(mem);
859 if ( sysctlbyname("hw.memsize",&mem,&size,NULL,0) == -1)
860 return 0;
861
862#elif defined(__unix__) || defined(__unix) || defined(unix)
863 mem = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
864
865#elif defined(_WIN16) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
866 MEMORYSTATUSEX status;
867
868 status.dwLength = sizeof(status);
869 GlobalMemoryStatusEx(&status);
870 // status.ullTotalPhys is an unsigned long long: check that it fits in a size_t
871 mem = status.ullTotalPhys & SIZE_MAX;
872 if (mem == status.ullTotalPhys) return mem;
873 else return SIZE_MAX;
874
875#else
876 fprintf(stderr,"\n ## Warning: %s: unknown system, recover of maximal memory"
877 " not available.\n",__func__);
878 return 0;
879#endif
880
881 return mem;
882}
883
892
893 assert ( mesh->memMax );
894 if ( mesh->info.mem <= 0 ) {
895 if ( mesh->memMax )
896 /* maximal memory = 50% of total physical memory */
898 else {
899 /* default value = 800 MB */
900 printf(" Maximum memory set to default value: %d MB.\n",MMG5_MEMMAX);
902 }
903 }
904 else {
905 /* memory asked by user if possible, otherwise total physical memory */
906 if ( (size_t)mesh->info.mem*MMG5_MILLION > (mesh->memMax/MMG5_MEMPERCENT) && mesh->memMax ) {
907 fprintf(stderr,"\n ## Warning: %s: asking for %d MB of memory ",
908 __func__,mesh->info.mem);
909 fprintf(stderr,"when only %zu available.\n",mesh->memMax/MMG5_MILLION);
910 }
911 else {
912 mesh->memMax= (size_t)mesh->info.mem*MMG5_MILLION;
913 }
914 }
915 return;
916}
917
918
920inline double MMG5_det3pt1vec(double c0[3],double c1[3],double c2[3],double v[3]) {
921 double m00,m10,m20,m01,m11,m21,det;
922
923 m00 = c1[0] - c0[0] ; m01 = c2[0] - c0[0];
924 m10 = c1[1] - c0[1] ; m11 = c2[1] - c0[1];
925 m20 = c1[2] - c0[2] ; m21 = c2[2] - c0[2];
926 det = v[0]*(m10*m21 - m20*m11) -v[1]*(m00*m21-m20*m01) + v[2]*(m00*m11-m10*m01);
927
928 return det;
929}
930
932inline double MMG5_det4pt(double c0[3],double c1[3],double c2[3],double c3[3]) {
933 double m[3];
934
935 m[0] = c3[0] - c0[0];
936 m[1] = c3[1] - c0[1];
937 m[2] = c3[2] - c0[2];
938
939 return MMG5_det3pt1vec(c0,c1,c2,m) ;
940}
941
951inline double MMG5_orvol(MMG5_pPoint point,MMG5_int *v) {
952 MMG5_pPoint p0,p1,p2,p3;
953
954 p0 = &point[v[0]];
955 p1 = &point[v[1]];
956 p2 = &point[v[2]];
957 p3 = &point[v[3]];
958
959 return MMG5_det4pt(p0->c,p1->c,p2->c,p3->c);
960}
961
962
971double MMG2D_quickarea(double a[2],double b[2],double c[2]) {
972 double abx,aby,acx,acy;//,bcx,bcy;
973 double aire;
974
975 abx = b[0] - a[0];
976 aby = b[1] - a[1];
977 acx = c[0] - a[0];
978 acy = c[1] - a[1];
979 // bcx = c[0] - b[0];
980 // bcy = c[1] - b[1];
981 //
982 /* orientation */
983 aire = abx*acy - aby*acx;
984
985 return aire;
986}
987
995 MMG5_pPoint ppt;
996 MMG5_int k;
997
998 for ( k=1; k<=mesh->np; k++ ) {
999 ppt = &mesh->point[k];
1000 if ( !MG_VOK(ppt) ) continue;
1001
1002 /* reset ppt->flag to detect isolated points in keep_subdomainElts */
1003 ppt->flag = 0;
1004 ppt->tag |= MG_NUL;
1005 }
1006
1007 return;
1008}
1009
1018void MMG5_mark_usedVertices ( MMG5_pMesh mesh,void (*delPt)(MMG5_pMesh,MMG5_int) ) {
1019 MMG5_pTria pt;
1020 MMG5_pQuad pq;
1021 MMG5_pPoint ppt;
1022 int i;
1023 MMG5_int k;
1024
1025 /* Preserve isolated required points */
1026 for ( k=1; k<=mesh->np; k++ ) {
1027 ppt = &mesh->point[k];
1028
1029 if ( ppt->flag || !(ppt->tag & MG_REQ) ) {
1030 continue;
1031 }
1032 ppt->tag &= ~MG_NUL;
1033 }
1034
1035 /* Mark points used by the connectivity */
1036 for ( k=1; k<=mesh->nt; k++ ) {
1037 pt = &mesh->tria[k];
1038 if ( !MG_EOK(pt) ) continue;
1039
1040 for (i=0; i<3; i++) {
1041 ppt = &mesh->point[ pt->v[i] ];
1042 ppt->tag &= ~MG_NUL;
1043 }
1044 }
1045
1046 for ( k=1; k<=mesh->nquad; k++ ) {
1047 pq = &mesh->quadra[k];
1048 if ( !MG_EOK(pq) ) continue;
1049
1050 for (i=0; i<4; i++) {
1051 ppt = &mesh->point[ pq->v[i] ];
1052 ppt->tag &= ~MG_NUL;
1053 }
1054 }
1055
1056 /* Finally, clean point array */
1057 while ( (!MG_VOK(&mesh->point[mesh->np])) && mesh->np ) {
1058 delPt(mesh,mesh->np);
1059 }
1060
1061 return;
1062}
1063
1073 int (*delElt)(MMG5_pMesh,MMG5_int) ) {
1074 MMG5_pTria pt;
1075 int i,iv;
1076 MMG5_int k,*adja,iadr,iadrv;
1077 int nfac = 3; // number of faces per elt
1078
1079 for ( k=1 ; k <= mesh->nt ; k++) {
1080 pt = &mesh->tria[k];
1081
1082 if ( !MG_EOK(pt) ) continue;
1083
1084 /* Mark triangle vertices as seen to be able to detect isolated points */
1085 mesh->point[pt->v[0]].flag = 1;
1086 mesh->point[pt->v[1]].flag = 1;
1087 mesh->point[pt->v[2]].flag = 1;
1088
1089 if ( pt->ref == nsd ) continue;
1090
1091 /* Update adjacency relationship: we will delete elt k so k adjacent will
1092 * not be adjacent to k anymore */
1093 if ( mesh->adja ) {
1094 iadr = nfac*(k-1) + 1;
1095 adja = &mesh->adja[iadr];
1096 for ( i=0; i<nfac; ++i ) {
1097 iadrv = adja[i];
1098 if ( !iadrv ) {
1099 continue;
1100 }
1101 iv = iadrv%nfac;
1102 iadrv /= nfac;
1103 mesh->adja[nfac*(iadrv-1)+1+iv] = 0;
1104 }
1105 }
1106
1107 /* Delete element (triangle in 2D and surface, tetra in 3D) */
1108 delElt(mesh,k);
1109 }
1110
1111 return;
1112}
1113
1122inline
1123double MMG5_test_mat_error( int8_t nelem,double m1[],double m2[] ) {
1124 double maxerr;
1125 int8_t k;
1126
1127 /* Compute max error */
1128 maxerr = 0;
1129 for( k = 0; k < nelem; k++ )
1130 maxerr = MG_MAX(maxerr,fabs(m1[k] - m2[k]));
1131
1132 return maxerr;
1133}
1134
1141 double A[2][2] = {{4.0,2.0},{1.0,1.0}}; /* Test matrix */
1142 double iAex[2][2] = {{0.5,-1.0},{-0.5,2.0}}; /* Analytical inverse */
1143 double iAnum[2][2]; /* Numerical inverse */
1144
1145 /* Compute matrix inverse */
1146 if( !MMG5_invmat22(A,iAnum) )
1147 return 0;
1148
1149 /* Check error in norm inf */
1150 double maxerr = MMG5_test_mat_error(4,(double *)iAex,(double *)iAnum);
1151 if( maxerr > MMG5_EPSD ) {
1152 fprintf(stderr," ## Error matrix inversion: in function %s, max error %e\n",
1153 __func__,maxerr);
1154 return 0;
1155 }
1156
1157 return 1;
1158}
1159
1166 double A[3][3] = {{7.0,2.0,1.0},{0.0,3.0,-1.0},{-3.0,4.0,-2.0}}; /* Test matrix */
1167 double iAex[3][3] = {{-2.0,8.0,-5.0},{3.0,-11.0,7.0},{9.0,-34.0,21.0}}; /* Analytical inverse */
1168 double iAnum[3][3]; /* Numerical inverse */
1169
1170 /* Compute matrix inverse */
1171 if( !MMG5_invmat33(A,iAnum) )
1172 return 0;
1173
1174 /* Check error in norm inf */
1175 double maxerr = MMG5_test_mat_error(9,(double *)iAex,(double *)iAnum);
1176 if( maxerr > MMG5_EPSD ) {
1177 fprintf(stderr," ## Error matrix inversion: in function %s, max error %e\n",
1178 __func__,maxerr);
1179 return 0;
1180 }
1181
1182 return 1;
1183}
MMG5_pMesh * mesh
#define MMG5_EPSD
#define MMG5_EPS
#define MG_REQ
#define MMG5_EPSOK
#define MG_EOK(pt)
#define MG_NUL
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#define MMG5_MILLION
#define MMG5_MEMPERCENT
#define MMG5_MEMMAX
#define MG_VOK(ppt)
#define MMG5_EPSD2
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_pQuad quadra
Definition: libmmgtypes.h:648
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_int * adja
Definition: libmmgtypes.h:624
MMG5_int nquad
Definition: libmmgtypes.h:613
size_t memMax
Definition: libmmgtypes.h:606
MMG5_int nt
Definition: libmmgtypes.h:612
MMG5_pTria tria
Definition: libmmgtypes.h:647
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
MMG5_int flag
Definition: libmmgtypes.h:282
MMG5_int v[4]
Definition: libmmgtypes.h:367
MMG5_int edg[3]
Definition: libmmgtypes.h:339
int16_t tag[3]
Definition: libmmgtypes.h:342
MMG5_int ref
Definition: libmmgtypes.h:335
MMG5_int v[3]
Definition: libmmgtypes.h:334
int MMG5_test_transpose3d()
Definition: tools.c:236
int MMG5_test_rmtr()
Definition: tools.c:435
int MMG5_nonUnitNorPts(MMG5_pMesh mesh, MMG5_int ip1, MMG5_int ip2, MMG5_int ip3, double *n)
Definition: tools.c:127
void MMG5_mn(double m[6], double n[6], double mn[9])
Definition: tools.c:337
size_t MMG5_memSize(void)
Definition: tools.c:852
double MMG2D_quickarea(double a[2], double b[2], double c[2])
Definition: tools.c:971
void MMG5_memOption_memSet(MMG5_pMesh mesh)
Definition: tools.c:891
double MMG5_nonorsurf(MMG5_pMesh mesh, MMG5_pTria pt)
Definition: tools.c:160
double MMG5_test_mat_error(int8_t nelem, double m1[], double m2[])
Definition: tools.c:1123
int MMG5_test_rotmatrix()
Definition: tools.c:512
int MMG5_norpts(MMG5_pMesh mesh, MMG5_int ip1, MMG5_int ip2, MMG5_int ip3, double *n)
Definition: tools.c:183
int MMG5_test_crossprod3d()
Definition: tools.c:311
double MMG5_det3pt1vec(double c0[3], double c1[3], double c2[3], double v[3])
Definition: tools.c:920
double MMG5_det4pt(double c0[3], double c1[3], double c2[3], double c3[3])
Definition: tools.c:932
void MMG5_nsort(int8_t n, double *val, int8_t *perm)
Definition: tools.c:49
void MMG5_mark_usedVertices(MMG5_pMesh mesh, void(*delPt)(MMG5_pMesh, MMG5_int))
Definition: tools.c:1018
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
void MMG5_mark_verticesAsUnused(MMG5_pMesh mesh)
Definition: tools.c:994
void MMG5_printTria(MMG5_pMesh mesh, char *fileName)
Definition: tools.c:825
int MMG5_test_mn()
Definition: tools.c:357
int MMG5_devangle(double *n1, double *n2, double crit)
Definition: tools.c:103
void MMG5_dotprod(int8_t dim, double *a, double *b, double *result)
Definition: tools.c:265
int MMG5_test_dotprod()
Definition: tools.c:276
int MMG5_nortri(MMG5_pMesh mesh, MMG5_pTria pt, double *n)
Definition: tools.c:209
double MMG5_orvol(MMG5_pPoint point, MMG5_int *v)
Definition: tools.c:951
int MMG5_rotmatrix(double n[3], double r[3][3])
Definition: tools.c:467
int MMG5_sys33sym(double a[6], double b[3], double r[3])
Definition: tools.c:769
int MMG5_test_invmat33()
Definition: tools.c:1165
void MMG5_transpose3d(double m[3][3])
Definition: tools.c:220
int MMG5_test_invmat22()
Definition: tools.c:1140
int MMG5_invmatg(double m[9], double mi[9])
Definition: tools.c:613
void MMG5_crossprod3d(double *a, double *b, double *result)
Definition: tools.c:300
void MMG5_nperm(int8_t n, int8_t shift, int8_t stride, double *val, double *oldval, int8_t *perm)
Definition: tools.c:80
void MMG5_keep_subdomainElts(MMG5_pMesh mesh, int nsd, int(*delElt)(MMG5_pMesh, MMG5_int))
Definition: tools.c:1072
int MMG5_invmat22(double m[2][2], double mi[2][2])
Definition: tools.c:745
int MMG5_invmat(double *m, double *mi)
Definition: tools.c:562