Mmg
Simplicial remeshers (mesh adaptation, isovalue discretization, lagrangian movement)
anisosiz.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"
36#include "mmgexterns_private.h"
38
49static inline
50double MMG5_surf(MMG5_pMesh mesh,double m[3][6],MMG5_pTria ptt) {
52 double surf,dens,J[3][2],mJ[3][2],tJmJ[2][2];
53 int8_t i,nullDens;
54 static int8_t mmgErr=0;
55
56 surf = 0.0;
57
58 if ( !MMG5_bezierCP(mesh,ptt,&b,1) ) return 0.0;
59
60 /* Compute density integrand of volume at the 3 vertices of T */
61 nullDens = 0;
62 for (i=0; i<3; i++) {
63 if ( i == 0 ) {
64 J[0][0] = 3.0*( b.b[7][0] - b.b[0][0] ) ; J[0][1] = 3.0*( b.b[6][0] - b.b[0][0] );
65 J[1][0] = 3.0*( b.b[7][1] - b.b[0][1] ) ; J[1][1] = 3.0*( b.b[6][1] - b.b[0][1] );
66 J[2][0] = 3.0*( b.b[7][2] - b.b[0][2] ) ; J[2][1] = 3.0*( b.b[6][2] - b.b[0][2] );
67 }
68 else if ( i == 1 ) {
69 J[0][0] = 3.0*( b.b[1][0] - b.b[8][0] ) ; J[0][1] = 3.0*( b.b[3][0] - b.b[8][0] );
70 J[1][0] = 3.0*( b.b[1][1] - b.b[8][1] ) ; J[1][1] = 3.0*( b.b[3][1] - b.b[8][1] );
71 J[2][0] = 3.0*( b.b[1][2] - b.b[8][2] ) ; J[2][1] = 3.0*( b.b[3][2] - b.b[8][2] );
72 }
73 else {
74 J[0][0] = 3.0*( b.b[4][0] - b.b[5][0] ) ; J[0][1] = 3.0*( b.b[2][0] - b.b[5][0] );
75 J[1][0] = 3.0*( b.b[4][1] - b.b[5][1] ) ; J[1][1] = 3.0*( b.b[2][1] - b.b[5][1] );
76 J[2][0] = 3.0*( b.b[4][2] - b.b[5][2] ) ; J[2][1] = 3.0*( b.b[2][2] - b.b[5][2] );
77 }
78
79 mJ[0][0] = m[i][0]*J[0][0] + m[i][1]*J[1][0] + m[i][2]*J[2][0];
80 mJ[1][0] = m[i][1]*J[0][0] + m[i][3]*J[1][0] + m[i][4]*J[2][0];
81 mJ[2][0] = m[i][2]*J[0][0] + m[i][4]*J[1][0] + m[i][5]*J[2][0];
82
83 mJ[0][1] = m[i][0]*J[0][1] + m[i][1]*J[1][1] + m[i][2]*J[2][1];
84 mJ[1][1] = m[i][1]*J[0][1] + m[i][3]*J[1][1] + m[i][4]*J[2][1];
85 mJ[2][1] = m[i][2]*J[0][1] + m[i][4]*J[1][1] + m[i][5]*J[2][1];
86
87 /* dens = sqrt(tJacsigma * M * Jacsigma )*/
88 tJmJ[0][0] = J[0][0]*mJ[0][0] + J[1][0]*mJ[1][0] + J[2][0]*mJ[2][0];
89 tJmJ[0][1] = J[0][0]*mJ[0][1] + J[1][0]*mJ[1][1] + J[2][0]*mJ[2][1];
90 tJmJ[1][0] = J[0][1]*mJ[0][0] + J[1][1]*mJ[1][0] + J[2][1]*mJ[2][0];
91 tJmJ[1][1] = J[0][1]*mJ[0][1] + J[1][1]*mJ[1][1] + J[2][1]*mJ[2][1];
92
93 dens = tJmJ[0][0]*tJmJ[1][1] - tJmJ[1][0]*tJmJ[0][1];
94 if ( dens <= MMG5_EPSD2 ) {
95#ifndef NDEBUG
96 if ( !mmgErr ) {
97 fprintf(stderr,"\n ## Warning: %s: at least 1 negative or null density.\n",
98 __func__);
99 mmgErr = 1;
100 }
101#endif
102 ++nullDens;
103 continue;
104 }
105 surf += sqrt(fabs(dens));
106 }
107
108 if ( nullDens==3 ) return 0;
109
110 surf *= MMG5_ATHIRD;
111 return surf;
112}
113
125 MMG5_pPoint p[3];
126 MMG5_int np[3];
127 double ux,uy,uz,m[3][6],rbasis[3][3];
128 int8_t i1,i2;
129 int i;
130
131 for (i=0; i<3; i++) {
132 np[i] = ptt->v[i];
133 p[i] = &mesh->point[np[i]];
134 }
135
136 /* Set metric tensors at vertices of tria iel */
137 for(i=0; i<3; i++) {
138
139 if ( MG_SIN(p[i]->tag) || (MG_NOM & p[i]->tag) ) {
140 memcpy(&m[i][0],&met->m[6*np[i]],6*sizeof(double));
141 }
142 else if ( p[i]->tag & MG_GEO ) {
143 i1 = MMG5_inxt2[i];
144 i2 = MMG5_iprv2[i];
145 ux = 0.5*(p[i1]->c[0]+p[i2]->c[0]) - p[i]->c[0];
146 uy = 0.5*(p[i1]->c[1]+p[i2]->c[1]) - p[i]->c[1];
147 uz = 0.5*(p[i1]->c[2]+p[i2]->c[2]) - p[i]->c[2];
148 /* Note that rbasis is unused in this function */
149 if ( !MMG5_buildridmet(mesh,met,np[i],ux,uy,uz,&m[i][0],rbasis) ) return 0.0;
150 }
151 else {
152 memcpy(&m[i][0],&met->m[6*np[i]],6*sizeof(double));
153 }
154 }
155 return MMG5_surf(mesh,m,ptt);
156
157}
158
172 double ma[6], double mb[6], double mc[6]) {
173 double mm[6];
174 double *a,*b,*c,abx,aby,abz,acx,acy,acz,dens[3],surf;
175 int i;
176 MMG5_int ia,ib,ic;
177
178 ia = ptt->v[0];
179 ib = ptt->v[1];
180 ic = ptt->v[2];
181
182 a = &mesh->point[ia].c[0];
183 b = &mesh->point[ib].c[0];
184 c = &mesh->point[ic].c[0];
185
186 abx = b[0] - a[0];
187 aby = b[1] - a[1];
188 abz = b[2] - a[2];
189 acx = c[0] - a[0];
190 acy = c[1] - a[1];
191 acz = c[2] - a[2];
192
193 /* Compute the mean of the metrics over the triangle */
194 for (i=0; i<6; i++)
195 mm[i] = MMG5_ATHIRD * (ma[i] + mb[i]+ mc[i]);
196
197 /* Compute sqrt(det(t^JmJ)) (= int_T sqrt(t^JmJ) for a non-curve element) */
198 dens[0] = (abx*abx*mm[0]+abx*aby*mm[1]+abx*abz*mm[2])
199 + (aby*abx*mm[1]+aby*aby*mm[3]+aby*abz*mm[4])
200 + (abz*abx*mm[2]+abz*aby*mm[4]+abz*abz*mm[5]);
201
202 dens[1] = (abx*acx*mm[0]+abx*acy*mm[1]+abx*acz*mm[2])
203 + (aby*acx*mm[1]+aby*acy*mm[3]+aby*acz*mm[4])
204 + (abz*acx*mm[2]+abz*acy*mm[4]+abz*acz*mm[5]);
205
206 dens[2] = (acx*acx*mm[0]+acx*acy*mm[1]+acx*acz*mm[2])
207 + (acy*acx*mm[1]+acy*acy*mm[3]+acy*acz*mm[4])
208 + (acz*acx*mm[2]+acz*acy*mm[4]+acz*acz*mm[5]);
209
210 surf = dens[0]*dens[2]-dens[1]*dens[1];
211
212 if ( surf < MMG5_EPSD ) return 0.0;
213
214 surf = sqrt(surf);
215
216 return surf;
217}
218
229{
230 MMG5_pPoint ppt;
231 double *m,*n,r[3][3],isqhmax;
232 MMG5_int k;
233
234 isqhmax = 1.0 / (mesh->info.hmax*mesh->info.hmax);
235 for (k=1; k<=mesh->np; k++) {
236 ppt = &mesh->point[k];
237 if ( !MG_VOK(ppt) || ppt->flag > 0 ) continue;
238
239 m = &met->m[6*k];
240 if(ismet) {
241 if ( !(MG_SIN(ppt->tag) || (ppt->tag & MG_NOM)) && (ppt->tag & MG_GEO) ) {
242 m[0] = m[1] = m[2] = m[3] = m[4] = isqhmax;
243 m[5] = 0;
244 }
245
246 ppt->flag = 1;
247 continue;
248 }
249
250 memset(m,0,6*sizeof(double));
251 if ( (MG_SIN(ppt->tag) || (MG_NOM & ppt->tag)) ) {
252 m[0] = m[3] = m[5] = isqhmax;
253 }
254 else if ( ppt->tag & MG_GEO ) {
255 /* We store the size in the tangent dir in m[0], in the n1 dir in m[1] and
256 * in the n2 dir in m[2]. */
257 m[0] = m[1] = m[2] = m[3] = m[4] = isqhmax;
258 }
259 else {
260 n = ppt->tag & MG_REF ? &mesh->xpoint[ppt->xp].n1[0] : ppt->n;
261 MMG5_rotmatrix(n,r);
262 m[0] = isqhmax*(r[0][0]*r[0][0]+r[1][0]*r[1][0]+r[2][0]*r[2][0]);
263 m[1] = isqhmax*(r[0][0]*r[0][1]+r[1][0]*r[1][1]+r[2][0]*r[2][1]);
264 m[2] = isqhmax*(r[0][0]*r[0][2]+r[1][0]*r[1][2]+r[2][0]*r[2][2]);
265 m[3] = isqhmax*(r[0][1]*r[0][1]+r[1][1]*r[1][1]+r[2][1]*r[2][1]);
266 m[4] = isqhmax*(r[0][1]*r[0][2]+r[1][1]*r[1][2]+r[2][1]*r[2][2]);
267 m[5] = isqhmax*(r[0][2]*r[0][2]+r[1][2]*r[1][2]+r[2][2]*r[2][2]);
268 }
269 ppt->flag = 2;
270 }
271}
272
290void MMG5_fillDefmetregSys( MMG5_int k, MMG5_pPoint p0, int i0, MMG5_Bezier b,
291 double r[3][3], double c[3],
292 double *lispoi,
293 double tAA[6], double tAb[3] )
294{
295 double b0[3],b1[3],d[3];
296 int j;
297
298 for(j=0; j<10; j++){
299 c[0] = b.b[j][0] - p0->c[0];
300 c[1] = b.b[j][1] - p0->c[1];
301 c[2] = b.b[j][2] - p0->c[2];
302
303 b.b[j][0] = r[0][0]*c[0] + r[0][1]*c[1] + r[0][2]*c[2];
304 b.b[j][1] = r[1][0]*c[0] + r[1][1]*c[1] + r[1][2]*c[2];
305 b.b[j][2] = r[2][0]*c[0] + r[2][1]*c[1] + r[2][2]*c[2];
306 }
307
308/* Mid-point along edge [i0;i1] and endpoint in the rotated frame */
309 if(i0 == 0){
310 memcpy(b0,&(b.b[7][0]),3*sizeof(double));
311 memcpy(b1,&(b.b[8][0]),3*sizeof(double));
312 }
313 else if(i0 == 1){
314 memcpy(b0,&(b.b[3][0]),3*sizeof(double));
315 memcpy(b1,&(b.b[4][0]),3*sizeof(double));
316 }
317 else{
318 memcpy(b0,&(b.b[5][0]),3*sizeof(double));
319 memcpy(b1,&(b.b[6][0]),3*sizeof(double));
320 }
321
322/* At this point, the two control points b0 and b1 are expressed in the
323 * rotated frame. We compute the physical coor of the curve edge's
324 * mid-point. */
325 c[0] = 3.0/8.0*b0[0] + 3.0/8.0*b1[0] + 1.0/8.0*lispoi[3*k+1];
326 c[1] = 3.0/8.0*b0[1] + 3.0/8.0*b1[1] + 1.0/8.0*lispoi[3*k+2];
327 c[2] = 3.0/8.0*b0[2] + 3.0/8.0*b1[2] + 1.0/8.0*lispoi[3*k+3];
328
329/* Fill matrice \sum tAA and second member \sum tAb with \f$A=( X_{P_i}^2
330 * Y_{P_i}^2 X_{P_i}Y_{P_i})\f$ and \f$b= Z_{P_i}\f$ with P_i the
331 * physical points at edge [i0;i1] extremities and middle. */
332 tAA[0] += c[0]*c[0]*c[0]*c[0];
333 tAA[1] += c[0]*c[0]*c[1]*c[1];
334 tAA[2] += c[0]*c[0]*c[0]*c[1];
335 tAA[3] += c[1]*c[1]*c[1]*c[1];
336 tAA[4] += c[0]*c[1]*c[1]*c[1];
337 tAA[5] += c[0]*c[0]*c[1]*c[1];
338
339 tAb[0] += c[0]*c[0]*c[2];
340 tAb[1] += c[1]*c[1]*c[2];
341 tAb[2] += c[0]*c[1]*c[2];
342
343 tAA[0] += lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+1];
344 tAA[1] += lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+2]*lispoi[3*k+2];
345 tAA[2] += lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+2];
346 tAA[3] += lispoi[3*k+2]*lispoi[3*k+2]*lispoi[3*k+2]*lispoi[3*k+2];
347 tAA[4] += lispoi[3*k+1]*lispoi[3*k+2]*lispoi[3*k+2]*lispoi[3*k+2];
348 tAA[5] += lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+2]*lispoi[3*k+2];
349
350 tAb[0] += lispoi[3*k+1]*lispoi[3*k+1]*lispoi[3*k+3];
351 tAb[1] += lispoi[3*k+2]*lispoi[3*k+2]*lispoi[3*k+3];
352 tAb[2] += lispoi[3*k+1]*lispoi[3*k+2]*lispoi[3*k+3];
353
354/* Mid-point along median edge (coor of mid-point in parametric space : (1/4
355 * 1/4)) and endpoint in the rotated frame (coor of end-point in parametric
356 * space (1/2 1/2)). */
357 if(i0 == 0){
358 c[0] = A64TH*(b.b[1][0] + b.b[2][0] + 3.0*(b.b[3][0] + b.b[4][0])) \
359 + 3.0*A16TH*(b.b[6][0] + b.b[7][0] + b.b[9][0]) + A32TH*(b.b[5][0] + b.b[8][0]);
360 c[1] = A64TH*(b.b[1][1] + b.b[2][1] + 3.0*(b.b[3][1] + b.b[4][1])) \
361 + 3.0*A16TH*(b.b[6][1] + b.b[7][1] + b.b[9][1]) + A32TH*(b.b[5][1] + b.b[8][1]);
362 c[2] = A64TH*(b.b[1][2] + b.b[2][2] + 3.0*(b.b[3][2] + b.b[4][2])) \
363 + 3.0*A16TH*(b.b[6][2] + b.b[7][2] + b.b[9][2]) + A32TH*(b.b[5][2] + b.b[8][2]);
364
365 d[0] = 0.125*b.b[1][0] + 0.375*(b.b[3][0] + b.b[4][0]) + 0.125*b.b[2][0];
366 d[1] = 0.125*b.b[1][1] + 0.375*(b.b[3][1] + b.b[4][1]) + 0.125*b.b[2][1];
367 d[2] = 0.125*b.b[1][2] + 0.375*(b.b[3][2] + b.b[4][2]) + 0.125*b.b[2][2];
368 }
369 else if(i0 == 1){
370 c[0] = A64TH*(b.b[0][0] + b.b[2][0] + 3.0*(b.b[5][0] + b.b[6][0])) \
371 + 3.0*A16TH*(b.b[3][0] + b.b[8][0] + b.b[9][0]) + A32TH*(b.b[4][0] + b.b[7][0]);
372 c[1] = A64TH*(b.b[0][1] + b.b[2][1] + 3.0*(b.b[5][1] + b.b[6][1])) \
373 + 3.0*A16TH*(b.b[3][1] + b.b[8][1] + b.b[9][1]) + A32TH*(b.b[4][1] + b.b[7][1]);
374 c[2] = A64TH*(b.b[0][2] + b.b[2][2] + 3.0*(b.b[5][2] + b.b[6][2])) \
375 + 3.0*A16TH*(b.b[3][2] + b.b[8][2] + b.b[9][2]) + A32TH*(b.b[4][2] + b.b[7][2]);
376
377 d[0] = 0.125*b.b[2][0] + 0.375*(b.b[5][0] + b.b[6][0]) + 0.125*b.b[0][0];
378 d[1] = 0.125*b.b[2][1] + 0.375*(b.b[5][1] + b.b[6][1]) + 0.125*b.b[0][1];
379 d[2] = 0.125*b.b[2][2] + 0.375*(b.b[5][2] + b.b[6][2]) + 0.125*b.b[0][2];
380 }
381 else{
382 c[0] = A64TH*(b.b[0][0] + b.b[1][0] + 3.0*(b.b[7][0] + b.b[8][0])) \
383 + 3.0*A16TH*(b.b[4][0] + b.b[5][0] + b.b[9][0]) + A32TH*(b.b[3][0] + b.b[6][0]);
384 c[1] = A64TH*(b.b[0][1] + b.b[1][1] + 3.0*(b.b[7][1] + b.b[8][1])) \
385 + 3.0*A16TH*(b.b[4][1] + b.b[5][1] + b.b[9][1]) + A32TH*(b.b[3][1] + b.b[6][1]);
386 c[2] = A64TH*(b.b[0][2] + b.b[1][2] + 3.0*(b.b[7][2] + b.b[8][2])) \
387 + 3.0*A16TH*(b.b[4][2] + b.b[5][2] + b.b[9][2]) + A32TH*(b.b[3][2] + b.b[6][2]);
388
389 d[0] = 0.125*b.b[0][0] + 0.375*(b.b[7][0] + b.b[8][0]) + 0.125*b.b[1][0];
390 d[1] = 0.125*b.b[0][1] + 0.375*(b.b[7][1] + b.b[8][1]) + 0.125*b.b[1][1];
391 d[2] = 0.125*b.b[0][2] + 0.375*(b.b[7][2] + b.b[8][2]) + 0.125*b.b[1][2];
392 }
393
394/* Fill matrice tAA and second member tAb*/
395 tAA[0] += c[0]*c[0]*c[0]*c[0];
396 tAA[1] += c[0]*c[0]*c[1]*c[1];
397 tAA[2] += c[0]*c[0]*c[0]*c[1];
398 tAA[3] += c[1]*c[1]*c[1]*c[1];
399 tAA[4] += c[0]*c[1]*c[1]*c[1];
400 tAA[5] += c[0]*c[0]*c[1]*c[1];
401
402 tAb[0] += c[0]*c[0]*c[2];
403 tAb[1] += c[1]*c[1]*c[2];
404 tAb[2] += c[0]*c[1]*c[2];
405
406 tAA[0] += d[0]*d[0]*d[0]*d[0];
407 tAA[1] += d[0]*d[0]*d[1]*d[1];
408 tAA[2] += d[0]*d[0]*d[0]*d[1];
409 tAA[3] += d[1]*d[1]*d[1]*d[1];
410 tAA[4] += d[0]*d[1]*d[1]*d[1];
411 tAA[5] += d[0]*d[0]*d[1]*d[1];
412
413 tAb[0] += d[0]*d[0]*d[2];
414 tAb[1] += d[1]*d[1]*d[2];
415 tAb[2] += d[0]*d[1]*d[2];
416
417 return;
418}
419
436int MMG5_solveDefmetregSys( MMG5_pMesh mesh, double r[3][3], double c[3],
437 double tAA[6], double tAb[3], double *m,
438 double isqhmin, double isqhmax, double hausd)
439{
440 double intm[3], kappa[2], vp[2][2], b0[3], b1[3], b2[3];
441 static int mmgWarn0=0;
442
443 memset(intm,0x0,3*sizeof(double));
444
445 /* case planar surface : tAb = 0 => no curvature */
446 /* isotropic metric with hmax size*/
447
448 if((tAb[0]*tAb[0] + tAb[1]*tAb[1] + tAb[2]*tAb[2]) < MMG5_EPSD) {
449 m[0] = isqhmax;
450 m[1] = 0;
451 m[2] = 0;
452 m[3] = isqhmax;
453 m[4] = 0;
454 m[5] = isqhmax;
455 return 1;
456 }
457
458 /* solve now (a b c) = tAA^{-1} * tAb */
459 if ( !MMG5_sys33sym(tAA,tAb,c) ) {
460 if ( !mmgWarn0 ) {
461 fprintf(stderr,"\n ## Warning: %s: unable to solve the system on at"
462 " least 1 point.\n",__func__);
463 mmgWarn0 = 1;
464 }
465 return 0;
466 }
467 intm[0] = 2.0*c[0];
468 intm[1] = c[2];
469 intm[2] = 2.0*c[1];
470
471 /* At this point, intm stands for the integral matrix of Taubin's approach : vp[0] and vp[1]
472 are the two pr. directions of curvature, and the two curvatures can be inferred from lambdas*/
473 MMG5_eigensym(intm,kappa,vp);
474
475 /* Truncation of eigenvalues */
476 kappa[0] = 2.0/9.0 * fabs(kappa[0])/hausd;
477 kappa[0] = MG_MIN(kappa[0],isqhmin);
478 kappa[0] = MG_MAX(kappa[0],isqhmax);
479
480 kappa[1] = 2.0/9.0 * fabs(kappa[1])/hausd;
481 kappa[1] = MG_MIN(kappa[1],isqhmin);
482 kappa[1] = MG_MAX(kappa[1],isqhmax);
483
484 /* Send back the metric to the canonical basis of tangent plane :
485 diag(lambda) = {^t}vp * M * vp, M = vp * diag(lambda) * {^t}vp */
486 intm[0] = kappa[0]*vp[0][0]*vp[0][0] + kappa[1]*vp[1][0]*vp[1][0];
487 intm[1] = kappa[0]*vp[0][0]*vp[0][1] + kappa[1]*vp[1][0]*vp[1][1];
488 intm[2] = kappa[0]*vp[0][1]*vp[0][1] + kappa[1]*vp[1][1]*vp[1][1];
489
490 /* At this point, intm (with 0 replaced by isqhmax in the z direction) is the
491 desired metric, except it is expressed in the rotated bc, that is intm = R
492 * metric in bc * ^t R, so metric in bc = ^tR*intm*R */
493 /* b0, b1 and b2 are the lines of matrix intm*R */
494 // intm = intm[0] intm[1] 0
495 // intm[1] intm[2] 0
496 // 0 0 isqhmax
497
498 b0[0] = intm[0]*r[0][0] + intm[1]*r[1][0];
499 b0[1] = intm[0]*r[0][1] + intm[1]*r[1][1];
500 b0[2] = intm[0]*r[0][2] + intm[1]*r[1][2];
501 b1[0] = intm[1]*r[0][0] + intm[2]*r[1][0];
502 b1[1] = intm[1]*r[0][1] + intm[2]*r[1][1];
503 b1[2] = intm[1]*r[0][2] + intm[2]*r[1][2];
504 b2[0] = isqhmax*r[2][0];
505 b2[1] = isqhmax*r[2][1];
506 b2[2] = isqhmax*r[2][2];
507
508 m[0] = r[0][0] * b0[0] + r[1][0] * b1[0] + r[2][0] * b2[0];
509 m[1] = r[0][0] * b0[1] + r[1][0] * b1[1] + r[2][0] * b2[1];
510 m[2] = r[0][0] * b0[2] + r[1][0] * b1[2] + r[2][0] * b2[2];
511
512 m[3] = r[0][1] * b0[1] + r[1][1] * b1[1] + r[2][1] * b2[1];
513 m[4] = r[0][1] * b0[2] + r[1][1] * b1[2] + r[2][1] * b2[2];
514
515 m[5] = r[0][2] * b0[2] + r[1][2] * b1[2] + r[2][2] * b2[2];
516
517 return 1;
518}
519
539 double r[3][3], double c[3],
540 double tAA[6], double tAb[3], double *m,
541 double isqhmin, double isqhmax, double hausd)
542{
543 MMG5_pPoint p1;
544 double intm[3], kappa[2], vp[2][2], b0[3], b1[3], b2[3], kappacur;
545 double gammasec[3],tau[2], ux, uy, uz, ps1, l, ll, *t, *t1;
546 int i;
547 static int8_t mmgWarn=0;
548
549 (void)hausd;
550
551 memset(intm,0x0,3*sizeof(double));
552
553 /* case planar surface : tAb = 0 => no curvature */
554 /* isotropic metric with hmax size*/
555 if((tAb[0]*tAb[0] + tAb[1]*tAb[1] + tAb[2]*tAb[2]) < MMG5_EPSD) {
556 m[0] = isqhmax;
557 m[1] = 0;
558 m[2] = 0;
559 m[3] = isqhmax;
560 m[4] = 0;
561 m[5] = isqhmax;
562 return 1;
563 }
564
565 /* solve now (a b c) = tAA^{-1} * tAb */
566 if ( !MMG5_sys33sym(tAA,tAb,c) ) {
567 if ( !mmgWarn ) {
568 fprintf(stderr,"\n ## Warning: %s: unable to solve the system on at"
569 " least 1 point.\n", __func__);
570 mmgWarn = 1;
571 }
572 return 0;
573 }
574 intm[0] = 2.0*c[0];
575 intm[1] = c[2];
576 intm[2] = 2.0*c[1];
577
578 /* At this point, intm stands for the integral matrix of Taubin's approach :
579 vp[0] and vp[1] are the two pr. directions of curvature, and the two
580 curvatures can be inferred from lambdas*/
581 MMG5_eigensym(intm,kappa,vp);
582
583 /* Truncation of eigenvalues */
584 kappa[0] = 2.0/9.0 * fabs(kappa[0])/mesh->info.hausd;
585 kappa[0] = MG_MIN(kappa[0],isqhmin);
586 kappa[0] = MG_MAX(kappa[0],isqhmax);
587
588 kappa[1] = 2.0/9.0 * fabs(kappa[1])/mesh->info.hausd;
589 kappa[1] = MG_MIN(kappa[1],isqhmin);
590 kappa[1] = MG_MAX(kappa[1],isqhmax);
591
592 /* Send back the metric to the canonical basis of tangent plane :
593 diag(lambda) = {^t}vp * M * vp, M = vp * diag(lambda) * {^t}vp */
594 intm[0] = kappa[0]*vp[0][0]*vp[0][0] + kappa[1]*vp[1][0]*vp[1][0];
595 intm[1] = kappa[0]*vp[0][0]*vp[0][1] + kappa[1]*vp[1][0]*vp[1][1];
596 intm[2] = kappa[0]*vp[0][1]*vp[0][1] + kappa[1]*vp[1][1]*vp[1][1];
597
598 /* Now express metric with respect to the approx of the underlying ref
599 * curve */
600 t = &p0->n[0];
601 kappacur = 0.0;
602
603 for (i=0; i<2; i++) {
604 p1 = &mesh->point[ipref[i]];
605 ux = p1->c[0] - p0->c[0];
606 uy = p1->c[1] - p0->c[1];
607 uz = p1->c[2] - p0->c[2];
608
609 ps1 = ux*t[0] + uy*t[1] + uz*t[2];
610 c[0] = MMG5_ATHIRD*ps1*t[0];
611 c[1] = MMG5_ATHIRD*ps1*t[1];
612 c[2] = MMG5_ATHIRD*ps1*t[2];
613
614 b0[0] = r[0][0]*c[0] + r[0][1]*c[1] + r[0][2]*c[2];
615 b0[1] = r[1][0]*c[0] + r[1][1]*c[1] + r[1][2]*c[2];
616 b0[2] = r[2][0]*c[0] + r[2][1]*c[1] + r[2][2]*c[2];
617
618 if ( (MG_CRN & p1->tag) || (MG_NOM & p1->tag) ) {
619 c[0] = p1->c[0] - MMG5_ATHIRD*ux;
620 c[1] = p1->c[1] - MMG5_ATHIRD*uy;
621 c[2] = p1->c[2] - MMG5_ATHIRD*uz;
622 }
623 else {
624 assert(MG_REF & p1->tag);
625 t1 = &(p1->n[0]);
626 ps1 = -(ux*t1[0] + uy*t1[1] + uz*t1[2]);
627 c[0] = p1->c[0] + MMG5_ATHIRD*ps1*t1[0];
628 c[1] = p1->c[1] + MMG5_ATHIRD*ps1*t1[1];
629 c[2] = p1->c[2] + MMG5_ATHIRD*ps1*t1[2];
630 }
631 c[0] -= p0->c[0];
632 c[1] -= p0->c[1];
633 c[2] -= p0->c[2];
634
635 b1[0] = r[0][0]*c[0] + r[0][1]*c[1] + r[0][2]*c[2];
636 b1[1] = r[1][0]*c[0] + r[1][1]*c[1] + r[1][2]*c[2];
637 b1[2] = r[2][0]*c[0] + r[2][1]*c[1] + r[2][2]*c[2];
638
639 /* Everything is expressed in the rotated frame */
640 tau[0] = 3.0*b0[0];
641 tau[1] = 3.0*b0[1];
642 ll = tau[0]*tau[0] + tau[1]*tau[1];
643 if ( ll < MMG5_EPSD ) {
644 kappacur = isqhmax;
645 continue;
646 }
647 l = 1.0 / sqrt(ll);
648 tau[0] *= l;
649 tau[1] *= l;
650
651 gammasec[0] = -12.0*b0[0] + 6.0*b1[0];
652 gammasec[1] = -12.0*b0[1] + 6.0*b1[1];
653 gammasec[2] = -12.0*b0[2] + 6.0*b1[2];
654
655 ps1 = tau[0]*gammasec[0] + tau[1]*gammasec[1];
656 c[0] = gammasec[0] - ps1*tau[0];
657 c[1] = gammasec[1] - ps1*tau[1];
658 c[2] = gammasec[2];
659
660 // p.s. with normal at p0
661 kappacur = MG_MAX(kappacur,MG_MAX(0.0,1.0/ll*fabs(c[2])));
662 }
663
664 /* Rotation of tangent vector : tau is reused */
665 c[0] = r[0][0]*t[0] + r[0][1]*t[1] + r[0][2]*t[2];
666 c[1] = r[1][0]*t[0] + r[1][1]*t[1] + r[1][2]*t[2];
667 c[2] = r[2][0]*t[0] + r[2][1]*t[1] + r[2][2]*t[2];
668 memcpy(tau,&c[0],2*sizeof(double));
669
670 /* Truncation of curvature */
671 kappacur = 1.0/8.0 * kappacur/mesh->info.hausd;
672 kappacur = MG_MIN(kappacur,isqhmin);
673 kappacur = MG_MAX(kappacur,isqhmax);
674
675 /* The associated matrix in basis (rt, orth rt) */
676 c[0] = kappacur*tau[0]*tau[0] + isqhmax*tau[1]*tau[1];
677 c[1] = (kappacur - isqhmax)*tau[0]*tau[1];
678 c[2] = kappacur*tau[1]*tau[1] + isqhmax*tau[0]*tau[0];
679
680 /* Reuse b0 for commodity */
681 MMG5_intmetsavedir(mesh,c,intm,b0);
682 memcpy(intm,b0,3*sizeof(double));
683
684 /* At this point, intm (with 0 replaced by isqhmax in the z direction) is the
685 desired metric, except it is expressed in the rotated bc, that is intm = R
686 * metric in bc * ^t R, so metric in bc = ^tR*intm*R */
687 // intm = intm[0] intm[1] 0
688 // intm[1] intm[2] 0
689 // 0 0 isqhmax
690
691 /* b0 and b1 serve now for nothing : let them be the lines of matrix intm*R */
692 b0[0] = intm[0]*r[0][0] + intm[1]*r[1][0];
693 b0[1] = intm[0]*r[0][1] + intm[1]*r[1][1];
694 b0[2] = intm[0]*r[0][2] + intm[1]*r[1][2];
695 b1[0] = intm[1]*r[0][0] + intm[2]*r[1][0];
696 b1[1] = intm[1]*r[0][1] + intm[2]*r[1][1];
697 b1[2] = intm[1]*r[0][2] + intm[2]*r[1][2];
698 b2[0] = isqhmax*r[2][0];
699 b2[1] = isqhmax*r[2][1];
700 b2[2] = isqhmax*r[2][2];
701
702 m[0] = r[0][0] * b0[0] + r[1][0] * b1[0] + r[2][0] * b2[0];
703 m[1] = r[0][0] * b0[1] + r[1][0] * b1[1] + r[2][0] * b2[1];
704 m[2] = r[0][0] * b0[2] + r[1][0] * b1[2] + r[2][0] * b2[2];
705
706 m[3] = r[0][1] * b0[1] + r[1][1] * b1[1] + r[2][1] * b2[1];
707 m[4] = r[0][1] * b0[2] + r[1][1] * b1[2] + r[2][1] * b2[2];
708
709 m[5] = r[0][2] * b0[2] + r[1][2] * b1[2] + r[2][2] * b2[2];
710
711 return 1;
712}
713
765 MMG5_int* iprid, double isqhmin,double isqhmax)
766{
767 int i;
768 double n0[3],tau[3],gammasec[3],c[3],ps,ll,l,m;
769 double b0[3],b1[3],kappacur;
770
771 m = isqhmax;
772 for (i=0; i<2; i++) {
773 // Remark: bezierEdge don't use n0 in case of a ridge so it's ok to call it
774 // with an undefined n0.
775 MMG5_bezierEdge(mesh,idp,iprid[i],b0,b1,1,n0);
776
777 /* tau is the bezier curve derivative in p0 (parametric coor t=0) */
778 tau[0] = 3.0*(b0[0] - p0->c[0]);
779 tau[1] = 3.0*(b0[1] - p0->c[1]);
780 tau[2] = 3.0*(b0[2] - p0->c[2]);
781 ll = tau[0]*tau[0] + tau[1]*tau[1] + tau[2]*tau[2];
782 if ( ll < MMG5_EPSD ) continue;
783 l = 1.0 / sqrt(ll);
784 tau[0] *= l;
785 tau[1] *= l;
786 tau[2] *= l;
787
788 /* Acceleration of the bezier curve in p0 (parameteric coor t=0) in
789 * canonical basis */
790 gammasec[0] = 6.0*p0->c[0] -12.0*b0[0] + 6.0*b1[0];
791 gammasec[1] = 6.0*p0->c[1] -12.0*b0[1] + 6.0*b1[1];
792 gammasec[2] = 6.0*p0->c[2] -12.0*b0[2] + 6.0*b1[2];
793
794 /* Scalar component of acceleration along tangent field (ie along velocity) */
795 ps = tau[0]*gammasec[0] + tau[1]*gammasec[1] + tau[2]*gammasec[2];
796
797 /* Normal component of acceleration along velocity (ps*tau[] being the vector
798 * component along velocity) */
799 c[0] = gammasec[0] - ps*tau[0];
800 c[1] = gammasec[1] - ps*tau[1];
801 c[2] = gammasec[2] - ps*tau[2];
802
803 /* Evaluation of curvature (derivative of unit tangent vector, i.e. change
804 * in direction): be T the unit tangent vector, s. a. T = v/||v||, kappa =
805 * ||T'||/||v|| = sqrt(c[0]) /||v||^2 */
806 kappacur = MG_MAX(0.0,1.0/ll*sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]));
807
808 /* Computation of size from the mesh dimension and the curvature */
809 kappacur = 1.0/8.0*kappacur/mesh->info.hausd;
810 kappacur = MG_MIN(kappacur,isqhmin);
811 kappacur = MG_MAX(kappacur,isqhmax);
812 m = MG_MAX(m,kappacur);
813 }
814 return m;
815}
816
836double MMG5_ridSizeInNormalDir(MMG5_pMesh mesh,int i0,double* bcu,
837 MMG5_Bezier *b,double isqhmin,double isqhmax)
838{
839 double lambda[2],Jacb[3][2],Hb[3][3],tau[3],ll,l,gammasec[3],c[3];
840 double ps,kappacur;
841
842 if ( i0 == 0 ) { // w = 1, u,v = 0
843 lambda[0] = bcu[1];
844 lambda[1] = bcu[2];
845
846 /* Jacb[i] = Jacobian matrix of i-th component of b at point p0.
847 Jacb[i] = (\partial_u S_p0[i], \partial_v S_p0[i] ) */
848 Jacb[0][0] = 3.0*(b->b[7][0]-b->b[0][0]);
849 Jacb[1][0] = 3.0*(b->b[7][1]-b->b[0][1]);
850 Jacb[2][0] = 3.0*(b->b[7][2]-b->b[0][2]);
851
852 Jacb[0][1] = 3.0*(b->b[6][0]-b->b[0][0]);
853 Jacb[1][1] = 3.0*(b->b[6][1]-b->b[0][1]);
854 Jacb[2][1] = 3.0*(b->b[6][2]-b->b[0][2]);
855
856 /* Hb[i] = hessian matrix of i-th component of b at point p0.
857 Hb[i] = (\partial_u^2 S_p0[i], \partial_v \partial_u S_p0[i],\partial_v^2 S_p0[i]) */
858 Hb[0][0] = 6.0*(b->b[0][0] - 2.0*b->b[7][0] + b->b[8][0]);
859 Hb[1][0] = 6.0*(b->b[0][1] - 2.0*b->b[7][1] + b->b[8][1]);
860 Hb[2][0] = 6.0*(b->b[0][2] - 2.0*b->b[7][2] + b->b[8][2]);
861
862 Hb[0][1] = 6.0*(b->b[0][0] - b->b[7][0] - b->b[6][0] + b->b[9][0]);
863 Hb[1][1] = 6.0*(b->b[0][1] - b->b[7][1] - b->b[6][1] + b->b[9][1]);
864 Hb[2][1] = 6.0*(b->b[0][2] - b->b[7][2] - b->b[6][2] + b->b[9][2]);
865
866 Hb[0][2] = 6.0*(b->b[0][0] - 2.0*b->b[6][0] + b->b[5][0]);
867 Hb[1][2] = 6.0*(b->b[0][1] - 2.0*b->b[6][1] + b->b[5][1]);
868 Hb[2][2] = 6.0*(b->b[0][2] - 2.0*b->b[6][2] + b->b[5][2]);
869 }
870 else if ( i0 == 1 ) { //w = v = 0, u = 1;
871 lambda[0] = bcu[0];
872 lambda[1] = bcu[1];
873
874 Jacb[0][0] = 3.0*(b->b[1][0]-b->b[8][0]);
875 Jacb[1][0] = 3.0*(b->b[1][1]-b->b[8][1]);
876 Jacb[2][0] = 3.0*(b->b[1][2]-b->b[8][2]);
877
878 Jacb[0][1] = 3.0*(b->b[3][0]-b->b[8][0]);
879 Jacb[1][1] = 3.0*(b->b[3][1]-b->b[8][1]);
880 Jacb[2][1] = 3.0*(b->b[3][2]-b->b[8][2]);
881
882 Hb[0][0] = 6.0*(b->b[1][0] - 2.0*b->b[8][0] + b->b[7][0]);
883 Hb[1][0] = 6.0*(b->b[1][1] - 2.0*b->b[8][1] + b->b[7][1]);
884 Hb[2][0] = 6.0*(b->b[1][2] - 2.0*b->b[8][2] + b->b[7][2]);
885
886 Hb[0][1] = 6.0*(b->b[7][0] - b->b[8][0] - b->b[9][0] + b->b[3][0]);
887 Hb[1][1] = 6.0*(b->b[7][1] - b->b[8][1] - b->b[9][1] + b->b[3][1]);
888 Hb[2][1] = 6.0*(b->b[7][2] - b->b[8][2] - b->b[9][2] + b->b[3][2]);
889
890 Hb[0][2] = 6.0*(b->b[4][0] - 2.0*b->b[9][0] + b->b[7][0]);
891 Hb[1][2] = 6.0*(b->b[4][1] - 2.0*b->b[9][1] + b->b[7][1]);
892 Hb[2][2] = 6.0*(b->b[4][2] - 2.0*b->b[9][2] + b->b[7][2]);
893 }
894 else { //w =u = 0, v =1
895 lambda[0] = bcu[2];
896 lambda[1] = bcu[0];
897
898 Jacb[0][0] = 3.0*(b->b[4][0]-b->b[5][0]);
899 Jacb[1][0] = 3.0*(b->b[4][1]-b->b[5][1]);
900 Jacb[2][0] = 3.0*(b->b[4][2]-b->b[5][2]);
901
902 Jacb[0][1] = 3.0*(b->b[2][0]-b->b[5][0]);
903 Jacb[1][1] = 3.0*(b->b[2][1]-b->b[5][1]);
904 Jacb[2][1] = 3.0*(b->b[2][2]-b->b[5][2]);
905
906 Hb[0][0] = 6.0*(b->b[3][0] - 2.0*b->b[9][0] + b->b[6][0]);
907 Hb[1][0] = 6.0*(b->b[3][1] - 2.0*b->b[9][1] + b->b[6][1]);
908 Hb[2][0] = 6.0*(b->b[3][2] - 2.0*b->b[9][2] + b->b[6][2]);
909
910 Hb[0][1] = 6.0*(b->b[4][0] - b->b[5][0] - b->b[9][0] + b->b[6][0]);
911 Hb[1][1] = 6.0*(b->b[4][1] - b->b[5][1] - b->b[9][1] + b->b[6][1]);
912 Hb[2][1] = 6.0*(b->b[4][2] - b->b[5][2] - b->b[9][2] + b->b[6][2]);
913
914 Hb[0][2] = 6.0*(b->b[2][0] - 2.0*b->b[5][0] + b->b[6][0]);
915 Hb[1][2] = 6.0*(b->b[2][1] - 2.0*b->b[5][1] + b->b[6][1]);
916 Hb[2][2] = 6.0*(b->b[2][2] - 2.0*b->b[5][2] + b->b[6][2]);
917 }
918
919 /* tau = jacb *(lambda0,lambda1)*/
920 tau[0] = Jacb[0][0]*lambda[0] + Jacb[0][1]*lambda[1];
921 tau[1] = Jacb[1][0]*lambda[0] + Jacb[1][1]*lambda[1];
922 tau[2] = Jacb[2][0]*lambda[0] + Jacb[2][1]*lambda[1];
923 ll = tau[0]*tau[0] + tau[1]*tau[1] + tau[2]*tau[2];
924 if ( ll < MMG5_EPSD ) return 0;
925
926 l = 1.0 / sqrt(ll);
927 tau[0] *= l;
928 tau[1] *= l;
929 tau[2] *= l;
930
931 gammasec[0] = Hb[0][0]*lambda[0]*lambda[0] + 2.0*Hb[0][1]*lambda[0]*lambda[1] + Hb[0][2]*lambda[1]*lambda[1];
932 gammasec[1] = Hb[1][0]*lambda[0]*lambda[0] + 2.0*Hb[1][1]*lambda[0]*lambda[1] + Hb[1][2]*lambda[1]*lambda[1];
933 gammasec[2] = Hb[2][0]*lambda[0]*lambda[0] + 2.0*Hb[2][1]*lambda[0]*lambda[1] + Hb[2][2]*lambda[1]*lambda[1];
934
935 ps = tau[0]*gammasec[0] + tau[1]*gammasec[1] + tau[2]*gammasec[2];
936
937 /* Normal component of acceleration along velocity (ps*tau[] being the vector
938 * component along velocity) */
939 c[0] = gammasec[0] - ps*tau[0];
940 c[1] = gammasec[1] - ps*tau[1];
941 c[2] = gammasec[2] - ps*tau[2];
942
943 /* Evaluation of curvature (derivative of unit tangent vector, i.e. change
944 * in direction) */
945 kappacur = MG_MAX(0.0,1.0/ll*sqrt(c[0]*c[0] + c[1]*c[1] + c[2]*c[2]));
946
947 /* Computation of size from the mesh dimension and the curvature */
948 kappacur = 1.0/8.0 * kappacur/mesh->info.hausd;
949 kappacur = MG_MIN(kappacur,isqhmin);
950 kappacur = MG_MAX(kappacur,isqhmax);
951
952 return kappacur;
953}
954
975MMG5_int MMG5_grad2metSurf(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria pt, MMG5_int np1,
976 MMG5_int np2)
977{
978 MMG5_pPoint p1,p2;
979 double *mm1,*mm2,*nn1,*nn2,ps1,ps2,ux,uy,uz,m1[6],m2[6],n1[3],n2[3],nt[3];
980 double r1[3][3],r2[3][3],t1[2],t2[2],c[3],mtan1[3],mtan2[3],mr1[6],mr2[6];
981 double mtmp[3][3],val,rbasis[3][3];
982 double /*,l1,l2*/l,dd;
983 double lambda[2],vp[2][2],alpha,beta,mu[3];
984 int kmin,idx;
985 int8_t ichg;
986
987 p1 = &mesh->point[np1];
988 p2 = &mesh->point[np2];
989
990 ux = p2->c[0] - p1->c[0];
991 uy = p2->c[1] - p1->c[1];
992 uz = p2->c[2] - p1->c[2];
993
994 mm1 = &met->m[6*np1];
995 mm2 = &met->m[6*np2];
996
997 if( !MMG5_nortri(mesh,pt,nt) )
998 return -1;
999
1000 /* Recover normal and metric associated to p1 */
1001 if( MG_SIN(p1->tag) || (MG_NOM & p1->tag)){
1002 memcpy(n1,nt,3*sizeof(double));
1003 memcpy(m1,mm1,6*sizeof(double));
1004 }
1005 else if( MG_GEO & p1->tag ){
1006 nn1 = &mesh->xpoint[p1->xp].n1[0];
1007 nn2 = &mesh->xpoint[p1->xp].n2[0];
1008 ps1 = nt[0]*nn1[0] + nt[1]*nn1[1] + nt[2]*nn1[2];
1009 ps2 = nt[0]*nn2[0] + nt[1]*nn2[1] + nt[2]*nn2[2];
1010
1011 if( fabs(ps1) < fabs(ps2))
1012 memcpy(n1,nn2,3*sizeof(double));
1013 else
1014 memcpy(n1,nn1,3*sizeof(double));
1015
1016 /* Note that rbasis is unused in this function */
1017 if( !MMG5_buildridmet(mesh,met,np1,ux,uy,uz,m1,rbasis) )
1018 return -1;
1019 }
1020 else if( ( MG_REF & p1->tag ) || (MG_BDY & p1->tag) ){
1021 // if MG_BDY, we are in mmg3d: the normal is stored in the xPoint
1022 memcpy(n1,&(mesh->xpoint[p1->xp].n1[0]),3*sizeof(double));
1023 memcpy(m1,mm1,6*sizeof(double));
1024 }
1025 else{
1026 // mmgs only
1027 memcpy(n1,p1->n,3*sizeof(double));
1028 memcpy(m1,mm1,6*sizeof(double));
1029 }
1030
1031 /* Recover normal and metric associated to p2 */
1032 if ( MG_SIN(p2->tag) || (MG_NOM & p2->tag)) {
1033 memcpy(n2,nt,3*sizeof(double));
1034 memcpy(m2,mm2,6*sizeof(double));
1035 }
1036 else if ( MG_GEO & p2->tag ) {
1037 nn1 = &mesh->xpoint[p2->xp].n1[0];
1038 nn2 = &mesh->xpoint[p2->xp].n2[0];
1039 ps1 = nt[0]*nn1[0] + nt[1]*nn1[1] + nt[2]*nn1[2];
1040 ps2 = nt[0]*nn2[0] + nt[1]*nn2[1] + nt[2]*nn2[2];
1041
1042 if( fabs(ps1) < fabs(ps2))
1043 memcpy(n2,nn2,3*sizeof(double));
1044 else
1045 memcpy(n2,nn1,3*sizeof(double));
1046
1047 /* Note that rbasis is unused in this function */
1048 if( !MMG5_buildridmet(mesh,met,np2,ux,uy,uz,m2,rbasis) )
1049 return -1;
1050 }
1051 else if( (MG_REF & p2->tag) || (MG_BDY & p2->tag) ){
1052 // if MG_BDY, we are in mmg3d: the normal is stored in the xPoint
1053 memcpy(n2,&(mesh->xpoint[p2->xp].n1[0]),3*sizeof(double));
1054 memcpy(m2,mm2,6*sizeof(double));
1055 }
1056 else{
1057 //mmgs only
1058 memcpy(n2,p2->n,3*sizeof(double));
1059 memcpy(m2,mm2,6*sizeof(double));
1060 }
1061
1062 /* Rotation matrices mapping n1/n2 to e_3 */
1063 MMG5_rotmatrix(n1,r1);
1064 MMG5_rotmatrix(n2,r2);
1065
1066 /* Geodesic length of support curve to edge i */
1067 l = sqrt(ux*ux+uy*uy+uz*uz);
1068
1069 /* Characteristic sizes in direction of support curve */
1070 MMG5_rmtr(r1,m1,mr1);
1071
1072 mtan1[0] = mr1[0];
1073 mtan1[1] = mr1[1];
1074 mtan1[2] = mr1[3];
1075
1076 c[0] = r1[0][0]*ux + r1[0][1]*uy + r1[0][2]*uz;
1077 c[1] = r1[1][0]*ux + r1[1][1]*uy + r1[1][2]*uz;
1078
1079 memcpy(t1,c,2*sizeof(double));
1080 /* Here we work in the tangent plane (thus in 2d) */
1081 dd = t1[0]*t1[0] + t1[1]*t1[1];
1082 if(dd < MMG5_EPSD2)
1083 return -1;
1084
1085 dd = 1.0/sqrt(dd);
1086 t1[0] *= dd;
1087 t1[1] *= dd;
1088
1089 /* edge length in metric mtan1: sqrt(t^(t1) * mtan1 * t1). */
1090 ps1 = mtan1[0]*t1[0]*t1[0] + 2.0*mtan1[1]*t1[0]*t1[1] + mtan1[2]*t1[1]*t1[1];
1091 assert ( ps1 > 0. );
1092 ps1 = sqrt(ps1);
1093
1094 MMG5_rmtr(r2,m2,mr2);
1095
1096 mtan2[0] = mr2[0];
1097 mtan2[1] = mr2[1];
1098 mtan2[2] = mr2[3];
1099
1100 c[0] = - ( r2[0][0]*ux + r2[0][1]*uy + r2[0][2]*uz );
1101 c[1] = - ( r2[1][0]*ux + r2[1][1]*uy + r2[1][2]*uz );
1102 memcpy(t2,c,2*sizeof(double));
1103
1104 dd = t2[0]*t2[0] + t2[1]*t2[1];
1105 if(dd < MMG5_EPSD2)
1106 return -1;
1107
1108 dd = 1.0/sqrt(dd);
1109 t2[0] *= dd;
1110 t2[1] *= dd;
1111
1112 /* edge length: sqrt(t^(t2) * mtan2 * t2) */
1113 ps2 = mtan2[0]*t2[0]*t2[0] + 2.0*mtan2[1]*t2[0]*t2[1] + mtan2[2]*t2[1]*t2[1];
1114 assert ( ps2 > 0. );
1115 ps2 = sqrt(ps2);
1116
1117 /* Metric in p1 has to be changed ( M1 > M2 ) */
1118 if( ps2 > ps1 ){
1119 /* compute alpha = h2 + hgrad*l */
1120 alpha = ps2 /(1.0+mesh->info.hgrad*l*ps2);
1121 if( ps1 >= alpha - MMG5_EPS ) {
1122 /* No need to graduate: l_{M2+hgrad*l} < l_{M1} => M2+hgrad*l > M1 */
1123 return -1;
1124 }
1125 MMG5_eigensym(mtan1,lambda,vp);
1126 /* Project the vector t1 along the main directions of the metric */
1127 /* Remark: along the third direction mr1 is already diagonal,
1128 * thus vp[2][.] =( 0 0 1) and vp[.][2] = 0. */
1129 c[0] = t1[0]*vp[0][0] + t1[1]*vp[0][1] ;
1130 c[1] = t1[0]*vp[1][0] + t1[1]*vp[1][1] ;
1131
1132 /* Find index of the maximum value of c: this allow to detect which of the
1133 * main directions of the metric is closest to our edge direction. We want
1134 * that our new metric respect the gradation related to the size associated
1135 * to this main direction (the ichg direction). */
1136 ichg = 0;
1137 val = fabs(c[ichg]);
1138 for (idx = 1; idx<2; ++idx) {
1139 if ( fabs(c[idx]) > val ) {
1140 val = fabs(c[idx]);
1141 ichg = idx;
1142 }
1143 }
1144 assert(c[ichg]*c[ichg] > MMG5_EPS );
1145 /* Compute beta coef such as lambda_1 = beta*lambda_1 => h1 = h2 + hgrad*l
1146 * with h1 = 1/ps1 and h2 = 1/ps2 (see p317 of Charles Dapogny Thesis). */
1147 beta = (alpha*alpha - ps1*ps1)/(c[ichg]*c[ichg]);
1148
1149 /* Metric update */
1150 if( MG_SIN(p1->tag) || (MG_NOM & p1->tag)){
1151 /* lambda_new = 0.5 lambda_1 + 0.5 beta lambda_1: here we choose to not
1152 * respect the gradation in order to restric the influence of the singular
1153 * points. */
1154 mm1[0] += 0.5*beta;
1155 mm1[3] += 0.5*beta;
1156 mm1[5] += 0.5*beta;
1157 }
1158 else if( p1->tag & MG_GEO ){
1159 /* lambda[ichg] is the metric eigenvalue associated to the main metric
1160 * direction closest to our edge direction. Find were is stored this
1161 * eigenvalue in our special storage of ridge metric (mm-lambda = 0) and
1162 * update it. */
1163 c[0] = fabs(mm1[0]-lambda[ichg]);
1164 c[1] = fabs(mm1[1]-lambda[ichg]);
1165 c[2] = fabs(mm1[2]-lambda[ichg]);
1166
1167 /* Find index of the minimum value of c */
1168 kmin = 0;
1169 val = fabs(c[kmin]);
1170 for (idx = 1; idx<3; ++idx) {
1171 if ( fabs(c[idx]) < val ) {
1172 val = fabs(c[idx]);
1173 kmin = idx;
1174 }
1175 }
1176 mm1[kmin] += beta;
1177 }
1178 else{
1179 /* Update the metric eigenvalue associated to the main metric direction
1180 * which is closest to our edge direction (because this is the one that is
1181 * the more influent on our edge length). */
1182 mu[0] = lambda[0];
1183 mu[1] = lambda[1];
1184 mu[2] = mr1[5];
1185
1186 mu[ichg] += beta;
1187
1188 mtan1[0] = mu[0]*vp[0][0]*vp[0][0] + mu[1]*vp[1][0]*vp[1][0];
1189 mtan1[1] = mu[0]*vp[0][0]*vp[0][1] + mu[1]*vp[1][0]*vp[1][1];
1190 mtan1[2] = mu[0]*vp[0][1]*vp[0][1] + mu[1]*vp[1][1]*vp[1][1];
1191
1192 /* Return in initial basis */
1193 /* Because of the rotation, we know that:
1194 * mr.[2] = mr.[4]= 0 */
1195 mtmp[0][0] = mtan1[0]*r1[0][0] + mtan1[1]*r1[1][0];
1196 mtmp[0][1] = mtan1[0]*r1[0][1] + mtan1[1]*r1[1][1];
1197 mtmp[0][2] = mtan1[0]*r1[0][2] + mtan1[1]*r1[1][2];
1198
1199 mtmp[1][0] = mtan1[1]*r1[0][0] + mtan1[2]*r1[1][0];
1200 mtmp[1][1] = mtan1[1]*r1[0][1] + mtan1[2]*r1[1][1];
1201 mtmp[1][2] = mtan1[1]*r1[0][2] + mtan1[2]*r1[1][2];
1202
1203 mtmp[2][0] = mr1[5]*r1[2][0];
1204 mtmp[2][1] = mr1[5]*r1[2][1];
1205 mtmp[2][2] = mr1[5]*r1[2][2];
1206
1207 m1[0] = r1[0][0]*mtmp[0][0] + r1[1][0]*mtmp[1][0] + r1[2][0]*mtmp[2][0];
1208 m1[1] = r1[0][0]*mtmp[0][1] + r1[1][0]*mtmp[1][1] + r1[2][0]*mtmp[2][1];
1209 m1[2] = r1[0][0]*mtmp[0][2] + r1[1][0]*mtmp[1][2] + r1[2][0]*mtmp[2][2];
1210
1211 m1[3] = r1[0][1]*mtmp[0][1] + r1[1][1]*mtmp[1][1] + r1[2][1]*mtmp[2][1];
1212 m1[4] = r1[0][1]*mtmp[0][2] + r1[1][1]*mtmp[1][2] + r1[2][1]*mtmp[2][2];
1213
1214 m1[5] = r1[0][2]*mtmp[0][2] + r1[1][2]*mtmp[1][2] + r1[2][2]*mtmp[2][2];
1215
1216 memcpy(mm1,m1,6*sizeof(double));
1217 }
1218 return np1;
1219 }
1220 /* Metric in p2 has to be changed ( M2 > M1 ) */
1221 else{
1222 alpha = ps1 /(1.0+mesh->info.hgrad*l*ps1);
1223 if( ps2 >= alpha - MMG5_EPS) {
1224 /* No need to graduate: l_{M1+hgrad*l} < l_{M2} => M1+hgrad*l > M2 */
1225 return -1;
1226 }
1227 MMG5_eigensym(mtan2,lambda,vp);
1228
1229 c[0] = t2[0]*vp[0][0] + t2[1]*vp[0][1] ;
1230 c[1] = t2[0]*vp[1][0] + t2[1]*vp[1][1] ;
1231
1232 /* Detect which of the main directions of the metric is closest to our edge
1233 * direction. */
1234 ichg = 0;
1235 val = fabs(c[ichg]);
1236 for (idx = 1; idx<2; ++idx) {
1237 if ( fabs(c[idx]) > val ) {
1238 val = fabs(c[idx]);
1239 ichg = idx;
1240 }
1241 }
1242 assert(c[ichg]*c[ichg] > MMG5_EPS );
1243
1244 /* Compute beta coef such as lambda_2new = beta*lambda_2 => h2 = h1 + hgrad*l
1245 * (see p317 of Charles Dapogny Thesis). */
1246 beta = (alpha*alpha - ps2*ps2)/(c[ichg]*c[ichg]);
1247
1248 /* Metric update: update the metric eigenvalue associated to the main metric
1249 * direction which is closest to our edge direction (because this is the
1250 * one that is the more influent on our edge length). */
1251 if( MG_SIN(p2->tag) || (MG_NOM & p2->tag)){
1252 /* lambda_new = 0.5 lambda_1 + 0.5 beta lambda_1: here we choose to not
1253 * respect the gradation in order to restric the influence of the singular
1254 * points. */
1255 mm2[0] += 0.5*beta;
1256 mm2[3] += 0.5*beta;
1257 mm2[5] += 0.5*beta;
1258 }
1259 else if( p2->tag & MG_GEO ){
1260 c[0] = fabs(mm2[0]-lambda[ichg]);
1261 c[1] = fabs(mm2[1]-lambda[ichg]);
1262 c[2] = fabs(mm2[2]-lambda[ichg]);
1263
1264 kmin = 0;
1265 val = fabs(c[kmin]);
1266 for (idx = 1; idx<3; ++idx) {
1267 if ( fabs(c[idx]) < val ) {
1268 val = fabs(c[idx]);
1269 kmin = idx;
1270 }
1271 }
1272 mm2[kmin] += beta;
1273 }
1274 else{
1275 mu[0] = lambda[0];
1276 mu[1] = lambda[1];
1277 mu[2] = mr2[5];
1278
1279 mu[ichg] += beta;
1280
1281 mtan2[0] = mu[0]*vp[0][0]*vp[0][0] + mu[1]*vp[1][0]*vp[1][0];
1282 mtan2[1] = mu[0]*vp[0][0]*vp[0][1] + mu[1]*vp[1][0]*vp[1][1];
1283 mtan2[2] = mu[0]*vp[0][1]*vp[0][1] + mu[1]*vp[1][1]*vp[1][1];
1284
1285 /* Return in initial basis */
1286 mtmp[0][0] = mtan2[0]*r2[0][0] + mtan2[1]*r2[1][0];
1287 mtmp[0][1] = mtan2[0]*r2[0][1] + mtan2[1]*r2[1][1];
1288 mtmp[0][2] = mtan2[0]*r2[0][2] + mtan2[1]*r2[1][2];
1289
1290 mtmp[1][0] = mtan2[1]*r2[0][0] + mtan2[2]*r2[1][0];
1291 mtmp[1][1] = mtan2[1]*r2[0][1] + mtan2[2]*r2[1][1];
1292 mtmp[1][2] = mtan2[1]*r2[0][2] + mtan2[2]*r2[1][2];
1293
1294 mtmp[2][0] = mr2[5]*r2[2][0];
1295 mtmp[2][1] = mr2[5]*r2[2][1];
1296 mtmp[2][2] = mr2[5]*r2[2][2];
1297
1298 m2[0] = r2[0][0]*mtmp[0][0] + r2[1][0]*mtmp[1][0] + r2[2][0]*mtmp[2][0];
1299 m2[1] = r2[0][0]*mtmp[0][1] + r2[1][0]*mtmp[1][1] + r2[2][0]*mtmp[2][1];
1300 m2[2] = r2[0][0]*mtmp[0][2] + r2[1][0]*mtmp[1][2] + r2[2][0]*mtmp[2][2];
1301
1302 m2[3] = r2[0][1]*mtmp[0][1] + r2[1][1]*mtmp[1][1] + r2[2][1]*mtmp[2][1];
1303 m2[4] = r2[0][1]*mtmp[0][2] + r2[1][1]*mtmp[1][2] + r2[2][1]*mtmp[2][2];
1304
1305 m2[5] = r2[0][2]*mtmp[0][2] + r2[1][2]*mtmp[1][2] + r2[2][2]*mtmp[2][2];
1306
1307 memcpy(mm2,m2,6*sizeof(double));
1308 }
1309 return np2;
1310 }
1311}
1312
1326int MMG5_simred2d(MMG5_pMesh mesh,double *m,double *n,double dm[2],
1327 double dn[2],double vp[2][2] ) {
1328
1329 double det,lambda[2],imn[4];
1330 int order;
1331 static int8_t mmgWarn0=0;
1332
1333 /* Compute imn = M^{-1}N */
1334 det = m[0]*m[2] - m[1]*m[1];
1335 if ( fabs(det) < MMG5_EPS*MMG5_EPS ) {
1336 if ( !mmgWarn0 ) {
1337 mmgWarn0 = 1;
1338 fprintf(stderr,"\n ## Warning: %s: at least 1 null metric det : %E \n",
1339 __func__,det);
1340 }
1341 return 0;
1342 }
1343 det = 1.0 / det;
1344
1345 imn[0] = det * ( m[2]*n[0] - m[1]*n[1]);
1346 imn[1] = det * ( m[2]*n[1] - m[1]*n[2]);
1347 imn[2] = det * (-m[1]*n[0] + m[0]*n[1]);
1348 imn[3] = det * (-m[1]*n[1] + m[0]*n[2]);
1349
1350 /* Find eigenvalues of imn */
1351 order = MMG5_eigenv2d(0,imn,lambda,vp);
1352
1353 if ( !order ) {
1354 if ( !mmgWarn0 ) {
1355 mmgWarn0 = 1;
1356 fprintf(stderr,"\n ## Warning: %s: at least 1 failing"
1357 " simultaneous reduction.\n",__func__);
1358 }
1359 return 0;
1360 }
1361
1362 /* First case : matrices m and n are homothetic: n = lambda0*m */
1363 if ( order == 2 ) {
1364
1365 /* Subcase where m is diaonal */
1366 if ( fabs(m[1]) < MMG5_EPS ) {
1367 dm[0] = m[0];
1368 dm[1] = m[2];
1369 vp[0][0] = 1;
1370 vp[0][1] = 0;
1371 vp[1][0] = 0;
1372 vp[1][1] = 1;
1373 }
1374 /* Subcase where m is not diagonal; dd,trimn,... are reused */
1375 else
1376 MMG5_eigensym(m,dm,vp);
1377
1378 /* Eigenvalues of metric n */
1379 dn[0] = lambda[0]*dm[0];
1380 dn[1] = lambda[0]*dm[1];
1381
1382 }
1383 /* Second case: both eigenvalues of imn are distinct ; theory says qf associated to m and n
1384 are diagonalizable in basis (vp[0], vp[1]) - the coreduction basis */
1385 else if( order == 1 ) {
1386
1387 /* Compute diagonal values in simultaneous reduction basis */
1388 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];
1389 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];
1390 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];
1391 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];
1392 }
1393
1394 assert ( dm[0] >= MMG5_EPSD2 && dm[1] >= MMG5_EPSD2 && "positive eigenvalue" );
1395 assert ( dn[0] >= MMG5_EPSD2 && dn[1] >= MMG5_EPSD2 && "positive eigenvalue" );
1396
1397 if ( dm[0] < MMG5_EPSOK || dn[0] < MMG5_EPSOK ) { return 0; }
1398 if ( dm[1] < MMG5_EPSOK || dn[1] < MMG5_EPSOK ) { return 0; }
1399
1400 return 1;
1401}
1402
1416int MMG5_simred3d(MMG5_pMesh mesh,double *m,double *n,double dm[3],
1417 double dn[3],double vp[3][3] ) {
1418
1419 double lambda[3],im[6],imn[9];
1420 int order;
1421 static int8_t mmgWarn0=0;
1422
1423 /* Compute imn = M^{-1}N */
1424 if ( !MMG5_invmat ( m,im ) ) {
1425 if ( !mmgWarn0 ) {
1426 mmgWarn0 = 1;
1427 fprintf(stderr,"\n ## Warning: %s: unable to invert the matrix.\n",__func__);
1428 }
1429 return 0;
1430 }
1431
1432 MMG5_mn(im,n,imn);
1433
1434 /* Find eigenvalues of imn */
1435 order = MMG5_eigenv3d(0,imn,lambda,vp);
1436
1437 if ( !order ) {
1438 if ( !mmgWarn0 ) {
1439 mmgWarn0 = 1;
1440 fprintf(stderr,"\n ## Warning: %s: at least 1 failing"
1441 " simultaneous reduction.\n",__func__);
1442 }
1443 return 0;
1444 }
1445
1446 if ( order == 3 ) {
1447 /* First case : matrices m and n are homothetic: n = lambda0*m */
1448 if ( (fabs(m[1]) < MMG5_EPS && fabs(m[2]) < MMG5_EPS
1449 && fabs(m[4]) < MMG5_EPS) ) {
1450 /* Subcase where m is diaonal */
1451 dm[0] = m[0];
1452 dm[1] = m[3];
1453 dm[2] = m[5];
1454 vp[0][0] = 1;
1455 vp[0][1] = 0;
1456 vp[0][2] = 0;
1457 vp[1][0] = 0;
1458 vp[1][1] = 1;
1459 vp[1][2] = 0;
1460 vp[2][0] = 0;
1461 vp[2][1] = 0;
1462 vp[2][2] = 1;
1463 }
1464 else {
1465 /* Subcase where m is not diagonal; dd,trimn,... are reused */
1466 MMG5_eigenv3d(1,m,dm,vp);
1467 }
1468 /* Eigenvalues of metric n */
1469 dn[0] = lambda[0]*dm[0];
1470 dn[1] = lambda[0]*dm[1];
1471 dn[2] = lambda[0]*dm[2];
1472 }
1473 else if( order == 2 ) {
1474 /* Second case: two eigenvalues of imn are coincident (first two entries of
1475 * the lambda array) and one is distinct (last entry).
1476 * Simultaneous reduction gives a block diagonalization. The 2x2 blocks are
1477 * homothetic and can be diagonalized through the eigenvectors of one of the
1478 * two blocks. */
1479 double mred[6],nred[6];
1480 /* project matrices on the coreduction basis: they should have the
1481 * block-diagonal form [ m0, m1, 0, m3, 0, m5 ] */
1482 MMG5_rmtr(vp,m,mred);
1483 MMG5_rmtr(vp,n,nred);
1484 /* compute projections on the last eigenvector (that with multiplicity 1) */
1485 dm[2] = mred[5];
1486 dn[2] = nred[5];
1487 /* re-arrange matrices so that the first three entries describe the
1488 * 2x2 blocks to be diagonalized (the two blocks are homothetic) */
1489 mred[2] = mred[3];
1490 nred[2] = nred[3];
1491 /* diagonalization of the first 2x2 block */
1492 if( fabs(mred[1]) < MMG5_EPS ) {
1493 /* first case: the blocks are diagonal, basis vp is unchanged */
1494 dm[0] = mred[0];
1495 dm[1] = mred[2];
1496 } else {
1497 /* second case: the blocks are not diagonal */
1498 double wp[2][2],up[2][3];
1499 int8_t i,j,k;
1500 MMG5_eigensym(mred,dm,wp);
1501 /* change the basis vp (vp[2] is unchanged) */
1502 for( j = 0; j < 2; j++ ) {
1503 for( i = 0; i < 3; i++ ) {
1504 up[j][i] = 0.;
1505 for( k = 0; k < 2; k++ ) {
1506 up[j][i] += vp[k][i]*wp[j][k];
1507 }
1508 }
1509 }
1510 for( j = 0; j < 2; j++ ) {
1511 for( i = 0; i < 3; i++ ) {
1512 vp[j][i] = up[j][i];
1513 }
1514 }
1515 }
1516 /* homothetic diagonalization of the second 2x2 block */
1517 dn[0] = lambda[0]*dm[0];
1518 dn[1] = lambda[0]*dm[1];
1519 }
1520 else {
1521 /* Third case: eigenvalues of imn are distinct ; theory says qf associated
1522 to m and n are diagonalizable in basis (vp[0], vp[1], vp[2]) - the
1523 coreduction basis */
1524 /* Compute diagonal values in simultaneous reduction basis */
1525 dm[0] = m[0]*vp[0][0]*vp[0][0] + 2.0*m[1]*vp[0][0]*vp[0][1] + 2.0*m[2]*vp[0][0]*vp[0][2]
1526 + m[3]*vp[0][1]*vp[0][1] + 2.0*m[4]*vp[0][1]*vp[0][2] + m[5]*vp[0][2]*vp[0][2];
1527 dm[1] = m[0]*vp[1][0]*vp[1][0] + 2.0*m[1]*vp[1][0]*vp[1][1] + 2.0*m[2]*vp[1][0]*vp[1][2]
1528 + m[3]*vp[1][1]*vp[1][1] + 2.0*m[4]*vp[1][1]*vp[1][2] + m[5]*vp[1][2]*vp[1][2];
1529 dm[2] = m[0]*vp[2][0]*vp[2][0] + 2.0*m[1]*vp[2][0]*vp[2][1] + 2.0*m[2]*vp[2][0]*vp[2][2]
1530 + m[3]*vp[2][1]*vp[2][1] + 2.0*m[4]*vp[2][1]*vp[2][2] + m[5]*vp[2][2]*vp[2][2];
1531
1532 dn[0] = n[0]*vp[0][0]*vp[0][0] + 2.0*n[1]*vp[0][0]*vp[0][1] + 2.0*n[2]*vp[0][0]*vp[0][2]
1533 + n[3]*vp[0][1]*vp[0][1] + 2.0*n[4]*vp[0][1]*vp[0][2] + n[5]*vp[0][2]*vp[0][2];
1534 dn[1] = n[0]*vp[1][0]*vp[1][0] + 2.0*n[1]*vp[1][0]*vp[1][1] + 2.0*n[2]*vp[1][0]*vp[1][2]
1535 + n[3]*vp[1][1]*vp[1][1] + 2.0*n[4]*vp[1][1]*vp[1][2] + n[5]*vp[1][2]*vp[1][2];
1536 dn[2] = n[0]*vp[2][0]*vp[2][0] + 2.0*n[1]*vp[2][0]*vp[2][1] + 2.0*n[2]*vp[2][0]*vp[2][2]
1537 + n[3]*vp[2][1]*vp[2][1] + 2.0*n[4]*vp[2][1]*vp[2][2] + n[5]*vp[2][2]*vp[2][2];
1538 }
1539
1540 assert ( dm[0] >= MMG5_EPSD2 && dm[1] >= MMG5_EPSD2 && dm[2] >= MMG5_EPSD2 && "positive eigenvalue" );
1541 assert ( dn[0] >= MMG5_EPSD2 && dn[1] >= MMG5_EPSD2 && dn[2] >= MMG5_EPSD2 && "positive eigenvalue" );
1542
1543 if ( dm[0] < MMG5_EPSOK || dn[0] < MMG5_EPSOK ) { return 0; }
1544 if ( dm[1] < MMG5_EPSOK || dn[1] < MMG5_EPSOK ) { return 0; }
1545 if ( dm[2] < MMG5_EPSOK || dn[2] < MMG5_EPSOK ) { return 0; }
1546
1547 return 1;
1548}
1549
1562void MMG5_sort_simred( int8_t dim,double *dm,double *dn,double *vp,
1563 double *swap,int8_t *perm ) {
1564 MMG5_nsort(dim,dm,perm);
1565 MMG5_nperm(dim,0,1,dm,swap,perm);
1566 MMG5_nperm(dim,0,1,dn,swap,perm);
1567 for( int8_t i = 0; i < dim; i++ )
1568 MMG5_nperm(dim,i,dim,vp,swap,perm);
1569}
1570
1585int MMG5_test_simred2d(MMG5_pMesh mesh,double *mex,double *nex,double *dmex,double *dnex,double vpex[][2]) {
1586 double dmnum[2],dnnum[2],vpnum[2][2],ivpnum[2][2],mnum[3],nnum[3]; /* Numerical quantities */
1587 double swap[2],maxerr,err;
1588 int8_t perm[2]; /* permutation array */
1589
1591 if( !MMG5_simred2d(mesh,mex,nex,dmnum,dnnum,vpnum ) )
1592 return 0;
1593
1594 /* Naively sort eigenpairs in increasing order */
1595 MMG5_sort_simred(2,dmnum,dnnum,(double *)vpnum,swap,perm);
1596
1597 /* Check diagonal values error in norm inf */
1598 maxerr = MMG5_test_mat_error(2,(double *)dmex,(double *)dmnum);
1599 if( maxerr > 100*MMG5_EPSOK ) {
1600 fprintf(stderr," ## Error first matrix coreduction values: in function %s, max error %e\n",
1601 __func__,maxerr);
1602 return 0;
1603 }
1604 maxerr = MMG5_test_mat_error(2,(double *)dnex,(double *)dnnum);
1605 if( maxerr > 1000*MMG5_EPSOK ) {
1606 fprintf(stderr," ## Error second matrix coreduction values: in function %s, max error %e\n",
1607 __func__,maxerr);
1608 return 0;
1609 }
1610
1611 /* Check eigenvectors error through scalar product */
1612 maxerr = 0.;
1613 for( int8_t i = 0; i < 2; i++ ) {
1614 err = 0.;
1615 for( int8_t j = 0; j < 2; j++ )
1616 err += vpex[i][j] * vpnum[i][j];
1617 err = 1.-fabs(err);
1618 maxerr = MG_MAX(maxerr,err);
1619 }
1620 if( maxerr > MMG5_EPSOK ) {
1621 fprintf(stderr," ## Error matrix coreduction vectors: in function %s, max error %e\n",
1622 __func__,maxerr);
1623 return 0;
1624 }
1625
1627 if( !MMG5_invmat22(vpnum,ivpnum) )
1628 return 0;
1629 MMG5_simredmat(2,mnum,dmnum,(double *)ivpnum);
1630 MMG5_simredmat(2,nnum,dnnum,(double *)ivpnum);
1631
1632 /* Check matrices in norm inf */
1633 maxerr = MMG5_test_mat_error(3,mex,mnum);
1634 if( maxerr > 1.e2*MMG5_EPSOK ) {
1635 fprintf(stderr," ## Error first matrix coreduction recomposition: in function %s, max error %e\n",
1636 __func__,maxerr);
1637 return 0;
1638 }
1639 maxerr = MMG5_test_mat_error(3,nex,nnum);
1640 if( maxerr > 1.e4*MMG5_EPSOK ) {
1641 fprintf(stderr," ## Error second matrix coreduction recomposition: in function %s, max error %e\n",
1642 __func__,maxerr);
1643 return 0;
1644 }
1645
1646 return 1;
1647}
1648
1663int MMG5_test_simred3d(MMG5_pMesh mesh,double *mex,double *nex,double *dmex,double *dnex,double vpex[][3]) {
1664 double dmnum[3],dnnum[3],vpnum[3][3],ivpnum[3][3],mnum[6],nnum[6]; /* Numerical quantities */
1665 double swap[3],maxerr,err;
1666 int8_t perm[3]; /* permutation array */
1667
1669 if( !MMG5_simred3d(mesh,mex,nex,dmnum,dnnum,vpnum ) )
1670 return 0;
1671
1672 /* Naively sort eigenpairs in increasing order */
1673 MMG5_sort_simred(3,dmnum,dnnum,(double *)vpnum,swap,perm);
1674
1675 /* Check diagonal values error in norm inf */
1676 maxerr = MMG5_test_mat_error(3,(double *)dmex,(double *)dmnum);
1677 if( maxerr > 100*MMG5_EPSOK ) {
1678 fprintf(stderr," ## Error first matrix coreduction values: in function %s, max error %e\n",
1679 __func__,maxerr);
1680 return 0;
1681 }
1682 maxerr = MMG5_test_mat_error(3,(double *)dnex,(double *)dnnum);
1683 if( maxerr > 1000*MMG5_EPSOK ) {
1684 fprintf(stderr," ## Error second matrix coreduction values: in function %s, max error %e\n",
1685 __func__,maxerr);
1686 return 0;
1687 }
1688
1689 /* Check eigenvectors error through scalar product */
1690 maxerr = 0.;
1691 for( int8_t i = 0; i < 3; i++ ) {
1692 err = 0.;
1693 for( int8_t j = 0; j < 3; j++ )
1694 err += vpex[i][j] * vpnum[i][j];
1695 err = 1.-fabs(err);
1696 maxerr = MG_MAX(maxerr,err);
1697 }
1698 if( maxerr > MMG5_EPSOK ) {
1699 fprintf(stderr," ## Error matrix coreduction vectors: in function %s, max error %e\n",
1700 __func__,maxerr);
1701 return 0;
1702 }
1703
1705 if( !MMG5_invmat33(vpnum,ivpnum) )
1706 return 0;
1707 MMG5_simredmat(3,mnum,dmnum,(double *)ivpnum);
1708 MMG5_simredmat(3,nnum,dnnum,(double *)ivpnum);
1709
1710 /* Check matrices in norm inf */
1711 maxerr = MMG5_test_mat_error(6,mex,mnum);
1712 if( maxerr > 1.e2*MMG5_EPSOK ) {
1713 fprintf(stderr," ## Error first matrix coreduction recomposition: in function %s, max error %e\n",
1714 __func__,maxerr);
1715 return 0;
1716 }
1717 maxerr = MMG5_test_mat_error(6,nex,nnum);
1718 if( maxerr > 1.e3*MMG5_EPSOK ) {
1719 fprintf(stderr," ## Error second matrix coreduction recomposition: in function %s, max error %e\n",
1720 __func__,maxerr);
1721 return 0;
1722 }
1723
1724 return 1;
1725}
1726
1741inline
1742int MMG5_updatemet2d_ani(double *m,double *n,double dm[2],double dn[2],
1743 double vp[2][2],int8_t ier ) {
1744 double det,ip[4];
1745
1746 det = vp[0][0]*vp[1][1] - vp[0][1]*vp[1][0];
1747 if ( fabs(det) < MMG5_EPS ) return 0;
1748 det = 1.0 / det;
1749
1750 ip[0] = vp[1][1]*det;
1751 ip[1] = -vp[1][0]*det;
1752 ip[2] = -vp[0][1]*det;
1753 ip[3] = vp[0][0]*det;
1754
1755 if ( ier & 1 ) {
1756 m[0] = dm[0]*ip[0]*ip[0] + dm[1]*ip[2]*ip[2];
1757 m[1] = dm[0]*ip[0]*ip[1] + dm[1]*ip[2]*ip[3];
1758 m[2] = dm[0]*ip[1]*ip[1] + dm[1]*ip[3]*ip[3];
1759 }
1760 if ( ier & 2 ) {
1761 n[0] = dn[0]*ip[0]*ip[0] + dn[1]*ip[2]*ip[2];
1762 n[1] = dn[0]*ip[0]*ip[1] + dn[1]*ip[2]*ip[3];
1763 n[2] = dn[0]*ip[1]*ip[1] + dn[1]*ip[3]*ip[3];
1764 }
1765 return 1;
1766}
1767
1782inline
1783int MMG5_updatemet3d_ani(double *m,double *n,double dm[3],double dn[3],
1784 double vp[3][3],int8_t ier ) {
1785 double ivp[3][3];
1786
1787 if( !MMG5_invmat33(vp,ivp) )
1788 return 0;
1789
1790 if ( ier & 1 ) {
1791 MMG5_simredmat(3,m,dm,(double *)ivp);
1792 }
1793 if ( ier & 2 ) {
1794 MMG5_simredmat(3,n,dn,(double *)ivp);
1795 }
1796 return 1;
1797}
1798
1806 double mex[3] = { 508., -504, 502.}; /* Test matrix 1 */
1807 double nex[3] = {4020.,-2020.,1020.}; /* Test matrix 2 */
1808 double dm[2] = { 1., 100. }; /* Exact cobasis projection 1 */
1809 double dn[2] = {500., 4. }; /* Exact cobasis projection 2 */
1810 double vp[2][2] = {{ 1./sqrt(2.),1./sqrt(2.)},
1811 {1./sqrt(5.),2./sqrt(5.)}}; /* Exact cobasis vectors */
1812 double mnum[3],nnum[3],maxerr; /* Numerical quantities */
1813
1815 if( !MMG5_updatemet2d_ani(mnum,nnum,dm,dn,vp,3) )
1816 return 0;
1817
1818 /* Check values error in norm inf */
1819 maxerr = MMG5_test_mat_error(3,(double *)mex,(double *)mnum);
1820 if( maxerr > 1.e4*MMG5_EPSOK ) {
1821 fprintf(stderr," ## Error first matrix recomposition from simultaneous reduction: in function %s, max error %e\n",
1822 __func__,maxerr);
1823 return 0;
1824 }
1825 maxerr = MMG5_test_mat_error(3,(double *)nex,(double *)nnum);
1826 if( maxerr > 1.e4*MMG5_EPSOK ) {
1827 fprintf(stderr," ## Error second matrix recomposition from simultaneous reduction: in function %s, max error %e\n",
1828 __func__,maxerr);
1829 return 0;
1830 }
1831
1832 return 1;
1833}
1834
1842 double mex[6] = {111./2.,-109./2., 89./2.,111./2.,-91./2.,111./2.}; /* Test matrix 1 */
1843 double nex[6] = {409./2.,-393./2.,-407./2.,409./2.,391./2.,409./2.}; /* Test matrix 2 */
1844 double dm[3] = {1., 10.,100.}; /* Exact cobasis projection 1 */
1845 double dn[3] = {8.,400., 1.}; /* Exact cobasis projection 2 */
1846 double vp[3][3] = {{1./sqrt(2.),1./sqrt(2.),0.},
1847 {0., 1./sqrt(2.),1./sqrt(2.)},
1848 {1./sqrt(2.), 0.,1./sqrt(2.)}}; /* Exact cobasis vectors */
1849 double mnum[6],nnum[6],maxerr; /* Numerical quantities */
1850
1852 if( !MMG5_updatemet3d_ani(mnum,nnum,dm,dn,vp,3) )
1853 return 0;
1854
1855 /* Check values error in norm inf */
1856 maxerr = MMG5_test_mat_error(6,(double *)mex,(double *)mnum);
1857 if( maxerr > 100*MMG5_EPSOK ) {
1858 fprintf(stderr," ## Error first matrix recomposition from simultaneous reduction: in function %s, max error %e\n",
1859 __func__,maxerr);
1860 return 0;
1861 }
1862 maxerr = MMG5_test_mat_error(6,(double *)nex,(double *)nnum);
1863 if( maxerr > 100*MMG5_EPSOK ) {
1864 fprintf(stderr," ## Error second matrix recomposition from simultaneous reduction: in function %s, max error %e\n",
1865 __func__,maxerr);
1866 return 0;
1867 }
1868
1869 return 1;
1870}
1871
1883void MMG5_gradEigenvreq(double *dm,double *dn,double difsiz,int8_t dir,int8_t *ier) {
1884 double hm,hn;
1885
1886 hm = 1.0 / sqrt(dm[dir]);
1887 hn = 1.0 / sqrt(dn[dir]);
1888
1889 if ( hn > hm + difsiz + MMG5_EPSOK ) {
1890 /* Decrease the size in \a ipslave */
1891 hn = hm+difsiz;
1892 dn[dir] = 1.0 / (hn*hn);
1893 (*ier) = 2;
1894 }
1895 else if ( hn + MMG5_EPSOK < hm - difsiz ) {
1896 /* Increase the size in \a ipslave */
1897 hn = hm-difsiz;
1898 dn[dir] = 1.0 / (hn*hn);
1899 (*ier) = 2;
1900 }
1901}
1902
1914int MMG5_updatemetreq_ani(double *n,double dn[2],double vp[2][2]) {
1915 double det,ip[4];
1916
1917 det = vp[0][0]*vp[1][1] - vp[0][1]*vp[1][0];
1918 if ( fabs(det) < MMG5_EPS ) return 0;
1919 det = 1.0 / det;
1920
1921 ip[0] = vp[1][1]*det;
1922 ip[1] = -vp[1][0]*det;
1923 ip[2] = -vp[0][1]*det;
1924 ip[3] = vp[0][0]*det;
1925
1926 n[0] = dn[0]*ip[0]*ip[0] + dn[1]*ip[2]*ip[2];
1927 n[1] = dn[0]*ip[0]*ip[1] + dn[1]*ip[2]*ip[3];
1928 n[2] = dn[0]*ip[1]*ip[1] + dn[1]*ip[3]*ip[3];
1929
1930 return 1;
1931}
1932
1952 MMG5_int npslave)
1953{
1954
1955 MMG5_pPoint p1,p2;
1956 double *mm1,*mm2,*nn1,*nn2,ps1,ps2,ux,uy,uz,m1[6],m2[6],n1[3],n2[3],nt[3];
1957 double r1[3][3],r2[3][3],mtan1[3],mtan2[3],mr1[6],mr2[6];
1958 double mtmp[3][3],rbasis1[3][3],rbasis2[3][3];
1959 double l,difsiz,rmet3D[6];
1960 double lambda[2],vp[2][2],beta,mu[3];
1961 int cfg_m2;
1962 int8_t ier;
1963
1964 p1 = &mesh->point[npmaster];
1965 p2 = &mesh->point[npslave];
1966
1967 ux = p2->c[0] - p1->c[0];
1968 uy = p2->c[1] - p1->c[1];
1969 uz = p2->c[2] - p1->c[2];
1970
1971 mm1 = &met->m[6*npmaster];
1972 mm2 = &met->m[6*npslave];
1973
1974 cfg_m2 = 0;
1975 ier = 0;
1976
1977 if( !MMG5_nortri(mesh,pt,nt) )
1978 return 0;
1979
1980 /* Recover normal and metric associated to p1 */
1981 if( MG_SIN(p1->tag) || (MG_NOM & p1->tag)){
1982 memcpy(n1,nt,3*sizeof(double));
1983 memcpy(m1,mm1,6*sizeof(double));
1984 }
1985 else if( MG_GEO & p1->tag ){
1986 nn1 = &mesh->xpoint[p1->xp].n1[0];
1987 nn2 = &mesh->xpoint[p1->xp].n2[0];
1988 ps1 = nt[0]*nn1[0] + nt[1]*nn1[1] + nt[2]*nn1[2];
1989 ps2 = nt[0]*nn2[0] + nt[1]*nn2[1] + nt[2]*nn2[2];
1990
1991 if( fabs(ps1) < fabs(ps2))
1992 memcpy(n1,nn2,3*sizeof(double));
1993 else
1994 memcpy(n1,nn1,3*sizeof(double));
1995
1996 if( !MMG5_buildridmetnor(mesh,met,npmaster,nt,m1,rbasis1) ) { return 0; }
1997 }
1998 else if( ( MG_REF & p1->tag ) || (MG_BDY & p1->tag) ){
1999 // if MG_BDY, we are in mmg3d: the normal is stored in the xPoint
2000 memcpy(n1,&(mesh->xpoint[p1->xp].n1[0]),3*sizeof(double));
2001 memcpy(m1,mm1,6*sizeof(double));
2002 }
2003 else{
2004 // mmgs only
2005 memcpy(n1,p1->n,3*sizeof(double));
2006 memcpy(m1,mm1,6*sizeof(double));
2007 }
2008
2009 /* Recover normal and metric associated to p2 */
2010 if ( MG_SIN(p2->tag) || (MG_NOM & p2->tag)) {
2011 memcpy(n2,nt,3*sizeof(double));
2012 memcpy(m2,mm2,6*sizeof(double));
2013 }
2014 else if ( MG_GEO & p2->tag ) {
2015 nn1 = &mesh->xpoint[p2->xp].n1[0];
2016 nn2 = &mesh->xpoint[p2->xp].n2[0];
2017 ps1 = nt[0]*nn1[0] + nt[1]*nn1[1] + nt[2]*nn1[2];
2018 ps2 = nt[0]*nn2[0] + nt[1]*nn2[1] + nt[2]*nn2[2];
2019
2020 if( fabs(ps1) < fabs(ps2))
2021 memcpy(n2,nn2,3*sizeof(double));
2022 else
2023 memcpy(n2,nn1,3*sizeof(double));
2024
2025 cfg_m2 = MMG5_buildridmetnor(mesh,met,npslave,nt,m2,rbasis2);
2026 if( !cfg_m2 ) { return 0; }
2027 }
2028 else if( (MG_REF & p2->tag) || (MG_BDY & p2->tag) ){
2029 // if MG_BDY, we are in mmg3d: the normal is stored in the xPoint
2030 memcpy(n2,&(mesh->xpoint[p2->xp].n1[0]),3*sizeof(double));
2031 memcpy(m2,mm2,6*sizeof(double));
2032 }
2033 else{
2034 //mmgs Only
2035 memcpy(n2,p2->n,3*sizeof(double));
2036 memcpy(m2,mm2,6*sizeof(double));
2037 }
2038
2039 /* Rotation matrices mapping n1/n2 to e_3 */
2040 MMG5_rotmatrix(n1,r1);
2041 MMG5_rotmatrix(n2,r2);
2042
2043 /* Geodesic length of support curve to edge i */
2044 l = sqrt(ux*ux+uy*uy+uz*uz);
2045
2046 /* Characteristic sizes in direction of support curve */
2047 MMG5_rmtr(r1,m1,mr1);
2048
2049 mtan1[0] = mr1[0];
2050 mtan1[1] = mr1[1];
2051 mtan1[2] = mr1[3];
2052
2053 MMG5_rmtr(r2,m2,mr2);
2054
2055 mtan2[0] = mr2[0];
2056 mtan2[1] = mr2[1];
2057 mtan2[2] = mr2[3];
2058
2059 difsiz = mesh->info.hgradreq*l;
2060
2061 /* Simultaneous reduction of mtan1 and mtan2 */
2062 if ( !MMG5_simred2d(mesh,mtan1,mtan2,lambda,mu,vp) ) {
2063 return 0;
2064 }
2065
2066 /* Gradation of sizes = 1/sqrt(eigenv of the tensors) in the first direction */
2067 MMG5_gradEigenvreq(lambda,mu,difsiz,0,&ier);
2068
2069 /* Gradation of sizes = 1/sqrt(eigenv of the tensors) in the second direction */
2070 MMG5_gradEigenvreq(lambda,mu,difsiz,1,&ier);
2071
2072 if ( !ier ) {
2073 return 0;
2074 }
2075
2076 /* Metric update using the simultaneous reduction technique */
2077 if( MG_SIN(p2->tag) || (MG_NOM & p2->tag)){
2078 /* We choose to not respect the gradation in order to restrict the influence
2079 * of the singular points. Thus:
2080 * lambda_new = = 0.5 lambda_1 + 0.5 lambda_new = lambda_1 + 0.5 beta.
2081 * with beta the smallest variation of the eigenvalues (lambda_new-lambda_1). */
2082
2083 /* This point can have an anisotropic metric if a user-provided metric is
2084 * found. So, compute the eigenvalues. */
2085 double ll[3],rr[3][3],llmin;
2086 int i;
2087 if( !MMG5_eigenv3d(1,mm2,ll, rr) ) {
2088 return 0;
2089 }
2090 llmin = DBL_MAX;
2091 for( i = 0; i < 3; i++ )
2092 if( ll[i] < llmin )
2093 llmin = ll[i];
2094
2095
2096 beta = mu[0] - llmin;
2097
2098 if ( fabs(beta) < fabs(llmin-mu[1]) ) {
2099 beta = mu[1] - llmin;
2100 }
2101 ll[0] += 0.5*beta;
2102 ll[1] += 0.5*beta;
2103 ll[2] += 0.5*beta;
2104 assert ( ll[0]>0. && ll[1]>0. && ll[2]>0. );
2105 mm2[0] = ll[0]*rr[0][0]*rr[0][0] + ll[1]*rr[1][0]*rr[1][0] + ll[2]*rr[2][0]*rr[2][0];
2106 mm2[1] = ll[0]*rr[0][0]*rr[0][1] + ll[1]*rr[1][0]*rr[1][1] + ll[2]*rr[2][0]*rr[2][1];
2107 mm2[2] = ll[0]*rr[0][0]*rr[0][2] + ll[1]*rr[1][0]*rr[1][2] + ll[2]*rr[2][0]*rr[2][2];
2108 mm2[3] = ll[0]*rr[0][1]*rr[0][1] + ll[1]*rr[1][1]*rr[1][1] + ll[2]*rr[2][1]*rr[2][1];
2109 mm2[4] = ll[0]*rr[0][1]*rr[0][2] + ll[1]*rr[1][1]*rr[1][2] + ll[2]*rr[2][1]*rr[2][2];
2110 mm2[5] = ll[0]*rr[0][2]*rr[0][2] + ll[1]*rr[1][2]*rr[1][2] + ll[2]*rr[2][2]*rr[2][2];
2111 }
2112 else if ( p2->tag & MG_GEO ){
2113 if ( !MMG5_updatemetreq_ani(mtan2,mu,vp) ) { return 0; }
2114
2115 /* Here mtan2 contains the gradated metric in the coreduction basis: compute
2116 * the sizes in the directions (t,u=t^n,n): Computation in 3D but it is
2117 * maybe more efficient to work in the tangent plane (but we need to compute
2118 * the basis of the ridge metric in the tangent plane) */
2119 rmet3D[0] = mtan2[0];
2120 rmet3D[1] = mtan2[1];
2121 rmet3D[2] = 0;
2122 rmet3D[3] = mtan2[2];
2123 rmet3D[4] = 0;
2124 rmet3D[5] = mr2[5];
2125
2126 mu[0] = rmet3D[0]*rbasis2[0][0]*rbasis2[0][0] + 2. * rmet3D[1]*rbasis2[1][0]*rbasis2[0][0]
2127 + 2. * rmet3D[2]*rbasis2[2][0]*rbasis2[0][0]
2128 + rmet3D[3]*rbasis2[1][0]*rbasis2[1][0] + 2. * rmet3D[4]*rbasis2[2][0]*rbasis2[1][0]
2129 + rmet3D[5]*rbasis2[2][0]*rbasis2[2][0];
2130
2131 /* h = 1/sqrt(t_e M e) */
2132 assert ( mu[0] > MMG5_EPSD2 );
2133
2134 mu[1] = rmet3D[0]*rbasis2[0][1]*rbasis2[0][1] + 2. * rmet3D[1]*rbasis2[1][1]*rbasis2[0][1]
2135 + 2. * rmet3D[2]*rbasis2[2][1]*rbasis2[0][1]
2136 + rmet3D[3]*rbasis2[1][1]*rbasis2[1][1] + 2. * rmet3D[4]*rbasis2[2][1]*rbasis2[1][1]
2137 + rmet3D[5]*rbasis2[2][1]*rbasis2[2][1];
2138
2139 /* h = 1/sqrt(t_e M e) */
2140 assert ( mu[1] > MMG5_EPSD2 );
2141
2142 /* Update the ridge metric */
2143 mm2[0] = mu[0];
2144
2145 assert ( cfg_m2 );
2146 mm2[cfg_m2] = mu[1];
2147
2148 }
2149 else{
2150 /* Update of the metrics */
2151 mu[2] = mr2[5];
2152
2153 if ( !MMG5_updatemetreq_ani(mtan2,mu,vp) ) { return 0; }
2154
2155 /* Return in initial basis */
2156 mtmp[0][0] = mtan2[0]*r2[0][0] + mtan2[1]*r2[1][0];
2157 mtmp[0][1] = mtan2[0]*r2[0][1] + mtan2[1]*r2[1][1];
2158 mtmp[0][2] = mtan2[0]*r2[0][2] + mtan2[1]*r2[1][2];
2159
2160 mtmp[1][0] = mtan2[1]*r2[0][0] + mtan2[2]*r2[1][0];
2161 mtmp[1][1] = mtan2[1]*r2[0][1] + mtan2[2]*r2[1][1];
2162 mtmp[1][2] = mtan2[1]*r2[0][2] + mtan2[2]*r2[1][2];
2163
2164 mtmp[2][0] = mr2[5]*r2[2][0];
2165 mtmp[2][1] = mr2[5]*r2[2][1];
2166 mtmp[2][2] = mr2[5]*r2[2][2];
2167
2168 m2[0] = r2[0][0]*mtmp[0][0] + r2[1][0]*mtmp[1][0] + r2[2][0]*mtmp[2][0];
2169 m2[1] = r2[0][0]*mtmp[0][1] + r2[1][0]*mtmp[1][1] + r2[2][0]*mtmp[2][1];
2170 m2[2] = r2[0][0]*mtmp[0][2] + r2[1][0]*mtmp[1][2] + r2[2][0]*mtmp[2][2];
2171
2172 m2[3] = r2[0][1]*mtmp[0][1] + r2[1][1]*mtmp[1][1] + r2[2][1]*mtmp[2][1];
2173 m2[4] = r2[0][1]*mtmp[0][2] + r2[1][1]*mtmp[1][2] + r2[2][1]*mtmp[2][2];
2174
2175 m2[5] = r2[0][2]*mtmp[0][2] + r2[1][2]*mtmp[1][2] + r2[2][2]*mtmp[2][2];
2176
2177#ifndef NDEBUG
2178 /* Check the validity of the output metric */
2179 ier = MMG5_eigenv3d(1,m2,mu, r2);
2180
2181 assert ( ier );
2182 assert ( mu[0] > 0.);
2183 assert ( mu[1] > 0.);
2184 assert ( mu[2] > 0.);
2185#endif
2186
2187 memcpy(mm2,m2,6*sizeof(double));
2188 }
2189
2190 return 1;
2191}
2192
2206 MMG5_pPoint p0;
2207 double lm;
2208 MMG5_int k,iadr;
2209 int mmgWarn = 0;
2210
2211 for ( k=1; k<=mesh->np; k++ ) {
2212 p0 = &mesh->point[k];
2213 if ( !MG_VOK(p0) ) continue;
2214
2215 if ( !p0->s ) continue;
2216
2217 iadr = met->size*k;
2218 lm = p0->s/met->m[iadr];
2219 met->m[iadr] = lm*lm;
2220
2221 if ( mesh->dim==2 ) {
2222 met->m[iadr+2] = met->m[iadr];
2223 }
2224 else if ( !MG_RID(p0->tag) ) {
2225 /* Classic metric */
2226 met->m[iadr+3] = met->m[iadr+5] = met->m[iadr];
2227 }
2228 else {
2229 /* Ridge metric */
2230 met->m[iadr+2] = met->m[iadr+1] = met->m[iadr];
2231 met->m[iadr+4] = met->m[iadr+3] = met->m[iadr];
2232 }
2233
2234 p0->flag = 3;
2235
2236 /* Warn the user that edge size is erased */
2237 if ( !mmgWarn ) {
2238 mmgWarn = 1;
2239 if ( mesh->info.ddebug || (mesh->info.imprim > 4) ) {
2240 printf("\n -- SIZEMAP CORRECTION : overwritten of sizes at required vertices\n");
2241 }
2242 }
2243 }
2244
2245 return 1;
2246}
2247
2260 MMG5_pTria pt;
2261 MMG5_pPoint p1,p2;
2262 int maxit;
2263 MMG5_int ier,k,np1,np2,nup,nu;
2264 int8_t i;
2265
2268
2269 for (k=1; k<=mesh->np; k++)
2270 mesh->point[k].flag = mesh->base;
2271
2272 (*it) = nup = 0;
2273 maxit = 100;
2274 do {
2275 mesh->base++;
2276 nu = 0;
2277 for (k=1; k<=mesh->nt; k++) {
2278 pt = &mesh->tria[k];
2279 if ( !MG_EOK(pt) ) continue;
2280
2281 for (i=0; i<3; i++) {
2282 np1 = pt->v[MMG5_inxt2[i]];
2283 np2 = pt->v[MMG5_iprv2[i]];
2284 p1 = &mesh->point[np1];
2285 p2 = &mesh->point[np2];
2286
2287 if ( p1->flag < mesh->base-1 && p2->flag < mesh->base-1 ) continue;
2288 /* Skip points belonging to a required edge */
2289 if ( p1->s || p2->s ) continue;
2290
2291 ier = MMG5_grad2met_ani(mesh,met,pt,np1,np2);
2292 if ( ier == np1 ) {
2293 p1->flag = mesh->base;
2294 nu++;
2295 }
2296 else if ( ier == np2 ) {
2297 p2->flag = mesh->base;
2298 nu++;
2299 }
2300 }
2301 }
2302 nup += nu;
2303 }
2304 while( ++(*it) < maxit && nu > 0 );
2305
2306 if ( abs(mesh->info.imprim) > 4 )
2307 fprintf(stdout," gradation: %7"MMG5_PRId" updated, %d iter.\n",nup,(*it));
2308
2309 return nup;
2310}
2311
2312
2323
2324 MMG5_pTria pt;
2325 MMG5_pPoint p1,p2;
2326 int it,maxit,ier;
2327 MMG5_int k,np1,np2,npslave,npmaster,nup,nu;
2328 int8_t i;
2329
2330
2331 if ( abs(mesh->info.imprim) > 5 || mesh->info.ddebug ) {
2332 fprintf(stdout," ** Grading required points.\n");
2333 }
2334
2335 if ( mesh->info.hgrad < 0. ) {
2339 }
2340
2341 it = nup = 0;
2342 maxit = 100;
2343
2344 do {
2345 nu = 0;
2346 for (k=1; k<=mesh->nt; k++) {
2347 pt = &mesh->tria[k];
2348 if ( !MG_EOK(pt) ) continue;
2349
2350 for (i=0; i<3; i++) {
2351 np1 = pt->v[MMG5_inxt2[i]];
2352 np2 = pt->v[MMG5_iprv2[i]];
2353 p1 = &mesh->point[np1];
2354 p2 = &mesh->point[np2];
2355
2356 if ( MMG5_abs ( p1->s - p2->s ) < 2 ) {
2357 /* No size to propagate */
2358 continue;
2359 }
2360 else if ( p1->s > p2->s ) {
2361 npmaster = np1;
2362 npslave = np2;
2363 }
2364 else {
2365 assert ( p2->s > p1->s );
2366 npmaster = np2;
2367 npslave = np1;
2368 }
2369
2370 /* Impose the gradation to npslave from npmaster: coming from mmgs,
2371 * MMG5_grad2metreq_ani is a pointer toward MMG5_grad2metSurfreq,
2372 * comming from mmg2d, it is a pointer toward MMG2D_grad2metreq_ani */
2373 ier = MMG5_grad2metreq_ani(mesh,met,pt,npmaster,npslave);
2374
2375 if ( ier ) {
2376 mesh->point[npslave].s = mesh->point[npmaster].s - 1;
2377 nu++;
2378 }
2379 }
2380 }
2381 nup += nu;
2382 }
2383 while ( ++it < maxit && nu > 0 );
2384
2385 if ( abs(mesh->info.imprim) > 4 && nup ) {
2386 fprintf(stdout," gradation (required): %7"MMG5_PRId" updated, %d iter.\n",nup,it);
2387 }
2388
2389 return 1;
2390}
int ier
MMG5_pMesh * mesh
int MMG5_gradsizreq_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz.c:2322
void MMG5_sort_simred(int8_t dim, double *dm, double *dn, double *vp, double *swap, int8_t *perm)
Definition: anisosiz.c:1562
int MMG5_test_updatemet3d_ani()
Definition: anisosiz.c:1841
int MMG5_test_simred2d(MMG5_pMesh mesh, double *mex, double *nex, double *dmex, double *dnex, double vpex[][2])
Definition: anisosiz.c:1585
void MMG5_fillDefmetregSys(MMG5_int k, MMG5_pPoint p0, int i0, MMG5_Bezier b, double r[3][3], double c[3], double *lispoi, double tAA[6], double tAb[3])
Definition: anisosiz.c:290
int MMG5_updatemetreq_ani(double *n, double dn[2], double vp[2][2])
Definition: anisosiz.c:1914
double MMG5_surftri33_ani(MMG5_pMesh mesh, MMG5_pTria ptt, double ma[6], double mb[6], double mc[6])
Definition: anisosiz.c:171
int MMG5_compute_meanMetricAtMarkedPoints_ani(MMG5_pMesh mesh, MMG5_pSol met)
Definition: anisosiz.c:2205
int MMG5_solveDefmetregSys(MMG5_pMesh mesh, double r[3][3], double c[3], double tAA[6], double tAb[3], double *m, double isqhmin, double isqhmax, double hausd)
Definition: anisosiz.c:436
int MMG5_test_updatemet2d_ani()
Definition: anisosiz.c:1805
int MMG5_simred3d(MMG5_pMesh mesh, double *m, double *n, double dm[3], double dn[3], double vp[3][3])
Definition: anisosiz.c:1416
void MMG5_gradEigenvreq(double *dm, double *dn, double difsiz, int8_t dir, int8_t *ier)
Definition: anisosiz.c:1883
void MMG5_defUninitSize(MMG5_pMesh mesh, MMG5_pSol met, int8_t ismet)
Definition: anisosiz.c:228
static double MMG5_surf(MMG5_pMesh mesh, double m[3][6], MMG5_pTria ptt)
Definition: anisosiz.c:50
MMG5_int MMG5_grad2metSurf(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria pt, MMG5_int np1, MMG5_int np2)
Definition: anisosiz.c:975
double MMG5_surftri_ani(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria ptt)
Definition: anisosiz.c:124
int MMG5_updatemet2d_ani(double *m, double *n, double dm[2], double dn[2], double vp[2][2], int8_t ier)
Definition: anisosiz.c:1742
double MMG5_ridSizeInNormalDir(MMG5_pMesh mesh, int i0, double *bcu, MMG5_Bezier *b, double isqhmin, double isqhmax)
Definition: anisosiz.c:836
int MMG5_grad2metSurfreq(MMG5_pMesh mesh, MMG5_pSol met, MMG5_pTria pt, MMG5_int npmaster, MMG5_int npslave)
Definition: anisosiz.c:1951
int MMG5_updatemet3d_ani(double *m, double *n, double dm[3], double dn[3], double vp[3][3], int8_t ier)
Definition: anisosiz.c:1783
int MMG5_simred2d(MMG5_pMesh mesh, double *m, double *n, double dm[2], double dn[2], double vp[2][2])
Definition: anisosiz.c:1326
int MMG5_solveDefmetrefSys(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int ipref[2], double r[3][3], double c[3], double tAA[6], double tAb[3], double *m, double isqhmin, double isqhmax, double hausd)
Definition: anisosiz.c:538
int MMG5_test_simred3d(MMG5_pMesh mesh, double *mex, double *nex, double *dmex, double *dnex, double vpex[][3])
Definition: anisosiz.c:1663
MMG5_int MMG5_gradsiz_ani(MMG5_pMesh mesh, MMG5_pSol met, int *it)
Definition: anisosiz.c:2259
double MMG5_ridSizeInTangentDir(MMG5_pMesh mesh, MMG5_pPoint p0, MMG5_int idp, MMG5_int *iprid, double isqhmin, double isqhmax)
Definition: anisosiz.c:764
void MMG5_bezierEdge(MMG5_pMesh mesh, MMG5_int i0, MMG5_int i1, double b0[3], double b1[3], int8_t isrid, double v[3])
Definition: bezier.c:51
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)
void MMG5_mark_pointsOnReqEdge_fromTria(MMG5_pMesh mesh)
Definition: isosiz.c:243
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_buildridmet(MMG5_pMesh mesh, MMG5_pSol met, MMG5_int np0, double ux, double uy, double uz, double mr[6], double r[3][3])
Definition: mettools.c:676
int MMG5_intmetsavedir(MMG5_pMesh mesh, double *m, double *n, double *mr)
Definition: mettools.c:635
#define MG_GEO
#define A64TH
void MMG5_mn(double m[6], double n[6], double mn[9])
Definition: tools.c:337
#define MMG5_EPSOK
#define MG_EOK(pt)
double MMG5_test_mat_error(int8_t nelem, double m1[], double m2[])
Definition: tools.c:1123
#define A16TH
#define MG_MIN(a, b)
#define MG_MAX(a, b)
static const uint8_t MMG5_iprv2[3]
#define MMG5_ATHIRD
#define MG_SIN(tag)
int MMG5_rmtr(double r[3][3], double m[6], double mr[6])
Definition: tools.c:405
int MMG5_invmat33(double m[3][3], double mi[3][3])
Definition: tools.c:653
#define MG_RID(tag)
static const uint8_t MMG5_inxt2[6]
#define MG_VOK(ppt)
int MMG5_nortri(MMG5_pMesh mesh, MMG5_pTria pt, double *n)
Definition: tools.c:209
#define MG_CRN
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
#define MG_BDY
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
#define MMG5_EPSD2
#define MG_REF
int MMG5_invmat22(double m[2][2], double mi[2][2])
Definition: tools.c:745
#define A32TH
int MMG5_invmat(double *m, double *mi)
Definition: tools.c:562
double b[10][3]
int8_t ddebug
Definition: libmmgtypes.h:532
double hgrad
Definition: libmmgtypes.h:518
double hmax
Definition: libmmgtypes.h:518
double hgradreq
Definition: libmmgtypes.h:518
double hausd
Definition: libmmgtypes.h:518
MMG mesh structure.
Definition: libmmgtypes.h:605
MMG5_Info info
Definition: libmmgtypes.h:651
MMG5_pPoint point
Definition: libmmgtypes.h:641
MMG5_pxPoint xpoint
Definition: libmmgtypes.h:642
MMG5_int base
Definition: libmmgtypes.h:616
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
double n[3]
Definition: libmmgtypes.h:272
int16_t tag
Definition: libmmgtypes.h:284
double c[3]
Definition: libmmgtypes.h:271
MMG5_int xp
Definition: libmmgtypes.h:279
MMG5_int s
Definition: libmmgtypes.h:283
MMG5_int flag
Definition: libmmgtypes.h:282
double * m
Definition: libmmgtypes.h:671
MMG5_int v[3]
Definition: libmmgtypes.h:334
double n2[3]
Definition: libmmgtypes.h:295
double n1[3]
Definition: libmmgtypes.h:295