Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QualityImprover/VertexMover/ConjugateGradient/ConjugateGradient.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  ***************************************************************** */
38 #include "ConjugateGradient.hpp"
39 #include <math.h>
40 #include "MsqDebug.hpp"
41 #include "MsqTimer.hpp"
42 #include "MsqFreeVertexIndexIterator.hpp"
43 
44 namespace Mesquite {
45 
47  MsqError &err) :
48  VertexMover(),
49  fGrad(NULL),
50  pGrad(NULL),
51  pMemento(NULL),
52  fNewGrad(NULL)
53 {
54  this->set_name("ConjugateGradient");
56  objFunc=objective;
57  //Michael:: default to global?
59  //set the default inner termination criterion
61  if(default_crit==NULL){
62  MSQ_SETERR(err)("QualityImprover did not create a default inner "
63  "termination criterion.", MsqError::INVALID_STATE);
64  return;
65  }
66  else{
68  MSQ_ERRRTN(err);
69  }
70 
71 }
72 
73 
75 {
76  // Checks that cleanup() has been called.
77  assert(fGrad==NULL);
78  assert(pGrad==NULL);
79  assert(pMemento==NULL);
80  assert(fNewGrad==NULL);
81 }
82 
84 {
85  MSQ_DBGOUT(2) << "\no Performing Conjugate Gradient optimization.\n";
86  arraySize=5;
87  fGrad = new Vector3D[ arraySize ];
88  pGrad = new Vector3D[ arraySize ];
89  fNewGrad = new Vector3D[ arraySize ];
90  //mCoord = new Vector3D[ arraySize ];
92 }
93 
94 
100  int patch_param1, int patch_param2)
101 {
103  PatchDataUser::set_patch_type(type, err, patch_param1, patch_param2);
104  } else {
105  MSQ_SETERR(err)("Type not supported by ConjugateGradient algorythm.",
107  }
108 }
109 
111  MsqError &/*err*/)
112 {
113 
114 }
115 
118  MsqError &err){
119  // pd.reorder();
120 
121  MSQ_FUNCTION_TIMER( "ConjugateGradient::optimize_vertex_positions" );
122 
123  Timer c_timer;
124  int num_vert=pd.num_vertices();
125  if(pd.num_free_vertices(err)<1){
126  MSQ_DBGOUT(1) << "\nEmpty free vertex list in ConjugateGradient\n";
127  return;
128  }
129 
130  if(num_vert>arraySize){
131  delete []fGrad;
132  delete []pGrad;
133  delete []fNewGrad;
134  //Increase number to try to avoid reallocating
135  arraySize=num_vert + 5;
136  fGrad = new Vector3D[ arraySize ];
137  pGrad = new Vector3D[ arraySize ];
138  fNewGrad = new Vector3D[ arraySize ];
139  }
140  //zero out arrays
141  int zero_loop=0;
142  while(zero_loop<arraySize){
143  fGrad[zero_loop].set(0,0,0);
144  pGrad[zero_loop].set(0,0,0);
145  fNewGrad[zero_loop].set(0,0,0);
146  ++zero_loop;
147  }
148 
149  // gets the array of vertices for the patch
150  MsqVertex* vertices=pd.get_vertex_array(err); MSQ_ERRRTN(err);
151  int ind;
152  //Michael cull list: possibly set soft_fixed flags here
153 
154  MsqFreeVertexIndexIterator free_iter(&pd, err); MSQ_ERRRTN(err);
155 
156 
157  double f=0;
158  //Michael, this isn't equivalent to CUBIT because we only want to check
159  //the objective function value of the 'bad' elements
160  //if invalid initial patch set an error.
161  bool temp_bool = objFunc->compute_gradient(pd, fGrad, f, err, num_vert);
162  if(MSQ_CHKERR(err))
163  return;
164  if( ! temp_bool){
165  MSQ_SETERR(err)("Conjugate Gradient not able to get valid gradient "
166  "and function values on intial patch.",
168  return;
169  }
170  double grad_norm=MSQ_MAX_CAP;
171 
172  if(conjGradDebug>0){
173  MSQ_PRINT(2)("\nCG's DEGUB LEVEL = %i \n",conjGradDebug);
174  grad_norm=Linf(fGrad,num_vert);
175  MSQ_PRINT(2)("\nCG's FIRST VALUE = %f,grad_norm = %f",f,grad_norm);
176  MSQ_PRINT(2)("\n TIME %f",c_timer.since_birth());
177  grad_norm=MSQ_MAX_CAP;
178  }
179 
180  ind=0;
181  //Initializing pGrad (search direction).
182  while(ind<num_vert){
183  pGrad[ind]=(-fGrad[ind]);
184  ++ind;
185  }
186  int j=0; // total nb of step size changes ... not used much
187  int i=0; // iteration counter
188  int m=0; //
189  double alp=MSQ_MAX_CAP; // alp: scale factor of search direction
190  //we know inner_criterion is false because it was checked in
191  //loop_over_mesh before being sent here.
193 
194  //while ((i<maxIteration && alp>stepBound && grad_norm>normGradientBound)
195  // && !inner_criterion){
196  while(!term_crit->terminate()){
197  ++i;
198  //std::cout<<"\Michael delete i = "<<i;
199  int k=0;
200  alp=get_step(pd,f,k,err);
201  j+=k;
202  if(conjGradDebug>2){
203  MSQ_PRINT(2)("\n Alp initial, alp = %20.18f",alp);
204  }
205 
206  // if alp == 0, revert to steepest descent search direction
207  if(alp==0){
208  free_iter.reset();
209  while (free_iter.next()) {
210  m=free_iter.value();
211  pGrad[m]=(-fGrad[m]);
212  }
213  alp=get_step(pd,f,k,err);
214  j+=k;
215  if(conjGradDebug>1){
216  MSQ_PRINT(2)("\n CG's search direction reset.");
217  if(conjGradDebug>2)
218  MSQ_PRINT(2)("\n Alp was zero, alp = %20.18f",alp);
219  }
220 
221  }
222  if(alp!=0){
223  free_iter.reset();
224  while (free_iter.next()) {
225  m=free_iter.value();
226  vertices[m] += (alp * pGrad[m]);
227  //Added move_to_ownever
228  pd.snap_vertex_to_domain(m,err);
229  }
230  if (! objFunc->compute_gradient(pd, fNewGrad, f, err, num_vert)){
231  MSQ_SETERR(err)("Error inside Conjugate Gradient, vertices moved "
232  "making function value invalid.",
234  return;
235  }
236 
237  if(conjGradDebug>0){
238  grad_norm=Linf(fNewGrad,num_vert);
239  MSQ_PRINT(2)("\nCG's VALUE = %f, iter. = %i, grad_norm = %f, alp = %f",f,i,grad_norm,alp);
240  MSQ_PRINT(2)("\n TIME %f",c_timer.since_birth());
241  }
242  double s11=0;
243  double s12=0;
244  double s22=0;
245  free_iter.reset();
246  while (free_iter.next()) {
247  m=free_iter.value();
248  s11+=fGrad[m]%fGrad[m];
249  s12+=fGrad[m]%fNewGrad[m];
250  s22+=fNewGrad[m]%fNewGrad[m];
251  }
252 
253  // Steepest Descent (takes 2-3 times as long as P-R)
254  //double bet=0;
255 
256  // Fletcher-Reeves (takes twice as long as P-R)
257  //double bet = s22/s11;
258 
259  // Polack-Ribiere
260  double bet = (s22-s12)/s11;
261  free_iter.reset();
262  while (free_iter.next()) {
263  m=free_iter.value();
264  pGrad[m]=(-fNewGrad[m]+(bet*pGrad[m]));
265  fGrad[m]=fNewGrad[m];
266  }
267  if(conjGradDebug>2){
268  MSQ_PRINT(2)(" \nSEARCH DIRECTION INFINITY NORM = %e",
269  Linf(fNewGrad,num_vert));
270  }
271 
272  }//end if on alp == 0
273  //Removing the following line of code (4/2/03) as it should not
274  //be needed with the new version of Termination Criterion.
275  //Update mesh before checking criterion
276  //pd.update_mesh(err);
277  term_crit->accumulate_inner( pd, f, fNewGrad, err ); MSQ_ERRRTN(err);
278  term_crit->accumulate_patch( pd, err ); MSQ_ERRRTN(err);
279  }//end while
280  if(conjGradDebug>0){
281  MSQ_PRINT(2)("\nConjugate Gradient complete i=%i ",i);
282  MSQ_PRINT(2)("\n- FINAL value = %f, alp=%4.2e grad_norm=%4.2e",f,alp,grad_norm);
283  MSQ_PRINT(2)("\n FINAL TIME %f",c_timer.since_birth());
284  }
285 }
286 
287 
289  MsqError &/*err*/)
290 {
291  // cout << "- Executing ConjugateGradient::iteration_complete()\n";
292 }
293 
294 
296 {
297  // cout << "- Executing ConjugateGradient::iteration_end()\n";
298  delete []fGrad; fGrad = NULL;
299  delete []pGrad; pGrad = NULL;
300  delete []fNewGrad; fNewGrad = NULL;
301  //pMemento->~PatchDataVerticesMemento();
302  delete pMemento;
303  pMemento = NULL;
304 }
305 
307 
314 double ConjugateGradient::get_step(PatchData &pd,double f0,int &j,
315  MsqError &err)
316 {
317  size_t num_vertices=pd.num_vertices();
318  //initial guess for alp
319  double alp=1.0;
320  int jmax=100;
321  double rho=0.5;
322  //feasible=false implies the mesh is not in the feasible region
323  bool feasible=false;
324  int found=0;
325  //f and fnew hold the objective function value
326  double f=0;
327  double fnew=0;
328  //Counter to avoid infinitly scaling alp
329  j=0;
330  //save memento
332  //if we must check feasiblility
333  //while step takes mesh into infeasible region and ...
334  while (j<jmax && !feasible && alp>MSQ_MIN) {
335  ++j;
336  pd.set_free_vertices_constrained(pMemento,pGrad,num_vertices,alp,err);
337  feasible=objFunc->evaluate(pd,f,err); MSQ_ERRZERO(err);
338  //if not feasible, try a smaller alp (take smaller step)
339  if(!feasible){
340  alp*=rho;
341  }
342  }//end while ...
343 
344  //if above while ended due to j>=jmax, no valid step was found.
345  if(j>=jmax){
346  MSQ_PRINT(2)("\nFeasible Point Not Found");
347  return 0.0;
348  }
349  //Message::print_info("\nOriginal f %f, first new f = %f, alp = %f",f0,f,alp);
350  //if new f is larger than original, our step was too large
351  if(f>=f0){
352  j=0;
353  while (j<jmax && found == 0){
354  ++j;
355  alp *= rho;
356  pd.set_free_vertices_constrained(pMemento,pGrad,num_vertices,alp,err);
357  //Get new obj value
358  //if patch is now invalid, then the feasible region is convex or
359  //we have an error. For now, we assume an error.
360  if(! objFunc->evaluate(pd,f,err) ){
361  MSQ_SETERR(err)("Non-convex feasiblility region found.",MsqError::INVALID_MESH);
362  }
364  //if our step has now improved the objective function value
365  if(f<f0){
366  found=1;
367  }
368  }// end while j less than jmax
369  //Message::print_info("\nj = %d found = %d f = %20.18f f0 = %20.18f\n",j,found,f,f0);
370  //if above ended because of j>=jmax, take no step
371  if(found==0){
372  //Message::print_info("alp = %10.8f, but returning zero\n",alp);
373  alp=0.0;
374  return alp;
375  }
376 
377  j=0;
378  //while shrinking the step improves the objFunc value further,
379  //scale alp down. Return alp, when scaling once more would
380  //no longer improve the objFunc value.
381  while(j<jmax){
382  ++j;
383  alp*=rho;
384  //step alp in search direction from original positions
385  pd.set_free_vertices_constrained(pMemento,pGrad,num_vertices,alp,err);MSQ_ERRZERO(err);
386 
387  //get new objective function value
388  if (! objFunc->evaluate(pd,fnew,err))
389  MSQ_SETERR(err)("Non-convex feasiblility region found while "
390  "computing new f.",MsqError::INVALID_MESH);
391  if(fnew<f){
392  f=fnew;
393  }
394  else{
395  //Reset the vertices to original position
397  alp/=rho;
398  return alp;
399  }
400  }
401  //Reset the vertices to original position and return alp
403  return alp;
404  }
405  //else our new f was already smaller than our original
406  else{
407  j=0;
408  //check to see how large of step we can take
409  while (j<jmax && found == 0) {
410  ++j;
411  //scale alp up (rho must be less than 1)
412  alp /= rho;
413  //step alp in search direction from original positions
414  pd.set_free_vertices_constrained(pMemento,pGrad,num_vertices,alp,err);MSQ_ERRZERO(err);
415 
416  feasible = objFunc->evaluate(pd,fnew, err);MSQ_ERRZERO(err);
417  if ( ! feasible ){
418  alp *= rho;
419 
420  //Reset the vertices to original position and return alp
422  return alp;
423  }
424  if (fnew<f) {
425  f = fnew;
426  }
427  else {
428  found=1;
429  alp *= rho;
430  }
431  }
432 
433  //Reset the vertices to original position and return alp
435  return alp;
436  }
437 }
438 
440 /*
441 double ConjugateGradient::get_step(PatchData &pd,double f0,int &j,
442  MsqError &err){
443  const double CGOLD = 0.3819660;
444  const double ZEPS = 1.0e-10;
445  int n=pd.num_free_vertices();
446  MsqVertex* vertices=pd.get_vertex_array(err);
447  double a,b,d,etemp,fb,fu,fv,fw,fx,p,q,r,tol,tol1,tol2,u,v,w,x,xm;
448  double e=0.0;
449  d=0.0;
450  tol=.001;
451  int iter, maxiter;
452  maxiter=100;
453  a=0;
454  b=.125;
455  int m=0;
456  fb=f0-1.0;
457  iter=0;
458  //find b such that a b 'should' bracket the min
459  while (fb<=f0 && iter<maxiter){
460  ++iter;
461  b*=2.0;
462  for(m=0;m<n;++m){
463  mCoord[m]=mCoord[m] + (b*pGrad[m]);
464  vertices[m]=(mCoord[m]);
465  }
466  fb=objFunc->evaluate(pd,err);
467  }
468  iter=0;
469  x=w=v=(b/2.0);
470  for(m=0;m<n;++m){
471  mCoord[m]=mCoord[m] + (x*pGrad[m]);
472  vertices[m]=(mCoord[m]);
473  }
474  fw=fv=fx=objFunc->evaluate(pd,err);
475  for(iter=0;iter<maxiter;++iter){
476  //Message::print_info("a=%f,b=%f,x=%f,iter=%i\n",a,b,x,iter);
477  xm=(a+b)*.5;
478  tol2=2.0*(tol1=tol*fabs(x)+ZEPS);
479  if(fabs(x-xm)<= (tol2-0.5*(b-a))){
480  return x;
481  }
482  if(fabs(e)>tol1){
483  r=(x-w)*(fx-fv);
484  q=(x-v)*(fx-fw);
485  p=(x-v)*q-(x-w)*r;
486  q=2.0*(q-r);
487  if(q>0.0)
488  p=-p;
489  q=fabs(q);
490  etemp=e;
491  e=d;
492  if(fabs(p)>=fabs(0.5*q*etemp)||(p<=q*(a-x))||(p>=q*(b-x))){
493  d=CGOLD*(e=(x>=xm?a-x:b-x));
494  }
495  else{
496  d=p/q;
497  u=x+d;
498  if(u-a<tol2||b-u<tol2)
499  {
500  if(tol1<0.0)
501  d=x-xm;
502  else
503  d=xm-x;
504  }
505  }
506  }
507 
508  else{
509  d=CGOLD*(e=(x>=xm?a-x:b-x));
510  }
511  if(tol<0.0)
512  u=(fabs(d)>=tol1?x+d:x-d);
513  else
514  u=(fabs(d)>=tol1?x+d:x+d);
515  for(m=0;m<n;++m){
516  mCoord[m]=mCoord[m] + (u*pGrad[m]);
517  vertices[m]=(mCoord[m]);
518  }
519  fu=objFunc->evaluate(pd,err);
520  if(fu<fx){
521  if(u>=x)
522  a=x;
523  else
524  b=x;
525  v=w;
526  w=x;
527  x=u;
528  fv=fw;
529  fw=fx;
530  fx=fu;
531  }
532  else{
533  if(u<x)
534  a=u;
535  else
536  b=u;
537  if(fu<=fw||w==x){
538  v=w;
539  w=u;
540  fv=fw;
541  fw=fu;
542  }
543  else if (fu<=fv||v==x||v==w){
544  v=u;
545  fv=fu;
546  }
547  }
548  }
549  for(m=0;m<n;++m){
550  vertices[m]=(mCoord[m]);
551  }
552  //PRINT_WARNING("TOO MANY ITERATIONS IN QUADRATIC LINE SEARCH");
553  return x;
554 }
555 */
556 
557 } //namespace Mesquite
558 
559 
560 
561 
void set_debugging_level(int new_lev)
Just for debugging purposes or for obtaining more data during the optimization process.
#define MSQ_ERRZERO(err)
Return zero/NULL on error.
size_t value()
Returns an index corresponding to a free vertex.
const double MSQ_MAX_CAP
Definition: Mesquite.hpp:173
virtual void set_patch_type(PatchData::PatchType patch_type, MsqError &err, int param1=0, int param2=0)
Sets the Patch Type.
j indices k indices k
Definition: Indexing.h:6
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. ...
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...
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 since_birth() const
double get_step(PatchData &pd, double f0, int &j, MsqError &err)
Returns the step distance to take in the search direction.
invalid function argument passed
#define MSQ_CHKERR(err)
Mesquite&#39;s Error Checking macro.
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 snap_vertex_to_domain(size_t vertex_index, MsqError &err)
Adjust the position of the specified vertex so that it lies on its constraining domain.
virtual void set_patch_type(PatchData::PatchType type, MsqError &err, int patch_param1=0, int patch_param2=0)
Set the patch type.
virtual void cleanup()
Delete arrays initially created in initialize().
PatchType
Tells MeshSet how to retrieve the mesh entities that will be stored in PatchData. ...
Vector3D * fGrad
Culls the vertex list free_vertex_list.
double Linf(Vector3D *const v, int n)
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
const MsqVertex * get_vertex_array(MsqError &err) const
Returns a pointer to the start of the vertex array.
void set_free_vertices_constrained(PatchDataVerticesMemento *memento, Vector3D dk[], size_t nb_vtx, double step_size, MsqError &err)
Terminates when the number of iterations exceeds a given integer.
virtual void initialize(PatchData &pd, MsqError &err)
Initialize data for smoothing process.
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 set(const double x, const double y, const double z)
void add_criterion_type_with_int(TCType tc_type, int bound, MsqError &err)
Sets the criterion by specifing the TCType and the integer value.
#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...
#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...
const double MSQ_MIN
Definition: Mesquite.hpp:160