Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QualityMetric/QualityMetric.cpp
Go to the documentation of this file.
1 /* *****************************************************************
2  MESQUITE -- The Mesh Quality Improvement Toolkit
3 
4  Copyright 2004 Sandia Corporation and Argonne National
5  Laboratory. Under the terms of Contract DE-AC04-94AL85000
6  with Sandia Corporation, the U.S. Government retains certain
7  rights in this software.
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public License
20  (lgpl.txt) along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 
23  diachin2@llnl.gov, djmelan@sandia.gov, mbrewer@sandia.gov,
24  pknupp@sandia.gov, tleurent@mcs.anl.gov, tmunson@mcs.anl.gov
25 
26  ***************************************************************** */
36 #include "QualityMetric.hpp"
37 #include "MsqVertex.hpp"
38 #include "MsqMeshEntity.hpp"
39 #include "MsqDebug.hpp"
40 #include "MsqTimer.hpp"
41 #include "PatchData.hpp"
42 
43 using namespace Mesquite;
44 
45 #ifdef MSQ_USE_OLD_STD_HEADERS
46 # include <vector.h>
47 #else
48 # include <vector>
49  using namespace std;
50 #endif
51 
82  MsqMeshEntity* el,
83  MsqVertex* free_vtces[],
84  Vector3D grad_vec[],
85  Matrix3D hessian[],
86  int num_free_vtx,
87  double &metric_value,
88  MsqError &err)
89 {
90  // first, checks that free vertices order is consistent with the
91  // element order.
92  vector<size_t> elem_vtx_indices;
93  vector<size_t>::const_iterator v;
94  el->get_vertex_indices(elem_vtx_indices);
95  int i;
96  v=elem_vtx_indices.begin();
97  for (i=0; i<num_free_vtx; ++i) {
98  while ( v!=elem_vtx_indices.end() &&
99  *v != pd.get_vertex_index(free_vtces[i]) ) {
100  ++v;
101  }
102  if ( v==elem_vtx_indices.end() ) {
103  MSQ_SETERR(err)("free vertices cannot be given in a different"
104  "order than the element's.", MsqError::INTERNAL_ERROR);
105  return false;
106  }
107  }
108 
109 
110  bool ret=false;
111  switch(hessianType)
112  {
113  case NUMERICAL_HESSIAN:
114  ret = compute_element_numerical_hessian(pd, el, free_vtces, grad_vec, hessian,
115  num_free_vtx, metric_value, err);
116  MSQ_ERRZERO(err);
117  break;
118  case ANALYTICAL_HESSIAN:
119  ret = compute_element_analytical_hessian(pd, el, free_vtces, grad_vec, hessian,
120  num_free_vtx, metric_value, err);
121  MSQ_ERRZERO(err);
122  break;
123  }
124  return ret;
125 }
126 
127 
136  MsqVertex &vertex,
137  MsqVertex* free_vtces[],
138  Vector3D grad_vec[],
139  int num_free_vtx,
140  double &metric_value,
141  MsqError &err)
142 {
143  MSQ_PRINT(1)("QualityMetric has no analytical gradient defined. "
144  "Defaulting to numerical gradient.\n");
145  set_gradient_type(NUMERICAL_GRADIENT);
146  bool b = compute_vertex_numerical_gradient(pd, vertex, free_vtces, grad_vec,
147  num_free_vtx, metric_value, err);
148  return !MSQ_CHKERR(err) && b;
149 }
150 
152 {
153  MSQ_SETERR(err)("This QualityMetric's MetricType can not be changed.",
155 }
156 
157 
165  MsqMeshEntity* element,
166  MsqVertex* free_vtces[], Vector3D grad_vec[],
167  int num_free_vtx, double &metric_value,
168  MsqError &err)
169 {
170  MSQ_PRINT(1)("QualityMetric has no analytical gradient defined. "
171  "Defaulting to numerical gradient.\n");
172  set_gradient_type(NUMERICAL_GRADIENT);
173  bool b = compute_element_numerical_gradient(pd, element, free_vtces, grad_vec, num_free_vtx, metric_value, err);
174  return !MSQ_CHKERR(err) && b;
175 }
176 
177 
186  MsqMeshEntity* element,
187  MsqVertex* free_vtces[], Vector3D grad_vec[],
188  Matrix3D hessian[],
189  int num_free_vtx, double &metric_value,
190  MsqError &err)
191 {
192  MSQ_PRINT(1)("QualityMetric has no analytical hessian defined. "
193  "Defaulting to numerical hessian.\n");
194  set_hessian_type(NUMERICAL_HESSIAN);
195  bool b = compute_element_numerical_hessian(pd, element, free_vtces, grad_vec,
196  hessian, num_free_vtx, metric_value, err);
197  return !MSQ_CHKERR(err) && b;
198 }
199 
200 
206  MsqMeshEntity* el,
207  MsqVertex* free_vtces[],
208  Vector3D grad_vec[],
209  int num_free_vtx,
210  double &metric_value,
211  MsqError &err)
212 {
213  int i, g, e;
214  bool ret;
215  Vector3D* grad_vec_nz = new Vector3D[num_free_vtx];
216  ret = compute_element_gradient(pd, el, free_vtces, grad_vec_nz,
217  num_free_vtx, metric_value, err);
218  if (MSQ_CHKERR(err)) {
219  delete [] grad_vec_nz;
220  return false;
221  }
222 
223  vector<size_t> gv_i;
224  gv_i.reserve(num_free_vtx);
225  i=0;
226  for (i=0; i<num_free_vtx; ++i) {
227  gv_i.push_back( pd.get_vertex_index(free_vtces[i]) );
228  }
229 
230  vector<size_t> ev_i;
231  el->get_vertex_indices(ev_i);
232 
233  bool inc;
234  vector<size_t>::iterator ev;
235  vector<size_t>::iterator gv;
236  for (ev=ev_i.begin(), e=0; ev!=ev_i.end(); ++ev, ++e) {
237  inc = false; g=0;
238  gv = gv_i.begin();
239  while (gv!=gv_i.end()) {
240  if (*ev == *gv) {
241  inc = true;
242  break;
243  }
244  ++gv; ++g;
245  }
246  if (inc == true)
247  grad_vec[e] = grad_vec_nz[g];
248  else
249  grad_vec[e] = 0;
250  }
251 
252  delete []grad_vec_nz;
253  return ret;
254 }
255 
256 
263  MsqMeshEntity* element,
264  MsqVertex* free_vtces[],
265  Vector3D grad_vec[],
266  int num_free_vtx, double &metric_value,
267  MsqError &err)
268 {
269  MSQ_FUNCTION_TIMER( "QualityMetric::compute_element_numerical_gradient" );
272  MSQ_PRINT(3)("Computing Numerical Gradient\n");
273 
274  bool valid=this->evaluate_element(pd, element, metric_value, err);
275  if (MSQ_CHKERR(err) || !valid)
276  return false;
277 
278  const double delta_C = 10e-6;
279  double delta = delta_C;
280  const double delta_inv_C = 1. / delta; // avoids division in the loop.
281  double delta_inv = delta_inv_C;
282  int counter=0;
283  double pos=0.0;
284  double metric_value1=0;
285  const int reduction_limit = 15;
286  for (int v=0; v<num_free_vtx; ++v)
287  {
288  /* gradient in the x, y, z direction */
289  for (int j=0;j<3;++j)
290  {
291  //re-initialize variables.
292  valid=false;
293  delta = delta_C;
294  delta_inv = delta_inv_C;
295  counter=0;
296  //perturb the node and calculate gradient. The while loop is a
297  //safety net to make sure the epsilon perturbation does not take
298  //the element out of the feasible region.
299  while(!valid && counter<reduction_limit){
300  //save the original coordinate before the perturbation
301  pos=(*free_vtces[v])[j];
302  // perturb the coordinates of the free vertex in the j direction
303  // by delta
304  (*free_vtces[v])[j]+=delta;
305  //compute the function at the perturbed point location
306  valid=this->evaluate_element(pd, element, metric_value1, err);
307  MSQ_CHKERR(err);
308  //compute the numerical gradient
309  grad_vec[v][j]=(metric_value1-metric_value)*delta_inv;
310  // put the coordinates back where they belong
311  (*free_vtces[v])[j] = pos;
312  ++counter;
313  delta*=0.1;
314  delta_inv*=10.;
315  }
316  if(counter>=reduction_limit){
317  MSQ_SETERR(err)("Perturbing vertex by delta caused an inverted element.",
319  return false;
320  }
321 
322  }
323  }
324  return true;
325 }
326 
327 
338  MsqMeshEntity* element,
339  MsqVertex* free_vtces[],
340  Vector3D grad_vec[],
341  Matrix3D hessian[],
342  int num_free_vtx, double &metric_value,
343  MsqError &err)
344 {
345  MSQ_FUNCTION_TIMER( "QualityMetric::compute_element_numerical_hessian" );
346  MSQ_PRINT(3)("Computing Numerical Hessian\n");
347 
348  bool valid=this->compute_element_gradient_expanded(pd, element, free_vtces, grad_vec,
349  num_free_vtx, metric_value, err);
350  if (MSQ_CHKERR(err) || !valid)
351  return false;
352 
353  double delta = 10e-6;
354  double delta_inv = 1./delta;
355  double vj_coord;
356  short nve = element->vertex_count();
357  Vector3D* grad_vec1 = new Vector3D[nve];
358  Vector3D fd;
359  vector<size_t> ev_i;
360  element->get_vertex_indices(ev_i);
361  short w, v, i, j, sum_w, mat_index, k;
362 
363  int fv_ind=0; // index in array free_vtces .
364 
365  // loop over all vertices in element.
366  for (v=0; v<nve; ++v) {
367 
368  // finds out whether vertex v in the element is fixed or free,
369  // as according to argument free_vtces[]
370  bool free_vertex = false;
371  for (k=0; k<num_free_vtx; ++k) {
372  if ( ev_i[v] == pd.get_vertex_index(free_vtces[k]) )
373  free_vertex = true;
374  }
375 
376  // If vertex is fixed, enters null blocks for that column.
377  // Note that null blocks for the row will be taken care of by
378  // the gradient null entries.
379  if (free_vertex==false) {
380  for (w=0; w<nve; ++w) {
381  if (v>=w) {
382  sum_w = w*(w+1)/2; // 1+2+3+...+w
383  mat_index = w*nve+v-sum_w;
384  hessian[mat_index] = 0.;
385  }
386  }
387  }
388  else {
389  // If vertex is free, use finite difference on the gradient to find the Hessian.
390  for (j=0;j<3;++j) {
391  // perturb the coordinates of the vertex v in the j direction by delta
392  vj_coord = (*free_vtces[fv_ind])[j];
393  (*free_vtces[fv_ind])[j]+=delta;
394  //compute the gradient at the perturbed point location
395  valid = this->compute_element_gradient_expanded(pd, element, free_vtces,
396  grad_vec1, num_free_vtx, metric_value, err); MSQ_CHKERR(err);
397  assert(valid);
398  //compute the numerical Hessian
399  for (w=0; w<nve; ++w) {
400  if (v>=w) {
401  //finite difference to get some entries of the Hessian
402  fd = (grad_vec1[w]-grad_vec[w])*delta_inv;
403  // For the block at position w,v in a matrix, we need the corresponding index
404  // (mat_index) in a 1D array containing only upper triangular blocks.
405  sum_w = w*(w+1)/2; // 1+2+3+...+w
406  mat_index = w*nve+v-sum_w;
407 
408  for (i=0; i<3; ++i)
409  hessian[mat_index][i][j] = fd[i];
410 
411  }
412  }
413  // put the coordinates back where they belong
414  (*free_vtces[fv_ind])[j] = vj_coord;
415  }
416  ++fv_ind;
417  }
418  }
419 
420  delete[] grad_vec1;
421 
422  return true;
423 }
424 
425 
432  MsqVertex &vertex,
433  MsqVertex* free_vtces[],
434  Vector3D grad_vec[],
435  int num_free_vtx,
436  double &metric_value,
437  MsqError &err)
438 {
441  MSQ_PRINT(2)("Computing Gradient (QualityMetric's numeric, vertex based.\n");
442 
443  bool valid=this->evaluate_vertex(pd, &(vertex), metric_value, err);
444  if (MSQ_CHKERR(err) || !valid)
445  return false;
446 
447  const double delta = 10e-6;
448  const double delta_inv = 1./delta;
449  double metric_value1=0;
450  double pos;
451  int v=0;
452  for (v=0; v<num_free_vtx; ++v)
453  {
454  /* gradient in the x, y, z direction */
455  int j=0;
456  for (j=0;j<3;++j)
457  {
458  //save the original coordinate before the perturbation
459  pos=(*free_vtces[v])[j];
460  // perturb the coordinates of the free vertex in the j direction by delta
461  (*free_vtces[v])[j]+=delta;
462  //compute the function at the perturbed point location
463  this->evaluate_vertex(pd, &(vertex), metric_value1, err); MSQ_ERRZERO(err);
464  //compute the numerical gradient
465  grad_vec[v][j]=(metric_value1-metric_value)*delta_inv;
466  // put the coordinates back where they belong
467  (*free_vtces[v])[j] = pos;
468  }
469  }
470  return true;
471 }
472 
473 
476  double& /*value*/, MsqError &err)
477  {
478  MSQ_SETERR(err)("No implementation for a "
479  "vertex-version of this metric.",
481  return false;
482  }
483 
486  MsqMeshEntity* /*element*/,
487  double& /*value*/, MsqError &err)
488  {
489  MSQ_SETERR(err)("No implementation for a element-version of this "
490  "metric.", MsqError::NOT_IMPLEMENTED);
491  return false;
492  }
493 
494 
496  int count,
497  MsqError& err )
498 {
499  double avg = 0.0;
500  int i, tmp_count;
501  double f;
502 
503  switch (avgMethod)
504  {
505 
506  case MINIMUM:
507  avg = metrics[0];
508  for (i = 1; i < count; ++i)
509  if (metrics[i] < avg)
510  avg = metrics[i];
511 
512  tmp_count = 0;
513  for (i = 0; i < count; ++i)
514  {
515  if( metrics[i] - avg <= MSQ_MIN )
516  {
517  metrics[i] = 1.0;
518  ++tmp_count;
519  }
520  else
521  {
522  metrics[i] = 0.0;
523  }
524  }
525 
526  f = 1.0 / tmp_count;
527  for (i = 0; i < count; ++i)
528  metrics[i] *= f;
529 
530  break;
531 
532 
533  case MAXIMUM:
534  avg = metrics[0];
535  for (i = 1; i < count; ++i)
536  if (metrics[i] > avg)
537  avg = metrics[i];
538 
539  tmp_count = 0;
540  for (i = 0; i < count; ++i)
541  {
542  if( avg - metrics[i] <= MSQ_MIN )
543  {
544  metrics[i] = 1.0;
545  ++tmp_count;
546  }
547  else
548  {
549  metrics[i] = 0.0;
550  }
551  }
552 
553  f = 1.0 / tmp_count;
554  for (i = 0; i < count; ++i)
555  metrics[i] *= f;
556 
557  break;
558 
559 
560  case SUM:
561  for (i = 0; i < count; ++i)
562  {
563  avg += metrics[i];
564  metrics[i] = 1.0;
565  }
566 
567  break;
568 
569 
570  case SUM_SQUARED:
571  for (i = 0; i < count; ++i)
572  {
573  avg += (metrics[i]*metrics[i]);
574  metrics[i] *= 2;
575  }
576 
577  break;
578 
579 
580  case LINEAR:
581  f = 1.0 / count;
582  for (i = 0; i < count; ++i)
583  {
584  avg += metrics[i];
585  metrics[i] = f;
586  }
587  avg *= f;
588 
589  break;
590 
591 
592  case GEOMETRIC:
593  for (i = 0; i < count; ++i)
594  avg += log(metrics[i]);
595  avg = exp( avg/count );
596 
597  f = avg / count;
598  for (i = 0; i < count; ++i)
599  metrics[i] = f / metrics[i];
600 
601  break;
602 
603 
604  case RMS:
605  for (i = 0; i < count; ++i)
606  avg += metrics[i] * metrics[i];
607  avg = sqrt( avg / count );
608 
609  f = 1. / (avg*count);
610  for (i = 0; i < count; ++i)
611  metrics[i] *= f;
612 
613  break;
614 
615 
616  case HARMONIC:
617  for (i = 0; i < count; ++i)
618  avg += 1.0 / metrics[i];
619  avg = count / avg;
620 
621  for (i = 0; i < count; ++i)
622  metrics[i] = (avg * avg) / (count * metrics[i] * metrics[i]);
623 
624  break;
625 
626 
627  case HMS:
628  for (i = 0; i < count; ++i)
629  avg += 1. / (metrics[i] * metrics[i]);
630  avg = sqrt( count / avg );
631 
632  f = avg*avg*avg / count;
633  for (i = 0; i < count; ++i)
634  metrics[i] = f / (metrics[i] * metrics[i] * metrics[i]);
635 
636  break;
637 
638 
639  default:
640  MSQ_SETERR(err)("averaging method not available.",MsqError::INVALID_STATE);
641  }
642 
643  return avg;
644 }
645 
#define MSQ_ERRZERO(err)
Return zero/NULL on error.
CImg< _cimg_Tfloat > exp(const CImg< T > &instance)
Definition: CImg.h:6016
bool compute_element_numerical_gradient(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], int num_free_vtx, double &metric_value, MsqError &err)
Non-virtual function which numerically computes the gradient of a QualityMetric of a given element fo...
bool compute_element_numerical_hessian(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], Matrix3D hessian[], int num_free_vtx, double &metric_value, MsqError &err)
j indices k indices k
Definition: Indexing.h:6
Used to hold the error state and return it to the application.
requested functionality is not (yet) implemented
MsqMeshEntity is the Mesquite object that stores information about the elements in the mesh...
Vector3D is the object that effeciently stores information about about three-deminsional vectors...
void get_vertex_indices(msq_std::vector< msq_stdc::size_t > &vertex_list) const
gets the vertices of the mesh entity
double sqrt(double d)
Definition: double.h:73
#define MAXIMUM
Definition: vinci_lass.c:25
virtual bool compute_element_analytical_hessian(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], Matrix3D hessian[], int num_free_vtx, double &metric_value, MsqError &err)
*********************************************************************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 and or **sell copies of the and to permit persons to whom the **Software is furnished to do subject to the following this list of conditions and the following disclaimers ****Redistributions in binary form must reproduce the above **copyright this list of conditions and the following **disclaimers in the documentation and or other materials **provided with the distribution ****Neither the names of the Center for Simulation of Advanced the University of nor the names of its **contributors may be used to endorse or promote products derived **from this Software without specific prior written permission ****THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY **EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES **OF FITNESS FOR A PARTICULAR PURPOSE AND **NONINFRINGEMENT IN NO EVENT SHALL THE CONTRIBUTORS OR **COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR **ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE **USE OR OTHER DEALINGS WITH THE SOFTWARE v
Definition: roccomf90.h:20
double average_metric_and_weights(double metric_values[], int num_metric_values, MsqError &err)
Given a list of metric values, calculate the average metric valude according to the current avgMethod...
bool compute_element_hessian(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], Matrix3D hessian[], int num_free_vtx, double &metric_value, MsqError &err)
For MetricType == ELEMENT_BASED. Calls either compute_element_numerical_hessian() or compute_element_...
CImg< _cimg_Tfloat > log(const CImg< T > &instance)
Definition: CImg.h:6021
virtual void change_metric_type(MetricType t, MsqError &err)
msq_stdc::size_t vertex_count() const
Returns the number of vertices in this element, based on its element type.
#define MSQ_CHKERR(err)
Mesquite&#39;s Error Checking macro.
3*3 Matric class, row-oriented, 0-based [i][j] indexing.
size_t get_vertex_index(MsqVertex *vertex)
#define MSQ_SETERR(err)
Macro to set error - use err.clear() to clear.
blockLoc i
Definition: read.cpp:79
void free_vertex(T_Vertex *v)
virtual bool compute_element_analytical_gradient(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], int num_free_vtx, double &metric_value, MsqError &err)
Virtual function that computes the gradient of the QualityMetric analytically. The base class impleme...
virtual bool evaluate_element(PatchData &, MsqMeshEntity *, double &, MsqError &err)
Evaluate the metric for an element.
virtual bool evaluate_vertex(PatchData &, MsqVertex *, double &, MsqError &err)
Evaluate the metric for a vertex.
j indices j
Definition: Indexing.h:6
#define MSQ_PRINT(flag)
Check debug flag and print printf-style formatted output.
bool compute_element_gradient_expanded(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], int num_free_vtx, double &metric_value, MsqError &err)
object is in an invalid state
MsqVertex is the Mesquite object that stores information about the vertices in the mesh...
virtual bool compute_vertex_analytical_gradient(PatchData &pd, MsqVertex &vertex, MsqVertex *vertices[], Vector3D grad_vec[], int num_vtx, double &metric_value, MsqError &err)
Virtual function that computes the gradient of the QualityMetric analytically. The base class impleme...
bool compute_vertex_numerical_gradient(PatchData &pd, MsqVertex &vertex, MsqVertex *vertices[], Vector3D grad_vec[], int num_vtx, double &metric_value, MsqError &err)
const double MSQ_MIN
Definition: Mesquite.hpp:160