Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FaceOffset_3.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: FaceOffset_3.C,v 1.34 2008/12/06 08:45:27 mtcampbe Exp $
24 
25 #include "FaceOffset_3.h"
26 #include "../Rocblas/include/Rocblas.h"
27 #include "../Rocsurf/include/Generic_element_2.h"
28 #include "../Rocsurf/include/Rocsurf.h"
29 #include <algorithm>
30 
32 
33 //============== Debug features =======
34 // Export debugging information to the user window, if user has
35 // the registered "back-door" attributes to get debug info such
36 // as normals. It should be set to true for development purpose.
37 #define EXPORT_DEBUG_INFO 1
38 
39 //=================================================
40 
41 const double FaceOffset_3::pi= 3.14159265358979;
42 
43 // Set parameters to default values
44 void FaceOffset_3::reset_default_parameters( bool feature_preserve) {
45 
46  // Two default feature modes:
47  if ( feature_preserve) {
48  // Feature-preserving mode: (Recommended for structured meshes)
50  _tol_angle_weak = 18.*pi/180;
51  }
52  else {
53  // Feature-smearing mode: (Recommended for unstructured meshes)
55  _tol_angle_weak = 30.*pi/180.;
56  }
57 
58  _dir_thres_weak = square(tan(0.5*_tol_angle_weak)); // 0.003;
59  _tol_angle_strong = 65.*pi/180;
60  _dir_thres_strong = 0.7;
61 
62  _tol_kstrong = 5;
63  _tol_kangle = (49./180.)*pi;
64  _tol_eangle = (25/180.)*pi;
65 
66  _tol_turn_angle = pi/4.5;
67  _tol_ad = pi/3;
69 
70  _nrm_dfsn = 1; _eig_thres = 0.003;
71  _eig_weak_lb = 1.e-4; _eig_weak_ub = 0.025;
72 
75  _wf_expn = true; _feature_layer=0;
76 }
77 
78 // Construct an object from a window manifold and a buffer window.
79 // Extend the buffer window to store eigenvalues, eigenvectors,
80 // tangent ranks, rescaling factors, and weights.
81 FaceOffset_3::FaceOffset_3( Manifold *wm, COM::Window *buf)
82  : Propagation_3( wm, buf)
83 {
84  // Determine whether the mesh is structured
85  _is_strtd = true;
86  std::vector< COM::Pane*>::iterator it = _panes.begin();
87  for (int i=0, local_npanes = _panes.size(); i<local_npanes; ++i, ++it) {
88  COM::Pane *pane = *it;
89  if ( !pane->is_structured()) _is_strtd = false;
90  }
91  if ( COMMPI_Initialized()) {
92  int s = _is_strtd;
93  MPI_Allreduce( &s, &_is_strtd, 1, MPI_INT, MPI_MIN,
94  _buf->get_communicator());
95  }
96 
97  // Set parameters to default values.
99 
100  // Extend buffer window
101  _facenormals = _buf->new_attribute( "facenormals", 'e', COM_DOUBLE, 3, "");
102  _buf->resize_array( _facenormals, 0);
103 
104  _facecenters = _buf->new_attribute( "facecenters", 'e', COM_DOUBLE, 3, "");
105  _buf->resize_array( _facecenters, 0);
106 
107  _faceareas = _buf->new_attribute( "faceareas", 'e', COM_DOUBLE, 1, "");
108  _buf->resize_array( _faceareas, 0);
109 
110  // This is used to store v-center for smoothing offset.
111  _vcenters = _buf->new_attribute( "vcenters", 'n', COM_DOUBLE, 3, "");
112  _buf->resize_array( _vcenters, 0);
113 
114  _eigvalues = _buf->new_attribute( "lambda", 'n', COM_DOUBLE, 3, "");
115  _buf->resize_array( _eigvalues, 0);
116 
117  _vnormals = _buf->new_attribute( "vnormals", 'n', COM_DOUBLE, 3, "");
118  _buf->resize_array( _vnormals, 0);
119 
120  _ridges = _buf->new_attribute( "ridges", 'p', COM_INT, 2, "");
121 
122  _ridgeneighbors = _buf->new_attribute( "ridgeneighbors", 'n', COM_INT, 4, "");
123  _buf->resize_array( _ridgeneighbors, 0);
124 
125  _weak = _buf->new_attribute( "weakfeature", 'n', COM_CHAR, 1, "");
126  _buf->resize_array( _weak, 0);
127 
128  _strong = _buf->new_attribute( "strongfeature", 'n', COM_CHAR, 1, "");
129  _buf->resize_array( _strong, 0);
130 
131  _As = _buf->new_attribute( "As", 'n', COM_DOUBLE, 9, "");
132  _buf->resize_array( _As, 0);
133 
134  _boffset = _buf->new_attribute( "boffset", 'n', COM_DOUBLE, 3, "");
135  _buf->resize_array( _boffset, 0);
136 
137  _bmedial = _buf->new_attribute( "bmedial", 'n', COM_DOUBLE, 3, "");
138  _buf->resize_array( _bmedial, 0);
139 
140  _eigvecs = _buf->new_attribute( "eigvecs", 'n', COM_DOUBLE, 9, "");
141  _buf->resize_array( _eigvecs, 0);
142 
143  _tangranks = _buf->new_attribute( "tangranks", 'n', COM_CHAR, 1, "");
144  _buf->resize_array( _tangranks, 0);
145 
146  _ctangranks = _buf->new_attribute( "ctangranks", 'n', COM_CHAR, 1, "");
147  _buf->resize_array( _ctangranks, 0);
148 
149  _scales = _buf->new_attribute( "scales", 'n', COM_DOUBLE, 1, "");
150  _buf->resize_array( _scales, 0);
151 
152  _weights = _buf->new_attribute( "weights", 'n', COM_DOUBLE, 1, "");
153  _buf->resize_array( _weights, 0);
154 
155  _buf->init_done(false);
156 }
157 
158 // Main entry of the algorithm
159 double FaceOffset_3::
160 time_stepping( const COM::Attribute *spds, double dt,
161  COM::Attribute *disps, int *smoothed) {
162 
163  COM_assertion_msg( spds || dt==0,
164  "If no speed function, then time step must be zero.");
165 
166  // Inherit speeds and displacement onto the buffer window
167  const COM::Attribute *spds_buf = spds ?
168  ( (spds->window() == _buf) ? spds :
169  _buf->inherit( const_cast<COM::Attribute*>(spds), "speeds_inherited",
170  COM::Pane::INHERIT_USE, true, NULL, 0)) : NULL;
171  COM::Attribute *disps_buf =
172  _buf->inherit( disps, "disps_inherited", COM::Pane::INHERIT_USE,
173  true, NULL, 0);
174  COM::Attribute *disps_tmp =
175  _buf->inherit( disps, "disps_inherited2", COM::Pane::INHERIT_CLONE,
176  true, NULL, 0);
177  _buf->init_done( false);
178 
179  // Compute the face areas and store them.
180  SURF::Rocsurf::compute_element_areas( _faceareas);
181 
182  // First, compute the quadrics to determine the offset intersection
183  // with given time step.
184  bool with_nodal_velo = dt>0 && spds->is_nodal() && spds->size_of_components()==3;
185 
186  // If wavefrontal, then perform two setps.
187  for ( int i=0; i<1+(_wf_expn && dt>0); ++i) {
188  compute_quadrics( dt, spds_buf, _boffset, i ? disps_buf : NULL);
189 
190  if ( with_nodal_velo)
191  Rocblas::mul_scalar( spds, &dt, disps_buf);
192  else
193  Rocblas::copy( _boffset, disps_buf);
194 
195  // Compute mean normals and offset directions during first iteration
196  if ( i==0 && _wf_expn && dt>0) {
197  compute_directions( !with_nodal_velo ? disps_buf : NULL, false);
198 
199  // Enforce constraints.
200  obtain_constrained_directions( disps_buf, NULL);
201  }
202  }
203 
204  // Filter out isolated ridge vertices and identify ridge edges.
207 
208  // Recompute mean normals and offset directions with only primary component
209  compute_directions( (dt!=0 && !with_nodal_velo) ? disps_buf : NULL, true);
210 
211  if ( dt==0)
212  denoise_surface( NULL, disps_buf);
213  else {
214  double zero=0.;
215  Rocblas::copy_scalar( &zero, disps_tmp);
216  denoise_surface( disps_buf, disps_tmp);
217  Rocblas::add( disps_buf, disps_tmp, disps_buf);
218  }
219 
220  bool needs_smoothing=(!smoothed || *smoothed);
221  if ( smoothed) *smoothed = true;
222 
223  if ( !needs_smoothing) {
224  Rocblas::copy( disps_buf, _vcenters);
225  if ( smoothed && *smoothed) *smoothed=false;
226  }
227  else if ( _is_strtd) {
228  update_vertex_centers(); // Update vertex centers for ridge vertices
230  _vcenters, disps_tmp, _weights);
231  }
232  else if ( _smoother == SMOOTHER_ANISOTROPIC) {
233  // Compute anisotropic vertex centers.
235  }
236  update_vertex_centers(); // Update vertex centers for ridge vertices
237 
238  // Recompute face normals if propagation under nodal velocity
239  if ( with_nodal_velo) {
240  _surf->compute_normals( _facenormals);
241  _surf->update_bd_normals( _facenormals, false);
242  }
243 
244  // Constrain the displacements and vertex-centers.
246  if (_bnd_set) {
247  bound_nodal_motion( disps_buf);
248  _surf->reduce_on_shared_nodes( disps_buf, Manifold::OP_MAXABS);
249  }
250 
251 #if EXPORT_DEBUG_INFO
252  COM::Attribute *ctypes = disps->window()->attribute( "cnstr_types_nodal");
253  if ( _cnstr_set && ctypes) Rocblas::copy( _cnstr_nodes, ctypes);
254 
255  COM::Attribute *tranks = disps->window()->attribute( "tangranks");
256  if ( tranks) Rocblas::copy( _tangranks, tranks);
257 
258  COM::Attribute *facenormals = disps->window()->attribute( "facenormals");
259  if ( facenormals) Rocblas::copy( _facenormals, facenormals);
260 
261  COM::Attribute *facecenters = disps->window()->attribute( "facecenters");
262  if ( facecenters) Rocblas::copy( _facecenters, facecenters);
263 
264  COM::Attribute *eigvecs = disps->window()->attribute( "eigvecs");
265  if ( eigvecs) Rocblas::copy( _eigvecs, eigvecs);
266 
267  COM::Attribute *lambdas = disps->window()->attribute( "lambdas");
268  if ( lambdas) Rocblas::copy( _eigvalues, lambdas);
269 
270  COM::Attribute *ridges = disps->window()->attribute( "ridges");
271  if ( ridges)
272  disps->window()->inherit( _ridges, "ridges", COM::Pane::INHERIT_CLONE,
273  true, NULL, 0);
274 
275  if ( dt>0) {
276  COM::Attribute *disps_novis = disps->window()->attribute( "disps_novis");
277  if ( disps_novis) Rocblas::copy( disps, disps_novis);
278  }
279 #endif
280 
281  // Second, reduce time step based on stability limit, and rescale
282  // displacements by the reduced time step and wavefrontal expansion.
283  double dt_sub = dt;
284  if ( _courant>0) {
285  for ( ;;) {
286  double scale = rescale_displacements( disps_buf, _vcenters);
287 
288  if ( scale==1) break;
289 
290  if ( dt==0 && _verb && _rank==0)
291  std::cout << "Rocprop: Scaled back displacement with a factor of "
292  << scale << std::endl;
293 
294  dt_sub *= scale;
295 
296  if ( !with_nodal_velo || _smoother == SMOOTHER_LAPLACIAN) break;
297  // If nodal velocity
298  Rocblas::mul_scalar( spds, &dt_sub, disps_buf);
299  if ( smoothed) smoothed=false;
300  }
301  }
302  else if ( dt==0) {
303  Rocblas::copy( _vcenters, disps_buf);
304  }
305 
306 #if EXPORT_DEBUG_INFO
307  if ( dt>0) {
308  COM::Attribute *scales = disps->window()->attribute( "scales");
309  if ( scales) Rocblas::copy( _scales, scales);
310  }
311 #endif
312 
313  _surf->reduce_on_shared_nodes( disps_buf, Manifold::OP_MAXABS);
314 
315  // Deallocate spds_buf and disps_buf
316  _buf->delete_attribute( disps_tmp->name());
317  _buf->delete_attribute( disps_buf->name());
318  if ( spds_buf && spds_buf!=spds)
319  _buf->delete_attribute( spds_buf->name());
320  _buf->init_done( false);
321 
322  // Finally, return the current time step.
323  return dt_sub;
324 }
325 
326 // This function computes the normal and center of the offset face. The
327 // speed can be a nodal attribute (scalar or 3-vector), or be an elemental
328 // attribute. (scalar associated with face center, 3-vector associated
329 // with face center, or 3-vectors associated with three quadrature points.
330 // Only triangular meshes supported for latter two cases.)
331 void FaceOffset_3::
332 obtain_face_offset( const Point_3 *pnts, const double *spd_ptr,
333  const Attribute *spd, double dt, const Vector_3 *dirs,
335  Vector_3 &ns_nz, Point_3 &cnt,
336  Vector_3 *disps, Vector_3 *ns) {
337 
338  const Vector_3 null_vec(0,0,0);
339  int ne=ene.size_of_edges();
340 
341  // Evaluate current face normal
342  Element_node_vectors_k_const<Point_3> ps; ps.set( pnts, ene, 1);
343  SURF::Generic_element_2 e(ne);
344  Point_3 pnts_buf[9];
345 
346  // Compute new position for all vertices
347  int ncomp = spd?spd->size_of_components():0;
348  COM_assertion_msg( !ncomp || ncomp==1 && spd->is_elemental() ||
349  ncomp==3 && spd->is_nodal(),
350  "Speed must be scalar-elemental or 3-vector-nodal");
351 
352  // Copy coordinates into buffer.
353  for ( int i=0; i<ne; ++i) pnts_buf[i] = ps[i];
354 
355  // If dirs is present, then compute the displacement
356  if ( dt!=0 && ncomp==3) { // Add dt*speed to each point
357  for ( int i=0; i<ne; ++i)
358  pnts_buf[i] += disps[i] = dt*((const Vector_3*)spd_ptr)[ene[i]-1];
359  }
360  else if ( dt==0) {
361  for ( int i=0; i<ne; ++i) disps[i] = null_vec;
362  }
363 
364  // Offset face normal equal to current face normal
365  e.interpolate_to_center((Vector_3*)pnts_buf, (Vector_3*)&cnt);
366 
367  // Compute normal directions.
368  Vector_2 nc(0.5,0.5);
369  Vector_3 J[2];
370  e.Jacobian( pnts_buf, nc, J);
371  ns_nz = Vector_3::cross_product( J[0], J[1]).normalize();
372 
373  if ( ne==3) {
374  ns[0] = ns[1] = ns[2] = ns_nz;
375  }
376  else {
377  for ( int k=0; k<ne; ++k) {
378  Vector_3 ts[] = { pnts_buf[(k+1)%ne]-pnts_buf[k],
379  pnts_buf[(k+ne-1)%ne]-pnts_buf[k]};
380  ns[k] = Vector_3::cross_product( ts[0], ts[1]);
381 
382  // If the angle is far from 180 or 0 degrees, then use triangle's normal
383  double l = ns[k].norm();
384  if ( l > std::abs(0.05*ts[0]*ts[1])) ns[k] /= l;
385  else ns[k] = ns_nz;
386  }
387  }
388 
389  // Compute points for normal motion.
390  if (dt!=0 && ncomp==1) {
391  double l = dt*spd_ptr[ene.id()-1];
392  Vector_3 d = l*ns_nz;
393  (Vector_3&)cnt += l*ns_nz;
394 
395  if ( ne==3) {
396  for ( int k=0; k<ne; ++k) pnts_buf[k] += (disps[k] = d);
397  }
398  else {
399  for ( int k=0; k<ne; ++k) pnts_buf[k] += (disps[k] = l * ns[k]);
400  }
401  }
402 
403  // If wave-frontal motion, recalculate the directions and displacements.
404  if ( dirs) {
405  for ( int i=0; i<ne; ++i) {
406  int vindex= ene[i]-1;
407 
408  if ( dirs[vindex].is_null()) {
409  disps[i] = null_vec;
410  pnts_buf[i] = ps[i] + disps[i];
411  }
412  else {
413  Vector_3 dir = dirs[vindex];
414  dir.normalize();
415 
416  Vector_3 tng = ( pnts_buf[(i+ne-1)%ne] - pnts_buf[i]) +
417  (pnts_buf[(i+1)%ne] - pnts_buf[i]);
418 
419  if ( tng * dir < 0) { // Expansion
420  double l = (disps[i] * ns[i]);
421  if ( dir * ns[i]<0) l=-l;
422 
423  (disps[i] = dir) *= l;
424 
425  pnts_buf[i] = ps[i] + disps[i];
426  }
427  }
428  }
429 
430  // Reevaluate normal directions.
431  e.Jacobian( pnts_buf, nc, J);
432  ns_nz = Vector_3::cross_product( J[0], J[1]).normalize();
433 
434  if ( ne==3) {
435  ns[0] = ns[1] = ns[2] = ns_nz;
436  }
437  else {
438  for ( int k=0; k<ne; ++k) {
440  ( pnts_buf[(k+1)%ne]-pnts_buf[k],
441  pnts_buf[(k+ne-1)%ne]-pnts_buf[k]).normalize();
442  }
443  }
444  }
445 }
446 
447 void FaceOffset_3::compute_directions( COM::Attribute *bo_attr, bool princ) {
448  // Loop through the panes and its real vertices
449  std::vector< COM::Pane*>::iterator it = _panes.begin();
450  for (int i=0, local_npanes = _panes.size(); i<local_npanes; ++i, ++it) {
451  COM::Pane *pane = *it;
452 
453  // Obtain pointers
454  Vector_3 *evs = reinterpret_cast<Vector_3*>
455  ( pane->attribute(_eigvecs->id())->pointer());
456  const Vector_3 *lambdas = reinterpret_cast<const Vector_3*>
457  ( pane->attribute(_eigvalues->id())->pointer());
458  Vector_3 *vnrms = reinterpret_cast<Vector_3*>
459  ( pane->attribute(_vnormals->id())->pointer());
460  Vector_3 *voffset = bo_attr ? reinterpret_cast<Vector_3*>
461  ( pane->attribute(bo_attr->id())->pointer()) : NULL;
462  const char *trank = princ ? reinterpret_cast<char*>
463  ( pane->attribute(_tangranks->id())->pointer()) : NULL;
464 
465  // Loop through all real nodes of the pane
466  for ( int j=0, jn=pane->size_of_real_nodes(); j<jn; ++j) {
467  obtain_directions( &evs[3*j], lambdas[j], princ ? 3-trank[j] : 3,
468  vnrms[j], voffset?voffset+j:NULL);
469  }
470  }
471 }
472 
473 // Obtain mean normal and offset direction at a vertex.
474 void FaceOffset_3::
475 obtain_directions( Vector_3 es[3], const Vector_3 &lambdas, int nrank,
476  Vector_3 &b_medial, Vector_3 *b_offset) const
477 {
478  // Use smaller threshold for acute angles.
479  double eps = lambdas[0]*_eig_thres;
480 
481  if ( b_offset) {
482  // Solve for x within primary space
483  Vector_3 d_offset(0,0,0);
484  for ( int k=0; k<nrank; ++k) {
485  if ( lambdas[k]>eps) {
486  d_offset += (es[k]* *b_offset/-lambdas[k])*es[k];
487  }
488  }
489 
490  *b_offset = d_offset;
491  }
492 
493  // Solve for x within primary space
494  Vector_3 d_medial(0,0,0);
495  for ( int k=0; k<nrank; ++k) {
496  if ( lambdas[k]>eps) {
497  d_medial += (es[k] * b_medial/-lambdas[k])*es[k];
498  }
499  }
500 
501  b_medial = d_medial.normalize();
502 }
503 
504 // Decompose propagation directions based on constraints
505 bool FaceOffset_3::
506 obtain_constrained_directions( COM::Attribute *disps_buf,
507  COM::Attribute *vcenters) {
508 
509  // Loop through the panes and its real faces
510  std::vector< COM::Pane*>::iterator it = _panes.begin();
511  Manifold::PM_iterator pm_it=_surf->pm_begin();
512 
513  const Vector_3 null_vec(0,0,0);
514 
515  // Loop through the panes and its real vertices
516  for (int i=0, local_npanes = _panes.size(); i<local_npanes; ++i, ++it) {
517  COM::Pane *pane = *it;
518 
519  // Obtain pointers
520  Vector_3 *evs = reinterpret_cast<Vector_3*>
521  ( pane->attribute(_eigvecs->id())->pointer());
522  Vector_3 *lambdas = reinterpret_cast<Vector_3*>
523  ( pane->attribute(_eigvalues->id())->pointer());
524  Vector_3 *ds = disps_buf ? reinterpret_cast<Vector_3*>
525  ( pane->attribute(disps_buf->id())->pointer()) : NULL;
526  const Vector_3 *bs = reinterpret_cast<Vector_3*>
527  ( pane->attribute(_boffset->id())->pointer());
528  const Vector_3 *bms = reinterpret_cast<Vector_3*>
529  ( pane->attribute(_bmedial->id())->pointer());
530 
531  // Feature information
532  const char *tranks = reinterpret_cast<char*>
533  ( pane->attribute(_tangranks->id())->pointer());
534  Vector_3 *vcnts = vcenters ? reinterpret_cast<Vector_3*>
535  ( pane->attribute(vcenters->id())->pointer()) : NULL;
536  const char *val_bndry_nodes = reinterpret_cast<const char*>
537  ( pane->attribute(_cnstr_bndry_nodes->id())->pointer());
538 
539  Vector_3 *As = reinterpret_cast<Vector_3*>
540  ( pane->attribute(_As->id())->pointer());
541  const int *cnstrs = _cnstr_nodes ? reinterpret_cast<int*>
542  ( pane->attribute(_cnstr_nodes->id())->pointer()) : NULL;
543 
544  // Loop through all real nodes of the pane
545  for ( int j=0, jn=pane->size_of_real_nodes(); j<jn; ++j) {
546  // Skip vertices with zero right-hand side, such as those at
547  // edge- and face-centers for quadratic elements
548  if ( lambdas[j][0]==0) continue;
549 
550  Vector_3 *es_v = &evs[3*j]; // eigen-vectors of current vertex.
551  int nrank = 3-tranks[j];
552 
553  Vector_3 V[2];
554  int ndirs = 0;
555  if ( cnstrs) get_constraint_directions( cnstrs[j], ndirs, V);
556 
557  if ( ndirs==3 ) { // Fixed point
558  lambdas[j] = es_v[0] = es_v[1] = es_v[2] = null_vec;
559 
560  if (ds) ds[j] = null_vec;
561  if (vcnts) vcnts[j] = null_vec;
562  continue;
563  }
564 
565  const Vector_3 *A_v = &As[3*j];
566  double eps = _eig_thres*lambdas[j][0];
567  // Propagate along the constrained direction.
568  double cos_fangle = 0.98481, sin_fangle = 0.17365; // (10 deg)
569 
570  if ( ds) {
571  Vector_3 b(0, 0, 0);
572  for ( int k=0; k<nrank; ++k) {
573  if ( lambdas[j][k]>eps)
574  b += ds[j]*es_v[k]*es_v[k];
575  }
576  ds[j] = b;
577  }
578 
579  if ( vcnts) { // Project tangent motion within null space
580  Vector_3 t(0, 0, 0);
581  for ( int k=1; k<3; ++k) {
582  if ( k>=nrank || lambdas[j][k]<eps)
583  // Note that vcnts may have component in domain space.
584  t += vcnts[j]*es_v[k]*es_v[k];
585  }
586  vcnts[j] = t;
587  }
588  if ( ndirs == 0) continue;
589 
590  // Evaluate surface normal
591  Vector_3 nrm_v;
592  if ( ds && ds[j]!=null_vec) {
593  nrm_v = ds[j]; nrm_v.normalize();
594  }
595  else {
596  if ( ds) ds[j] = null_vec;
597 
598  nrm_v = bms[j];
599  obtain_directions( es_v, lambdas[j], tranks[j], nrm_v);
600  }
601 
602  // Propagate along the constrained direction.
603  if ( ndirs == 2) {
604  // Split planar constraints
605  Vector_3 nrm = Vector_3::cross_product( V[0],V[1]);
606  double det = std::abs(nrm*nrm_v);
607 
608  if ( det < cos_fangle || val_bndry_nodes[j]) {
609  // Split into two directions.
610  V[0] = nrm_v; V[0] -= V[0]*nrm*nrm; V[0].normalize();
611  V[1] = Vector_3::cross_product( V[0], nrm);
612 
613  if (vcnts) vcnts[j] = vcnts[j]*V[1]*V[1];
614  }
615  else if (vcnts) { // Plane is tangent space
616  vcnts[j] -= vcnts[j]*nrm*nrm;
617 
618  if ( ds) ds[j] = null_vec;
619  continue;
620  }
621  }
622  else if ( vcnts && !val_bndry_nodes[j] &&
623  ( tranks[j]==1 && std::abs(V[0]*es_v[2]) > cos_fangle ||
624  tranks[j]==2 && std::abs(V[0]*nrm_v) < sin_fangle)) {
625  // ndir == 1
626  vcnts[j] = vcnts[j]*V[0]*V[0];
627  if ( ds) ds[j] = null_vec;
628  continue;
629  }
630 
631  if ( ds && !ds[j].is_null()) {
632  double VAV=Vector_3(V[0]*A_v[0],V[0]*A_v[1],V[0]*A_v[2])*V[0];
633  double Vb = V[0]*bs[j];
634 
635  if ( VAV<eps)
636  ds[j] = null_vec;
637  else {
638  ds[j] = (-Vb/VAV)*V[0];
639  if ( ndirs==1 && vcnts) vcnts[j] = null_vec;
640  }
641  }
642  }
643  }
644 
645  if ( _conserv && !disps_buf) balance_mass();
646 
647  return true;
648 }
649 
650 // Reduce time step based on stability limit, and rescale displacements
651 // by the reduced time step. Introduce dissipation.
652 // This function returns the reduced time step.
653 double FaceOffset_3::
654 rescale_displacements( COM::Attribute *disps,
655  COM::Attribute *vcenters, int depth) {
656 
657  double alpha = HUGE_VAL;
658 
659  // Loop through the panes and its real faces
660  std::vector< COM::Pane*>::iterator it = _panes.begin();
661  Manifold::PM_iterator pm_it=_surf->pm_begin();
662  for ( int i=0, local_npanes = _panes.size(); i<local_npanes;
663  ++i, ++it, ++pm_it) {
664  COM::Pane *pane = *it;
665 
666  const Point_3 *pnts = reinterpret_cast<Point_3*>
667  (pane->attribute(COM_NC)->pointer());
668  const Vector_3 *ds = reinterpret_cast<const Vector_3*>
669  ( pane->attribute(disps->id())->pointer());
670  const Vector_3 *vcnts = reinterpret_cast<const Vector_3*>
671  ( pane->attribute(vcenters->id())->pointer());
672  const Vector_3 *fnrms = reinterpret_cast<Vector_3*>
673  ( pane->attribute(_facenormals->id())->pointer());
674  const char *tranks = reinterpret_cast<char*>
675  ( pane->attribute(_tangranks->id())->pointer());
676 
677  // Loop through real elements of the current pane
678  Element_node_enumerator ene( pane, 1);
679 
680  for ( int j=0, nj=pane->size_of_real_elements(); j<nj; ++j, ene.next()) {
681  int ne = ene.size_of_edges();
682  int uindex=ene[ne-1]-1, vindex=ene[0]-1, windex=0;
683 
684  // Loop through all vertices of current face.
685  for ( int k=0; k<ne; ++k, uindex=vindex, vindex=windex ) {
686  windex = ene[(k+1==ne)?0:k+1]-1;
687 
688  if ( k!=0 && ne!=4 && (tranks[uindex] == 2 || tranks[vindex] == 2))
689  continue;
690 
691  Vector_3 tngs[2] = { pnts[uindex]-pnts[vindex],
692  pnts[windex]-pnts[vindex]};
693 
694  Vector_3 disp_v = ds[vindex]+vcnts[vindex];
695  Vector_3 dsps[2] = { ds[uindex]+vcnts[uindex]-disp_v,
696  ds[windex]+vcnts[windex]-disp_v };
697 
698  Vector_3 nrm = Vector_3::cross_product( tngs[0], tngs[1]);
699  Vector_3 dt = Vector_3::cross_product( dsps[0], tngs[1])+
700  Vector_3::cross_product( tngs[0], dsps[1]);
701  Vector_3 dd = Vector_3::cross_product( dsps[0], dsps[1]);
702 
703  double a = dd*nrm;
704  double b = dt*nrm;
705  double c = nrm*nrm;
706 
707  std::pair<double, double> roots=solve_quadratic_func(a,b,c);
708  if ( roots.first<alpha && roots.first>0) alpha = roots.first;
709  if ( roots.second<alpha && roots.second>0) alpha = roots.second;
710 
711  // Solve for time-step constraints at edges.
712  Edge_ID eid(j+1,k), eid_opp = pm_it->get_opposite_real_edge( eid);
713  bool is_border_edge = pm_it->is_physical_border_edge( eid_opp);
714 
715  if ( tranks[uindex] != 2 && tranks[vindex] != 2 && !is_border_edge) {
716  const Vector_3 &n1 = fnrms[j];
717  const Vector_3 &n2 = eid_opp.is_border() ?
718  pm_it->get_bd_normal( eid_opp) : fnrms[eid_opp.eid()-1];
719 
720  nrm = n1+n2;
721  double a = dd*nrm;
722  double b = dt*nrm;
723  double c = nrm*nrm;
724 
725  roots=solve_quadratic_func(a,b,c);
726  if ( roots.first<alpha && roots.first>0) alpha = roots.first;
727  if ( roots.second<alpha && roots.second>0) alpha = roots.second;
728  }
729  }
730  }
731  }
732 
733  // Reduce alpha on all processors.
734  MPI_Comm comm = _buf->get_communicator();
735  int needs_rescale = alpha*_courant<=1;
736 
737  if ( COMMPI_Initialized() && COMMPI_Comm_size( comm)>0) {
738  double local = alpha;
739  MPI_Allreduce(&local, &alpha, 1, MPI_DOUBLE, MPI_MIN, comm);
740 
741  int local_nr = needs_rescale;
742  MPI_Allreduce( &local_nr, &needs_rescale, 1, MPI_INT, MPI_LOR, comm);
743  }
744 
745  // We need to scale back displacement
746  if ( _courant>0 && alpha*_courant<=1) {
747  double scale = 0.9*_courant*alpha;
748 
749  Rocblas::mul_scalar( disps, &scale, disps);
750  Rocblas::mul_scalar( vcenters, &scale, vcenters);
751 
752  const int maxdepth=6;
753  if ( depth>maxdepth) {
754  std::cerr << "Rocprop: Mesh too distorted. Stopping" << std::endl;
755  COM_assertion_msg( depth<=maxdepth, "Too many sub-iterations.");
756  abort();
757  }
758 
759  // Recursively call the function to recompute the scale.
760  return scale*rescale_displacements( disps, vcenters, depth+1);
761  }
762  else {
763  // Add tangential components to normal components.
764  Rocblas::add( disps, vcenters, disps);
765 
766  return 1.;
767  }
768 }
769 
770 // Solve for equation a*t^2+b*t+c=0 and find the roots between 0 and 1.
771 std::pair<double,double>
772 FaceOffset_3::solve_quadratic_func( double a, double b, double c) {
773  double max_abc = std::max( std::max(std::abs(a), std::abs(b)), std::abs(c));
774 
775  if ( max_abc > 0)
776  { a /= max_abc; b /= max_abc; c /= max_abc; }
777 
778  if ( a == 0) {
779  if ( b == 0) {
780  return std::make_pair(HUGE_VAL, HUGE_VAL);
781  }
782 
783  return std::make_pair(-c/b, HUGE_VAL);
784  }
785  else {
786  double det = b*b - 4*a*c;
787  if ( det < 0) {
788  return std::make_pair(HUGE_VAL, HUGE_VAL);
789  }
790 
791  double sqrt_d = std::sqrt( det);
792 
793  if ( b>0) {
794  double temp = -b - sqrt_d;
795  return std::make_pair(2*c/temp, 0.5*temp/a);
796  }
797  else {
798  double temp = -b + sqrt_d;
799  return std::make_pair( 0.5*temp/a, 2*c/temp);
800  }
801  }
802 }
803 
805 
806 
807 
808 
809 
810 
COM::Attribute * _scales
Definition: FaceOffset_3.h:424
COM::Attribute * _ridgeneighbors
Definition: FaceOffset_3.h:422
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 _tol_kangle
Definition: FaceOffset_3.h:388
virtual double time_stepping(const COM::Attribute *spds, double dt, COM::Attribute *disps, int *smoothed=NULL)
Main entry of the algorithm.
Definition: FaceOffset_3.C:160
double _eig_weak_ub
Definition: FaceOffset_3.h:397
const NT & d
An Attribute object is a data member of a window.
Definition: Attribute.h:51
j indices k indices k
Definition: Indexing.h:6
COM::Attribute * _cnstr_nodes
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
void filter_and_identify_ridge_edges(bool filter_curves)
Filter out isolated ridge vertices and identify ridge edges.
bool obtain_constrained_directions(COM::Attribute *disps, COM::Attribute *vcenters)
Decompose propagation directions based on constraints.
Definition: FaceOffset_3.C:506
#define PROP_BEGIN_NAMESPACE
Definition: propbasic.h:28
#define COM_assertion_msg(EX, msg)
double s
Definition: blastest.C:80
double _tol_cos_osta
Definition: FaceOffset_3.h:391
MAP::Facet_ID Edge_ID
Definition: Manifold_2.h:49
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:354
COM::Attribute * _vcenters
Definition: FaceOffset_3.h:415
double _tol_ad
Definition: FaceOffset_3.h:393
COM::Attribute * _faceareas
Definition: FaceOffset_3.h:414
COM::Attribute * _boffset
Definition: FaceOffset_3.h:404
here we put it at the!beginning of the common block The point to point and collective!routines know about but MPI_TYPE_STRUCT as yet does not!MPI_STATUS_IGNORE and MPI_STATUSES_IGNORE are similar objects!Until the underlying MPI library implements the C version of these are declared as arrays of MPI_STATUS_SIZE!The types and are OPTIONAL!Their values are zero if they are not available Note that!using these reduces the portability of MPI_IO INTEGER MPI_BOTTOM INTEGER MPI_DOUBLE_PRECISION INTEGER MPI_LOGICAL INTEGER MPI_2REAL INTEGER MPI_2DOUBLE_COMPLEX INTEGER MPI_LB INTEGER MPI_WTIME_IS_GLOBAL INTEGER MPI_GROUP_EMPTY INTEGER MPI_MIN
void update_vertex_centers()
C/C++ Data types.
Definition: roccom_basic.h:129
void compute_directions(COM::Attribute *b_offset, bool in_principle)
Compute mean normals.
Definition: FaceOffset_3.C:447
SURF::Vector_3< Real > Vector_3
Definition: rfc_basic.h:42
COM::Attribute * _tangranks
Definition: FaceOffset_3.h:417
double sqrt(double d)
Definition: double.h:73
Vector_3 & normalize()
Definition: mapbasic.h:114
CImg< _cimg_Tfloat > tan(const CImg< T > &instance)
Definition: CImg.h:6046
int id() const
Get the local id of the element within the pane.
std::pair< double, double > solve_quadratic_func(double a, double b, double c)
Definition: FaceOffset_3.C:772
double _inv_sqrt_c
Definition: FaceOffset_3.h:379
void denoise_surface(const COM::Attribute *disps_buf, COM::Attribute *normal_motion)
int COMMPI_Comm_size(MPI_Comm c)
Definition: commpi.h:165
std::vector< COM::Pane * > _panes
COM::Attribute * _eigvecs
Definition: FaceOffset_3.h:407
double _tol_angle_strong
Definition: FaceOffset_3.h:385
static double square(double x)
virtual void bound_nodal_motion(COM::Attribute *disps)
This is a helper class for accessing nodal data.
COM::Attribute * _facecenters
Definition: FaceOffset_3.h:413
double _eig_weak_lb
Definition: FaceOffset_3.h:396
double _tol_eangle
Definition: FaceOffset_3.h:389
static void add(const Attribute *x, const Attribute *y, Attribute *z)
Operation wrapper for addition.
Definition: op3args.C:221
double _dir_thres_strong
Definition: FaceOffset_3.h:382
SURF::Window_manifold_2 Manifold
Definition: propbasic.h:46
static void mul_scalar(const Attribute *x, const void *y, Attribute *z, int swap=0)
Operation wrapper for multiplication with y as a scalar pointer.
Definition: op3args.C:347
double _tol_angle_weak
Definition: FaceOffset_3.h:384
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
void reset_default_parameters(bool b=false)
Definition: FaceOffset_3.C:44
COM::Attribute * _bmedial
Definition: FaceOffset_3.h:405
Manifold * _surf
COM::Attribute * _weights
Definition: FaceOffset_3.h:425
static Vector_3 cross_product(const Vector_3 &v, const Vector_3 &w)
Definition: mapbasic.h:104
void obtain_directions(Vector_3 es[3], const Vector_3 &lambdas, int nrank, Vector_3 &b_medial, Vector_3 *b_offset=NULL) const
Definition: FaceOffset_3.C:475
void compute_anisotropic_vertex_centers(const COM::Attribute *disps_buf)
bool is_nodal() const
Checks whether the attribute is associated with a node.
Definition: Attribute.h:194
COM::Attribute * _weak
Definition: FaceOffset_3.h:419
COM::Attribute * _ridges
Definition: FaceOffset_3.h:421
here we put it at the!beginning of the common block The point to point and collective!routines know about but MPI_TYPE_STRUCT as yet does not!MPI_STATUS_IGNORE and MPI_STATUSES_IGNORE are similar objects!Until the underlying MPI library implements the C version of these are declared as arrays of MPI_STATUS_SIZE!The types and are OPTIONAL!Their values are zero if they are not available Note that!using these reduces the portability of MPI_IO INTEGER MPI_BOTTOM INTEGER MPI_DOUBLE_PRECISION INTEGER MPI_LOGICAL INTEGER MPI_2REAL INTEGER MPI_2DOUBLE_COMPLEX INTEGER MPI_LB INTEGER MPI_WTIME_IS_GLOBAL INTEGER MPI_GROUP_EMPTY INTEGER MPI_BAND INTEGER MPI_LOR
double det(const Matrix3D &A)
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
double rescale_displacements(COM::Attribute *disps, COM::Attribute *vcenters, int depth=0)
Reduce time step based on stability limit, and rescale displacements by the reduced time step and dif...
Definition: FaceOffset_3.C:654
static const double pi
Definition: FaceOffset_3.h:429
double _eig_thres
Definition: FaceOffset_3.h:394
COM::Attribute * _cnstr_bndry_nodes
void set(const Value *p, Element_node_enumerator &ene, int strd)
initialize the accessor with a pointer and a specific stride.
NT abs(const NT &x)
Definition: number_utils.h:130
static void copy(const Attribute *x, Attribute *y)
Wrapper for copy.
Definition: op2args.C:333
COM::Attribute * _vnormals
Definition: FaceOffset_3.h:410
static void get_constraint_directions(int type, int &ndirs, Vector_3 dirs[2])
Get orthonormals of the constraints.
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
double _courant
Definition: FaceOffset_3.h:378
int COMMPI_Initialized()
Definition: commpi.h:168
COM::Attribute * _strong
Definition: FaceOffset_3.h:420
bool _feature_layer
Definition: FaceOffset_3.h:401
double _tol_turn_angle
Definition: FaceOffset_3.h:392
void balance_mass()
Definition: cons_diff.C:33
This class provides some common primitives used by various propagation algorithms.
Definition: Propagation_3.h:40
void nulaplacian_smooth(const COM::Attribute *vert_normals, const COM::Attribute *tangranks, const COM::Attribute *disps, COM::Attribute *vcenters, COM::Attribute *buf, COM::Attribute *vert_weights_buf, const COM::Attribute *edge_weights=NULL)
Redistribute smooth vertices by NuLaplacian smoothing.
Definition: NuLaplacian.C:36
FaceOffset_3()
Default constructor.
Definition: FaceOffset_3.h:43
NT & cos
bool is_elemental() const
Checks whether the attribute is associated with an element.
Definition: Attribute.h:192
Type norm() const
Definition: mapbasic.h:112
COM::Attribute * _facenormals
Definition: FaceOffset_3.h:412
COM::Attribute * _ctangranks
Definition: FaceOffset_3.h:418
int size_of_components() const
Obtain the number of components in the attribute.
Definition: Attribute.h:203