Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
quadric_analysis.C
Go to the documentation of this file.
1 /* *******************************************************************
2  * Rocstar Simulation Suite *
3  * Copyright@2015, Illinois Rocstar LLC. All rights reserved. *
4  * *
5  * Illinois Rocstar LLC *
6  * Champaign, IL *
7  * www.illinoisrocstar.com *
8  * sales@illinoisrocstar.com *
9  * *
10  * License: See LICENSE file in top level of distribution package or *
11  * http://opensource.org/licenses/NCSA *
12  *********************************************************************/
13 /* *******************************************************************
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES *
16  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
17  * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR *
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
21  * USE OR OTHER DEALINGS WITH THE SOFTWARE. *
22  *********************************************************************/
23 // $Id: quadric_analysis.C,v 1.15 2008/12/06 08:45:28 mtcampbe Exp $
24 
25 #include "FaceOffset_3.h"
26 #include "../Rocblas/include/Rocblas.h"
27 #include "../Rocsurf/include/Rocsurf.h"
28 #include <algorithm>
29 
31 
32 // If predicted is present, then the motion is wavefrontal.
33 void FaceOffset_3::
34 compute_quadrics( double dt, const COM::Attribute *spds,
35  COM::Attribute *bo_attr, COM::Attribute *predicted) {
36 
37  COM_assertion_msg( spds || dt==0,
38  "If no speed function, then time step must be zero.");
39 
40  const double zero = 0., eps = 1.e-100;
41  if ( bo_attr) Rocblas::copy_scalar( &zero, bo_attr);
42  if ( dt==0) bo_attr = NULL;
43 
44  // Use the following buffer spaces: _As for matrix A; _eigvalues to
45  // store bm; _sumangles to store sum of angles
46  COM::Attribute *A_attr = _As;
47  COM::Attribute *bm_attr = _eigvalues;
48  COM::Attribute *w_attr = _weights;
49 
50  Rocblas::copy_scalar( &zero, A_attr);
51  Rocblas::copy_scalar( &zero, bm_attr);
52  Rocblas::copy_scalar( &eps, w_attr);
54 
55  COM::Attribute *sa_attr =
56  _buf->new_attribute( "sumangles", 'n', COM_DOUBLE, 1, "");
57  _buf->resize_array( sa_attr, 0);
58 
59  bool shear= _smoother==SMOOTHER_LAPLACIAN || _is_strtd ||
60  _smoother!=SMOOTHER_ANISOTROPIC && (dt==0 || bo_attr==0);
61 
62  // Loop through the panes and its real faces
63  std::vector< COM::Pane*>::iterator it = _panes.begin();
64  Manifold::PM_iterator pm_it=_surf->pm_begin();
65  for ( int i=0, local_npanes = _panes.size();
66  i<local_npanes; ++i, ++it, ++pm_it) {
67  COM::Pane *pane = *it;
68 
69  // Obtain nodal coordinates of current pane, assuming contiguous layout
70  const Point_3 *pnts = reinterpret_cast<Point_3*>
71  (pane->attribute(COM_NC)->pointer());
72  Vector_3 *fnrms = reinterpret_cast<Vector_3*>
73  ( pane->attribute(_facenormals->id())->pointer());
74  Point_3 *fcnts = reinterpret_cast<Point_3*>
75  ( pane->attribute(_facecenters->id())->pointer());
76 
77  double *ws = reinterpret_cast<double*>
78  ( pane->attribute(w_attr->id())->pointer());
79  Vector_3 *vcnts = reinterpret_cast<Vector_3*>
80  ( pane->attribute(_vcenters->id())->pointer());
81 
82  // Obtain the pointer to speed function
83  const double *spds_ptr = spds?reinterpret_cast<const double*>
84  (pane->attribute( spds->id())->pointer()):NULL;
85 
86  // Obtain pointers
87  Vector_3 *As = reinterpret_cast<Vector_3*>
88  ( pane->attribute(A_attr->id())->pointer());
89  Vector_3 *bs_m = reinterpret_cast<Vector_3*>
90  ( pane->attribute(bm_attr->id())->pointer());
91  Vector_3 *bs_o = bo_attr ? reinterpret_cast<Vector_3*>
92  ( pane->attribute(bo_attr->id())->pointer()) : NULL;
93  Vector_3 *pred_dirs = predicted ? reinterpret_cast<Vector_3*>
94  ( pane->attribute(predicted->id())->pointer()) : NULL;
95  double *sa = reinterpret_cast<double*>
96  ( pane->attribute(sa_attr->id())->pointer());
97  double *areas = reinterpret_cast<double*>
98  ( pane->attribute(_faceareas->id())->pointer());
99 
100  // Loop through real elements of the current pane
101  Element_node_enumerator ene( pane, 1);
102  for ( int j=0, nj=pane->size_of_real_elements(); j<nj; ++j, ene.next()) {
103  // If speed is uniform within a face, then unit normal is the same
104  // after propagation.
105  Point_3 &cnt = fcnts[j];
106 
107  int ne = ene.size_of_edges();
108  int uindex=ene[ne-1]-1, vindex=ene[0]-1, windex=0;
109 
110  Vector_3 disps[9], nrms[9];
111 
112  // Compute signed distance from current face.
113  obtain_face_offset( pnts, spds_ptr, spds, dt, pred_dirs,
114  ene, fnrms[j], cnt, disps, nrms);
115 
116  double delta=0;
117  // Loop through all vertices of current face.
118  for ( int k=0; k<ne; ++k, uindex=vindex, vindex=windex) {
119  windex = ene[(k+1==ne)?0:k+1]-1;
120 
121  // Evaluate angle at each vertex.
122  Vector_3 ts[2] = { pnts[uindex]-pnts[vindex],
123  pnts[windex]-pnts[vindex]};
124  Vector_3 ns_nz = nrms[k];
125 
126  if ( bo_attr) { // Update delta
127  delta = -disps[k]*ns_nz;
128  }
129 
130  double angle = eval_angle( ts[0], ts[1]);
131  Vector_3 nrm = ns_nz;
132  double w=1;
133  if ( _wght_scheme!=SURF::E2N_ONE) {
134  switch ( _wght_scheme) {
135  case SURF::E2N_ANGLE: {
136  double s = std::sqrt((ts[0]*ts[0])*(ts[1]*ts[1]));
137  if ( s==0) w = 0;
138  else w = angle;
139 
140  break;
141  }
142  case SURF::E2N_AREA: {
143  w = areas[j]; break;
144  }
145  default: ; // w=1;
146  }
147  nrm *= w;
148  }
149 
150  // Obtain the addresses of the linear system and weight
151  Vector_3 *A_v = &As[3*vindex];
152 
153  // Update A, b_o, b_m, and as_v for the current vertex
154  A_v[0] += ns_nz[0]*nrm;
155  A_v[1] += ns_nz[1]*nrm;
156  A_v[2] += ns_nz[2]*nrm;
157 
158  if ( delta!=0) bs_o[vindex] += delta*nrm;
159  bs_m[vindex] -= nrm;
160  sa[vindex] += angle;
161 
162  if ( shear) {
163  Vector_3 diff = cnt-pnts[vindex];
164  ws[vindex] += 1.;
165  vcnts[vindex] += diff;
166  }
167  } // for k (edges)
168  } // for j (elements)
169  } // for i (panes)
170 
171  // Reduce on shared nodes for A, b_m, b_o, and r
172  _surf->reduce_on_shared_nodes( A_attr, Manifold::OP_SUM);
173  _surf->reduce_on_shared_nodes( bm_attr, Manifold::OP_SUM);
174  if ( bo_attr) _surf->reduce_on_shared_nodes( bo_attr, Manifold::OP_SUM);
175  _surf->reduce_on_shared_nodes( sa_attr, Manifold::OP_SUM);
176 
177  // Copy bm_attr into _vnormals and _bmedial
178  Rocblas::copy( bm_attr, _vnormals);
179  Rocblas::copy( bm_attr, _bmedial);
180 
181  // Reduce to maxabs so that shared nodes have exactly the same value
182  _surf->reduce_on_shared_nodes( A_attr, Manifold::OP_MAXABS);
183  _surf->reduce_on_shared_nodes( sa_attr, Manifold::OP_MAXABS);
184 
185  if ( shear) {
186  _surf->reduce_on_shared_nodes( w_attr, Manifold::OP_SUM);
187  _surf->reduce_on_shared_nodes( _vcenters, Manifold::OP_SUM);
188  // Obtain angle-weighted average of mass center at each vertex.
189  Rocblas::div( _vcenters, w_attr, _vcenters);
190  }
191 
192  // Loop through the panes and its real vertices to determine trank
193  it = _panes.begin();
194  for (int i=0, local_npanes = _panes.size(); i<local_npanes; ++i, ++it) {
195  COM::Pane *pane = *it;
196 
197  // Obtain pointers
198  Vector_3 *As = reinterpret_cast<Vector_3*>
199  ( pane->attribute(A_attr->id())->pointer());
200  Vector_3 *evs = reinterpret_cast<Vector_3*>
201  ( pane->attribute(_eigvecs->id())->pointer());
202  Vector_3 *bs_m = reinterpret_cast<Vector_3*>
203  ( pane->attribute(bm_attr->id())->pointer());
204  double *sa = reinterpret_cast<double*>
205  ( pane->attribute(sa_attr->id())->pointer());
206 
207  // Feature information
208  char *tranks = reinterpret_cast<char*>
209  ( pane->attribute(_tangranks->id())->pointer());
210 
211  // Loop through all real nodes of the pane
212  for ( int j=0, jn=pane->size_of_real_nodes(); j<jn; ++j) {
213  // Skip vertices with zero right-hand side, such as those at
214  // edge- and face-centers for quadratic elements
215  if ( bs_m[j].is_null()) continue;
216 
217  Vector_3 *A_v = &As[3*j];
218  Vector_3 *es = &evs[3*j]; // eigen-vectors of current vertex.
219  std::copy( A_v, A_v+3, es);
220 
221  // Perform eigen-analysis for the vertex using medial quadric
222  // nrank is the rank of the normal (primary) space of A.
223  char nrank = eigen_analyze_vertex( es, bs_m[j], 2*pi-sa[j]);
224 
225  // Disable features if f-angle is greater than 1.
226  if ( _dir_thres_weak>0.99) nrank=1;
227  tranks[j] = 3-nrank;
228  }
229  }
230 
231  _buf->delete_attribute( sa_attr->name());
232  _buf->init_done( false);
233 
234  // Reduce tangranks to ensure shared nodes have the same value across panes
235  _surf->reduce_on_shared_nodes( _tangranks, Manifold::OP_MIN);
236 }
237 
238 // Solve the minimization problem (x^T)Ax+2b^Tx with eigen-decomposition.
239 int FaceOffset_3::
241  double angle_defect) {
242 
243  // A_io will be replaced by its eigenvectors.
244  Vector_3 *es = A_io;
245 
246  // Create a backup of b_io, as b_io will be replaced by eigenvalues.
247  const Vector_3 b = b_io;
248  Vector_3 &lambdas = b_io;
249 
250  // Compute the eigenvalues and eigenvectors of the matrix.
251  // Note that lambdas will be in decreasing order!
252  compute_eigenvectors( es, lambdas);
253 
254  // Classify offset intersection based on acos(-b.norm()/rv) and lambdas
255  if ( std::abs(angle_defect) >= _tol_ad)
256  return 3; // Sharp corner
257  else if (lambdas[1] < _dir_thres_weak*lambdas[0])
258  return 1; // Ridge
259  else if ( lambdas[2] < _dir_thres_strong*lambdas[1])
260  return 2; // Flat
261  else // Vertices that are neither sharp nor flat, but have
262  return 4; // ambiguous ridge directions
263 }
264 
265 // Update tangential motion of ridge vertices
266 void FaceOffset_3::
268  COM::Attribute *vcenters_buf =
269  _buf->new_attribute( "FO_vcenters_buf", 'n', COM_DOUBLE, 3, "");
270  COM::Attribute *vecdiff_buf =
271  _buf->new_attribute( "FO_vecdiff_buf", 'n', COM_DOUBLE, 3, "");
272  _buf->resize_array( vcenters_buf, 0);
273  _buf->resize_array( vecdiff_buf, 0);
274 
275  // Loop through the panes and ridge edges
276  std::vector< COM::Pane*>::iterator it = _panes.begin();
277  Manifold::PM_iterator pm_it=_surf->pm_begin();
278 
279  for ( int i=0, local_npanes = _panes.size(); i<local_npanes;
280  ++i, ++it, ++pm_it) {
281  COM::Pane *pane = *it;
282  const std::set< Edge_ID> &eset_pn = _edges[i]; // List of ridge edges
283 
284  const Point_3 *pnts = reinterpret_cast<Point_3*>
285  (pane->attribute(COM_NC)->pointer());
286  Vector_3 *vcs = reinterpret_cast<Vector_3*>
287  (pane->attribute(vcenters_buf->id())->pointer());
288  Vector_3 *vdiff = reinterpret_cast<Vector_3*>
289  (pane->attribute(vecdiff_buf->id())->pointer());
290 
291  for ( std::set< Edge_ID>::const_iterator eit=eset_pn.begin(),
292  eend=eset_pn.end(); eit!=eend; ++eit) {
293  // Make sure that eid_opp is not border
294  Edge_ID eid = *eit, eid_opp = pm_it->get_opposite_real_edge( eid);
295  bool is_border_edge = pm_it->is_physical_border_edge( eid_opp);
296 
297  Element_node_enumerator ene( pane, eid.eid());
298  int lid = eid.lid(), neighbor = (lid+1)%ene.size_of_edges();
299  int vindex = ene[lid]-1, windex = ene[neighbor]-1;
300 
301  // For ridge and flat vertices, compute based on edge centers
302  Vector_3 diff = pnts[ windex] - pnts[vindex];
303  vcs[vindex] += diff;
304  if ( vdiff[vindex].is_null()) vdiff[vindex] = diff;
305  else vdiff[vindex] -= diff;
306 
307  if ( is_border_edge) {
308  vcs[windex] -= diff;
309  if ( vdiff[windex].is_null()) vdiff[windex] = -diff;
310  else vdiff[windex] += diff;
311  }
312  }
313  }
314 
315  _surf->reduce_on_shared_nodes( vcenters_buf, Manifold::OP_SUM);
316  _surf->reduce_on_shared_nodes( vecdiff_buf, Manifold::OP_DIFF);
317 
318  const Vector_3 null_vec(0,0,0);
319  it = _panes.begin();
320  // Finally, copy from vcenters_buf to vcenters
321  for ( int i=0, local_npanes = _panes.size();
322  i<local_npanes; ++i, ++it) {
323  COM::Pane *pane = *it;
324 
325  Vector_3 *vcs_buf = reinterpret_cast<Vector_3*>
326  (pane->attribute(vcenters_buf->id())->pointer());
327  Vector_3 *vcs = reinterpret_cast<Vector_3*>
328  (pane->attribute(_vcenters->id())->pointer());
329  Vector_3 *vdiff = reinterpret_cast<Vector_3*>
330  (pane->attribute(vecdiff_buf->id())->pointer());
331  const char *tranks = reinterpret_cast<const char*>
332  ( pane->attribute(_tangranks->id())->pointer());
333  const char *cranks = reinterpret_cast<const char*>
334  ( pane->attribute(_ctangranks->id())->pointer());
335  const char *val_bndry_nodes = reinterpret_cast<const char*>
336  ( pane->attribute(_cnstr_bndry_nodes->id())->pointer());
337 
338  for (int j=0, jn=pane->size_of_real_nodes(); j<jn; ++j) if (cranks[j]!=2) {
339  if ( cranks[j]==0)
340  vcs[ j] = null_vec;
341  else if ( val_bndry_nodes && val_bndry_nodes[j] && !vdiff[j].is_null()) {
342  vcs_buf[j] = (vcs_buf[j]*vdiff[j]*vdiff[j])/vdiff[j].squared_norm();
343 
344  vcs[ j] = (1./4.)*vcs_buf[j];
345  }
346  }
347  }
348 
349  _buf->delete_attribute( vecdiff_buf->name());
350  _buf->delete_attribute( vcenters_buf->name());
351  _buf->init_done( false);
352 }
353 
354 // Mark weak vertices, i.e. the vertices that are not on or incident
355 // on features but has non-trivial second-largest eigenvalues.
357  char zero_c=0;
358  Rocblas::copy_scalar( &zero_c, _weak);
359 
360  std::vector< COM::Pane*>::iterator it = _panes.begin();
361  Manifold::PM_iterator pm_it=_surf->pm_begin();
362  for ( int i=0, local_npanes = _panes.size();
363  i<local_npanes; ++i, ++it, ++pm_it) {
364  COM::Pane *pane = *it;
365  char *tranks = reinterpret_cast<char*>
366  ( pane->attribute(_tangranks->id())->pointer());
367  char *weak = reinterpret_cast<char*>
368  ( pane->attribute(_weak->id())->pointer());
369  const Vector_3 *lambdas = reinterpret_cast<const Vector_3*>
370  ( pane->attribute(_eigvalues->id())->pointer());
371 
372  for ( int j=0, nj=pane->size_of_real_nodes(); j<nj; ++j) {
373  weak[j] = tranks[j]==2 &&
374  lambdas[j][1] >= _eig_weak_lb*lambdas[j][0] &&
375  lambdas[j][1] <= _eig_weak_ub*lambdas[j][0] ||
376  tranks[j]<=1 && _eig_thres*lambdas[j][0] > lambdas[j][1];
377  }
378  }
379 
380  _surf->reduce_on_shared_nodes( _weak, Manifold::OP_MIN);
381 }
382 
383 inline double SQR( double x) { return (x*x); }
384 
385 // ----------------------------------------------------------------------------
386 void dsytrd3(double A[3][3], double Q[3][3], double d[3], double e[2])
387 // ----------------------------------------------------------------------------
388 // Reduces a symmetric 3x3 matrix to tridiagonal form by applying
389 // (unitary) Householder transformations:
390 // [ d[0] e[0] ]
391 // A = Q . [ e[0] d[1] e[1] ] . Q^T
392 // [ e[1] d[2] ]
393 // The function accesses only the diagonal and upper triangular parts of
394 // A. The access is read-only.
395 // ----------------------------------------------------------------------------
396 // Note: Based on implementat of Joachim Kopp (www.mpi-hd.mpg.de/~jkopp/3x3/)
397 // ---------------------------------------------------------------------------
398 {
399  double u[3], q[3];
400  double omega, f;
401  double K, h, g;
402 
403  // Initialize Q to the identitity matrix
404  for (int i=0; i < 3; i++)
405  {
406  Q[i][i] = 1.0;
407  for (int j=0; j < i; j++)
408  Q[i][j] = Q[j][i] = 0.0;
409  }
410 
411  // Bring first row and column to the desired form
412  h = SQR(A[0][1]) + SQR(A[0][2]);
413  if (A[0][1] > 0)
414  g = -sqrt(h);
415  else
416  g = sqrt(h);
417  e[0] = g;
418  f = g * A[0][1];
419  u[1] = A[0][1] - g;
420  u[2] = A[0][2];
421 
422  omega = h - f;
423  if (omega > 0.0)
424  {
425  omega = 1.0 / omega;
426  K = 0.0;
427  for (int i=1; i < 3; i++)
428  {
429  f = A[1][i] * u[1] + A[i][2] * u[2];
430  q[i] = omega * f; // p
431  K += u[i] * f; // u* A u
432  }
433  K *= 0.5 * SQR(omega);
434 
435  for (int i=1; i < 3; i++)
436  q[i] = q[i] - K * u[i];
437 
438  d[0] = A[0][0];
439  d[1] = A[1][1] - 2.0*q[1]*u[1];
440  d[2] = A[2][2] - 2.0*q[2]*u[2];
441 
442  // Store inverse Householder transformation in Q
443  for (int j=1; j < 3; j++)
444  {
445  f = omega * u[j];
446  for (int i=1; i < 3; i++)
447  Q[i][j] = Q[i][j] - f*u[i];
448  }
449 
450  // Calculate updated A[1][2] and store it in e[1]
451  e[1] = A[1][2] - q[1]*u[2] - u[1]*q[2];
452  }
453  else
454  {
455  for (int i=0; i < 3; i++)
456  d[i] = A[i][i];
457  e[1] = A[1][2];
458  }
459 }
460 
461 // ----------------------------------------------------------------------------
462 int dsyevq3(double A[3][3], double Q[3][3], double w[3])
463 // ----------------------------------------------------------------------------
464 // Calculates the eigenvalues and normalized eigenvectors of a symmetric 3x3
465 // matrix A using the QL algorithm with implicit shifts, preceded by a
466 // Householder reduction to tridiagonal form.
467 // The function accesses only the diagonal and upper triangular parts of A.
468 // The access is read-only.
469 // ----------------------------------------------------------------------------
470 // Parameters:
471 // A: The symmetric input matrix
472 // Q: Storage buffer for eigenvectors
473 // w: Storage buffer for eigenvalues
474 // ----------------------------------------------------------------------------
475 // Return value:
476 // 0: Success
477 // -1: Error (no convergence)
478 // ----------------------------------------------------------------------------
479 // Dependencies:
480 // dsytrd3()
481 // ----------------------------------------------------------------------------
482 // Note: Based on implementat of Joachim Kopp (www.mpi-hd.mpg.de/~jkopp/3x3/)
483 // ----------------------------------------------------------------------------
484 {
485  double e[3]; // The third element is used only as temporary workspace
486  double g, r, p, f, b, s, c, t; // Intermediate storage
487  int nIter;
488  int m;
489 
490  // Transform A to real tridiagonal form by the Householder method
491  dsytrd3(A, Q, w, e);
492 
493  // Calculate eigensystem of the remaining real symmetric tridiagonal matrix
494  // with the QL method
495  //
496  // Loop over all off-diagonal elements
497  for (int l=0; l < 2; l++)
498  {
499  nIter = 0;
500  for (;;)
501  {
502  // Check for convergence and exit iteration loop if off-diagonal
503  // element e(l) is zero
504  for (m=l; m < 2; m++)
505  {
506  g = fabs(w[m])+fabs(w[m+1]);
507  if (fabs(e[m]) + g == g)
508  break;
509  }
510  if (m == l)
511  break;
512 
513  if (nIter++ >= 30)
514  return -1;
515 
516  // Calculate g = d_m - k
517  g = (w[l+1] - w[l]) / (e[l] + e[l]);
518  r = sqrt(SQR(g) + 1.0);
519  if (g > 0)
520  g = w[m] - w[l] + e[l]/(g + r);
521  else
522  g = w[m] - w[l] + e[l]/(g - r);
523 
524  s = c = 1.0;
525  p = 0.0;
526  for (int i=m-1; i >= l; i--)
527  {
528  f = s * e[i];
529  b = c * e[i];
530  if (fabs(f) > fabs(g))
531  {
532  c = g / f;
533  r = sqrt(SQR(c) + 1.0);
534  e[i+1] = f * r;
535  c *= (s = 1.0/r);
536  }
537  else
538  {
539  s = f / g;
540  r = sqrt(SQR(s) + 1.0);
541  e[i+1] = g * r;
542  s *= (c = 1.0/r);
543  }
544 
545  g = w[i+1] - p;
546  r = (w[i] - g)*s + 2.0*c*b;
547  p = s * r;
548  w[i+1] = g + p;
549  g = c*r - b;
550 
551  // Form eigenvectors
552  for (int k=0; k < 3; k++)
553  {
554  t = Q[k][i+1];
555  Q[k][i+1] = s*Q[k][i] + c*t;
556  Q[k][i] = c*Q[k][i] - s*t;
557  }
558  }
559  w[l] -= p;
560  e[l] = g;
561  e[m] = 0.0;
562  }
563  }
564 
565  return 0;
566 }
567 
568 // Compute eigenvalues and eigenvectors of a 3x3 matrix A.
569 // At output, the eigenvalues are saved in lambdas in decending order.
570 // The columns of A are replaced by the orthonormal eigenvectors.
571 void FaceOffset_3::
573 
574  double abuf[3][3] = { {A[0][0], A[0][1], A[0][2]},
575  {A[1][0], A[1][1], A[1][2]},
576  {A[2][0], A[2][1], A[2][2]}};
577  double ebuf[3][3];
578 
579  int info = dsyevq3( abuf, ebuf, &lambdas[0]);
580  COM_assertion_msg( info==0, "Computation of eigenvectos failed");
581 
582  std::swap( ebuf[0][1], ebuf[1][0]);
583  std::swap( ebuf[0][2], ebuf[2][0]);
584  std::swap( ebuf[1][2], ebuf[2][1]);
585 
586  const Vector_3 *buf = (const Vector_3*)&ebuf[0][0];
587 
588  if ( lambdas[0]<lambdas[1]) {
589  if ( lambdas[1]<lambdas[2]) { // l2>l1>l0
590  std::swap( lambdas[0], lambdas[2]);
591  A[0] = buf[2]; A[1] = buf[1]; A[2] = buf[0];
592  }
593  else {
594  double t = lambdas[0];
595  lambdas[0] = lambdas[1];
596  A[0] = buf[1];
597 
598  if ( t<lambdas[2]) { // l1>=l2>l0
599  lambdas[1] = lambdas[2]; lambdas[2] = t;
600  A[1] = buf[2]; A[2] = buf[0];
601  }
602  else { // l1>l0>=l2
603  lambdas[1] = t;
604  A[1] = buf[0]; A[2] = buf[2];
605  }
606  }
607  }
608  else if ( lambdas[0]<lambdas[2]) { // l2>l0>=l1
609  double t = lambdas[0];
610  lambdas[0] = lambdas[2]; lambdas[2] = lambdas[1]; lambdas[1] = t;
611  A[0] = buf[2]; A[1] = buf[0]; A[2] = buf[1];
612  }
613  else {
614  A[0] = buf[0];
615  if ( lambdas[1]<lambdas[2]) { // l0>=l2>l1
616  std::swap( lambdas[1], lambdas[2]);
617  A[1] = buf[2]; A[2] = buf[1];
618  }
619  else {// l0>=l1>=l2
620  A[1] = buf[1]; A[2] = buf[2];
621  }
622  }
623 }
624 
626 
627 
628 
629 
630 
631 
static void compute_eigenvectors(Vector_3 A[3], Vector_3 &lambdas)
void swap(int &a, int &b)
Definition: buildface.cpp:88
COM::Attribute * _eigvalues
Definition: FaceOffset_3.h:406
COM::Window * _buf
An adaptor for enumerating node IDs of an element.
#define PROP_END_NAMESPACE
Definition: propbasic.h:29
COM::Attribute * _As
Definition: FaceOffset_3.h:403
double _eig_weak_ub
Definition: FaceOffset_3.h:397
const NT & d
j indices k indices k
Definition: Indexing.h:6
void obtain_face_offset(const Point_3 *pnts, const double *spd_ptr, const COM::Attribute *spd, double dt, const Vector_3 *dirs, COM::Element_node_enumerator &ene, Vector_3 &ns_nz, Point_3 &cnt, Vector_3 *disps, Vector_3 *ns)
Definition: FaceOffset_3.C:332
#define PROP_BEGIN_NAMESPACE
Definition: propbasic.h:28
#define COM_assertion_msg(EX, msg)
double s
Definition: blastest.C:80
MAP::Facet_ID Edge_ID
Definition: Manifold_2.h:49
COM::Attribute * _vcenters
Definition: FaceOffset_3.h:415
double _tol_ad
Definition: FaceOffset_3.h:393
COM::Attribute * _faceareas
Definition: FaceOffset_3.h:414
void update_vertex_centers()
COM::Attribute * _tangranks
Definition: FaceOffset_3.h:417
double sqrt(double d)
Definition: double.h:73
std::vector< COM::Pane * > _panes
COM::Attribute * _eigvecs
Definition: FaceOffset_3.h:407
*********************************************************************Illinois Open Source License ****University of Illinois NCSA **Open Source License University of Illinois All rights reserved ****Developed free of to any person **obtaining a copy of this software and associated documentation to deal with the Software without including without limitation the rights to ** copy
Definition: roccomf90.h:20
COM::Attribute * _facecenters
Definition: FaceOffset_3.h:413
double _eig_weak_lb
Definition: FaceOffset_3.h:396
rational * A
Definition: vinci_lass.c:67
double _dir_thres_strong
Definition: FaceOffset_3.h:382
double SQR(double x)
Definition: smooth_medial.C:45
double _dir_thres_weak
Definition: FaceOffset_3.h:381
int size_of_edges() const
Number of edges per element.
void compute_quadrics(double dt, const COM::Attribute *spds, COM::Attribute *rhs, COM::Attribute *predicted)
Compute quadrics for every vertex.
blockLoc i
Definition: read.cpp:79
double angle(Vector_3< double > v1, Vector_3< double > v2)
Compute the angle between two vectors.
Definition: geometry.C:61
void int int REAL * x
Definition: read.cpp:74
COM::Attribute * _bmedial
Definition: FaceOffset_3.h:405
Manifold * _surf
COM::Attribute * _weights
Definition: FaceOffset_3.h:425
static void div(const Attribute *x, const Attribute *y, Attribute *z)
Operation wrapper for division.
Definition: op3args.C:269
static double eval_angle(const Vector_3 &v1, const Vector_3 &v2)
Definition: FaceOffset_3.h:323
COM::Attribute * _weak
Definition: FaceOffset_3.h:419
static void copy_scalar(const void *x, Attribute *y)
Operation wrapper for copy (x is a scalar pointer).
Definition: op2args.C:583
void mark_weak_vertices()
Mark vertices that are weak.
j indices j
Definition: Indexing.h:6
static const double pi
Definition: FaceOffset_3.h:429
double _eig_thres
Definition: FaceOffset_3.h:394
NT q
COM::Attribute * _cnstr_bndry_nodes
std::vector< std::set< Edge_ID > > _edges
Definition: FaceOffset_3.h:427
NT abs(const NT &x)
Definition: number_utils.h:130
int dsyevq3(double A[3][3], double Q[3][3], double w[3])
static void copy(const Attribute *x, Attribute *y)
Wrapper for copy.
Definition: op2args.C:333
COM::Attribute * _vnormals
Definition: FaceOffset_3.h:410
void next()
Go to the next element within the connectivity tables of a pane.
void int * nj
Definition: read.cpp:74
Some basic geometric data types.
Definition: mapbasic.h:54
void dsytrd3(double A[3][3], double Q[3][3], double d[3], double e[2])
Definition: smooth_medial.C:48
void info()
Print informations about CImg environement variables.
Definition: CImg.h:5702
COM::Attribute * _facenormals
Definition: FaceOffset_3.h:412
COM::Attribute * _ctangranks
Definition: FaceOffset_3.h:418
int eigen_analyze_vertex(Vector_3 A_io[3], Vector_3 &b_io, double angle_defect=0)