Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AnisotropicSmoothing.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: AnisotropicSmoothing.C,v 1.6 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 
31 
32 #define ANISOTROPIC 0
33 #define MIN_ANGLE_WEIGHTED 1
34 
35 bool FaceOffset_3::
36 is_strong( const Vector_3 *es, const Vector_3 &lambdas,
37  const Vector_3 &mn, int nrank) const {
38  if ( lambdas[1]>_dir_thres_strong*lambdas[0]) return true;
39 
40  return is_acute_ridge( es, lambdas, mn, nrank) ||
41  is_acute_corner( es, lambdas, mn, nrank);
42 }
43 
44 
45 // Obtain weight for nonuniform mesh fairing.
46 double FaceOffset_3::
47 get_nonuniform_weight( const Vector_3 &lambdas, int trank) {
48 
49  const double eps=1.e-6;
50  double w = 1/lambdas[0];
51 
52  if (trank == 2) return w;
53  else if ( trank==1 ) return eps*w;
54  else return eps*eps*w;
55 }
56 
57 void FaceOffset_3::
58 get_tangents( const Vector_3 *es, const Vector_3 &lambdas,
59  const Vector_3 &mn, int nrank,
60  Vector_3 vs[2], double scales[2], int *is_strong) const {
61  vs[0] = es[1];
62  vs[1] = es[2];
63 
64  // Bound from two ends appear to be the most robust.
65  const double max_scale=0.07, min_scale=0.005;
66 
67  if ( scales) {
68  scales[0] = std::min( max_scale, std::max(lambdas[1]/lambdas[0], min_scale));
69  scales[1] = std::min( max_scale, std::max(lambdas[2]/lambdas[0], min_scale));
70 
71  scales[0] = std::sqrt( scales[0]);
72  scales[1] = std::sqrt( scales[1]);
73 
74  if ( is_strong) {
75  bool acute_ridge = FaceOffset_3::is_acute_ridge( es, lambdas, mn, nrank);
76  bool acute_corner = FaceOffset_3::is_acute_corner( es, lambdas, mn, nrank);
77 
78  *is_strong = acute_ridge || acute_corner ||
79  lambdas[1]>_dir_thres_strong*lambdas[0];
80  }
81  }
82 }
83 
84 void FaceOffset_3::
85 compute_anisotropic_vertex_centers( const COM::Attribute *nodal_disps) {
86 
87  const double zero = 0., eps = 1.e-100;
88 
91 
92  // Loop through the panes and its real faces
93  std::vector< COM::Pane*>::iterator it = _panes.begin();
94  Manifold::PM_iterator pm_it=_surf->pm_begin();
95  for ( int i=0, local_npanes = _panes.size();
96  i<local_npanes; ++i, ++it, ++pm_it) {
97  COM::Pane *pane = *it;
98 
99  const Point_3 *pnts = reinterpret_cast<const Point_3*>
100  (pane->attribute(COM_NC)->pointer());
101  const Vector_3 *disps = nodal_disps?reinterpret_cast<const Vector_3*>
102  (pane->attribute(nodal_disps->id())->pointer()):NULL;
103  const Point_3 *fcnts = reinterpret_cast<const Point_3*>
104  ( pane->attribute(_facecenters->id())->pointer());
105  Vector_3 *vcnts = reinterpret_cast<Vector_3*>
106  ( pane->attribute(_vcenters->id())->pointer());
107  double *ws = reinterpret_cast<double*>
108  ( pane->attribute(_weights->id())->pointer());
109 
110 #if ANISOTROPIC
111  const Vector_3 *As = reinterpret_cast<const Vector_3*>
112  ( pane->attribute(_As->id())->pointer());
113  const Vector_3 *bs = reinterpret_cast<const Vector_3*>
114  ( pane->attribute(_bmedial->id())->pointer());
115 
116  const char *tranks = reinterpret_cast<const char*>
117  ( pane->attribute(_tangranks->id())->pointer());
118 
119  const char *strong = reinterpret_cast<char*>
120  ( pane->attribute(_strong->id())->pointer());
121 #endif
122 
123  // Loop through real elements of the current pane
124  Element_node_enumerator ene( pane, 1);
125  for ( int j=0, nj=pane->size_of_real_elements(); j<nj; ++j, ene.next()) {
126  int ne = ene.size_of_edges();
127  const Point_3 &cnt = fcnts[j];
128  Vector_3 anipnt;
129 
130 #if ANISOTROPIC
131  bool has_feature=false;
132  Vector_3 Ae[3], mn; // Matrix at an edge
133 
134  // First, compute medial quadric for the face
135  Ae[0] = Ae[1] = Ae[2] = mn = Vector_3(0,0,0);
136 
137  for ( int k=0; k<ne; ++k) {
138  int vindex = ene[k]-1;
139  has_feature |= tranks[vindex]!=2;
140 
141  // Obtain the quadric at the face
142  const Vector_3 *As_v=&As[3*vindex];
143  Ae[0] += As_v[0];
144  Ae[1] += As_v[1];
145  Ae[2] += As_v[2];
146 
147  mn += bs[vindex];
148  }
149 
150  // Perform eigen-analysis
151  Vector_3 lambdas = mn;
152  int nrank = eigen_analyze_vertex( Ae, lambdas);
153 
154  Vector_3 vs_e[2];
155  double scales_e[2];
156 
157  mn = Ae[0]; nrank = 1;
158  get_tangents( Ae, lambdas, mn, nrank, vs_e, scales_e);
159 
160  Vector_3 mn_face;
161  Vector_3 vs_f[2];
162  double scales_f[2];
163  if ( has_feature) {
164  // Compute eigen-vector of weighted-sum of the tensors.
165  Ae[0] = Ae[1] = Ae[2] = Vector_3(0,0,0);
166  for ( int k=0; k<ne; ++k) {
167  int vindex = ene[k]-1;
168 
169  double w=1;
170  switch (tranks[ vindex]) {
171  case 0: {
172  w = 1.e-12;
173  break;
174  }
175  case 1: {
176  if ( strong[vindex]) {
177  w = 1.e-6;
178  break;
179  }
180  }
181  default: w = 1.;
182  }
183 
184  // Obtain the quadric at the face
185  const Vector_3 *As_v=&As[3*vindex];
186  Ae[0] += w*As_v[0];
187  Ae[1] += w*As_v[1];
188  Ae[2] += w*As_v[2];
189  }
190 
191  // Perform eigen-analysis
192  eigen_analyze_vertex( Ae, lambdas);
193  mn_face = Ae[0];
194 
195  get_tangents( Ae, lambdas, mn_face, 1, vs_f, scales_f);
196  }
197  else {
198  mn_face = Ae[0];
199 
200  scales_f[0] = scales_e[0]; scales_f[1] = scales_e[1];
201  vs_f[0] = vs_e[0]; vs_f[1] = vs_e[1];
202  }
203 #endif
204 
205  int uindex=ene[ne-1]-1, vindex=ene[0]-1;
206  // Loop through all vertices of current face.
207  for ( int k=0; k<ne; ++k) {
208  int windex = ene[(k+1==ne)?0:k+1]-1;
209 
210  Point_3 ps[3] = { pnts[uindex], pnts[vindex], pnts[windex] };
211  if ( disps) {
212  ps[0] += disps[uindex]; ps[1] += disps[vindex];
213  ps[2] += disps[windex];
214  }
215 
216 #if ANISOTROPIC
217  double scales_v[2];
218  Vector_3 vs_v[2];
219 
220  // Note: is_border node.
221  if ( _feature_layer &&
222  ( tranks[uindex]==2 || tranks[windex]==2)) {
223  scales_v[0] = scales_e[0]; scales_v[1] = scales_e[1];
224  vs_v[0] = vs_e[0]; vs_v[1] = vs_e[1];
225  }
226  else {
227  scales_v[0] = scales_f[0]; scales_v[1] = scales_f[1];
228  vs_v[0] = vs_f[0]; vs_v[1] = vs_f[1];
229  }
230 
231  const Vector_3 diff = cnt-ps[1];
232  anipnt = scales_v[0]*(diff*vs_v[0])*vs_v[0]+
233  scales_v[1]*(diff*vs_v[1])*vs_v[1];
234  if ( disps) anipnt += disps[vindex];
235 #else
236  anipnt = cnt-ps[1];
237 #endif
238 
239 #if MIN_ANGLE_WEIGHTED
240  double w = std::min( eval_angle( ps[1]-ps[0], ps[2]-ps[0]),
241  eval_angle( ps[1]-ps[2], ps[0]-ps[2]));
242 #else
243  double w=1;
244 #endif
245 
246  vcnts[vindex] += w*anipnt;
247  ws[vindex] += w;
248 
249  uindex=vindex; vindex=windex;
250  }
251  }
252  }
253 
254  _surf->reduce_on_shared_nodes( _vcenters, Manifold::OP_SUM);
255  _surf->reduce_on_shared_nodes( _weights, Manifold::OP_SUM);
257 }
258 
259 void FaceOffset_3::
260 denoise_surface( const COM::Attribute *nodal_disps,
261  COM::Attribute *normal_motion) {
262 
263  const double zero = 0., eps = 1.e-100;
264 
265  Rocblas::copy_scalar( &zero, normal_motion);
267 
268  // Loop through the panes and its real faces
269  std::vector< COM::Pane*>::iterator it = _panes.begin();
270  Manifold::PM_iterator pm_it=_surf->pm_begin();
271  for ( int i=0, local_npanes = _panes.size();
272  i<local_npanes; ++i, ++it, ++pm_it) {
273  COM::Pane *pane = *it;
274 
275  const Vector_3 *As = reinterpret_cast<const Vector_3*>
276  ( pane->attribute(_As->id())->pointer());
277  const Vector_3 *vnrms = reinterpret_cast<const Vector_3*>
278  ( pane->attribute(_vnormals->id())->pointer());
279 
280  const Point_3 *pnts = reinterpret_cast<const Point_3*>
281  (pane->attribute(COM_NC)->pointer());
282  const Vector_3 *disps = nodal_disps ? reinterpret_cast<const Vector_3*>
283  (pane->attribute(nodal_disps->id())->pointer()) : NULL;
284  const Point_3 *fcnts = reinterpret_cast<const Point_3*>
285  ( pane->attribute(_facecenters->id())->pointer());
286  const char *tranks = reinterpret_cast<const char*>
287  ( pane->attribute(_tangranks->id())->pointer());
288  const Vector_3 *lambdas = reinterpret_cast<const Vector_3*>
289  ( pane->attribute(_eigvalues->id())->pointer());
290 
291  Vector_3 *nmotion = normal_motion ? reinterpret_cast<Vector_3*>
292  ( pane->attribute(normal_motion->id())->pointer()) : NULL;
293  double *ws = normal_motion ? reinterpret_cast<double*>
294  ( pane->attribute(_weights->id())->pointer()) : NULL;
295  const double *farea = normal_motion ? reinterpret_cast<double*>
296  ( pane->attribute(_faceareas->id())->pointer()) : NULL;
297  const char *weak = reinterpret_cast<const char*>
298  ( pane->attribute(_weak->id())->pointer());
299  const int *cnstrs = _cnstr_nodes ? reinterpret_cast<const int*>
300  ( pane->attribute(_cnstr_nodes->id())->pointer()) : NULL;
301 
302  // Loop through real elements of the current pane
303  Element_node_enumerator ene( pane, 1);
304  for ( int j=0, nj=pane->size_of_real_elements(); j<nj; ++j, ene.next()) {
305  int ne = ene.size_of_edges();
306  const Point_3 &cnt = fcnts[j];
307 
308  Vector_3 Ae[3]; // Matrix at an edge
309  Ae[0] = Ae[1] = Ae[2] = Vector_3(0,0,0);
310  bool is_weak = false;
311 
312  for ( int k=0; k<ne; ++k) {
313  int vindex = ene[k]-1;
314  if ( weak[vindex]) { is_weak = true; break; }
315  }
316  if ( !is_weak) continue;
317 
318 
319  for ( int k=0; k<ne; ++k) {
320  int vindex = ene[k]-1;
321 
322  // Obtain the quadric at the face
323  const Vector_3 *As_v=&As[3*vindex];
324 
325  double w = get_nonuniform_weight
326  ( lambdas[vindex], tranks[vindex]-(cnstrs && cnstrs[vindex]));
327 
328  Ae[0] += w*As_v[0];
329  Ae[1] += w*As_v[1];
330  Ae[2] += w*As_v[2];
331  }
332 
333  // Perform eigen-analysis to obtain diffused face normal
334  Vector_3 ls;
335  compute_eigenvectors( Ae, ls);
336  Vector_3 mn_face = Ae[0];
337 
338  for ( int k=0; k<ne; ++k) {
339  int vindex = ene[k]-1;
340 
341  if ( weak[vindex]) {
342  Vector_3 diff = (cnt-pnts[vindex]);
343  if ( disps) diff -= disps[vindex];
344 
345  double offset = diff*mn_face, cos_a=mn_face*vnrms[vindex];
346  if (cos_a<0) offset = -offset;
347 
348  // Use eigenvalue to control amount of dissipation
349  double w = farea[j];
350  double a = lambdas[vindex][1]/lambdas[vindex][0];
351  nmotion[vindex] += a*(w*offset)*vnrms[vindex];
352 
353  ws[vindex] += w;
354  }
355  }
356  }
357  }
358 
359  _surf->reduce_on_shared_nodes( normal_motion, Manifold::OP_SUM);
360  _surf->reduce_on_shared_nodes( _weights, Manifold::OP_SUM);
361  Rocblas::div( normal_motion, _weights, normal_motion);
362 }
363 
365 
366 
367 
368 
369 
370 
371 
static void compute_eigenvectors(Vector_3 A[3], Vector_3 &lambdas)
COM::Attribute * _eigvalues
Definition: FaceOffset_3.h:406
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
j indices k indices k
Definition: Indexing.h:6
COM::Attribute * _cnstr_nodes
#define PROP_BEGIN_NAMESPACE
Definition: propbasic.h:28
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
COM::Attribute * _faceareas
Definition: FaceOffset_3.h:414
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
real *8 function offset(vNorm, x2, y2, z2)
Definition: PlaneNorm.f90:211
void denoise_surface(const COM::Attribute *disps_buf, COM::Attribute *normal_motion)
std::vector< COM::Pane * > _panes
bool is_strong(const Vector_3 *es, const Vector_3 &lambdas, const Vector_3 &mn, int nrank) const
COM::Attribute * _facecenters
Definition: FaceOffset_3.h:413
double _dir_thres_strong
Definition: FaceOffset_3.h:382
bool is_acute_ridge(const Vector_3 *es, const Vector_3 &lambdas, const Vector_3 &mn, int nrank) const
Definition: FaceOffset_3.h:352
int size_of_edges() const
Number of edges per element.
blockLoc i
Definition: read.cpp:79
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
void compute_anisotropic_vertex_centers(const COM::Attribute *disps_buf)
bool is_acute_corner(const Vector_3 *es, const Vector_3 &lambdas, const Vector_3 &mn, int nrank) const
Definition: FaceOffset_3.h:357
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
Vector_n min(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:346
static void copy_scalar(const void *x, Attribute *y)
Operation wrapper for copy (x is a scalar pointer).
Definition: op2args.C:583
j indices j
Definition: Indexing.h:6
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
double get_nonuniform_weight(const Vector_3 &lambdas, int trank)
void get_tangents(const Vector_3 *es, const Vector_3 &lambdas, const Vector_3 &mn, int nrank, Vector_3 vs[2], double scales[2], int *is_strong=NULL) const
COM::Attribute * _strong
Definition: FaceOffset_3.h:420
bool _feature_layer
Definition: FaceOffset_3.h:401
int eigen_analyze_vertex(Vector_3 A_io[3], Vector_3 &b_io, double angle_defect=0)