Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QualityImprover/VertexMover/FeasibleNewton/FeasibleNewton.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 //
28 // AUTHOR: Thomas Leurent <tleurent@mcs.anl.gov>
29 // ORG: Argonne National Laboratory
30 // E-MAIL: tleurent@mcs.anl.gov
31 //
32 // ORIG-DATE: 15-Jan-03 at 08:05:56
33 // LAST-MOD: 15-Jun-04 at 15:45:00 by Thomas Leurent
34 //
35 // DESCRIPTION:
36 // ============
47 // DESCRIP-END.
48 //
49 
50 
51 #include "FeasibleNewton.hpp"
52 #include "MsqFreeVertexIndexIterator.hpp"
53 #include "MsqDebug.hpp"
54 
55 using namespace Mesquite;
56 
58  VertexMover()
59 {
60  coordsMem=NULL;
61  objFunc=of;
62  MsqError err;
63  convTol=1e-6;
64  this->set_name("FeasibleNewton");
67  default_crit->add_criterion_type_with_double(
69  MSQ_CHKERR(err);
70 }
71 
72 
74 {
75  // Cannot do anything. Variable sizes with maximum size dependent
76  // upon the entire MeshSet.
78 }
79 
81 {
82  pd.reorder();
83 }
84 
86  MsqError &err)
87 {
88  MSQ_FUNCTION_TIMER( "FeasibleNewton::optimize_vertex_positions" );
89  MSQ_DBGOUT(2) << "\no Performing Feasible Newton optimization.\n";
90 
91  const double sigma = 1e-4;
92  const double beta0 = 0.25;
93  const double beta1 = 0.80;
94  const double tol1 = 1e-8;
95  const double tol2 = 1e-12;
96  const double epsilon = 1e-10;
97  double original_value, new_value;
98  double beta;
99 
100  int nv = pd.num_vertices();
101  msq_std::vector<Vector3D> grad_vect(nv), d_vect(nv);
102  Vector3D* grad = &grad_vect[0];
103  Vector3D* d = &d_vect[0];
104  bool fn_bool=true;// bool used for determining validity of patch
105 
106  int i;
107 
108  // TODD -- Don't blame the code for bad things happening when using a
109  // bad termination test or requesting more accuracy than is
110  // possible.
111  //
112  // Also,
113 
114  // 1. Allocate a hessian and calculate the sparsity pattern.
115  mHessian.initialize(pd, err); MSQ_ERRRTN(err);
116 
117  // 3. Calculate the norm of the gradient for the patch
118  MSQ_DBGOUT(3) << " o gradient norm: " << length(grad, nv) << msq_stdio::endl;
119 
120  // does the Feasible Newton iteration until stopping is required.
121  // Terminate when inner termination criterion signals.
122 
123  /* Computes the value of the stopping criterion*/
125  while ( !term_crit->terminate() ) {
126  fn_bool = objFunc->compute_hessian( pd, mHessian, grad, original_value, err );
127  MSQ_ERRRTN(err);
128  if (!fn_bool) {
129  MSQ_SETERR(err)("invalid patch for hessian calculation", MsqError::INTERNAL_ERROR);
130  return;
131  }
132 
133  // Prints out free vertices coordinates.
134  if (MSQ_DBG(3)) {
135  MSQ_DBGOUT(3) << "\n o Free vertices ("<< pd.num_free_vertices(err)
136  <<")original coordinates:\n ";
137  MSQ_ERRRTN(err);
138  MsqVertex* toto1 = pd.get_vertex_array(err); MSQ_ERRRTN(err);
139  MsqFreeVertexIndexIterator ind1(&pd, err); MSQ_ERRRTN(err);
140  ind1.reset();
141  while (ind1.next()) {
142  MSQ_DBGOUT(3) << "\t\t\t" << toto1[ind1.value()];
143  }
144  }
145 
146  // 4. Calculate a direction using preconditionned conjugate gradients
147  // to find a zero of the Newton system of equations (H*d = -g)
148  // (a) stop if conjugate iteration limit reached
149  // (b) stop if relative residual is small
150  // (c) stop if direction of negative curvature is obtained
151 
152  mHessian.cg_solver(d, grad, err); MSQ_ERRRTN(err);
153 
154  // 5. Check for descent direction (inner produce of gradient and
155  // direction is negative.
156  double alpha = inner(grad, d, nv);
157  // TODD -- Add back in if you encounter problems -- do a gradient
158  // step if the direction from the conjugate gradient solver
159  // is not a descent direction for the objective function. We
160  // SHOULD always get a descent direction from the conjugate
161  // method though, unless the preconditioner is not positive
162  // definite.
163  // If direction is positive, does a gradient (steepest descent) step.
164 
165  if (alpha > -epsilon) {
166  MSQ_PRINT(1)("Newton direction not guaranteed descent. Ensure preconditioner is positive definite.\n");
167 
168  // TODD: removed performing gradient step here since we will use
169  // gradient if step does not produce descent. Instead we set
170  // alpha to a small negative value.
171 
172  alpha = -epsilon;
173 
174  // alpha = inner(grad, grad, nv); // compute norm squared of gradient
175  // if (alpha < 1) alpha = 1; // take max with constant
176  // for (i = 0; i < nv; ++i) {
177  // d[i] = -grad[i] / alpha; // compute scaled gradient
178  // }
179  // alpha = inner(grad, d, nv); // recompute alpha
180  // // equal to one for large gradient
181  }
182 
183  alpha *= sigma;
184  beta = 1.0;
186 
187  // TODD: Unrolling the linesearch loop. We do a function and
188  // gradient evaluation when beta = 1. Otherwise, we end up
189  // in the linesearch regime. We expect that several
190  // evaluations will be made, so we only do a function evaluation
191  // and finish with a gradient evaluation. When beta = 1, we also
192  // check the gradient for stability.
193 
194  // TODD -- the Armijo linesearch is based on the objective function,
195  // so theoretically we only need to evaluate the objective
196  // function. However, near a very accurate solution, say with
197  // the two norm of the gradient of the objective function less
198  // than 1e-5, the numerical error in the objective function
199  // calculation is enough that the Armijo linesearch will
200  // fail. To correct this situation, the iterate is accepted
201  // when the norm of the gradient is also small. If you need
202  // high accuracy and have a large mesh, talk with Todd about
203  // the numerical issues so that we can fix it.
204 
205  // TODD -- the Armijo linesearch here is only good for differentiable
206  // functions. When projections are involved, you should change
207  // to a form of the linesearch meant for nondifferentiable
208  // functions.
209 
210  pd.move_free_vertices_constrained(d, nv, beta, err); MSQ_ERRRTN(err);
211  fn_bool = objFunc->compute_gradient(pd, grad, new_value, err); MSQ_ERRRTN(err);
212  if ((fn_bool && (original_value - new_value >= -alpha*beta - epsilon)) ||
213  (fn_bool && (length(grad, nv) < 100*convTol))) {
214  // Armijo linesearch rules passed.
215  }
216  else {
217  if (!fn_bool) {
218  // Function undefined. Use the higher decrease rate.
219  beta *= beta0;
220  }
221  else {
222  // Function defined, but not sufficient decrease
223  // Use the lower decrease rate.
224  beta *= beta1;
225  }
227 
228  // Standard Armijo linesearch rules
229 
230  while (beta >= tol1) {
231  // 6. Search along the direction
232  // (a) trial = x + beta*d
233  pd.move_free_vertices_constrained(d, nv, beta, err); MSQ_ERRRTN(err);
234  // (b) function evaluation
235  fn_bool = objFunc->evaluate(pd, new_value, err); MSQ_ERRRTN(err);
236  // (c) check for sufficient decrease and stop
237  if (!fn_bool) {
238  // function not defined at trial point
239  beta *= beta0;
240  }
241  else if (original_value - new_value >= -alpha*beta - epsilon ) {
242  // iterate is acceptable.
243  break;
244  }
245  else {
246  // iterate is not acceptable -- shrink beta
247  beta *= beta1;
248  }
250  }
251 
252  if (beta < tol1) {
253  // assert(pd.set_to_vertices_memento called last)
254 
255  // TODD -- Lower limit on steplength reached. Direction does not
256  // appear to make sufficient progress decreasing the
257  // objective function. This can happen when you are
258  // very near a solution due to numerical errors in
259  // computing the objective function. It can also happen
260  // when the direction is not a descent direction and when
261  // you are projecting the iterates onto a surface.
262  //
263  // The latter cases require the use of a linesearch on
264  // a gradient step. If this linesearch terminate with
265  // insufficient decrease, then you are at a critical
266  // point and should stop!
267  //
268  // The numerical errors with the objective function cannot
269  // be overcome. Eventually, the gradient step will
270  // fail to compute a new direction and you will stop.
271 
272  MSQ_PRINT(1)("Sufficient decrease not obtained in linesearch; switching to gradient.\n");
273 
274  alpha = inner(grad, grad, nv); // compute norm squared of gradient
275  if (alpha < 1) alpha = 1; // take max with constant
276  for (i = 0; i < nv; ++i) {
277  d[i] = -grad[i] / alpha; // compute scaled gradient
278  }
279  alpha = inner(grad, d, nv); // recompute alpha
280  alpha *= sigma; // equal to one for large gradient
281  beta = 1.0;
282 
283  // Standard Armijo linesearch rules
284  while (beta >= tol2) {
285  // 6. Search along the direction
286  // (a) trial = x + beta*d
287  pd.move_free_vertices_constrained(d, nv, beta, err); MSQ_ERRRTN(err);
288  // (b) function evaluation
289  fn_bool = objFunc->evaluate(pd, new_value, err); MSQ_ERRRTN(err);
290  // (c) check for sufficient decrease and stop
291  if (!fn_bool) {
292  // function not defined at trial point
293  beta *= beta0;
294  }
295  else if (original_value - new_value >= -alpha*beta - epsilon ) {
296  // iterate is acceptable.
297  break;
298  }
299  else {
300  // iterate is not acceptable -- shrink beta
301  beta *= beta1;
302  }
304  }
305 
306  if (beta < tol2) {
307  // assert(pd.set_to_vertices_memento called last)
308 
309  // TODD -- Lower limit on steplength reached. Gradient does not
310  // appear to make sufficient progress decreasing the
311  // objective function. This can happen when you are
312  // very near a solution due to numerical errors in
313  // computing the objective function. Most likely you
314  // are at a critical point for the problem.
315 
316  MSQ_PRINT(1)("Sufficient decrease not obtained with gradient; critical point likely found.\n");
317  break;
318  }
319  }
320 
321  // Compute the gradient at the new point -- needed by termination check
322  fn_bool = objFunc->compute_gradient(pd, grad, new_value, err); MSQ_ERRRTN(err);
323  }
324 
325  // Prints out free vertices coordinates.
326  if (MSQ_DBG(3)) {
327  MSQ_DBGOUT(3) << " o Free vertices new coordinates: \n";
328  MsqVertex* toto1 = pd.get_vertex_array(err); MSQ_ERRRTN(err);
329  MsqFreeVertexIndexIterator ind(&pd, err); MSQ_ERRRTN(err);
330  ind.reset();
331  while (ind.next()) {
332  MSQ_DBGOUT(3) << "\t\t\t" << toto1[ind.value()];
333  }
334  }
335 
336  // checks stopping criterion
337  term_crit->accumulate_inner( pd, new_value, grad, err ); MSQ_ERRRTN(err);
338  term_crit->accumulate_patch( pd, err ); MSQ_ERRRTN(err);
339  }
340  MSQ_PRINT(2)("FINISHED\n");
341 }
342 
343 
345 {
346 
347  //Michael:: Should the vertices memento be delete here???
348  // cout << "- Executing FeasibleNewton::iteration_complete()\n";
349 }
350 
352 {
353  delete coordsMem; coordsMem = NULL;
354 }
355 
356 
#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.
bool compute_hessian(PatchData &patch, MsqHessian &hessian, Vector3D *const &grad, double &OF_val, MsqError &err)
Calls compute_analytical_hessian. Function returns &#39;false&#39; if the patch is not within a required feas...
virtual void set_patch_type(PatchData::PatchType patch_type, MsqError &err, int param1=0, int param2=0)
Sets the Patch Type.
PatchDataVerticesMemento * coordsMem
const NT & d
Used to hold the error state and return it to the application.
void accumulate_patch(PatchData &pd, MsqError &err)
Common code for both inner and outer termination criteria during inner iteration. ...
virtual void optimize_vertex_positions(PatchData &pd, MsqError &err)
void recreate_vertices_memento(PatchDataVerticesMemento *memento, MsqError &err, bool include_higher_order=false)
reinstantiates a memento to holds the current state of the PatchData coordinates. ...
bool evaluate(PatchData &patch, double &fval, MsqError &err)
The TerminationCriterion class contains functionality to terminate the VertexMover&#39;s optimization...
void set_name(msq_std::string name)
provides a name to the QualityImprover (use it in constructor).
Vector3D is the object that effeciently stores information about about three-deminsional vectors...
checks the gradient of objective function against a double and stops when
virtual void terminate_mesh_iteration(PatchData &pd, MsqError &err)
bool terminate()
Check if termination criterion has been met.
void set_to_vertices_memento(PatchDataVerticesMemento *memento, MsqError &err)
Restore the PatchData coordinates to the state contained in the memento.
int num_free_vertices(MsqError &err) const
Returns the number of elements in the current patch who are free to move.
bool next()
Increments the iterator. returns false if there is no more free vertex.
PatchDataVerticesMemento * create_vertices_memento(MsqError &err, bool include_higher_order=false)
Creates a memento that holds the current state of the PatchData coordinates.
double length(Vector3D *const v, int n)
#define MSQ_CHKERR(err)
Mesquite&#39;s Error Checking macro.
void cg_solver(Vector3D x[], Vector3D b[], MsqError &err)
bool compute_gradient(PatchData &patch, Vector3D *const &grad, double &OF_val, MsqError &err, size_t array_size=0)
Calls either compute_numerical_gradient or compute_analytical_gradient depending on the value of grad...
#define MSQ_SETERR(err)
Macro to set error - use err.clear() to clear.
blockLoc i
Definition: read.cpp:79
void add_criterion_type_with_double(TCType tc_type, double eps, MsqError &err)
Sets the criterion by specifing the TCType and the eps value.
size_t num_vertices() const
number of vertices in the patch.
void accumulate_inner(PatchData &pd, MsqError &err)
Accumulate data during inner iteration.
TerminationCriterion * get_inner_termination_criterion()
return the inner termination criterion pointer
void move_free_vertices_constrained(Vector3D dk[], size_t nb_vtx, double step_size, MsqError &err)
Moves free vertices and then snaps the free vertices to the domain.
const MsqVertex * get_vertex_array(MsqError &err) const
Returns a pointer to the start of the vertex array.
#define MSQ_PRINT(flag)
Check debug flag and print printf-style formatted output.
void reorder()
Reorders the mesh data.
void initialize(PatchData &pd, MsqError &err)
creates a sparse structure for a Hessian, based on the connectivity information contained in the Patc...
virtual void initialize_mesh_iteration(PatchData &pd, MsqError &err)
#define MSQ_DBGOUT(flag)
Check debug flag and return ostream associated with flag.
iterates over indexes of free vetices in a PatchData.
MsqVertex is the Mesquite object that stores information about the vertices in the mesh...
double inner(const Vector3D lhs[], const Vector3D rhs[], int n)
#define MSQ_ERRRTN(err)
If passed error is true, return from a void function.
Base class for concrete Objective Functions ObjectiveFunction contains a pointer to a QualityMetric...