Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
includeLinks/NonSmoothSteepestDescent.hpp
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  ***************************************************************** */
39 #ifndef Mesquite_NonSmoothSteepestDescent_hpp
40 #define Mesquite_NonSmoothSteepestDescent_hpp
41 
42 #include "Mesquite.hpp"
43 #include "VertexMover.hpp"
44 #include "ObjectiveFunction.hpp"
46 #include "MsqDebug.hpp"
47 
48 namespace Mesquite
49 {
50 #define MSQ_XDIR 0
51 #define MSQ_YDIR 1
52 #define MSQ_ZDIR 2
53 #define MSQ_BIG_POS_NMBR 1E300
54 #define MSQ_BIG_NEG_NMBR -1E300
55 #define MSQ_MAX_OPT_ITER 20
56 
57 #define MSQ_CCW 1
58 #define MSQ_CW 0
59 #define MSQ_NO_EQUIL 101
60 #define MSQ_CHECK_TOP_DOWN 102
61 #define MSQ_CHECK_BOTTOM_UP 103
62 #define MSQ_TWO_PT_PLANE 104
63 #define MSQ_THREE_PT_PLANE 105
64 #define MSQ_CHECK_Y_COORD_DIRECTION 106
65 #define MSQ_CHECK_X_COORD_DIRECTION 107
66 #define MSQ_CHECK_Z_COORD_DIRECTION 108
67 #define MSQ_EQUIL 109
68 #define MSQ_HULL_TEST_ERROR 110
69 
70 #define MSQ_STEP_ACCEPTED 100
71 #define MSQ_IMP_TOO_SMALL 101
72 #define MSQ_FLAT_NO_IMP 102
73 #define MSQ_STEP_TOO_SMALL 103
74 #define MSQ_EQUILIBRIUM 104
75 #define MSQ_ZERO_SEARCH 105
76 #define MSQ_MAX_ITER_EXCEEDED 106
77 
78 #define MSQ_STEP_DONE 101
79 #define MSQ_STEP_NOT_DONE 102
80 
81 #define MAX_NUM_ELEMENTS 150
82 #define MAX_FUNC_PER_ELEMENT 6
83 #define MSQ_MACHINE_EPS 1E-16
84 #define MSQ_TRUE 1
85 #define MSQ_FALSE 0
86 #define MSQ_MAX(a,b) (a > b ? a : b)
87 #define MSQ_MIN(a,b) (a < b ? a : b)
88 #define MSQ_LESS_THAN_MACHINE_EPS(x) ( ((fabs(x)+1.0) > 1.0) ? 0 : 1 )
89 
90 #define MSQ_DOT(c,a,b,n) {\
91  int i99; \
92  if (n==2) c = a[0]*b[0] + a[1]*b[1]; \
93  else if (n==3) c = a[0]*b[0] + a[1]*b[1] + a[2]*b[2];\
94  else { \
95  c = 0; \
96  for (i99=0;i99<n;i99++) c += a[i99]*b[i99]; \
97  } \
98 }
99 
100 #define MSQ_NORMALIZE(v,n) {\
101  int i99; \
102  double mag99; \
103  if (n==2){ \
104  mag99 = sqrt(v[0]*v[0] + v[1]*v[1]) ; \
105  if (mag99 != 0) { \
106  v[0] = v[0]/mag99; \
107  v[1] = v[1]/mag99; \
108  } \
109  } else if (n==3) {\
110  mag99 = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]) ; \
111  if (mag99 != 0) { \
112  v[0] = v[0]/mag99; \
113  v[1] = v[1]/mag99; \
114  v[2] = v[2]/mag99; \
115  } \
116  } else { \
117  mag99 = 0; \
118  for (i99=0;i99<n;i99++) mag99+=v[i99]+v[i99]; \
119  if (mag99 != 0) { \
120  for (i99=0;i99<n;i99++) v[i99] = v[i99]/mag99;\
121  } \
122  }\
123 }
124 
125 #define MSQ_COPY_VECTOR(a,b,n) { \
126  int i99; \
127  if (n==2) { \
128  a[0] = b[0]; a[1] = b[1]; \
129  } else if (n==3) {\
130  a[0] = b[0]; a[1] = b[1]; a[2] = b[2]; \
131  } else { \
132  for (i99=0;i99<n;i99++) a[i99] = b[i99]; \
133  } \
134 }
135 
136 
137  struct ActiveSet
138  {
142  int active_ind[150]; // need a better way of setting max number of active values
143  };
144 
146  {
147  public:
149 
151 
152  protected:
153  virtual void initialize(PatchData &pd, MsqError &err);
154  virtual void optimize_vertex_positions(PatchData &pd,
155  MsqError &err);
156  virtual void initialize_mesh_iteration(PatchData &pd, MsqError &err);
157  virtual void terminate_mesh_iteration(PatchData &pd, MsqError &err);
158  virtual void cleanup();
159 
160  private:
161  /* local copy of patch data */
162  // PatchData patch_data;
168  int numFree;
170 
171  /* smoothing parameters */
174  double minStepSize;
175 
176  /* optimization data */
181  double *mFunction;
182  double *testFunction;
184  double **mGradient;
188  double mSearch[3];
189  double mAlpha;
190  double maxAlpha;
191  double *mGS;
193  double **mG;
194  double **mPDG;
195  int pdgInd[3];
199 
200  /* functions */
201  void init_opt(MsqError &err);
202  void init_max_step_length(MsqError &err);
203 
204  /* optimize */
205  void minmax_opt(PatchData &pd, MsqError &err);
206  void step_acceptance(PatchData &pd, MsqError &err);
207  void get_min_estimate(double *final_est, MsqError &err);
209  void compute_alpha(MsqError &err);
210  void copy_active(ActiveSet *active1, ActiveSet *active2, MsqError &err);
211 
212  /* function/gradient/active set computations */
213  bool compute_function(PatchData *pd, double *function, MsqError &err);
214  double** compute_gradient(PatchData *pd, MsqError &err);
215  void find_active_set(double *function, ActiveSet *active_set, MsqError &err);
216  void print_active_set(ActiveSet *active_set, double *func, MsqError &err);
217 
218  /* checking validity/improvement */
219  int improvement_check(MsqError &err);
220  int validity_check(MsqError &err);
221 
222  /* checking equilibrium routines */
223  void check_equilibrium(int *equil, int *opt_status, MsqError &err);
224  int convex_hull_test(double **vec, int num_vec, MsqError &err);
225  int check_vector_dots(double **vec, int num_vec, double *normal, MsqError &err);
226  void find_plane_normal(double pt1[3], double pt2[3], double pt3[3],
227  double *cross, MsqError &err);
228  void find_plane_points(int dir1, int dir2, double **vec, int num_vec, double *pt1,
229  double *pt2, double*pt3, int *opt_status, MsqError &err);
230 
231  /* from the matrix file */
232  void form_grammian(double **vec, MsqError &err);
233  void form_PD_grammian(MsqError &err);
234  void singular_test(int n, double **A, int *singular, MsqError &err);
235  void condition3x3(double **A, double *cond, MsqError &err);
236  void solve2x2(double a11, double a12, double a21, double a22,
237  double b1, double b2, double **x,MsqError &err);
238  void form_reduced_matrix(double ***P, MsqError &err);
239 
240  /* search direction */
241  void search_direction(PatchData &pd, MsqError &err);
242  void search_edges_faces(double **dir, MsqError &err);
243  void get_active_directions(double **gradient,
244  double ***dir, MsqError &err);
245  };
246 
247 
248 inline bool NonSmoothSteepestDescent::compute_function(PatchData *patch_data, double *func, MsqError &err)
249 {
250  // ASSUMES ONE VALUE PER ELEMENT; ALSO NEED 1.0/FUNCTION WHICH IS ONLY
251  // TRUE OF CONDITION NUMBER
252 
253  // MSQ_DEBUG_PRINT(2,"Computing Function\n");
254 // FUNCTION_TIMER_START("Compute Function");
255 
256  //TODO need to switch this to element or vertex metric evaluations
257  //TODO need to include boolean testing for validity
258  int i;
259  bool valid_bool=true;
260 
261  for (i=0;i<numElements;i++) func[i]=0.0;
263  if(currentQM==NULL){
264  currentQM = objFunc->get_quality_metric_list().front();
265  }
266 
267  for (i=0;i<numElements;i++) {
268  valid_bool = currentQM->evaluate_element(*patch_data,
269  &(patch_data->element_by_index(i)),
270  func[i], err); MSQ_ERRZERO(err);
271  // MSQ_DEBUG_ACTION(3,{fprintf(stdout," Function value[%d]=%g\n",i,func[i]);});
272  }
273 // FUNCTION_TIMER_END();
274  return(valid_bool);
275 }
276 
277 
279 {
280 // FUNCTION_TIMER_START("Compute Gradient");
281 
282  MSQ_DBGOUT(2) << "Computing Gradient\n";
283 
284  double delta = 10e-6;
285 
286  for (int i=0;i<numElements;i++) {
287  for (int j=0;j<3;j++) mGradient[i][j] = 0.0;
288  }
290  if(currentQM==NULL)
291  currentQM = objFunc->get_quality_metric_list().front();
292 
293  double *func, *fdelta;
294  func = (double *)malloc(sizeof(double)*150);
295  fdelta = (double *)malloc(sizeof(double)*150);
296 
297  this->compute_function(patch_data, func, err);
298  if (MSQ_CHKERR(err)) {
299  free(func);
300  free(fdelta);
301  return 0;
302  }
303 
304  /* gradient in the x, y, z direction */
305 
306  for (int j=0;j<3;j++) {
307 
308  // perturb the coordinates of the free vertex in the j direction by delta
309  mCoords[freeVertexIndex][j] += delta;
310 
311  //compute the function at the perturbed point location
312  this->compute_function(patch_data, fdelta, err);
313  if (MSQ_CHKERR(err)) {
314  free(func);
315  free(fdelta);
316  return 0;
317  }
318 
319  //compute the numerical gradient
320  for (int i=0;i<numFunctionValues;i++) {
321  mGradient[i][j] = (fdelta[i] - func[i])/delta;
322  // MSQ_DEBUG_ACTION(3,{fprintf(stdout," Gradient value[%d][%d]=%g\n",i,j,mGradient[i][j]);});
323  }
324 
325  // put the coordinates back where they belong
326  mCoords[freeVertexIndex][j] -= delta;
327  }
328 
329  free(func);
330  free(fdelta);
331 // FUNCTION_TIMER_END();
332  return(mGradient);
333 }
334 
335 inline void NonSmoothSteepestDescent::find_active_set(double *function,
336  ActiveSet *active_set,
337  MsqError & /*err*/ )
338 {
339  int i, ind;
340  double function_val;
341  double active_value0;
342  double temp;
343 
344 // FUNCTION_TIMER_START("Find Active Set");
345  MSQ_DBGOUT(2) << "\nFinding the active set\n";
346 
347  // initialize the active set indices to zero
348  for (i=0;i<numFunctionValues;i++) active_set->active_ind[i] = 0;
349 
350  /* the first function value is our initial active value */
351  active_set->num_active = 1;
352  active_set->num_equal = 0;
353  active_set->active_ind[0] = 0;
354  active_set->true_active_value = function[0];
355  // MSQ_DEBUG_ACTION(3,{fprintf(stdout," function value[0]: %g\n",function[0]);});
356 
357  /* first sort out the active set...
358  all vals within active_epsilon of largest val */
359 
360  for (i=1;i<numFunctionValues;i++) {
361  function_val = function[i];
362  active_set->true_active_value = MSQ_MAX(function_val,active_set->true_active_value);
363  active_value0 = function[active_set->active_ind[0]];
364  temp = fabs(function_val - active_value0);
365  // MSQ_DEBUG_ACTION(3,{fprintf(stdout," function value[%d]: %g\n",i,function[i]);});
366  if ( function_val > active_value0 ) {
367  if ( temp > activeEpsilon) {
368  active_set->num_active = 1;
369  active_set->num_equal = 0;
370  active_set->active_ind[0] = i;
371  } else if ( temp < activeEpsilon) {
372  active_set->num_active += 1;
373  ind = active_set->num_active - 1;
374  active_set->active_ind[ind] = i;
375  if (fabs(function_val - active_value0) < MSQ_MACHINE_EPS) {
376  active_set->num_equal += 1;
377  }
378  }
379  } else {
380  if (temp < activeEpsilon) {
381  active_set->num_active += 1;
382  ind = active_set->num_active - 1;
383  active_set->active_ind[ind] = i;
384  if (fabs(function_val - active_value0) < MSQ_MACHINE_EPS) {
385  active_set->num_equal += 1;
386  }
387  }
388  }
389  }
390 
391 }
392 
393 
395 
396 {
397 // FUNCTION_TIMER_START("Validity Check");
398 
399  // ONLY FOR SIMPLICIAL MESHES - THERE SHOULD BE A VALIDITY CHECKER ASSOCIATED
400  // WITH MSQ ELEMENTS
401 
402  /* check that the simplicial mesh is still valid, based on right handedness.
403  Returns a 1 or a 0 */
404 
405  // TODO as a first step we can switch this over to the function
406  // evaluation and use the rest of the code as is
407  int valid = 1;
408  double dEps = 1.e-13;
409 
410  double x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4;
411 
412  if (mDimension == 2)
413  {
414  for (int i=0;i<numElements;i++)
415  {
416  double dummy = 0;
420 
421  double a = x2*y3 - x3*y2;
422  double b = y2 - y3;
423  double c = x3 - x2;
424 
425  if (.5*(a+b*x1+c*y1) < .01*MSQ_MACHINE_EPS)
426  valid=0;
427  }
428  }
429 
430  if (mDimension == 3)
431  {
432  for (int i=0;i<numElements;i++)
433  {
438 
439  double dDX2 = x2 - x1;
440  double dDX3 = x3 - x1;
441  double dDX4 = x4 - x1;
442 
443  double dDY2 = y2 - y1;
444  double dDY3 = y3 - y1;
445  double dDY4 = y4 - y1;
446 
447  double dDZ2 = z2 - z1;
448  double dDZ3 = z3 - z1;
449  double dDZ4 = z4 - z1;
450 
451  /* dDet is proportional to the cell volume */
452  double dDet = dDX2*dDY3*dDZ4 + dDX3*dDY4*dDZ2 + dDX4*dDY2*dDZ3
453  - dDZ2*dDY3*dDX4 - dDZ3*dDY4*dDX2 - dDZ4*dDY2*dDX3 ;
454 
455  /* Compute a length scale based on edge lengths. */
456  double dScale = ( sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) +
457  (z1-z2)*(z1-z2)) +
458  sqrt((x1-x3)*(x1-x3) + (y1-y3)*(y1-y3) +
459  (z1-z3)*(z1-z3)) +
460  sqrt((x1-x4)*(x1-x4) + (y1-y4)*(y1-y4) +
461  (z1-z4)*(z1-z4)) +
462  sqrt((x2-x3)*(x2-x3) + (y2-y3)*(y2-y3) +
463  (z2-z3)*(z2-z3)) +
464  sqrt((x2-x4)*(x2-x4) + (y2-y4)*(y2-y4) +
465  (z2-z4)*(z2-z4)) +
466  sqrt((x3-x4)*(x3-x4) + (y3-y4)*(y3-y4) +
467  (z3-z4)*(z3-z4)) ) / 6.;
468 
469  /* Use the length scale to get a better idea if the tet is flat or
470  just really small. */
471  if (fabs(dScale) < MSQ_MACHINE_EPS)
472  {
473  return(valid = 0);
474  }
475  else
476  {
477  dDet /= (dScale*dScale*dScale);
478  }
479 
480  if (dDet > dEps)
481  {
482  valid = 1;
483  }
484  else if (dDet < -dEps)
485  {
486  valid = -1;
487  }
488  else
489  {
490  valid = 0;
491  }
492  } // end for i=1,numElements
493  } // end mDimension==3
494 
495  // MSQ_DEBUG_ACTION(2,{fprintf(stdout,"Mesh Validity is: %d \n",valid);});
496 
497 // FUNCTION_TIMER_END();
498  return(valid);
499 }
500 
501 
502 inline void NonSmoothSteepestDescent::get_active_directions(double **gradient,
503  double ***dir,
504  MsqError &/*err*/)
505 {
506  int i;
507  int num_active = mActive->num_active;
508 
509  (*dir) =(double **)malloc(sizeof(double *)*num_active);
510  for (i=0;i<num_active;i++) {
511  (*dir)[i] =(double *)malloc(sizeof(double)*mDimension);
512  MSQ_COPY_VECTOR((*dir)[i],gradient[mActive->active_ind[i]],mDimension);
513  }
514 }
515 
516 
518  int num_vec,
519  double *normal,
520  MsqError &/*err*/)
521 {
522  int equil;
523  int i, ind;
524  double test_dot, dot;
525 
526  equil = MSQ_FALSE;
527  MSQ_DOT(test_dot,vec[0],normal,3);
528  ind = 1;
529  while ((fabs(test_dot) < MSQ_MACHINE_EPS) && (ind<num_vec)) {
530  MSQ_DOT(test_dot,vec[ind],normal,3);
531  ind++;
532  }
533 
534  for (i=ind;i<num_vec;i++) {
535  MSQ_DOT(dot,vec[i],normal,3);
536  if ( ((dot>0 && test_dot<0) || (dot<0 && test_dot>0)) &&
537  (fabs(dot)>MSQ_MACHINE_EPS)) {
538  return(equil = MSQ_TRUE);
539 
540  }
541  }
542  return(equil);
543 }
544 
545 
547  double pt2[3],
548  double pt3[3],
549  double *cross,
550  MsqError &/*err*/)
551 {
552  int i;
553  double vecA[3], vecB[3];
554 
555  for (i=0;i<3;i++) {
556  vecA[i] = pt2[i] - pt1[i];
557  vecB[i] = pt3[i] - pt1[i];
558  }
559  cross[0] = vecA[1]*vecB[2] - vecA[2]*vecB[1];
560  cross[1] = vecA[2]*vecB[0] - vecA[0]*vecB[2];
561  cross[2] = vecA[0]*vecB[1] - vecA[1]*vecB[0];
562  MSQ_NORMALIZE(cross, 3);
563 }
564 
565 
566 inline int NonSmoothSteepestDescent::convex_hull_test(double **vec, int num_vec, MsqError &err)
567 {
568 // int ierr;
569  int equil;
570  int status, dir_done;
571  double pt1[3], pt2[3], pt3[3];
572  double normal[3];
573 
574 // FUNCTION_TIMER_START("Convex Hull Test");
575  /* tries to determine equilibrium for the 3D case */
576  equil = 0;
578  dir_done = -1;
579 
580  if (num_vec <= 2) status = MSQ_NO_EQUIL;
581 
582  while ((status != MSQ_EQUIL) && (status != MSQ_NO_EQUIL) &&
583  (status != MSQ_HULL_TEST_ERROR)) {
584  if (status == MSQ_CHECK_Z_COORD_DIRECTION) {
586  vec, num_vec, pt1, pt2, pt3, &status, err);
587  dir_done = 2;
588  }
589  if (status == MSQ_CHECK_Y_COORD_DIRECTION) {
591  vec, num_vec, pt1, pt2, pt3, &status, err);
592  dir_done = 1;
593  }
594  if (status == MSQ_CHECK_X_COORD_DIRECTION) {
596  vec, num_vec, pt1, pt2, pt3, &status, err);
597  dir_done = 0;
598  }
599  if (status == MSQ_TWO_PT_PLANE) {
600  pt3[0]=0.; pt3[1]=0.; pt3[2]=0.;
601  }
602  if ((status == MSQ_TWO_PT_PLANE) || (status == MSQ_THREE_PT_PLANE)){
603  this->find_plane_normal(pt1,pt2,pt3,normal,err);
604  equil = this->check_vector_dots(vec,num_vec,normal,err);
605  if (equil == 1) {
606  switch(dir_done){
607  case 2:
608  equil = 0; status = MSQ_CHECK_Y_COORD_DIRECTION;
609  break;
610  case 1:
611  equil = 0; status = MSQ_CHECK_X_COORD_DIRECTION;
612  break;
613  case 0:
614  equil = 1; status = MSQ_EQUIL;
615  }
616  } else if (equil == 0) {
617  status = MSQ_NO_EQUIL;
618  } else {
619  MSQ_SETERR(err)("equil flag not set to 0 or 1",MsqError::INVALID_STATE);
620  }
621  }
622  }
623  switch (status){
624  case MSQ_NO_EQUIL:
625  MSQ_PRINT(3)("Not an equilibrium point\n");
626  equil = 0;
627  break;
628  case MSQ_EQUIL:
629  MSQ_PRINT(3)("An equilibrium point\n");
630  equil = 1;
631  break;
632  default:
633  MSQ_PRINT(3)("Failed to determine equil or not; status = %d\n",status);
634  }
635 // FUNCTION_TIMER_END();
636  return (equil);
637 }
638 
639 inline void NonSmoothSteepestDescent::form_grammian(double **vec, MsqError &err)
640 {
641  int i, j;
642  int num_active = mActive->num_active;
643 
644  if (num_active > 150) {
645  MSQ_SETERR(err)("Exceeded maximum allowed active values",MsqError::INVALID_STATE);
646  return;
647  }
648  /* form the grammian with the dot products of the gradients */
649  for (i=0; i<num_active; i++) {
650  for (j=i; j<num_active; j++) {
651  mG[i][j] = 0.;
652  MSQ_DOT(mG[i][j],vec[i],vec[j],mDimension);
653  mG[j][i] = mG[i][j];
654  }
655  }
656 }
657 
658 inline void NonSmoothSteepestDescent::check_equilibrium(int *equil, int *status, MsqError &err)
659 {
660 // int ierr;
661  int i,j;
662  int ind1, ind2;
663  double min;
664  double **dir;
665  double mid_vec[3], mid_cos, test_cos;
666 
667  //TODO - this subroutine is no longer clear to me... is it still
668  // appropriate for quads and hexes? I think it might be in 2D, but
669  // 3D is less clear. Is there a more general algorithm to use?
670  // ask Todd/check in numerical optimization
671 
672  *equil = MSQ_FALSE;
673  ind1 = ind2 = -1;
674 
675  int num_active = mActive->num_active;
676 
677  if (num_active==numFunctionValues)
678  {
679  *equil = 1; *status = MSQ_EQUILIBRIUM;
680  MSQ_PRINT(3)("All the function values are in the active set\n");
681  }
682 
683  /* set up the active mGradient directions */
684  this->get_active_directions(mGradient,&dir,err);
685 
686  /* normalize the active directions */
687  for (j=0;j<num_active;j++) MSQ_NORMALIZE(dir[j],mDimension);
688 
689  if (mDimension == 2) {
690  /* form the grammian */
691  this->form_grammian(dir,err);
692 
693  /* find the minimum element in the upper triangular portion of G*/
694  min = 1;
695  for (i=0;i<num_active;i++) {
696  for (j=i+1;j<num_active;j++) {
697  if ( fabs(-1 - mG[i][j]) < 1E-08 ) {
698  *equil = 1; *status = MSQ_EQUILIBRIUM;
699  MSQ_PRINT(3)("The gradients are antiparallel, eq. pt\n");
700  }
701  if (mG[i][j] < min) {
702  ind1 = i; ind2 = j;
703  min = mG[i][j];
704  }
705  }
706  }
707 
708  if ((ind1 != -1) && (ind2 != -1)) {
709  /* find the diagonal of the parallelepiped */
710  for (j=0;j<mDimension;j++) {
711  mid_vec[j]=.5*(dir[ind1][j]+dir[ind2][j]);
712  }
713  MSQ_NORMALIZE(mid_vec,mDimension);
714  MSQ_DOT(mid_cos,dir[ind1],mid_vec,mDimension);
715 
716  /* test the other vectors to be sure they lie in the cone */
717  for (i=0;i<num_active;i++) {
718  if ((i != ind1) && (i != ind2)) {
719  MSQ_DOT(test_cos,dir[i],mid_vec,mDimension);
720  if ((test_cos < mid_cos) && fabs(test_cos-mid_cos) > MSQ_MACHINE_EPS) {
721  MSQ_PRINT(3)("An equilibrium point \n");
722  *equil = 1; *status = MSQ_EQUILIBRIUM;
723  }
724  }
725  }
726  }
727  }
728  if (mDimension == 3) {
729  *equil = this->convex_hull_test(dir,num_active,err);
730  if (*equil == 1) *status = MSQ_EQUILIBRIUM;
731  }
732 }
733 
734 
735 
736 inline void NonSmoothSteepestDescent::condition3x3(double **A, double *cond,
737  MsqError &/*err*/)
738 {
739 // int ierr;
740  double a11, a12, a13;
741  double a21, a22, a23;
742  double a31, a32, a33;
743 // double s1, s2, s4, s3, t0;
744  double s1, s2, s3;
745  double denom;
746 // double one = 1.0;
747  double temp;
748  int zero_denom = MSQ_TRUE;
749 
750  a11 = A[0][0]; a12=A[0][1]; a13=A[0][2];
751  a21 = A[1][0]; a22=A[1][1]; a23=A[1][2];
752  a31 = A[2][0]; a32=A[2][1]; a33=A[2][2];
753 
754  denom = -a11*a22*a33+a11*a23*a32+a21*a12*a33-a21*a13*a32-
755  a31*a12*a23+a31*a13*a22;
756 
757  if ( (fabs(a11) > MSQ_MACHINE_EPS) &&
758  (fabs(denom/a11) > MSQ_MACHINE_EPS)) {
759  zero_denom = MSQ_FALSE;
760  }
761  if ( (fabs(a22) > MSQ_MACHINE_EPS) &&
762  (fabs(denom/a22) > MSQ_MACHINE_EPS)) {
763  zero_denom = MSQ_FALSE;
764  }
765  if ( (fabs(a33) > MSQ_MACHINE_EPS) &&
766  (fabs(denom/a33) > MSQ_MACHINE_EPS)) {
767  zero_denom = MSQ_FALSE;
768  }
769 
770  if (zero_denom) {
771  (*cond) = 1E300;
772  } else {
773  s1 = sqrt(a11*a11 + a12*a12 + a13*a13 +
774  a21*a21 + a22*a22 + a23*a23 +
775  a31*a31 + a32*a32 + a33*a33);
776 
777  temp = (-a22*a33+a23*a32)/denom;
778  s3 = temp*temp;
779  temp =(a12*a33-a13*a32)/denom;
780  s3 += temp*temp;
781  temp = (a12*a23-a13*a22)/denom;
782  s3 += temp*temp;
783  temp = (a21*a33-a23*a31)/denom;
784  s3 += temp*temp;
785  temp = (a11*a33-a13*a31)/denom;
786  s3 += temp*temp;
787  temp = (a11*a23-a13*a21)/denom;
788  s3 += temp*temp;
789  temp = (a21*a32-a22*a31)/denom;
790  s3 += temp*temp;
791  temp = (-a11*a32+a12*a31)/denom;
792  s3 += temp*temp;
793  temp = (-a11*a22+a12*a21)/denom;
794  s3 += temp*temp;
795 
796  s2 = sqrt(s3);
797  (*cond) = s1*s2;
798  }
799 }
800 
801 inline void NonSmoothSteepestDescent::singular_test(int n, double **A, int *singular, MsqError &err)
802 {
803 // int test;
804 // double determinant;
805  double cond;
806 
807  if ((n>3) || (n<1)) {
808  MSQ_SETERR(err)("Singular test works only for n=1 to n=3",MsqError::INVALID_ARG);
809  return;
810  }
811 
812  (*singular)=MSQ_TRUE;
813  switch(n) {
814  case 1:
815  if (A[0][0] > 0) (*singular) = MSQ_FALSE;
816  break;
817  case 2:
818  if (fabs(A[0][0]*A[1][1] - A[0][1]*A[1][0]) > MSQ_MACHINE_EPS)
819  (*singular) = MSQ_FALSE;
820  break;
821  case 3:
822  /* calculate the condition number */
823  this->condition3x3(A, &cond, err);
824  if (cond < 1E14) (*singular)=MSQ_FALSE;
825  break;
826  }
827 }
828 
829 
831 {
832  int i,j,k;
833  int g_ind_1;
834  int singular;
835 
836  int num_active = mActive->num_active;
837 
838  /* this assumes the grammian has been formed */
839  for (i=0;i<num_active;i++) {
840  for (j=0;j<num_active;j++) {
841  if (mG[i][j]==-1) {
842  MSQ_SETERR(err)("Grammian not computed properly",MsqError::INVALID_STATE);
843  return;
844  }
845  }
846  }
847 
848  /* use the first gradient in the active set */
849  g_ind_1 = 0;
850  mPDG[0][0] = mG[0][0];
851  pdgInd[0] = mActive->active_ind[0];
852 
853  /* test the rest and add them as appropriate */
854  k = 1; i = 1;
855  while( (k<mDimension) && (i < num_active) ) {
856  mPDG[0][k] = mPDG[k][0] = mG[0][i];
857  mPDG[k][k] = mG[i][i];
858  if ( k == 2) { /* add the dot product of g1 and g2 */
859  mPDG[1][k] = mPDG[k][1] = mG[g_ind_1][i];
860  }
861  this->singular_test(k+1,mPDG,&singular,err);
862  if (!singular) {
863  pdgInd[k] = mActive->active_ind[i];
864  if (k==1) g_ind_1 = i;
865  k++;
866  }
867  i++;
868  }
869 }
870 
871 
873 {
874 // int ierr;
875  int i,j,k;
876  int viable;
877  double a,b,denom;
878  double g_bar[3];
879  double temp_search[3];
880  double projection, min_projection;
881 
882  int num_active = mActive->num_active;
883 
884  if ( (mDimension != 2) && (mDimension != 3)) {
885  MSQ_SETERR(err)("Dimension must be 2 or 3", MsqError::INVALID_MESH);
886  }
887 
888  /* initialize the search direction to 0,0 */
889  for (i=0;i<mDimension;i++) temp_search[i] = 0;
890 
891  /* Check for viable faces */
892  min_projection = 1E300;
893  for (i=0; i<num_active; i++) {
894  /* FACE I */
895  viable = 1;
896 
897  /* test the viability */
898  for (j=0;j<num_active;j++) { /* lagrange multipliers>0 */
899  if (mG[j][i] < 0) viable = 0;
900  }
901 
902  /* find the minimum of viable directions */
903  if ((viable) && (mG[i][i] < min_projection)) {
904  min_projection = mG[i][i];
905  MSQ_COPY_VECTOR(temp_search,dir[i],mDimension);
907  }
908 
909  /* INTERSECTION IJ */
910  for (j=i+1; j<num_active; j++) {
911  viable = 1;
912 
913  /* find the coefficients of the intersection
914  and test the viability */
915  denom = 2*mG[i][j] - mG[i][i] - mG[j][j];
916  a = b = 0;
917  if (fabs(denom) > MSQ_MACHINE_EPS) {
918  b = (mG[i][j] - mG[i][i])/denom;
919  a = 1 - b;
920  if ((b < 0) || (b > 1)) viable=0; /* 0 < b < 1 */
921  for (k=0;k<num_active;k++) { /* lagrange multipliers>0 */
922  if ((a*mG[k][i] + b*mG[k][j]) <= 0) viable=0;
923  }
924  } else {
925  viable = 0; /* Linearly dependent */
926  }
927 
928  /* find the minimum of viable directions */
929  if (viable) {
930  for (k=0;k<mDimension;k++) {
931  g_bar[k] = a * dir[i][k] + b * dir[j][k];
932  }
933  MSQ_DOT(projection,g_bar,g_bar,mDimension);
934  if (projection < min_projection) {
935  min_projection = projection;
936  MSQ_COPY_VECTOR(temp_search,g_bar,mDimension);
938  }
939  }
940  }
941  }
942  if (optStatus != MSQ_EQUILIBRIUM) {
943  MSQ_COPY_VECTOR(mSearch,temp_search,mDimension);
944  }
945 }
946 
947 
948 inline void NonSmoothSteepestDescent::solve2x2(double a11, double a12,
949  double a21, double a22,
950  double b1, double b2,
951  double **x, MsqError &/*err*/)
952 {
953  double factor;
954 
955  /* if the system is not singular, solve it */
956  if (fabs(a11*a22 - a21*a12) > MSQ_MACHINE_EPS) {
957  (*x)=(double *)malloc(sizeof(double)*2);
958  if (fabs(a11) > MSQ_MACHINE_EPS) {
959  factor = (a21/a11);
960  (*x)[1] = (b2 - factor*b1)/(a22 - factor*a12);
961  (*x)[0] = (b1 - a12*(*x)[1])/a11;
962  } else if (fabs(a21) > MSQ_MACHINE_EPS) {
963  factor = (a11/a21);
964  (*x)[1] = (b1 - factor*b2)/(a12 - factor*a22);
965  (*x)[0] = (b2 - a22*(*x)[1])/a21;
966  }
967  } else {
968  (*x) = NULL;
969  }
970 }
971 
972 
974  MsqError &/*err*/)
975 {
976  int i,j;
977  int num_active = mActive->num_active;
978 
979  (*P)=(double **)malloc(sizeof(double *)*(num_active-1));
980  for (i=0; i<num_active-1; i++)
981  (*P)[i]=(double *)malloc(sizeof(double)*(num_active-1));
982 
983  for (i=0;i<num_active-1;i++) {
984  (*P)[i][i] = mG[0][0] - 2*mG[0][i+1] + mG[i+1][i+1];
985  for (j=i+1;j<num_active-1;j++) {
986  (*P)[i][j] = mG[0][0] - mG[0][j+1] - mG[i+1][0] + mG[i+1][j+1];
987  (*P)[j][i] = (*P)[i][j];
988  }
989  }
990 }
991 
992 
993 inline void NonSmoothSteepestDescent::get_min_estimate(double *final_est,
994  MsqError &/*err*/)
995 {
996  int i;
997  double est_imp;
998 
999  *final_est = -1E300;
1000  for (i=0;i<mActive->num_active;i++) {
1001  est_imp = -mAlpha*mGS[mActive->active_ind[i]];
1002  if (est_imp>*final_est) *final_est = est_imp;
1003  }
1004  if (*final_est == 0) {
1005  *final_est = -1E300;
1006  for (i=0;i<numFunctionValues;i++) {
1007  est_imp = -mAlpha*mGS[i];
1008  if ((est_imp>*final_est) && (fabs(est_imp) > MSQ_MACHINE_EPS)) {
1009  *final_est = est_imp;
1010  }
1011  }
1012  }
1013 }
1014 
1015 
1017 {
1018  for (int i=0;i<numFunctionValues;i++)
1020 
1021  MSQ_PRINT(3)("steepest in get_gradient_projections %d\n",mSteepest);
1022 }
1023 
1024 
1026 {
1027 // int ierr;
1028 // int j;
1029  int i;
1030 // int ind;
1031  int num_values;
1032  double steepest_function;
1033  double steepest_grad;
1034  double alpha_i;
1035  double min_positive_value=1E300;
1036 
1037 // FUNCTION_TIMER_START("Compute Alpha");
1038 
1039  MSQ_PRINT(2)("In compute alpha\n");
1040 
1041  num_values = numFunctionValues;
1042  mAlpha = 1E300;
1043 
1044  steepest_function = mFunction[mSteepest];
1045  steepest_grad = mGS[mSteepest];
1046  for (i=0;i<num_values;i++)
1047  {
1048  /* if it's not active */
1049  if (i!=mSteepest)
1050  {
1051  alpha_i = steepest_function - mFunction[i];
1052 
1053  if (fabs(mGS[mSteepest] - mGS[i])>1E-13) {
1054  /* compute line intersection */
1055  alpha_i = alpha_i/(steepest_grad - mGS[i]);
1056  } else {
1057  /* the lines don't intersect - it's not under consideration*/
1058  alpha_i = 0;
1059  }
1060  if ((alpha_i > minStepSize ) && (fabs(alpha_i) < fabs(mAlpha))) {
1061  mAlpha = fabs(alpha_i);
1062  MSQ_PRINT(3)("Setting alpha %d %g\n",i,alpha_i);
1063  }
1064  if ((alpha_i > 0) && (alpha_i < min_positive_value)) {
1065  min_positive_value = alpha_i;
1066  }
1067  }
1068  }
1069 
1070  if ((mAlpha == 1E300) && (min_positive_value != 1E300)) {
1071  mAlpha = min_positive_value;
1072  }
1073 
1074  /* if it never gets set, set it to the default */
1075  if (mAlpha == 1E300) {
1076  mAlpha = maxAlpha;
1077  MSQ_PRINT(3)("Setting alpha to the maximum step length\n");
1078  }
1079 
1080  MSQ_PRINT(3)(" The initial step size: %f\n",mAlpha);
1081 
1082 // FUNCTION_TIMER_END();
1083 }
1084 
1085 
1087  MsqError &err)
1088 {
1089  if (active1==NULL || active2==NULL) {
1090  MSQ_SETERR(err)("Null memory in copy_active\n",MsqError::INVALID_ARG);
1091  return;
1092  }
1093 
1094  active2->num_active = active1->num_active;
1095  active2->num_equal = active1->num_equal;
1096  active2->true_active_value = active1->true_active_value;
1097  for (int i=0;i<active1->num_active;i++) {
1098  active2->active_ind[i] = active1->active_ind[i];
1099  }
1100 }
1101 
1102 
1104  double * func,
1105  MsqError &err)
1106 {
1107  if (active_set==0) {
1108  MSQ_SETERR(err)("Null ActiveSet", MsqError::INVALID_ARG);
1109  return;
1110  }
1111 
1112  if (active_set->num_active == 0) MSQ_DBGOUT(3)<< "No active values\n";
1113  /* print the active set */
1114  for (int i=0;i<active_set->num_active;i++) {
1115  MSQ_PRINT(3)("Active value %d: %f \n",
1116  i+1,func[active_set->active_ind[i]]);
1117  }
1118 }
1119 
1120 
1122 {
1123  int i, j;
1124 
1125  MSQ_PRINT(2)("\nInitializing Optimization \n");
1126  if (numFunctionValues > 150) {
1127  MSQ_SETERR(err)("num_values exceeds 150", MsqError::INVALID_STATE);
1128  }
1129  /* for the purposes of initialization will be set to zero after */
1130  equilibriumPt = 0;
1131  optStatus = 0;
1132  iterCount = 0;
1133  optIterCount = 0;
1134  mSteepest = 0;
1135  mAlpha = 0;
1136  maxAlpha = 0;
1137 
1138  MSQ_PRINT(3)(" Initialized Constants \n");
1139  for (i=0;i<3;i++) {
1140  mSearch[i] = 0;
1141  pdgInd[i] = -1;
1142  for (j=0;j<3;j++) mPDG[i][j] = 0;
1143  }
1144 
1145  MSQ_PRINT(3)(" Initialized search and PDG \n");
1146  for (i=0;i<numFunctionValues;i++) {
1147  mFunction[i] = 0;
1148  testFunction[i] = 0;
1149  originalFunction[i] = 0;
1150  mGS[i] = 0;
1151  for (j=0;j<3;j++) {
1152  mGradient[i][j] = 0;
1153  }
1154  }
1155  MSQ_PRINT(3)(" Initialized function/gradient \n");
1156  if (numFunctionValues > 150) {
1157  for (i=0;i<150;i++) {
1158  for (j=0;j<150;j++) mG[i][j] = -1;
1159  }
1160  } else {
1161  for (i=0;i<numFunctionValues;i++) {
1162  for (j=0;j<numFunctionValues;j++) mG[i][j] = -1;
1163  }
1164  }
1165  MSQ_PRINT(3)(" Initialized G\n");
1166 
1167  for (i=0;i<100;i++) prevActiveValues[i] = 0;
1168  MSQ_PRINT(3)(" Initialized prevActiveValues\n");
1169 }
1170 
1171 
1173 {
1174  int i, j, k;
1175  double max_diff = 0;
1176  double diff=0;
1177 
1178  MSQ_PRINT(2)("In init_max_step_length\n");
1179 
1180  /* check that the input data is correct */
1181  if (numElements==0) {
1182  MSQ_SETERR(err)("Num incident vtx = 0\n",MsqError::INVALID_MESH);
1183  return;
1184  }
1185  if ((mDimension!=2) && (mDimension!=3)) {
1186  MSQ_SETERR(err)("Problem dimension is incorrect", MsqError::INVALID_MESH);
1187  return;
1188  }
1189 
1190  /* find the maximum distance between two incident vertex locations */
1191  for (i=1;i<numVertices;i++) {
1192  for (j=i;j<numVertices+1;j++) {
1193  diff=0;
1194  for (k=0;k<mDimension;k++) {
1195  diff += (mCoords[i][k]-mCoords[j][k])*(mCoords[i][k]-mCoords[j][k]);
1196  }
1197  if (max_diff < diff) max_diff=diff;
1198  }
1199  }
1200  max_diff = sqrt(max_diff);
1201  if (max_diff==0) {
1202  MSQ_SETERR(err)("Maximum distance between incident vertices = 0\n",
1204  return;
1205  }
1206  maxAlpha = max_diff/100;
1207 
1208  MSQ_PRINT(3)(" Maximum step is %g\n",maxAlpha);
1209 }
1210 
1211 
1212 } // namespace
1213 
1214 #endif // Mesquite_NonSmoothSteepestDescent_hpp
void find_plane_points(int dir1, int dir2, double **vec, int num_vec, double *pt1, double *pt2, double *pt3, int *opt_status, MsqError &err)
msq_stdc::size_t get_vertex_index(msq_stdc::size_t vertex_in_element) const
#define MSQ_ERRZERO(err)
Return zero/NULL on error.
NVec< 3, T > cross(const NVec< 3, T > &u, const NVec< 3, T > &v)
j indices k indices k
Definition: Indexing.h:6
Used to hold the error state and return it to the application.
void check_equilibrium(int *equil, int *opt_status, MsqError &err)
Base class for concrete quality metrics.
double ** compute_gradient(PatchData *pd, MsqError &err)
MsqMeshEntity is the Mesquite object that stores information about the elements in the mesh...
double sqrt(double d)
Definition: double.h:73
void singular_test(int n, double **A, int *singular, MsqError &err)
virtual msq_std::list< QualityMetric * > get_quality_metric_list()
invalid function argument passed
int convex_hull_test(double **vec, int num_vec, MsqError &err)
rational * A
Definition: vinci_lass.c:67
void get_coordinates(double &x, double &y, double &z) const
void get_active_directions(double **gradient, double ***dir, MsqError &err)
#define MSQ_CHKERR(err)
Mesquite&#39;s Error Checking macro.
const double MSQ_MAX
Definition: Mesquite.hpp:172
#define MSQ_SETERR(err)
Macro to set error - use err.clear() to clear.
blockLoc i
Definition: read.cpp:79
void int int REAL * x
Definition: read.cpp:74
void get_min_estimate(double *final_est, MsqError &err)
const NT & n
void solve2x2(double a11, double a12, double a21, double a22, double b1, double b2, double **x, MsqError &err)
void condition3x3(double **A, double *cond, MsqError &err)
MsqMeshEntity & element_by_index(size_t index)
virtual bool evaluate_element(PatchData &, MsqMeshEntity *, double &, MsqError &err)
Evaluate the metric for an element.
Vector_n min(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:346
void find_active_set(double *function, ActiveSet *active_set, MsqError &err)
j indices j
Definition: Indexing.h:6
#define MSQ_PRINT(flag)
Check debug flag and print printf-style formatted output.
object is in an invalid state
void find_plane_normal(double pt1[3], double pt2[3], double pt3[3], double *cross, MsqError &err)
CGAL_KERNEL_LARGE_INLINE PointS3< FT > projection(const PointS3< FT > &p, const PlaneS3< FT > &h)
#define MSQ_DBGOUT(flag)
Check debug flag and return ostream associated with flag.
bool compute_function(PatchData *pd, double *function, MsqError &err)
int check_vector_dots(double **vec, int num_vec, double *normal, MsqError &err)
for(;;)
MsqVertex is the Mesquite object that stores information about the vertices in the mesh...
CGAL_BEGIN_NAMESPACE void const NT NT NT NT & denom
Base class for concrete Objective Functions ObjectiveFunction contains a pointer to a QualityMetric...
void copy_active(ActiveSet *active1, ActiveSet *active2, MsqError &err)
void print_active_set(ActiveSet *active_set, double *func, MsqError &err)