Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
mettools.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 "mmgcommon_private.h"
37
51static inline
52void MMG5_eigenvmat_buildsym(MMG5_pMesh mesh,int8_t dim,double m[],
53 double lambda[],double v[]) {
54 int8_t i,j,k,ij;
55
56 /* Storage of a matrix as a one-dimensional array: (dim+1)*dim/2 entries for a
57 * symmetric matrix (loop on each symmetric entry only once). */
58 ij = 0;
59
60 /* Loop on matrix rows */
61 for( i = 0; i < dim; i++ ) {
62 /* Loop on the upper-triangular part of the matrix */
63 for( j = i; j < dim; j++ ) {
64 /* Initialize matrix entry */
65 m[ij] = 0.0;
66 /* Compute matrix entry as the recomposition of eigenvalues and
67 * eigenvectors:
68 *
69 * M_{ij} = \sum_{k,l} V_{ik} Lambda_{kl} V_{jl} =
70 * = \sum_{k} lambda_{k} V_{ik} V_{jk}
71 *
72 * Eigenvectors are stored as rows in Mmg (not columns) so their indices
73 * have to be exchanged when implementing the above formula. */
74 for( k = 0; k < dim; k++ ) {
75 m[ij] += lambda[k]*v[k*dim+i]*v[k*dim+j];
76 }
77 /* Go to next entry */
78 ++ij;
79 }
80 }
81 assert( ij == (dim+1)*dim/2 );
82}
83
99static inline
100void MMG5_eigenvmat_buildnonsym(MMG5_pMesh mesh,int8_t dim,double m[],
101 double lambda[],double v[],double iv[]){
102 int8_t i,j,k,ij;
103
104 /* Storage of a matrix as a one-dimensional array: dim^2 entries for a
105 * non-symmetric matrix. */
106 ij = 0;
107
108 /* Loop on matrix rows */
109 for( i = 0; i < dim; i++ ) {
110 /* Loop on matrix columns */
111 for( j = 0; j < dim; j++ ) {
112 /* Initialize matrix entry */
113 m[ij] = 0.0;
114 /* Compute matrix entry as the recomposition of eigenvalues and
115 * eigenvectors:
116 *
117 * M_{ij} = \sum_{k,l} V_{ik} Lambda_{kl} V^{-1}_{lj} =
118 * = \sum_{k} lambda_{k} V_{ik} V^{-1}_{kj}
119 *
120 * Eigenvectors are stored as rows in Mmg (not columns) so their indices
121 * have to be exchanged when implementing the above formula. */
122 for( k = 0; k < dim; k++ ) {
123 m[ij] += lambda[k]*v[k*dim+i]*iv[j*dim+k];
124 }
125 /* Go to next entry */
126 ++ij;
127 }
128 }
129 assert( ij == dim*dim );
130}
131
144int MMG5_eigenvmatsym2d(MMG5_pMesh mesh,double m[],double lambda[],double v[][2]) {
145
146 /* Build matrix */
147 MMG5_eigenvmat_buildsym(mesh,2,m,lambda,(double *)v);
148
149 return 1;
150}
151
164int MMG5_eigenvmatsym3d(MMG5_pMesh mesh,double m[],double lambda[],double v[][3]) {
165
166 /* Build matrix */
167 MMG5_eigenvmat_buildsym(mesh,3,m,lambda,(double *)v);
168
169 return 1;
170}
171
184int MMG5_eigenvmatnonsym2d(MMG5_pMesh mesh,double m[],double lambda[],double v[][2]) {
185 double iv[2][2];
186
187 /* Compute the inverse of the eigenvectors matrix */
188 if( !MMG5_invmat22(v,iv) )
189 return 0;
190
191 /* Build matrix */
192 MMG5_eigenvmat_buildnonsym(mesh,2,m,lambda,(double *)v,(double *)iv);
193
194 return 1;
195}
196
209int MMG5_eigenvmatnonsym3d(MMG5_pMesh mesh,double m[],double lambda[],double v[][3]) {
210 double iv[3][3];
211
212 /* Compute the inverse of the eigenvectors matrix */
213 if( !MMG5_invmat33(v,iv) )
214 return 0;
215
216 /* Build matrix */
217 MMG5_eigenvmat_buildnonsym(mesh,3,m,lambda,(double *)v,(double *)iv);
218
219 return 1;
220}
221
233int MMG5_eigenvmat_check(MMG5_pMesh mesh,int8_t dim,int8_t symmat,double m[],
234 double mnew[]) {
235
236 /* Compute eigendecomposition, recompose matrix from eigendecomposition */
237 if( dim == 2 ) {
238 double lambda[2],v[2][2];
239
240 if( !MMG5_eigenv2d(symmat,m,lambda,v) )
241 return 0;
242
243 if( symmat ) {
244 if( !MMG5_eigenvmatsym2d(mesh,mnew,lambda,v) )
245 return 0;
246 } else {
247 if( !MMG5_eigenvmatnonsym2d(mesh,mnew,lambda,v) )
248 return 0;
249 }
250
251 } else if( dim == 3 ) {
252 double lambda[3],v[3][3];
253
254 if( !MMG5_eigenv3d(symmat,m,lambda,v) )
255 return 0;
256
257 if( symmat ) {
258 if( !MMG5_eigenvmatsym3d(mesh,mnew,lambda,v) )
259 return 0;
260 } else {
261 if( !MMG5_eigenvmatnonsym3d(mesh,mnew,lambda,v) )
262 return 0;
263 }
264 }
265
266 return 1;
267}
268
279void MMG5_sort_eigenv( int8_t dim,double *lambda,double *vp,
280 double *swap,int8_t *perm ) {
281 MMG5_nsort(dim,lambda,perm);
282 MMG5_nperm(dim,0,1,lambda,swap,perm);
283 for( int8_t i = 0; i < dim; i++ )
284 MMG5_nperm(dim,i,dim,vp,swap,perm);
285}
286
301int MMG5_test_eigenvmatsym2d(MMG5_pMesh mesh,double *mex,double lambdaex[],
302 double vpex[][2]) {
303 double mnum[3],lambdanum[2],vpnum[2][2]; /* Numerical quantities */
304 double swap[2],maxerr,err;
305 int8_t perm[2] = {0,1}; /* eigenvalues permutation array */
306
307
309 MMG5_eigenvmat_buildsym(mesh,2,mnum,lambdaex,(double *)vpex);
310
311 /* Check error in norm inf */
312 maxerr = MMG5_test_mat_error(3,(double *)mex,(double *)mnum);
313 if( maxerr > 10.*MMG5_EPSOK ) {
314 fprintf(stderr," ## Error matrix recomposition: in function %s, max error %e\n",
315 __func__,maxerr);
316 return 0;
317 }
318
319
321 if( !MMG5_eigenv2d(1,mex,lambdanum,vpnum) )
322 return 0;
323
324 /* Naively sort eigenpairs in increasing order */
325 MMG5_sort_eigenv(2,lambdanum,(double *)vpnum,swap,perm);
326
327 /* Check eigenvalues error in norm inf */
328 maxerr = MMG5_test_mat_error(2,(double *)lambdaex,(double *)lambdanum);
329 if( maxerr > 10*MMG5_EPSOK ) {
330 fprintf(stderr," ## Error matrix eigenvalues: in function %s, max error %e\n",
331 __func__,maxerr);
332 return 0;
333 }
334
335 /* Check eigenvectors error through scalar product */
336 maxerr = 0.;
337 for( int8_t i = 0; i < 2; i++ ) {
338 err = 0.;
339 for( int8_t j = 0; j < 2; j++ )
340 err += vpex[i][j] * vpnum[i][j];
341 err = 1.-fabs(err);
342 maxerr = MG_MAX(maxerr,err);
343 }
344 if( maxerr > MMG5_EPSOK ) {
345 fprintf(stderr," ## Error matrix eigenvectors: in function %s, max error %e\n",
346 __func__,maxerr);
347 return 0;
348 }
349
350
352 if( !MMG5_eigenvmat_check(mesh,2,1,mex,mnum) )
353 return 0;
354 maxerr = MMG5_test_mat_error(3,(double *)mex,(double *)mnum);
355 if( maxerr > 10*MMG5_EPSOK ) {
356 fprintf(stderr," ## Error matrix eigendecomposition and recomposition: in function %s, max error %e\n",
357 __func__,maxerr);
358 return 0;
359 }
360
361 return 1;
362}
363
379int MMG5_test_eigenvmatnonsym2d(MMG5_pMesh mesh,double *mex,double lambdaex[],
380 double vpex[][2],double ivpex[][2]) {
381 double mnum[4],lambdanum[2],vpnum[2][2]; /* Numerical quantities */
382 double swap[2],maxerr,err;
383 int8_t perm[2] = {0,1}; /* eigenvalues permutation array */
384
385
387 MMG5_eigenvmat_buildnonsym(mesh,2,mnum,lambdaex,(double *)vpex,(double *)ivpex);
388
389 /* Check error in norm inf */
390 maxerr = MMG5_test_mat_error(4,(double *)mex,(double *)mnum);
391 if( maxerr > 100.*MMG5_EPSOK ) {
392 fprintf(stderr," ## Error matrix recomposition: in function %s, max error %e\n",
393 __func__,maxerr);
394 return 0;
395 }
396
397
399 if( !MMG5_eigenv2d(0,mex,lambdanum,vpnum) )
400 return 0;
401
402 /* Naively sort eigenpairs in increasing order */
403 MMG5_sort_eigenv(2,lambdanum,(double *)vpnum,swap,perm);
404
405 /* Check eigenvalues error in norm inf */
406 maxerr = MMG5_test_mat_error(2,(double *)lambdaex,(double *)lambdanum);
407 if( maxerr > 10*MMG5_EPSOK ) {
408 fprintf(stderr," ## Error matrix eigenvalues: in function %s, max error %e\n",
409 __func__,maxerr);
410 return 0;
411 }
412
413 /* Check eigenvectors error through scalar product */
414 maxerr = 0.;
415 for( int8_t i = 0; i < 2; i++ ) {
416 err = 0.;
417 for( int8_t j = 0; j < 2; j++ )
418 err += vpex[i][j] * vpnum[i][j];
419 err = 1.-fabs(err);
420 maxerr = MG_MAX(maxerr,err);
421 }
422 if( maxerr > MMG5_EPSOK ) {
423 fprintf(stderr," ## Error matrix eigenvectors: in function %s, max error %e\n",
424 __func__,maxerr);
425 return 0;
426 }
427
428
430 if( !MMG5_eigenvmat_check(mesh,2,0,mex,mnum) )
431 return 0;
432 maxerr = MMG5_test_mat_error(4,(double *)mex,(double *)mnum);
433 if( maxerr > 100*MMG5_EPSOK ) {
434 fprintf(stderr," ## Error matrix eigendecomposition and recomposition: in function %s, max error %e\n",
435 __func__,maxerr);
436 return 0;
437 }
438
439 return 1;
440}
441
456int MMG5_test_eigenvmatsym3d(MMG5_pMesh mesh,double *mex,double lambdaex[],
457 double vpex[][3]) {
458 double mnum[6],lambdanum[3],vpnum[3][3]; /* Numerical quantities */
459 double swap[3],maxerr,err;
460 int8_t perm[3] = {0,1,2}; /* eigenvalues permutation array */
461
462
464 MMG5_eigenvmat_buildsym(mesh,3,mnum,lambdaex,(double *)vpex);
465
466 /* Check error in norm inf */
467 maxerr = MMG5_test_mat_error(6,(double *)mex,(double *)mnum);
468 if( maxerr > 100.*MMG5_EPSOK ) {
469 fprintf(stderr," ## Error matrix recomposition: in function %s, max error %e\n",
470 __func__,maxerr);
471 return 0;
472 }
473
474
476 if( !MMG5_eigenv3d(1,mex,lambdanum,vpnum) )
477 return 0;
478
479 /* Naively sort eigenpairs in increasing order */
480 MMG5_sort_eigenv(3,lambdanum,(double *)vpnum,swap,perm);
481
482 /* Check eigenvalues error in norm inf */
483 maxerr = MMG5_test_mat_error(3,(double *)lambdaex,(double *)lambdanum);
484 if( maxerr > 10*MMG5_EPSOK ) {
485 fprintf(stderr," ## Error matrix eigenvalues: in function %s, max error %e\n",
486 __func__,maxerr);
487 return 0;
488 }
489
490 /* Check eigenvectors orthogonality (checking numerical eigenvectors against
491 * the exact ones does not make sense in case of multiple eigenvalues) */
492 maxerr = 0.;
493 for( int8_t i = 0; i < 2; i++ ) {
494 for( int8_t j = i+1; j < 3; j++ ) {
495 err = 0.;
496 for( int8_t k = 0; k < 3; k++ )
497 err += vpnum[i][k] * vpnum[j][k];
498 err = fabs(err);
499 maxerr = MG_MAX(maxerr,err);
500 }
501 }
502 if( maxerr > MMG5_EPSOK ) {
503 fprintf(stderr," ## Error matrix eigenvectors orthogonality: in function %s, max error %e\n",
504 __func__,maxerr);
505 return 0;
506 }
507
508
510 if( !MMG5_eigenvmat_check(mesh,3,1,mex,mnum) )
511 return 0;
512 maxerr = MMG5_test_mat_error(6,(double *)mex,(double *)mnum);
513 if( maxerr > 100*MMG5_EPSOK ) {
514 fprintf(stderr," ## Error matrix eigendecomposition and recomposition: in function %s, max error %e\n",
515 __func__,maxerr);
516 return 0;
517 }
518
519 return 1;
520}
521
536int MMG5_test_eigenvmatnonsym3d(MMG5_pMesh mesh,double *mex,double lambdaex[],
537 double vpex[][3],double ivpex[][3]) {
538 double mnum[9],lambdanum[3],vpnum[3][3]; /* Numerical quantities */
539 double swap[3],maxerr;
540 int8_t perm[3] = {0,1,2}; /* eigenvalues permutation array */
541
542
544 MMG5_eigenvmat_buildnonsym(mesh,3,mnum,lambdaex,(double *)vpex,(double *)ivpex);
545
546 /* Check error in norm inf */
547 maxerr = MMG5_test_mat_error(9,(double *)mex,(double *)mnum);
548 if( maxerr > 1000.*MMG5_EPSOK ) {
549 fprintf(stderr," ## Error matrix recomposition: in function %s, max error %e\n",
550 __func__,maxerr);
551 return 0;
552 }
553
554
556 if( !MMG5_eigenv3d(0,mex,lambdanum,vpnum) )
557 return 0;
558
559 /* Naively sort eigenpairs in increasing order */
560 MMG5_sort_eigenv(3,lambdanum,(double *)vpnum,swap,perm);
561
562 /* Check eigenvalues error in norm inf */
563 maxerr = MMG5_test_mat_error(3,(double *)lambdaex,(double *)lambdanum);
564 if( maxerr > 1000*MMG5_EPSOK ) {
565 fprintf(stderr," ## Error matrix eigenvalues: in function %s, max error %e\n",
566 __func__,maxerr);
567 return 0;
568 }
569
570 /* skip eigenvectors check */
571
572
574 if( !MMG5_eigenvmat_check(mesh,3,0,mex,mnum) )
575 return 0;
576 maxerr = MMG5_test_mat_error(9,(double *)mex,(double *)mnum);
577 if( maxerr > 1000*MMG5_EPSOK ) {
578 fprintf(stderr," ## Error matrix eigendecomposition and recomposition: in function %s, max error %e\n",
579 __func__,maxerr);
580 return 0;
581 }
582
583 return 1;
584}
585
600inline int
601MMG5_buildridmetfic(MMG5_pMesh mesh,double t[3],double n[3],double dtan,
602 double dv,double dn,double m[6]) {
603 double u[3],r[3][3];
604
605 u[0] = n[1]*t[2] - n[2]*t[1];
606 u[1] = n[2]*t[0] - n[0]*t[2];
607 u[2] = n[0]*t[1] - n[1]*t[0];
608
609 /* If u = n1 ^ t, matrix of the desired metric in (t,u,n1) = diag(dtan,dv,dn)*/
610 r[0][0] = t[0]; r[0][1] = u[0]; r[0][2] = n[0];
611 r[1][0] = t[1]; r[1][1] = u[1]; r[1][2] = n[1];
612 r[2][0] = t[2]; r[2][1] = u[2]; r[2][2] = n[2];
613
614 m[0] = dtan*r[0][0]*r[0][0] + dv*r[0][1]*r[0][1] + dn*r[0][2]*r[0][2];
615 m[1] = dtan*r[0][0]*r[1][0] + dv*r[0][1]*r[1][1] + dn*r[0][2]*r[1][2];
616 m[2] = dtan*r[0][0]*r[2][0] + dv*r[0][1]*r[2][1] + dn*r[0][2]*r[2][2];
617 m[3] = dtan*r[1][0]*r[1][0] + dv*r[1][1]*r[1][1] + dn*r[1][2]*r[1][2];
618 m[4] = dtan*r[1][0]*r[2][0] + dv*r[1][1]*r[2][1] + dn*r[1][2]*r[2][2];
619 m[5] = dtan*r[2][0]*r[2][0] + dv*r[2][1]*r[2][1] + dn*r[2][2]*r[2][2];
620
621 return 1;
622}
623
635int MMG5_intmetsavedir(MMG5_pMesh mesh, double *m,double *n,double *mr) {
636 int i;
637 double lambda[2],vp[2][2],siz,isqhmin;
638
639 isqhmin = 1.0 / (mesh->info.hmin * mesh->info.hmin);
640 MMG5_eigensym(m,lambda,vp);
641
642 for (i=0; i<2; i++) {
643 siz = n[0]*vp[i][0]*vp[i][0] + 2.0*n[1]*vp[i][0]*vp[i][1]
644 + n[2]*vp[i][1]*vp[i][1];
645 lambda[i] = MG_MAX(lambda[i],siz);
646 lambda[i] = MG_MIN(lambda[i],isqhmin);
647 }
648 mr[0] = lambda[0]*vp[0][0]*vp[0][0] + lambda[1]*vp[1][0]*vp[1][0];
649 mr[1] = lambda[0]*vp[0][0]*vp[0][1] + lambda[1]*vp[1][0]*vp[1][1];
650 mr[2] = lambda[0]*vp[0][1]*vp[0][1] + lambda[1]*vp[1][1]*vp[1][1];
651
652 return 1;
653}
654
677 double ux,double uy,double uz,double mr[6],
678 double r[3][3] ) {
679 MMG5_pPoint p0;
680 MMG5_pxPoint go;
681 double ps1,ps2,*n1,*n2,*t,*m,dv,dn,u[3];
682
683 p0 = &mesh->point[np0];
684 if ( !(MG_GEO & p0->tag) ) return 0;
685 m = &met->m[6*np0];
686 t = &p0->n[0];
687
688 /* Check that ridge tangent is not null */
689 assert ( t[0]*t[0] + t[1]*t[1] + t[2]*t[2] > 0. && "Null tangent");
690
691 go = &mesh->xpoint[p0->xp];
692
693 /* Decide between the two possible configurations */
694 n1 = &go->n1[0];
695 n2 = &go->n2[0];
696
697 ps1 = ux*n1[0] + uy*n1[1] + uz*n1[2];
698 ps2 = ux*n2[0] + uy*n2[1] + uz*n2[2];
699
700 if ( fabs(ps2)<fabs(ps1) ) {
701 n1 = &go->n2[0];
702 dv = m[2];
703 dn = m[4];
704 }
705 else{
706 dv = m[1];
707 dn = m[3];
708 }
709
710 /* Check that choosed normal is not null */
711 /* Remark: a null second normal along ridge point in mmg3d may be the
712 * consequence of the computation of the same normal with opposite sign for n1
713 * and n2 at a previously inserted ridge point. This append when the ridge
714 * delimits a closed angle an we choose the wrong point normal in bezierCP. */
715 assert ( n1[0]*n1[0] + n1[1]*n1[1] + n1[2]*n1[2] > 0. && "Null normal");
716
717 u[0] = n1[1]*t[2] - n1[2]*t[1];
718 u[1] = n1[2]*t[0] - n1[0]*t[2];
719 u[2] = n1[0]*t[1] - n1[1]*t[0];
720
721 /* If u = n1 ^ t, matrix of the desired metric in (t,u,n1) =
722 * diag(m[0],dv,dn). Now, compute the metric in the canonical basis. */
723 r[0][0] = t[0]; r[0][1] = u[0]; r[0][2] = n1[0];
724 r[1][0] = t[1]; r[1][1] = u[1]; r[1][2] = n1[1];
725 r[2][0] = t[2]; r[2][1] = u[2]; r[2][2] = n1[2];
726
727 mr[0] = m[0]*r[0][0]*r[0][0] + dv*r[0][1]*r[0][1] + dn*r[0][2]*r[0][2];
728 mr[1] = m[0]*r[0][0]*r[1][0] + dv*r[0][1]*r[1][1] + dn*r[0][2]*r[1][2];
729 mr[2] = m[0]*r[0][0]*r[2][0] + dv*r[0][1]*r[2][1] + dn*r[0][2]*r[2][2];
730 mr[3] = m[0]*r[1][0]*r[1][0] + dv*r[1][1]*r[1][1] + dn*r[1][2]*r[1][2];
731 mr[4] = m[0]*r[1][0]*r[2][0] + dv*r[1][1]*r[2][1] + dn*r[1][2]*r[2][2];
732 mr[5] = m[0]*r[2][0]*r[2][0] + dv*r[2][1]*r[2][1] + dn*r[2][2]*r[2][2];
733 return 1;
734}
735
751int MMG5_buildridmetnor(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int np0,double nt[3],
752 double mr[6],double r[3][3] ) {
753 MMG5_pPoint p0;
754 MMG5_pxPoint go;
755 double ps1,ps2,*n1,*n2,*t,*m,dv,dn,u[3];
756 int ier = 0;
757
758 p0 = &mesh->point[np0];
759 if ( !(MG_GEO & p0->tag) ) return 0;
760 m = &met->m[6*np0];
761 t = &p0->n[0];
762 go = &mesh->xpoint[p0->xp];
763
764 /* Decide between the two possible configurations */
765 n1 = &go->n1[0];
766 n2 = &go->n2[0];
767
768 ps1 = nt[0]*n1[0] + nt[1]*n1[1] + nt[2]*n1[2];
769 ps2 = nt[0]*n2[0] + nt[1]*n2[1] + nt[2]*n2[2];
770
771 if ( fabs(ps2) > fabs(ps1) ) {
772 n1 = &go->n2[0];
773 dv = m[2];
774 dn = m[4];
775 ier = 2;
776 }
777 else{
778 dv = m[1];
779 dn = m[3];
780 ier = 1;
781 }
782
783 u[0] = n1[1]*t[2] - n1[2]*t[1];
784 u[1] = n1[2]*t[0] - n1[0]*t[2];
785 u[2] = n1[0]*t[1] - n1[1]*t[0];
786
787 /* If u = n1 ^ t, matrix of the desired metric in (t,u,n1) = diag(m[0],dv,0).
788 Now, compute the metric in the canonical basis.*/
789 r[0][0] = t[0]; r[0][1] = u[0]; r[0][2] = n1[0];
790 r[1][0] = t[1]; r[1][1] = u[1]; r[1][2] = n1[1];
791 r[2][0] = t[2]; r[2][1] = u[2]; r[2][2] = n1[2];
792
793 mr[0] = m[0]*r[0][0]*r[0][0] + dv*r[0][1]*r[0][1] + dn*r[0][2]*r[0][2];
794 mr[1] = m[0]*r[0][0]*r[1][0] + dv*r[0][1]*r[1][1] + dn*r[0][2]*r[1][2];
795 mr[2] = m[0]*r[0][0]*r[2][0] + dv*r[0][1]*r[2][1] + dn*r[0][2]*r[2][2];
796 mr[3] = m[0]*r[1][0]*r[1][0] + dv*r[1][1]*r[1][1] + dn*r[1][2]*r[1][2];
797 mr[4] = m[0]*r[1][0]*r[2][0] + dv*r[1][1]*r[2][1] + dn*r[1][2]*r[2][2];
798 mr[5] = m[0]*r[2][0]*r[2][0] + dv*r[2][1]*r[2][1] + dn*r[2][2]*r[2][2];
799
800 return ier;
801}
802
814int MMG5_intersecmet22(MMG5_pMesh mesh, double *m,double *n,double *mr) {
815 double det,imn[4],lambda[2],vp[2][2],dm[2],dn[2],d0,d1,ip[4];
816 double isqhmin,isqhmax;
817 static int8_t mmgWarn0 = 0;
818 int order;
819
820 isqhmin = 1.0 / (mesh->info.hmin*mesh->info.hmin);
821 isqhmax = 1.0 / (mesh->info.hmax*mesh->info.hmax);
822
823 /* Compute imn = M^{-1}N */
824 det = m[0]*m[2] - m[1]*m[1];
825 if ( fabs(det) < MMG5_EPS*MMG5_EPS ) {
826 if ( !mmgWarn0 ) {
827 fprintf(stderr,"\n ## Warning: %s: null metric det : %E \n",__func__,det);
828 mmgWarn0 = 1;
829 }
830 return 0;
831 }
832 det = 1.0 / det;
833
834 imn[0] = det * ( m[2]*n[0] - m[1]*n[1]);
835 imn[1] = det * ( m[2]*n[1] - m[1]*n[2]);
836 imn[2] = det * (-m[1]*n[0] + m[0]*n[1]);
837 imn[3] = det * (-m[1]*n[1] + m[0]*n[2]);
838
839 /* Find eigenvalues of imn */
840 order = MMG5_eigenv2d(0,imn,lambda,vp);
841
842 if ( !order ) {
843 if ( !mmgWarn0 ) {
844 mmgWarn0 = 1;
845 fprintf(stderr,"\n ## Warning: %s: at least 1 failing"
846 " simultaneous reduction.\n",__func__);
847 }
848 return 0;
849 }
850
851 /* First case : matrices m and n are homothetic : n = lambda0*m */
852 if ( order == 2 ) {
853 /* Diagonalize m and truncate eigenvalues : trimn, det, etc... are reused */
854 if ( fabs(m[1]) < MMG5_EPS ) {
855 dm[0] = m[0];
856 dm[1] = m[2];
857 vp[0][0] = 1;
858 vp[0][1] = 0;
859 vp[1][0] = 0;
860 vp[1][1] = 1;
861 }
862 else {
863 MMG5_eigensym(m,dm,vp);
864 }
865 /* Eigenvalues of the resulting matrix*/
866 dn[0] = MG_MAX(dm[0],lambda[0]*dm[0]);
867 dn[0] = MG_MIN(isqhmin,MG_MAX(isqhmax,dn[0]));
868 dn[1] = MG_MAX(dm[1],lambda[0]*dm[1]);
869 dn[1] = MG_MIN(isqhmin,MG_MAX(isqhmax,dn[1]));
870
871 /* Intersected metric = P diag(d0,d1){^t}P, P = (vp0, vp1) stored in columns */
872 mr[0] = dn[0]*vp[0][0]*vp[0][0] + dn[1]*vp[1][0]*vp[1][0];
873 mr[1] = dn[0]*vp[0][0]*vp[0][1] + dn[1]*vp[1][0]*vp[1][1];
874 mr[2] = dn[0]*vp[0][1]*vp[0][1] + dn[1]*vp[1][1]*vp[1][1];
875
876 return 1;
877 }
878
879 /* Second case : both eigenvalues of imn are distinct ; theory says qf associated to m and n
880 are diagonalizable in basis (vp0, vp1) - the coreduction basis */
881 else if( order == 1 ) {
882
883 /* Compute diagonal values in simultaneous reduction basis */
884 dm[0] = m[0]*vp[0][0]*vp[0][0] + 2.0*m[1]*vp[0][0]*vp[0][1] + m[2]*vp[0][1]*vp[0][1];
885 dm[1] = m[0]*vp[1][0]*vp[1][0] + 2.0*m[1]*vp[1][0]*vp[1][1] + m[2]*vp[1][1]*vp[1][1];
886 dn[0] = n[0]*vp[0][0]*vp[0][0] + 2.0*n[1]*vp[0][0]*vp[0][1] + n[2]*vp[0][1]*vp[0][1];
887 dn[1] = n[0]*vp[1][0]*vp[1][0] + 2.0*n[1]*vp[1][0]*vp[1][1] + n[2]*vp[1][1]*vp[1][1];
888
889 /* Diagonal values of the intersected metric */
890 d0 = MG_MAX(dm[0],dn[0]);
891 d0 = MG_MIN(isqhmin,MG_MAX(d0,isqhmax));
892
893 d1 = MG_MAX(dm[1],dn[1]);
894 d1 = MG_MIN(isqhmin,MG_MAX(d1,isqhmax));
895
896 /* Intersected metric = tP^-1 diag(d0,d1)P^-1, P = (vp0, vp1) stored in columns */
897 det = vp[0][0]*vp[1][1] - vp[0][1]*vp[1][0];
898 if ( fabs(det) < MMG5_EPS ) return 0;
899 det = 1.0 / det;
900
901 ip[0] = vp[1][1]*det;
902 ip[1] = -vp[1][0]*det;
903 ip[2] = -vp[0][1]*det;
904 ip[3] = vp[0][0]*det;
905
906 mr[0] = d0*ip[0]*ip[0] + d1*ip[2]*ip[2];
907 mr[1] = d0*ip[0]*ip[1] + d1*ip[2]*ip[3];
908 mr[2] = d0*ip[1]*ip[1] + d1*ip[3]*ip[3];
909 }
910 return 1;
911}
912
924int MMG5_intersecmet33(MMG5_pMesh mesh, double *m,double *n,double *mr) {
925 double vp[3][3],dm[3],dn[3],d[3],ivp[3][3];
926 double isqhmin,isqhmax;
927 int8_t i;
928
929 isqhmin = 1.0 / (mesh->info.hmin*mesh->info.hmin);
930 isqhmax = 1.0 / (mesh->info.hmax*mesh->info.hmax);
931
932 /* Simultaneous reduction */
933 if( !MMG5_simred3d(mesh,m,n,dm,dn,vp) )
934 return 0;
935
936 /* Diagonal values of the intersected metric */
937 for( i = 0; i < 3; i++ ) {
938 d[i] = MG_MAX(dm[i],dn[i]);
939 d[i] = MG_MIN(isqhmin,MG_MAX(d[i],isqhmax));
940 }
941
942 /* Intersected metric = tP^-1 diag(d0,d1,d2)P^-1, P = (vp0, vp1,vp2) stored in
943 * columns */
944
945 /* Compute the inverse of the eigenvectors matrix */
946 if( !MMG5_invmat33(vp,ivp) )
947 return 0;
948
949 /* Recompose matrix */
950 MMG5_simredmat(3,mr,d,(double *)ivp);
951
952 return 1;
953}
954
963 double m[3] = { 508., -504, 502.}; /* Test matrix 1 */
964 double n[3] = {4020.,-2020.,1020.}; /* Test matrix 2 */
965 double intex[3] = {4500.,-2500.,1500.}; /* Exact intersection */
966 double intnum[3],maxerr; /* Numerical quantities */
967
969 if( !MMG5_intersecmet22(mesh,m,n,intnum) )
970 return 0;
971
972 /* Check error in norm inf */
973 maxerr = MMG5_test_mat_error(3,intex,intnum);
974 if( maxerr > 1000.*MMG5_EPSOK ) {
975 fprintf(stderr," ## Error metric intersection: in function %s, line %d, max error %e\n",
976 __func__,__LINE__,maxerr);
977 return 0;
978 }
979
982 for( int8_t it = 0; it < 20; it++ ) {
983
985 if( !MMG5_intersecmet22(mesh,n,intnum,intnum) )
986 return 0;
987
988 /* Check error in norm inf */
989 maxerr = MMG5_test_mat_error(3,intex,intnum);
990 if( maxerr > 1.e5*MMG5_EPSOK ) {
991 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
992 __func__,__LINE__,it,maxerr);
993 return 0;
994 }
995
996
998 if( !MMG5_intersecmet22(mesh,intnum,n,intnum) )
999 return 0;
1000
1001 /* Check error in norm inf */
1002 maxerr = MMG5_test_mat_error(3,intex,intnum);
1003 if( maxerr > 1.e5*MMG5_EPSOK ) {
1004 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1005 __func__,__LINE__,it,maxerr);
1006 return 0;
1007 }
1008
1009
1011 if( !MMG5_intersecmet22(mesh,m,intnum,intnum) )
1012 return 0;
1013
1014 /* Check error in norm inf */
1015 maxerr = MMG5_test_mat_error(3,intex,intnum);
1016 if( maxerr > 1.e5*MMG5_EPSOK ) {
1017 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1018 __func__,__LINE__,it,maxerr);
1019 return 0;
1020 }
1021
1022
1024 if( !MMG5_intersecmet22(mesh,intnum,m,intnum) )
1025 return 0;
1026
1027 /* Check error in norm inf */
1028 maxerr = MMG5_test_mat_error(3,intex,intnum);
1029 if( maxerr > 1.e5*MMG5_EPSOK ) {
1030 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1031 __func__,__LINE__,it,maxerr);
1032 return 0;
1033 }
1034
1035 }
1036
1037 return 1;
1038}
1039
1048 double m[6] = {111./2.,-109./2., 89./2.,111./2.,-91./2.,111./2.}; /* Test matrix 1 */
1049 double n[6] = {409./2.,-393./2.,-407./2.,409./2.,391./2.,409./2.}; /* Test matrix 2 */
1050 double intex[6] = {254.,-246.,-154.,254.,146.,254.}; /* Exact intersection */
1051 double intnum[6],maxerr; /* Numerical quantities */
1052
1054 if( !MMG5_intersecmet33(mesh,m,n,intnum) )
1055 return 0;
1056
1057 /* Check error in norm inf */
1058 maxerr = MMG5_test_mat_error(6,intex,intnum);
1059 if( maxerr > 1000.*MMG5_EPSOK ) {
1060 fprintf(stderr," ## Error metric intersection: in function %s, line %d, max error %e\n",
1061 __func__,__LINE__,maxerr);
1062 return 0;
1063 }
1064
1067 for( int8_t it = 0; it < 20; it++ ) {
1068
1070 if( !MMG5_intersecmet33(mesh,n,intnum,intnum) )
1071 return 0;
1072
1073 /* Check error in norm inf */
1074 maxerr = MMG5_test_mat_error(6,intex,intnum);
1075 if( maxerr > 1.e5*MMG5_EPSOK ) {
1076 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1077 __func__,__LINE__,it,maxerr);
1078 return 0;
1079 }
1080
1081
1083 if( !MMG5_intersecmet33(mesh,intnum,n,intnum) )
1084 return 0;
1085
1086 /* Check error in norm inf */
1087 maxerr = MMG5_test_mat_error(6,intex,intnum);
1088 if( maxerr > 1.e5*MMG5_EPSOK ) {
1089 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1090 __func__,__LINE__,it,maxerr);
1091 return 0;
1092 }
1093
1094
1096 if( !MMG5_intersecmet33(mesh,m,intnum,intnum) )
1097 return 0;
1098
1099 /* Check error in norm inf */
1100 maxerr = MMG5_test_mat_error(6,intex,intnum);
1101 if( maxerr > 1.e5*MMG5_EPSOK ) {
1102 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1103 __func__,__LINE__,it,maxerr);
1104 return 0;
1105 }
1106
1107
1109 if( !MMG5_intersecmet33(mesh,intnum,m,intnum) )
1110 return 0;
1111
1112 /* Check error in norm inf */
1113 maxerr = MMG5_test_mat_error(6,intex,intnum);
1114 if( maxerr > 1.e5*MMG5_EPSOK ) {
1115 fprintf(stderr," ## Error metric re-intersection: in function %s, line %d, iteration %d, max error %e\n",
1116 __func__,__LINE__,it,maxerr);
1117 return 0;
1118 }
1119
1120 }
1121
1122 return 1;
1123}
1124
1139int MMG5_mmgIntextmet(MMG5_pMesh mesh,MMG5_pSol met,MMG5_int np,double me[6],
1140 double n[3]) {
1141 MMG5_pPoint p0;
1142 MMG5_pxPoint go;
1143 double hu,isqhmin,isqhmax,dd,alpha1,alpha2,alpha3,u[3];
1144 double lambda[3],vp[3][3];
1145 double *m,*n1,*n2,*t,r[3][3],mrot[6],mr[3],mtan[3],metan[3];
1146 int order;
1147 int8_t i;
1148 static int8_t mmgWarn=0, mmgWarn1=0, mmgWarn2=0;
1149
1150 isqhmin = 1.0 / (mesh->info.hmin*mesh->info.hmin);
1151 isqhmax = 1.0 / (mesh->info.hmax*mesh->info.hmax);
1152
1153 p0 = &mesh->point[np];
1154 m = &met->m[6*np];
1155
1158 if ( MG_SIN(p0->tag) || (p0->tag & MG_NOM) ) {
1159
1180 order = MMG5_eigenv3d(1,me,lambda,vp);
1181 if ( !order ) {
1182 if ( !mmgWarn ) {
1183 fprintf(stderr,"\n ## Warning: %s: Unable to diagonalize at least"
1184 " 1 metric.\n",__func__);
1185 mmgWarn = 1;
1186 }
1187 return 0;
1188 }
1189
1190 hu = 0.0;
1191 for( i = 0; i < 3; i++ ) {
1192 hu = MG_MAX(hu,lambda[i]);
1193 }
1194
1196 hu = MG_MIN(isqhmin,hu);
1197 hu = MG_MAX(isqhmax,hu);
1198
1200 if( hu > m[0] )
1201 m[0] = m[3] = m[5] = hu;
1202
1203 }
1205 else if ( p0->tag & MG_GEO ) {
1206 /* Size prescribed by metric me in direction t */
1207 t = n;
1208 hu = me[0]*t[0]*t[0] + me[3]*t[1]*t[1] + me[5]*t[2]*t[2] \
1209 + 2.0*me[1]*t[0]*t[1] + 2.0*me[2]*t[0]*t[2] + 2.0*me[4]*t[1]*t[2];
1210
1211 hu = MG_MIN(isqhmin,hu);
1212 hu = MG_MAX(isqhmax,hu);
1213 m[0] = MG_MAX(m[0],hu);
1214
1216 assert ( p0->xp );
1217 go = &mesh->xpoint[p0->xp];
1218 n1 = &go->n1[0];
1219 n2 = &go->n2[0];
1220
1221 u[0] = n1[1]*t[2] - n1[2]*t[1];
1222 u[1] = n1[2]*t[0] - n1[0]*t[2];
1223 u[2] = n1[0]*t[1] - n1[1]*t[0];
1224 dd = u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
1225 if ( dd > MMG5_EPSD ) {
1226 dd = 1.0 / sqrt(dd);
1227
1228 u[0] *= dd;
1229 u[1] *= dd;
1230 u[2] *= dd;
1231
1232 hu = me[0]*u[0]*u[0] + me[3]*u[1]*u[1] + me[5]*u[2]*u[2] \
1233 + 2.0*me[1]*u[0]*u[1] + 2.0*me[2]*u[0]*u[2] + 2.0*me[4]*u[1]*u[2];
1234
1235 hu = MG_MIN(isqhmin,hu);
1236 hu = MG_MAX(isqhmax,hu);
1237 m[1] = MG_MAX(m[1],hu);
1238 }
1240 u[0] = n2[1]*t[2] - n2[2]*t[1];
1241 u[1] = n2[2]*t[0] - n2[0]*t[2];
1242 u[2] = n2[0]*t[1] - n2[1]*t[0];
1243 dd = u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
1244 if ( dd > MMG5_EPSD ) {
1245 dd = 1.0 / sqrt(dd);
1246
1247 u[0] *= dd;
1248 u[1] *= dd;
1249 u[2] *= dd;
1250
1251 hu = me[0]*u[0]*u[0] + me[3]*u[1]*u[1] + me[5]*u[2]*u[2] \
1252 + 2.0*me[1]*u[0]*u[1] + 2.0*me[2]*u[0]*u[2] + 2.0*me[4]*u[1]*u[2];
1253
1254 hu = MG_MIN(isqhmin,hu);
1255 hu = MG_MAX(isqhmax,hu);
1256 m[2] = MG_MAX(m[2],hu);
1257 }
1258
1260 hu = me[0]*n1[0]*n1[0] + me[3]*n1[1]*n1[1] + me[5]*n1[2]*n1[2]
1261 + 2.0*me[1]*n1[0]*n1[1] + 2.0*me[2]*n1[0]*n1[2] + 2.0*me[4]*n1[1]*n1[2];
1262
1263 hu = MG_MIN(isqhmin,hu);
1264 hu = MG_MAX(isqhmax,hu);
1265 m[3] = hu;
1266
1268 hu = me[0]*n2[0]*n2[0] + me[3]*n2[1]*n2[1] + me[5]*n2[2]*n2[2]
1269 + 2.0*me[1]*n2[0]*n2[1] + 2.0*me[2]*n2[0]*n2[2] + 2.0*me[4]*n2[1]*n2[2];
1270
1271 hu = MG_MIN(isqhmin,hu);
1272 hu = MG_MAX(isqhmax,hu);
1273 m[4] = hu;
1274 }
1276 else {
1277 MMG5_rotmatrix(n,r);
1278
1280 MMG5_rmtr(r,m,mrot);
1281 mtan[0] = mrot[0];
1282 mtan[1] = mrot[1];
1283 mtan[2] = mrot[3];
1284
1285
1286 MMG5_rmtr(r,me,mrot);
1287 metan[0] = mrot[0];
1288 metan[1] = mrot[1];
1289 metan[2] = mrot[3];
1290
1292 if ( !MMG5_intersecmet22(mesh,mtan,metan,mr) ) {
1293 if ( !mmgWarn1 ) {
1294 fprintf(stderr,"\n ## Warning: %s: impossible metric intersection:"
1295 " surfacic metric skipped.\n",__func__);
1296 mmgWarn1 = 1;
1297 }
1298 m[0] = me[0];
1299 m[1] = me[1];
1300 m[2] = me[2];
1301 m[3] = me[3];
1302 m[4] = me[4];
1303 m[5] = me[5];
1304
1305 return 0;
1306 }
1307
1310 mtan[0] = mr[0]*r[0][0] + mr[1]*r[1][0];
1311 mtan[1] = mr[0]*r[0][1] + mr[1]*r[1][1];
1312 mtan[2] = mr[0]*r[0][2] + mr[1]*r[1][2];
1313 metan[0] = mr[1]*r[0][0] + mr[2]*r[1][0];
1314 metan[1] = mr[1]*r[0][1] + mr[2]*r[1][1];
1315 metan[2] = mr[1]*r[0][2] + mr[2]*r[1][2];
1316
1317 alpha1 = r[2][0]*mrot[5];
1318 alpha2 = r[2][1]*mrot[5];
1319 alpha3 = r[2][2]*mrot[5];
1320
1321 m[0] = r[0][0] * mtan[0] + r[1][0] * metan[0] + r[2][0]*alpha1;
1322 m[1] = r[0][0] * mtan[1] + r[1][0] * metan[1] + r[2][0]*alpha2;
1323 m[2] = r[0][0] * mtan[2] + r[1][0] * metan[2] + r[2][0]*alpha3;
1324 m[3] = r[0][1] * mtan[1] + r[1][1] * metan[1] + r[2][1]*alpha2;
1325 m[4] = r[0][1] * mtan[2] + r[1][1] * metan[2] + r[2][1]*alpha3;
1326 m[5] = r[0][2] * mtan[2] + r[1][2] * metan[2] + r[2][2]*alpha3;
1327
1330 order = MMG5_eigenv3d(1,m,lambda,vp);
1331 if ( !order ) {
1332 if ( !mmgWarn ) {
1333 fprintf(stderr,"\n ## Warning: %s: Unable to diagonalize at least"
1334 " 1 metric.\n",__func__);
1335 mmgWarn = 1;
1336 }
1337 return 0;
1338 }
1339
1340 for (i=0; i<3; i++) {
1341 if( lambda[i]<=0) {
1342 if ( !mmgWarn2 ) {
1343 fprintf(stderr,"\n ## Warning: %s: at least 1 wrong metric "
1344 "(eigenvalues : %e %e %e): surfacic metric skipped.\n",
1345 __func__,lambda[0],lambda[1],lambda[2]);
1346 mmgWarn2 = 1;
1347 }
1348 m[0] = me[0];
1349 m[1] = me[1];
1350 m[2] = me[2];
1351 m[3] = me[3];
1352 m[4] = me[4];
1353 m[5] = me[5];
1354 return 0;
1355 }
1356 lambda[i]=MG_MIN(isqhmin,lambda[i]);
1357 lambda[i]=MG_MAX(isqhmax,lambda[i]);
1358 }
1359
1360 m[0] = vp[0][0]*vp[0][0]*lambda[0] + vp[1][0]*vp[1][0]*lambda[1]
1361 + vp[2][0]*vp[2][0]*lambda[2];
1362 m[1] = vp[0][0]*vp[0][1]*lambda[0] + vp[1][0]*vp[1][1]*lambda[1]
1363 + vp[2][0]*vp[2][1]*lambda[2];
1364 m[2] = vp[0][0]*vp[0][2]*lambda[0] + vp[1][0]*vp[1][2]*lambda[1]
1365 + vp[2][0]*vp[2][2]*lambda[2];
1366 m[3] = vp[0][1]*vp[0][1]*lambda[0] + vp[1][1]*vp[1][1]*lambda[1]
1367 + vp[2][1]*vp[2][1]*lambda[2];
1368 m[4] = vp[0][1]*vp[0][2]*lambda[0] + vp[1][1]*vp[1][2]*lambda[1]
1369 + vp[2][1]*vp[2][2]*lambda[2];
1370 m[5] = vp[0][2]*vp[0][2]*lambda[0] + vp[1][2]*vp[1][2]*lambda[1]
1371 + vp[2][2]*vp[2][2]*lambda[2];
1372 }
1373
1374 return 1;
1375}
1376
1390int MMG5_paratmet(double c0[3],double n0[3],double m[6],double c1[3],double n1[3],double mt[6]) {
1391 double r[3][3],mrot[6],mtan[3],lambda[2],vp[2][2],u[3],ps,ll;
1392
1393 /* Take the induced metric tensor in the tangent plane by change of basis : R * M * {^t}R*/
1394 if ( !MMG5_rotmatrix(n0,r) ) return 0;
1395 MMG5_rmtr(r,m,mrot);
1396 mtan[0] = mrot[0];
1397 mtan[1] = mrot[1];
1398 mtan[2] = mrot[3];
1399
1400 /* Take eigenvectors of metric tensor in tangent plane */
1401 MMG5_eigensym(mtan,lambda,vp);
1402
1403 /* Eigenvector in canonical basis = {t}R*vp[0] */
1404 u[0] = r[0][0]*vp[0][0] + r[1][0]*vp[0][1];
1405 u[1] = r[0][1]*vp[0][0] + r[1][1]*vp[0][1];
1406 u[2] = r[0][2]*vp[0][0] + r[1][2]*vp[0][1];
1407
1408 /* Projection in the tangent plane of c1 */
1409 ps = u[0]*n1[0] + u[1]*n1[1] + u[2]*n1[2];
1410 u[0] -= ps*n1[0];
1411 u[1] -= ps*n1[1];
1412 u[2] -= ps*n1[2];
1413 ll = u[0]*u[0] + u[1]*u[1] + u[2]*u[2];
1414 if ( ll < MMG5_EPSD ) return 0;
1415 ll = 1.0 / sqrt(ll);
1416 u[0] *= ll;
1417 u[1] *= ll;
1418 u[2] *= ll;
1419
1420 /* And the transported metric is diag(lambda[0], lambda[1], mrot[5]) in basis
1421 * (u,n1^u,n1) */
1422 r[0][0] = u[0];
1423 r[1][0] = u[1];
1424 r[2][0] = u[2];
1425
1426 r[0][1] = n1[1]*u[2] - n1[2]*u[1];
1427 r[1][1] = n1[2]*u[0] - n1[0]*u[2];
1428 r[2][1] = n1[0]*u[1] - n1[1]*u[0];
1429
1430 ll = r[0][1]*r[0][1] + r[1][1]*r[1][1] + r[2][1]*r[2][1];
1431 if ( ll < MMG5_EPSD ) return 0;
1432 ll = 1.0 / sqrt(ll);
1433 r[0][1] *= ll;
1434 r[1][1] *= ll;
1435 r[2][1] *= ll;
1436
1437 r[0][2] = n1[0];
1438 r[1][2] = n1[1];
1439 r[2][2] = n1[2];
1440
1441 /*mt = R * diag(lambda[0], lambda[1], mrot[5])*{^t}R */
1442 mt[0] = lambda[0]*r[0][0]*r[0][0] + lambda[1]*r[0][1]*r[0][1]
1443 + mrot[5]*r[0][2]*r[0][2];
1444
1445 mt[1] = lambda[0]*r[0][0]*r[1][0]
1446 + lambda[1]*r[0][1]*r[1][1] + mrot[5]*r[0][2]*r[1][2];
1447
1448 mt[2] = lambda[0]*r[0][0]*r[2][0]
1449 + lambda[1]*r[0][1]*r[2][1] + mrot[5]*r[0][2]*r[2][2];
1450
1451 mt[3] = lambda[0]*r[1][0]*r[1][0] + lambda[1]*r[1][1]*r[1][1]
1452 + mrot[5]*r[1][2]*r[1][2];
1453
1454 mt[4] = lambda[0]*r[2][0]*r[1][0]
1455 + lambda[1]*r[2][1]*r[1][1] + mrot[5]*r[2][2]*r[1][2];
1456
1457 mt[5] = lambda[0]*r[2][0]*r[2][0] + lambda[1]*r[2][1]*r[2][1]
1458 + mrot[5]*r[2][2]*r[2][2];
1459
1460 return 1;
1461}
int ier
MMG5_pMesh * mesh
int MMG5_simred3d(MMG5_pMesh mesh, double *m, double *n, double dm[3], double dn[3], double vp[3][3])
Definition: anisosiz.c:1416
int MMG5_eigensym(double m[3], double lambda[2], double vp[2][2])
Definition: eigenv.c:973
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
int MMG5_eigenv2d(int symmat, double *mat, double lambda[2], double vp[2][2])
Find eigenvalues and vectors of a 2x2 matrix.
Definition: eigenv.c:780
#define MMG5_EPSD
#define MMG5_EPS
static void MMG5_simredmat(int8_t dim, double *m, double *dm, double *iv)
int MMG5_eigenvmat_check(MMG5_pMesh mesh, int8_t dim, int8_t symmat, double m[], double mnew[])
Definition: mettools.c:233
int MMG5_test_intersecmet33(MMG5_pMesh mesh)
Definition: mettools.c:1047
int MMG5_intersecmet33(MMG5_pMesh mesh, double *m, double *n, double *mr)
Definition: mettools.c:924
int MMG5_eigenvmatsym3d(MMG5_pMesh mesh, double m[], double lambda[], double v[][3])
Definition: mettools.c:164
int MMG5_eigenvmatnonsym2d(MMG5_pMesh mesh, double m[], double lambda[], double v[][2])
Definition: mettools.c:184
int MMG5_intersecmet22(MMG5_pMesh mesh, double *m, double *n, double *mr)
Definition: mettools.c:814
int MMG5_buildridmetnor(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np0, double nt[3], double mr[6], double r[3][3])
Definition: mettools.c:751
int MMG5_test_eigenvmatsym3d(MMG5_pMesh mesh, double *mex, double lambdaex[], double vpex[][3])
Definition: mettools.c:456
static void MMG5_eigenvmat_buildsym(MMG5_pMesh mesh, int8_t dim, double m[], double lambda[], double v[])
Definition: mettools.c:52
int MMG5_test_eigenvmatnonsym2d(MMG5_pMesh mesh, double *mex, double lambdaex[], double vpex[][2], double ivpex[][2])
Definition: mettools.c:379
int MMG5_paratmet(double c0[3], double n0[3], double m[6], double c1[3], double n1[3], double mt[6])
Definition: mettools.c:1390
int MMG5_eigenvmatsym2d(MMG5_pMesh mesh, double m[], double lambda[], double v[][2])
Definition: mettools.c:144
int MMG5_eigenvmatnonsym3d(MMG5_pMesh mesh, double m[], double lambda[], double v[][3])
Definition: mettools.c:209
int MMG5_buildridmetfic(MMG5_pMesh mesh, double t[3], double n[3], double dtan, double dv, double dn, double m[6])
Definition: mettools.c:601
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
static void MMG5_eigenvmat_buildnonsym(MMG5_pMesh mesh, int8_t dim, double m[], double lambda[], double v[], double iv[])
Definition: mettools.c:100
int MMG5_test_eigenvmatsym2d(MMG5_pMesh mesh, double *mex, double lambdaex[], double vpex[][2])
Definition: mettools.c:301
void MMG5_sort_eigenv(int8_t dim, double *lambda, double *vp, double *swap, int8_t *perm)
Definition: mettools.c:279
int MMG5_mmgIntextmet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np, double me[6], double n[3])
Definition: mettools.c:1139
int MMG5_test_eigenvmatnonsym3d(MMG5_pMesh mesh, double *mex, double lambdaex[], double vpex[][3], double ivpex[][3])
Definition: mettools.c:536
int MMG5_test_intersecmet22(MMG5_pMesh mesh)
Definition: mettools.c:962
int MMG5_intmetsavedir(MMG5_pMesh mesh, double *m, double *n, double *mr)
Definition: mettools.c:635
#define MG_GEO
#define MMG5_EPSOK
double MMG5_test_mat_error(int8_t nelem, double m1[], double m2[])
Definition: tools.c:1123
#define MG_MIN(a, b)
#define MG_MAX(a, b)
#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
int MMG5_rotmatrix(double n[3], double r[3][3])
Definition: tools.c:467
void MMG5_nsort(int8_t, double *, int8_t *)
Definition: tools.c:49
#define MG_NOM
void MMG5_nperm(int8_t n, int8_t shift, int8_t stride, double *val, double *oldval, int8_t *perm)
Definition: tools.c:80
int MMG5_invmat22(double m[2][2], double mi[2][2])
Definition: tools.c:745
double hmin
Definition: libmmgtypes.h:518
double hmax
Definition: libmmgtypes.h:518
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
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
MMG5_int xp
Definition: libmmgtypes.h:279
double * m
Definition: libmmgtypes.h:671
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