Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QualityImprover/VertexMover/NonSmoothSteepestDescent/NonSmoothSteepestDescent.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  ***************************************************************** */
27 // -*- Mode : c++; tab-width: 3; c-tab-always-indent: t; indent-tabs-mode: nil; c-basic-offset: 3 -*-
28 
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <vector>
40 #include "MeshSet.hpp"
41 #include "MsqTimer.hpp"
42 
43 using namespace Mesquite;
44 
46 {
47  objFunc=of;
48  this->set_name("NonSmoothSteepestDescent");
49 
50  mFunction = (double *)malloc(sizeof(double)*150);
51  testFunction = (double *)malloc(sizeof(double)*150);
52  originalFunction = (double *)malloc(sizeof(double)*150);
53  mGradient = (double **)malloc(sizeof(double *)*150);
54  mGS = (double *)malloc(sizeof(double)*150);
55  mG = (double **)malloc(sizeof(double *)*150);
56  mPDG = (double **)malloc(sizeof(double *)*3);
57  prevActiveValues=(double *)malloc(sizeof(double)*150);
58 
59  int i;
60  for (i=0;i<150;i++) {
61  mGradient[i] = (double *)malloc(sizeof(double)*3);
62  mG[i] = (double *)malloc(sizeof(double)*150);
63  }
64  for (i=0;i<3;i++) mPDG[i] = (double *)malloc(sizeof(double)*3);
65 
66  mActive = (ActiveSet *)malloc(sizeof(ActiveSet));
67  testActive = (ActiveSet *)malloc(sizeof(ActiveSet));
68  originalActive = (ActiveSet *)malloc(sizeof(ActiveSet));
69  MSQ_DBGOUT(1) << "- Executed NonSmoothSteepestDescent::NonSmoothSteepestDescent()\n";
70 }
71 
72 
74 {
76 
77  // local parameter initialization
78  activeEpsilon = .00003;
79  // activeEpsilon = .000000003;
81  minStepSize = 1e-6;
82  MSQ_DBGOUT(1) << "- Executed NonSmoothSteepestDescent::initialize()\n";
83 }
84 
86  MsqError &/*err*/)
87 {
88 }
90  MsqError &err)
91 {
92  MSQ_FUNCTION_TIMER( "NonSmoothSteepestDescent" );
93 
94  // cout << "- Executing NonSmoothSteepestDescent::optimize_node_positions()\n";
95  /* perform the min max smoothing algorithm */
96  MSQ_PRINT(2)("\nInitializing the patch iteration\n");
97 
99  MSQ_PRINT(3)("Number of Vertices: %d\n",numVertices);
100  numElements = pd.num_elements();
101  MSQ_PRINT(3)("Number of Elements: %d\n",numElements);
102  //Michael: Note: is this a reliable way to get the dimension?
104  MSQ_PRINT(3)("Spatial Dimension: %d\n",mDimension);
105 
106  numFree=pd.num_free_vertices(err); MSQ_ERRRTN(err);
107  MSQ_PRINT(3)("Num Free = %d\n",numFree);
108 
109  MsqFreeVertexIndexIterator free_iter(&pd, err); MSQ_ERRRTN(err);
110  free_iter.reset();
111  free_iter.next();
112  freeVertexIndex = free_iter.value();
113  MSQ_PRINT(3)("Free Vertex Index = %d\n",freeVertexIndex);
114 
115  mCoords = pd.get_vertex_array(err); MSQ_ERRRTN(err);
116 
117  if (MSQ_DBG(3)) {
118  for (int i99=0;i99<numVertices;i99++) {
119  MSQ_PRINT(3)("coords: %g %g\n",mCoords[i99][0],mCoords[i99][1]);
120  }
121  }
122 
124  if (MSQ_DBG(3)) {
125  msq_std::vector<size_t> indices;
126  for (int i99=0;i99<numElements;i99++) {
127  mConnectivity[i99].get_vertex_indices(indices);
128  MSQ_PRINT(3)("connectivity: %d %d %d\n",indices[0],
129  indices[1],indices[2]);
130  }
131  }
132 
133  // TODO - need to switch to validity via metric evaluations should
134  // be associated with the compute_function somehow
135  /* check for an invalid mesh; if it's invalid return and ask the user
136  to use untangle */
137  if (this->validity_check(err)!=1) {
138  MSQ_PRINT(1)("ERROR: Invalid mesh\n");
139  MSQ_SETERR(err)("Invalid Mesh: Use untangle to create a valid "
140  "triangulation", MsqError::INVALID_MESH);
141  return;
142  }
143 
144  /* assumes one function value per element */
145  // TODO - need to include vertex metrics
147 
148  /* initialize the optimization data up to numFunctionValues */
149  this->init_opt(err); MSQ_ERRRTN(err);
150  this->init_max_step_length(err); MSQ_ERRRTN(err);
151  MSQ_PRINT(3)("Done initializing optimization\n");
152 
153  /* compute the initial function values */
154  //TODO this should return a bool with the validity
155  this->compute_function(&pd, originalFunction, err); MSQ_ERRRTN(err);
156 
157  // find the initial active set
159 
160  this->minmax_opt(pd,err); MSQ_ERRRTN(err);
161 }
162 
163 
165  MsqError &/*err*/)
166 {
167 }
168 
170 {
171  MSQ_DBGOUT(1) << "- Executing NonSmoothSteepestDescent::cleanup()\n";
172  int i;
173  for (i=0;i<150;i++) {
174  free(mGradient[i]);
175  free(mG[i]);
176  }
177  for (i=0;i<3;i++) free(mPDG[i]);
178 
179  free(mFunction);
180  free(testFunction);
181  free(originalFunction);
182  free(mGradient);
183  free(mGS);
184  free(mG);
185  free(mPDG);
186  free(prevActiveValues);
187  free(mActive);
188  free(testActive);
189  free(originalActive);
190  MSQ_DBGOUT(1) << "- Done with NonSmoothSteepestDescent::cleanup()\n";
191 }
192 
193 
194 
196 {
197  int improved = 1;
198 
199  /* check to see that the mesh didn't get worse */
200  if (originalValue < mActive->true_active_value) {
201  MSQ_PRINT(2)("The local mesh got worse; initial value %f; final value %f\n",
203  improved = 0;
204  }
205 
206  return(improved);
207 
208 }
209 
210 
211 
212 
214  double **vec, int num_vec,
215  double *pt1, double *pt2,
216  double* /*pt3*/, int *status,
217  MsqError &/*err*/)
218 {
219  int i;
220  int ind[50], num_min, num_max;
221  int rotate=MSQ_CW;
222  int num_rotated=0;
223  double pt_1, pt_2;
224  double min, inv_slope;
225  double min_inv_slope=0.;
226  double max;
227  double max_inv_slope=0;
228  double inv_origin_slope=0;
229 
230  *status = MSQ_CHECK_BOTTOM_UP;
231  /* find the minimum points in dir1 starting at -1 */
232  num_min = 0; ind[0]=-1; ind[1]=-1; ind[2]=-1; min=1.0;
233  for (i=0;i<num_vec;i++) {
234  if (vec[i][dir1]<min) {
235  min = vec[i][dir1]; ind[0] = i; num_min = 1;
236  } else if (fabs(vec[i][dir1] - min) < MSQ_MACHINE_EPS) {
237  ind[num_min++] = i;
238  }
239  }
240  if (min >= 0) *status = MSQ_NO_EQUIL;
241 
242  if (*status != MSQ_NO_EQUIL) {
243  switch(num_min) {
244  case 1: /* rotate to find the next point */
245  MSQ_COPY_VECTOR(pt1,vec[ind[0]],3);
246  pt_1 = pt1[dir1]; pt_2 = pt1[dir2];
247  if (pt1[dir2] <= 0){rotate=MSQ_CCW; max_inv_slope=MSQ_BIG_NEG_NMBR;}
248  if (pt1[dir2] > 0){rotate=MSQ_CW; min_inv_slope=MSQ_BIG_POS_NMBR;}
249  switch(rotate) {
250  case MSQ_CCW:
251  for (i=0;i<num_vec;i++) {
252  if (i!=ind[0]) {
253  inv_slope = (vec[i][dir2] - pt_2)/(vec[i][dir1]-pt_1);
254  if ((inv_slope>max_inv_slope) &&
255  (fabs(inv_slope - max_inv_slope) > MSQ_MACHINE_EPS)) {
256  ind[1] = i; max_inv_slope=inv_slope; num_rotated = 1;
257  } else if (fabs(inv_slope - max_inv_slope) < MSQ_MACHINE_EPS) {
258  ind[2] = i; num_rotated++;
259  }
260  }
261  }
262  break;
263  case MSQ_CW:
264  for (i=0;i<num_vec;i++) {
265  if (i!=ind[0]) {
266  inv_slope = (vec[i][dir2] - pt_2)/(vec[i][dir1]-pt_1);
267  if ((inv_slope<min_inv_slope) &&
268  (fabs(inv_slope - max_inv_slope) > MSQ_MACHINE_EPS)){
269  ind[1] = i; min_inv_slope=inv_slope; num_rotated = 1;
270  } else if (fabs(inv_slope - min_inv_slope) < MSQ_MACHINE_EPS) {
271  ind[2] = i; num_rotated++;
272  }
273  }
274  }
275  }
276  switch(num_rotated) {
277  case 0:
278  MSQ_PRINT(3)("No points in the rotation ... odd\n");
279  *status = MSQ_HULL_TEST_ERROR;
280  break;
281  case 1:
282  MSQ_PRINT(3)("Found a line in the convex hull\n");
283  MSQ_COPY_VECTOR(pt2,vec[ind[1]],3); *status = MSQ_TWO_PT_PLANE;
284  break;
285  default:
286  MSQ_PRINT(3)("Found 2 or more points in the rotation\n");
287  if (fabs(pt_1) > MSQ_MACHINE_EPS) inv_origin_slope = pt_2/pt_1;
288  switch(rotate) {
289  case MSQ_CCW:
290  if (inv_origin_slope >= max_inv_slope) *status=MSQ_NO_EQUIL;
291  else *status=MSQ_CHECK_TOP_DOWN;
292  break;
293  case MSQ_CW:
294  if (inv_origin_slope <= min_inv_slope) *status=MSQ_NO_EQUIL;
295  else *status=MSQ_CHECK_TOP_DOWN;
296  }
297  }
298  break;
299  case 2: /* use these two points to define the plane */
300  MSQ_PRINT(3)("Found two minimum points to define the plane\n");
301  MSQ_COPY_VECTOR(pt1,vec[ind[0]],3);
302  MSQ_COPY_VECTOR(pt2,vec[ind[1]],3);
303  *status = MSQ_TWO_PT_PLANE;
304  break;
305  default: /* check to see if all > 0 */
306  MSQ_PRINT(3)("Found 3 or more points in min plane %f\n",min);
307  if (vec[ind[0]][dir1] >= 0) *status = MSQ_NO_EQUIL;
308  else *status = MSQ_CHECK_TOP_DOWN;
309  }
310  }
311 
312  /***************************/
313  /* failed to find any information, checking top/down this coord*/
314  /***************************/
315 
316  if (*status == MSQ_CHECK_TOP_DOWN) {
317  /* find the maximum points in dir1 starting at 1 */
318  num_max = 0; ind[0]=-1; ind[1]=-1; ind[2]=-1; max=-1.0;
319  for (i=0;i<num_vec;i++) {
320  if (vec[i][dir1] > max) {
321  max = vec[i][dir1]; ind[0] = i; num_max = 1;
322  } else if (fabs(vec[i][dir1] - max) < MSQ_MACHINE_EPS) {
323  ind[num_max++] = i;
324  }
325  }
326  if (max <= 0) *status = MSQ_NO_EQUIL;
327 
328  if (*status != MSQ_NO_EQUIL) {
329  switch(num_max) {
330  case 1: /* rotate to find the next point */
331  MSQ_COPY_VECTOR(pt1,vec[ind[0]],3);
332  pt_1 = pt1[dir1]; pt_2 = pt1[dir2];
333  if (pt1[dir2] < 0){rotate=MSQ_CW; min_inv_slope=1E300;}
334  if (pt1[dir2] >= 0){rotate=MSQ_CCW; max_inv_slope=-1E300;}
335  switch(rotate) {
336  case MSQ_CCW:
337  for (i=0;i<num_vec;i++) {
338  if (i!=ind[0]) {
339  inv_slope = (vec[i][dir2] - pt_2)/(vec[i][dir1]-pt_1);
340  if (inv_slope>max_inv_slope) {
341  ind[1] = i; max_inv_slope=inv_slope; num_rotated = 1;
342  } else if (fabs(inv_slope - max_inv_slope) < MSQ_MACHINE_EPS) {
343  ind[2] = i; num_rotated++;
344  }
345  }
346  }
347  break;
348  case MSQ_CW:
349  for (i=0;i<num_vec;i++) {
350  if (i!=ind[0]) {
351  inv_slope = (vec[i][dir2] - pt_2)/(vec[i][dir1]-pt_1);
352  if (inv_slope<min_inv_slope) {
353  ind[1] = i; min_inv_slope=inv_slope; num_rotated = 1;
354  } else if (fabs(inv_slope - min_inv_slope) < MSQ_MACHINE_EPS) {
355  ind[2] = i; num_rotated++;
356  }
357  }
358  }
359  }
360  switch(num_rotated) {
361  case 0:
362  MSQ_PRINT(3)("No points in the rotation ... odd\n");
363  *status = MSQ_HULL_TEST_ERROR;
364  break;
365  case 1:
366  MSQ_PRINT(3)("Found a line in the convex hull\n");
367  MSQ_COPY_VECTOR(pt2,vec[ind[1]],3);
368  *status = MSQ_TWO_PT_PLANE;
369  break;
370  default:
371  MSQ_PRINT(3)("Found 2 or more points in the rotation\n");
372  /* check to see if rotation got past origin */
373  inv_origin_slope = pt_2/pt_1;
374  switch(rotate) {
375  case MSQ_CCW:
376  if (inv_origin_slope >= max_inv_slope) *status=MSQ_NO_EQUIL;
377  else if (dir1 == 2) *status=MSQ_CHECK_Y_COORD_DIRECTION;
378  else if (dir1 == 1) *status=MSQ_CHECK_X_COORD_DIRECTION;
379  else *status=MSQ_EQUIL;
380  break;
381  case MSQ_CW:
382  if (inv_origin_slope <= min_inv_slope) *status=MSQ_NO_EQUIL;
383  else if (dir1 == 2) *status=MSQ_CHECK_Y_COORD_DIRECTION;
384  else if (dir1 == 1) *status=MSQ_CHECK_X_COORD_DIRECTION;
385  else *status=MSQ_EQUIL;
386  }
387  }
388  break;
389  case 2: /* use these two points to define the plane */
390  MSQ_COPY_VECTOR(pt1,vec[ind[0]],3);
391  MSQ_COPY_VECTOR(pt2,vec[ind[1]],3);
392  *status = MSQ_TWO_PT_PLANE;
393  break;
394  default: /* check to see if all > 0 */
395  MSQ_PRINT(3)("Found 3 in max plane %f\n",max);
396  if (vec[ind[0]][dir1] <= 0) *status = MSQ_NO_EQUIL;
397  else if (dir1==2) *status=MSQ_CHECK_Y_COORD_DIRECTION;
398  else if (dir1==1) *status=MSQ_CHECK_X_COORD_DIRECTION;
399  else *status = MSQ_EQUIL;
400  }
401  }
402  }
403 
404 }
405 
407  MsqError &err)
408 {
409  int i;
410  int viable;
411  int singular;
412  double a, b, c, denom;
413  double **dir;
414  double R0, R1;
415  double **P, *x;
416  double search_mag;
417 
418  int num_active = mActive->num_active;
419 
420  //TODO This might be o.k. actually - i don't see any dependence
421  // on the element geometry here... try it and see if it works.
422  // if not, try taking all of the gradients in the active set
423  // and let the search direction be the average of those.
424 // MSQ_FUNCTION_TIMER( "Search Direction" );
425 
426  MSQ_PRINT(2)("\nIn Search Direction\n");
427  this->print_active_set(mActive, mFunction, err); MSQ_ERRRTN(err);
428 
429  if (num_active==0) {
430  MSQ_SETERR(err)("No active values in search",MsqError::INVALID_STATE);
431  return;
432  }
433 
434  switch(num_active) {
435  case 1:
438  break;
439  case 2:
440  /* if there are two active points, move in the direction of the
441  intersection of the planes. This is the steepest descent
442  direction found by analytically solving the QP */
443 
444  /* set up the active gradient directions */
445  this->get_active_directions(mGradient,&dir,err);
446  if (MSQ_CHKERR(err)) { free(dir); return; }
447 
448  /* form the grammian */
449  this->form_grammian(dir,err);
450  if (MSQ_CHKERR(err)) { free(dir); return; }
451  this->form_PD_grammian(err);
452  if (MSQ_CHKERR(err)) { free(dir); return; }
453 
454  denom = (mG[0][0] + mG[1][1] - 2*mG[0][1]);
455  viable = 1;
456  if (fabs(denom) > MSQ_MACHINE_EPS) {
457  /* gradients are LI, move along their intersection */
458  b = (mG[0][0] - mG[0][1])/denom;
459  a = 1 - b;
460  if ((b < 0) || (b > 1)) viable=0; /* 0 < b < 1 */
461  if (viable) {
462  for (i=0;i<mDimension;i++) {
463  mSearch[i] = a*dir[0][i] + b*dir[1][i];
464  }
465  } else {
466  /* the gradients are dependent, move along one face */
468  }
469  } else {
470  /* the gradients are dependent, move along one face */
472  }
474 
475  for (i=0;i<num_active;i++) free(dir[i]);
476  free(dir);
477 
478  break;
479  default:
480  /* as in case 2: solve the QP problem to find the steepest
481  descent direction. This can be done analytically - as
482  is done in Gill, Murray and Wright
483  for 3 active points in 3 directions - test PD of G
484  otherwise we know it's SP SD so search edges and faces */
485 
486  /* get the active gradient directions */
487  this->get_active_directions(mGradient,&dir,err); MSQ_ERRRTN(err);
488 
489  /* form the entries of the grammian matrix */
490  this->form_grammian(dir,err);
491  if (MSQ_CHKERR(err)) { free(dir); return; }
492  this->form_PD_grammian(err);
493  if (MSQ_CHKERR(err)) { free(dir); return; }
494 
495  switch(mDimension) {
496  case 2:
497  this->search_edges_faces(dir,err);
498  if (MSQ_CHKERR(err)) { free(dir); return; }
499  break;
500  case 3:
501  if (num_active == 3) {
502  this->singular_test(num_active,mG,&singular,err);
503  if (MSQ_CHKERR(err)) { free(dir); return; }
504  if (!singular) {
505  /* form the entries of P=Z^T G Z where Z = [-1...-1; I ] */
506  this->form_reduced_matrix(&P,err);
507  if (MSQ_CHKERR(err)) { free(dir); return; }
508  /* form the RHS and solve the system for the coeffs */
509  R0 = mG[0][0] - mG[1][0]; R1 = mG[0][0] - mG[2][0];
510  this->solve2x2(P[0][0],P[0][1],P[1][0],P[1][1],R0,R1,&x,err);
511  if (MSQ_CHKERR(err)) { free(dir); return; }
512  if (x!=NULL) {
513  a = 1 - x[0] - x[1]; b = x[0]; c = x[1];
514  for (i=0;i<mDimension;i++) {
515  mSearch[i] = a*dir[0][i] + b*dir[1][i] +
516  c*dir[2][i];
517  }
519  for (i=0;i<num_active-1;i++) free(P[i]);
520  free(P); free(x);
521  } else {
522  this->search_edges_faces(dir, err);
523  if (MSQ_CHKERR(err)) { free(dir); return; }
524  }
525  } else {
526  this->search_edges_faces(dir, err);
527  if (MSQ_CHKERR(err)) { free(dir); return; }
528  }
529  } else {
530  this->search_edges_faces(dir, err);
531  if (MSQ_CHKERR(err)) { free(dir); return; }
532  }
533  break;
534  }
535  for (i=0;i<num_active;i++) free(dir[i]);
536  free(dir);
537  }
538 
539  /* if the search direction is essentially zero, equilibrium pt */
540  MSQ_DOT(search_mag,mSearch,mSearch,mDimension);
541  MSQ_PRINT(3)(" Search Magnitude %g \n",search_mag);
542 
543  if (fabs(search_mag)<1E-13) optStatus = MSQ_ZERO_SEARCH;
545  MSQ_PRINT(3)(" Search Direction %g %g Steepest %d\n",mSearch[0],mSearch[1],mSteepest);
546 }
547 
549 {
550 // int valid;
551  MSQ_FUNCTION_TIMER( "Minmax Opt" );
552  MSQ_PRINT(2)("In minmax_opt\n");
553 
556 
557  iterCount = 0;
558  optIterCount = 0;
559 
560  MSQ_PRINT(3)("Done copying original function to function\n");
561 
562  this->find_active_set(mFunction, mActive, err); MSQ_ERRRTN(err);
564 
565  /* check for equilibrium point */
566  /* compute the gradient */
567  mGradient = this->compute_gradient(&pd, err); MSQ_ERRRTN(err);
568 
569  if (mActive->num_active >= 2) {
570  MSQ_PRINT(3)("Testing for an equilibrium point \n");
572 
573  if (MSQ_DBG(2) && equilibriumPt )
574  MSQ_PRINT(2)("Optimization Exiting: An equilibrium point \n");
575  }
576 
577  /* terminate if we have found an equilibrium point or if the step is
578  too small to be worthwhile continuing */
579  while ((optStatus != MSQ_EQUILIBRIUM) &&
582  (optStatus != MSQ_FLAT_NO_IMP) &&
583  (optStatus != MSQ_ZERO_SEARCH) &&
585 
586  /* increase the iteration count by one */
587  /* smooth_param->iter_count += 1; */
588  iterCount += 1;
589  optIterCount += 1;
591 
592  MSQ_PRINT(3)("\nITERATION %d \n",iterCount);
593 
594  /* compute the gradient */
595  mGradient = this->compute_gradient(&pd, err); MSQ_ERRRTN(err);
596 
597  MSQ_PRINT(3)("Computing the search direction \n");
598  this->search_direction(pd, err); MSQ_ERRRTN(err);
599 
600  /* if there are viable directions to search */
601  if ((optStatus != MSQ_ZERO_SEARCH) &&
603 
604  MSQ_PRINT(3)("Computing the projections of the gradients \n");
605  this->get_gradient_projections(err); MSQ_ERRRTN(err);
606 
607  MSQ_PRINT(3)("Computing the initial step size \n");
608  this->compute_alpha(err); MSQ_ERRRTN(err);
609 
610  MSQ_PRINT(3)("Testing whether to accept this step \n");
611  this->step_acceptance(pd, err); MSQ_ERRRTN(err);
612  MSQ_PRINT(3)("The new free vertex position is %f %f %f\n",
614 
615  if (MSQ_DBG(3)) {
616  /* Print the active set */
617  this->print_active_set(mActive, mFunction, err);
618  MSQ_ERRRTN(err);
619  }
620 
621  /* check for equilibrium point */
622  if (mActive->num_active >= 2) {
623  MSQ_PRINT(3)("Testing for an equilibrium point \n");
624  this->check_equilibrium(&equilibriumPt, &optStatus, err);
625  MSQ_ERRRTN(err);
626 
627  if (MSQ_DBG(2) && equilibriumPt)
628  MSQ_PRINT(2)("Optimization Exiting: An equilibrium point \n");
629  }
630 
631  /* record the values */
633 
634  } else {
635  /* decrease the iteration count by one */
636  /* smooth_param->iter_count -= 1; */
637  iterCount -= 1;
638  if (MSQ_DBG(2)) {
639  MSQ_PRINT(2)("Optimization Exiting: No viable directions; equilibrium point \n");
640  /* Print the old active set */
641  this->print_active_set(mActive,mFunction,err); MSQ_ERRRTN(err);
642  }
643  }
644  }
645 
646  MSQ_PRINT(2)("Checking the validity of the mesh\n");
647  if (!this->validity_check(err)) MSQ_PRINT(2)("The final mesh is not valid\n");
648  MSQ_ERRRTN(err);
649 
650  MSQ_PRINT(2)("Number of optimization iterations %d\n", iterCount);
651 
652  switch(optStatus) {
653  case MSQ_EQUILIBRIUM:
654  MSQ_PRINT(2)("Optimization Termination OptStatus: Equilibrium\n"); break;
655  case MSQ_STEP_TOO_SMALL:
656  MSQ_PRINT(2)("Optimization Termination OptStatus: Step Too Small\n"); break;
657  case MSQ_IMP_TOO_SMALL:
658  MSQ_PRINT(2)("Optimization Termination OptStatus: Improvement Too Small\n"); break;
659  case MSQ_FLAT_NO_IMP:
660  MSQ_PRINT(2)("Optimization Termination OptStatus: Flat No Improvement\n"); break;
661  case MSQ_ZERO_SEARCH:
662  MSQ_PRINT(2)("Optimization Termination OptStatus: Zero Search\n"); break;
664  MSQ_PRINT(2)("Optimization Termination OptStatus: Max Iter Exceeded\n"); break;
665  }
666 }
667 
668 
670 {
671 // int ierr;
672  int i;
673  int num_values, num_steps;
674  int valid = 1, step_status;
675  int accept_alpha;
676  double estimated_improvement;
677  double current_improvement = 1E300;
678  double previous_improvement = 1E300;
679  double current_percent_diff = 1E300;
680  double original_point[3];
681 
682 // MSQ_FUNCTION_TIMER( "Step Acceptance" );
683  num_values = numFunctionValues;
684 
685  step_status = MSQ_STEP_NOT_DONE;
686  optStatus = 0;
687  num_steps = 0;
688 
689  if (mAlpha < minStepSize) {
691  step_status = MSQ_STEP_DONE;
692  MSQ_PRINT(3)("Alpha starts too small, no improvement\n");
693  }
694 
695  /* save the original function and active set */
698  this->copy_active(mActive, originalActive, err); MSQ_ERRRTN(err);
699 
700  while (step_status == MSQ_STEP_NOT_DONE) {
701 
702  num_steps++; if (num_steps >= 100) step_status = MSQ_STEP_DONE;
703 
704  accept_alpha = MSQ_FALSE;
705 
706  while (!accept_alpha && mAlpha>minStepSize) {
707 
708  /* make the step */
709  for (i=0;i<mDimension;i++) {
711  }
712  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
713 
714  MSQ_PRINT(2)("search direction %f %f \n",mSearch[0],mSearch[1]);
715  MSQ_PRINT(2)("new vertex position %f %f \n",mCoords[freeVertexIndex][0],mCoords[freeVertexIndex][1]);
716 
717  /* assume alpha is acceptable */
718  accept_alpha=MSQ_TRUE;
719 
720  /* never take a step that makes a valid mesh invalid or worsens the quality */
721  // TODO Validity check revision -- do the compute function up here
722  // and then the rest based on validity
723  valid = validity_check(err); MSQ_ERRRTN(err);
724  if (valid) valid=improvement_check(err); MSQ_ERRRTN(err);
725  if (!valid) {
726  accept_alpha=MSQ_FALSE;
727  for (i=0;i<mDimension;i++) {
729  }
730  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
731  mAlpha = mAlpha/2;
732  MSQ_PRINT(2)("Step not accepted, the new alpha %f\n",mAlpha);
733 
734  if (mAlpha < minStepSize) {
736  step_status = MSQ_STEP_DONE;
737  MSQ_PRINT(2)("Step too small\n");
738  /* get back the original point, mFunction, and active set */
739  MSQ_COPY_VECTOR(mCoords[freeVertexIndex],original_point,mDimension);
740  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
742  this->copy_active(originalActive, mActive, err);
743  }
744  }
745  }
746 
747  if (valid && (mAlpha > minStepSize)) {
748  /* compute the new function and active set */
749  this->compute_function(&pd, mFunction, err); MSQ_ERRRTN(err);
750  this->find_active_set(mFunction, mActive, err); MSQ_ERRRTN(err);
751 
752  /* estimate the minimum improvement by taking this step */
753  this->get_min_estimate(&estimated_improvement, err); MSQ_ERRRTN(err);
754  MSQ_PRINT(2)("The estimated improvement for this step: %f\n",
755  estimated_improvement);
756 
757  /* calculate the actual increase */
758  current_improvement = mActive->true_active_value - prevActiveValues[iterCount-1];
759 
760  MSQ_PRINT(3)("Actual improvement %f\n",current_improvement);
761 
762  /* calculate the percent difference from estimated increase */
763  current_percent_diff = fabs(current_improvement-estimated_improvement)/
764  fabs(estimated_improvement);
765 
766  /* determine whether to accept a step */
767  if ((fabs(previous_improvement) > fabs(current_improvement)) &&
768  (previous_improvement < 0)) {
769  /* accept the previous step - it was better */
770  MSQ_PRINT(2)("Accepting the previous step\n");
771 
772  /* subtract alpha in again (previous step) */
773  for (i=0;i<mDimension;i++) {
775  }
776  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
777 
778  /* does this make an invalid mesh valid? */
779  //TODO Validity check revisison
780  valid = 1;
781  valid = validity_check(err); MSQ_ERRRTN(err);
782  if (valid) valid=improvement_check(err); MSQ_ERRRTN(err);
783 
784  /* copy test function and active set */
786  this->copy_active(testActive, mActive, err); MSQ_ERRRTN(err);
787 
788  optStatus = MSQ_STEP_ACCEPTED; step_status = MSQ_STEP_DONE;
789 
790  /* check to see that we're still making good improvements */
791  if (fabs(previous_improvement) < minAcceptableImprovement) {
792  optStatus = MSQ_IMP_TOO_SMALL; step_status = MSQ_STEP_DONE;
793  MSQ_PRINT(2)("Optimization Exiting: Improvement too small\n");
794  }
795 
796  } else if (((fabs(current_improvement) > fabs(estimated_improvement)) ||
797  (current_percent_diff < .1)) && (current_improvement<0)) {
798  /* accept this step, exceeded estimated increase or was close */
799  optStatus = MSQ_STEP_ACCEPTED; step_status = MSQ_STEP_DONE;
800 
801  /* check to see that we're still making good improvements */
802  if (fabs(current_improvement) < minAcceptableImprovement) {
803  MSQ_PRINT(2)("Optimization Exiting: Improvement too small\n");
804  optStatus = MSQ_IMP_TOO_SMALL; step_status = MSQ_STEP_DONE;
805  }
806 
807  } else if ((current_improvement > 0) && (previous_improvement > 0) &&
808  (fabs(current_improvement) < minAcceptableImprovement) &&
809  (fabs(previous_improvement) < minAcceptableImprovement)) {
810 
811  /* we are making no progress, quit */
812  optStatus = MSQ_FLAT_NO_IMP; step_status = MSQ_STEP_DONE;
813  MSQ_PRINT(2)("Opimization Exiting: Flat no improvement\n");
814 
815  /* get back the original point, function, and active set */
816  MSQ_COPY_VECTOR(mCoords[freeVertexIndex],original_point,mDimension);
817  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
819  this->copy_active(originalActive, mActive, err); MSQ_CHKERR(err);
820 
821  }
822  else
823  {
824  /* halve alpha and try again */
825  /* add out the old step */
826  for (i=0;i<mDimension;i++) mCoords[freeVertexIndex][i] += mAlpha*mSearch[i];
827  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
828 
829  /* halve step size */
830  mAlpha = mAlpha/2;
831  MSQ_PRINT(3)("Step not accepted, the new alpha %f\n",mAlpha);
832 
833  if (mAlpha < minStepSize)
834  {
835  /* get back the original point, function, and active set */
836  MSQ_PRINT(2)("Optimization Exiting: Step too small\n");
837  MSQ_COPY_VECTOR(mCoords[freeVertexIndex],original_point,mDimension);
838  //pd.set_coords_array_element(mCoords[freeVertexIndex],0,err);
840  this->copy_active(originalActive, mActive, err); MSQ_ERRRTN(err);
841  optStatus = MSQ_STEP_TOO_SMALL; step_status = MSQ_STEP_DONE;
842  }
843  else
844  {
846  this->copy_active(mActive, testActive, err); MSQ_ERRRTN(err);
847  previous_improvement = current_improvement;
848  }
849  }
850  }
851  }
852  if (current_improvement>0 && optStatus==MSQ_STEP_ACCEPTED) {
853  MSQ_PRINT(2)("Accepted a negative step %f \n",current_improvement);
854  }
855 
856 }
void find_plane_points(int dir1, int dir2, double **vec, int num_vec, double *pt1, double *pt2, double *pt3, int *opt_status, MsqError &err)
#define MSQ_DBG(flag)
Check if a debug flag is activated - evaluates to a bool.
size_t value()
Returns an index corresponding to a free vertex.
int space_dim() const
Returns the number of coordinates in the Mesh&#39;s geometric coordinate system.
virtual void set_patch_type(PatchData::PatchType patch_type, MsqError &err, int param1=0, int param2=0)
Sets the Patch Type.
Used to hold the error state and return it to the application.
void check_equilibrium(int *equil, int *opt_status, MsqError &err)
Vector_n max(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:354
double ** compute_gradient(PatchData *pd, MsqError &err)
void set_name(msq_std::string name)
provides a name to the QualityImprover (use it in constructor).
void get_vertex_indices(msq_std::vector< msq_stdc::size_t > &vertex_list) const
gets the vertices of the mesh entity
int num_free_vertices(MsqError &err) const
Returns the number of elements in the current patch who are free to move.
void singular_test(int n, double **A, int *singular, MsqError &err)
bool next()
Increments the iterator. returns false if there is no more free vertex.
size_t num_elements() const
number of elements in the Patch.
void get_active_directions(double **gradient, double ***dir, MsqError &err)
#define MSQ_CHKERR(err)
Mesquite&#39;s Error Checking macro.
#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)
void solve2x2(double a11, double a12, double a21, double a22, double b1, double b2, double **x, MsqError &err)
size_t num_vertices() const
number of vertices in the patch.
Vector_n min(const Array_n_const &v1, const Array_n_const &v2)
Definition: Vector_n.h:346
const MsqVertex * get_vertex_array(MsqError &err) const
Returns a pointer to the start of the vertex array.
void find_active_set(double *function, ActiveSet *active_set, MsqError &err)
#define MSQ_PRINT(flag)
Check debug flag and print printf-style formatted output.
object is in an invalid state
#define MSQ_DBGOUT(flag)
Check debug flag and return ostream associated with flag.
const MsqMeshEntity * get_element_array(MsqError &err) const
Returns a pointer to the start of the element array.
bool compute_function(PatchData *pd, double *function, MsqError &err)
iterates over indexes of free vetices in a PatchData.
#define MSQ_ERRRTN(err)
If passed error is true, return from a void function.
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)