Rocstar  1.0
Rocstar multiphysics simulation application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ObjectiveFunction/LPtoPTemplate.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  ***************************************************************** */
37 #include <math.h>
38 #include "LPtoPTemplate.hpp"
39 #include "MsqFreeVertexIndexIterator.hpp"
40 #include "MsqTimer.hpp"
41 #include "MsqHessian.hpp"
42 #include "MsqDebug.hpp"
43 
44 using namespace Mesquite;
45 
46 LPtoPTemplate::LPtoPTemplate(QualityMetric *qualitymetric, short Pinput, MsqError &err){
47  set_quality_metric(qualitymetric);
48  pVal=Pinput;
49  if(pVal<1){
50  MSQ_SETERR(err)("P_VALUE must be greater than 0.", MsqError::INVALID_ARG);
51  return;
52  }
54  //set_use_local_gradient(true);
55  set_negate_flag(qualitymetric->get_negate_flag());
56  dividingByN=false;
57 }
58 
59 //Michael: need to clean up here
61 
62 }
63 
65  MsqError &err){
66  size_t index=0;
67  MsqMeshEntity* elems=pd.get_element_array(err);
68  bool obj_bool=true;
69  //double check for pVal=0;
70  if(pVal==0){
71  MSQ_SETERR(err)("pVal equal zero not allowed. L_0 is not a valid norm.",
73  return false;
74  }
75 
76  //Michael: this may not do what we want
77  //Set currentQM to be the first quality metric* in the list
78  QualityMetric* currentQM = get_quality_metric();
79  if(currentQM==NULL)
80  currentQM=get_quality_metric_list().front();
81  if(currentQM==NULL) {
82  MSQ_SETERR(err)("NULL QualityMetric pointer in LPtoPTemplate",
84  return false;
85  }
86  size_t num_elements=pd.num_elements();
87  size_t num_vertices=pd.num_vertices();
88  size_t total_num=0;
90  total_num=num_elements;
91  else if (currentQM->get_metric_type()==QualityMetric::VERTEX_BASED)
92  total_num=num_vertices;
93  else {
94  MSQ_SETERR(err)("Make sure MetricType is initialised in concrete "
95  "QualityMetric constructor.", MsqError::INVALID_STATE);
96  return false;
97  }
98 
99  msq_std::vector<double> metric_values(total_num);
101  {
102  for (index=0; index<num_elements;index++)
103  {
104  //if invalid return false after clean-up
105  obj_bool=currentQM->evaluate_element(pd, (&elems[index]),
106  metric_values[index], err);
107  if(MSQ_CHKERR(err) || !obj_bool){
108  fval=0.0;
109  return false;
110  }
111 
112  metric_values[index]=fabs(metric_values[index]);
113  MSQ_DBGOUT(3) << " o Quality metric value for element "
114  << index << "\t: " << metric_values[index] << "\n";
115  }
116  }
117  else if(currentQM->get_metric_type()==QualityMetric::VERTEX_BASED)
118  {
119  MsqVertex* vertices=pd.get_vertex_array(err); MSQ_ERRZERO(err);
120  for (index=0; index<num_vertices;index++)
121  {
122  //evaluate metric for this vertex
123  obj_bool=currentQM->evaluate_vertex(pd, (&vertices[index]),
124  metric_values[index], err);
125  //if invalid return false after clean-up
126  if(MSQ_CHKERR(err) || !obj_bool){
127  fval=0.0;
128  return false;
129  }
130 
131  metric_values[index]=fabs(metric_values[index]);
132  }
133  }
134  fval=compute_function(&metric_values[0], total_num, err);
135  return !MSQ_CHKERR(err);
136 }
137 
138 /* virtual function reimplemented from QualityMetric. No doxygen doc needed. */
140  Vector3D *const &grad,
141  double &OF_val,
142  MsqError &err, size_t array_size)
143 {
144  MSQ_FUNCTION_TIMER( "LPtoPTemplate::compute_analytical_gradient" );
145 
146  //initialize the scaling value
147  double scaling_value=1.0;
148 
149  size_t num_elements=pd.num_elements();
150  size_t num_vertices=pd.num_vertices();
151  if( num_vertices!=array_size && array_size>0)
152  {
153  MSQ_SETERR(err)("Incorrect array size.", MsqError::INVALID_ARG);
154  return false;
155  }
156 
157  MsqMeshEntity* elems=pd.get_element_array(err); MSQ_ERRZERO(err);
158  MsqVertex* vertices=pd.get_vertex_array(err); MSQ_ERRZERO(err);
159  bool qm_bool=true;
160  double QM_val;
161  OF_val = 0.;
162  size_t i;
163  int p1;
164 
165  //Set currentQM to be quality metric (possibly composite) associated with the objective function
166  QualityMetric* currentQM = get_quality_metric();
167  if(currentQM==NULL) {
168  MSQ_SETERR(err)("LPtoPTemplate has NULL QualityMetric pointer.",MsqError::INVALID_STATE);
169  return false;
170  }
171  enum QualityMetric::MetricType qm_type=currentQM->get_metric_type();
172 
173  if (qm_type!=QualityMetric::ELEMENT_BASED &&
174  qm_type!=QualityMetric::VERTEX_BASED) {
175  MSQ_SETERR(err)("Make sure MetricType is initialised"
176  "in concrete QualityMetric constructor.",
178  return false;
179  }
180 
181 
182  // zeros out objective function gradient
183  for (i=0; i<num_vertices; ++i)
184  grad[i] =0;
185 
186  // Computes objective function gradient for an element based metric
187  if(qm_type==QualityMetric::ELEMENT_BASED){
188  //if scaling, divid by num_elements
189  if(dividingByN){
190  if(num_elements<=0) {
191  MSQ_SETERR(err)("The number of elements should not be zero.",MsqError::INVALID_MESH);
192  return false;
193  }
194 
195  scaling_value/=num_elements;
196  }
197  size_t e, ve;
198  size_t nfve; // num free vtx in element
199  size_t nve; // num vtx in element
200  MsqVertex* ele_free_vtces[MSQ_MAX_NUM_VERT_PER_ENT];
201  const size_t *ele_vtces_ind;
202 
203  // loops over all elements.
204  for (e=0; e<num_elements; ++e) {
205  // stores the pointers to the free vertices within the element
206  // (using pointer arithmetic).
207  nfve = 0;
208  nve = elems[e].vertex_count();
209  ele_vtces_ind = elems[e].get_vertex_index_array();
210  for (ve=0; ve<nve; ++ve) {
211  if (vertices[ele_vtces_ind[ve]].is_free_vertex()) {
212  ele_free_vtces[nfve] = vertices + ele_vtces_ind[ve];
213  ++nfve;
214  }
215  }
216 
217  // Computes q and grad(q)
219  qm_bool = currentQM->compute_element_gradient(
220  pd, &elems[e],
221  ele_free_vtces,
222  grad_vec, nfve, QM_val, err);
223  if(MSQ_CHKERR(err) || !qm_bool) return false;
224 
225  // computes p*|Q(e)|^{p-1}
226  QM_val = fabs(QM_val);
227  double QM_pow=1.0;
228  double factor;
229  if (pVal==1) factor=1;
230  else {
231  QM_pow=QM_val;
232  for (p1=1; p1<pVal-1; ++p1)
233  QM_pow*=QM_val;
234  factor = QM_pow * pVal;
235  }
236  //this scales the gradient
237  factor *= (scaling_value * get_negate_flag());
238 
239  // computes Objective Function value \sum_{i=1}^{N_e} |q_i|^P
240  // possibly scaled by 1/num.
241  OF_val += (scaling_value * QM_pow * QM_val);
242 
243  // For each free vertex in the element ...
244  for (i=0; i<nfve; ++i) {
245  // ... computes p*q^{p-1}*grad(q) ...
246  grad_vec[i] *= factor;
247  // ... and accumulates it in the objective function gradient.
248  grad[pd.get_vertex_index(ele_free_vtces[i])] += grad_vec[i];
249  }
250  }
251  }
252 
253  // Computes objective function gradient for a vertex based metric
254  else if (qm_type==QualityMetric::VERTEX_BASED){
255  //if scaling, divide by the number of vertices
256  if(dividingByN){
257  if(num_elements<=0) {
258  MSQ_SETERR(err)("The number of vertices should not be zero.",MsqError::INVALID_MESH);
259  return false;
260  }
261 
262  scaling_value/=num_vertices;
263  }
264  //vector for storing indices of vertex's connected elems
265  msq_std::vector<size_t> vert_on_vert_ind;
266  //position in pd's vertex array
267  size_t vert_count=0;
268  //position in vertex array
269  size_t vert_pos=0;
270  //loop over the free vertex indices to find the gradient...
271  size_t vfv_array_length=10;//holds the current legth of vert_free_vtces
272  msq_std::vector<MsqVertex*> vert_free_vtces(vfv_array_length);
273  msq_std::vector<Vector3D> grad_vec(vfv_array_length);
274  for(vert_count=0; vert_count<num_vertices; ++vert_count){
275  //For now we compute the metric for attached vertices and this
276  //vertex, the above line gives us the attached vertices. Now,
277  //we must add this vertex.
278  pd.get_adjacent_vertex_indices(vert_count,
279  vert_on_vert_ind,err);
280  vert_on_vert_ind.push_back(vert_count);
281  size_t vert_num_vtces = vert_on_vert_ind.size();
282 
283  // dynamic memory management if arrays are too small.
284  if(vert_num_vtces > vfv_array_length){
285  vfv_array_length=vert_num_vtces+5;
286  vert_free_vtces.resize(vfv_array_length);
287  grad_vec.resize(vfv_array_length);
288  }
289 
290  size_t vert_num_free_vtces=0;
291  //loop over the vertices connected to this one (vert_count)
292  //and put the free ones into vert_free_vtces
293  while(!vert_on_vert_ind.empty()){
294  vert_pos=(vert_on_vert_ind.back());
295  //clear the vector as we go
296  vert_on_vert_ind.pop_back();
297  //if the vertex is free, add it to ver_free_vtces
298  if(vertices[vert_pos].is_free_vertex()){
299  vert_free_vtces[vert_num_free_vtces]=&vertices[vert_pos];
300  ++vert_num_free_vtces ;
301  }
302  }
303 
304  qm_bool=currentQM->compute_vertex_gradient(pd,
305  vertices[vert_count],
306  &vert_free_vtces[0],
307  &grad_vec[0],
308  vert_num_free_vtces,
309  QM_val, err);
310  if(MSQ_CHKERR(err) || !qm_bool){
311  return false;
312  }
313  // computes p*|Q(e)|^{p-1}
314  QM_val = fabs(QM_val);
315  double QM_pow = 1.0;
316  double factor;
317  if (pVal==1) factor=1;
318  else {
319  QM_pow=QM_val;
320  for (p1=1; p1<pVal-1; ++p1)
321  QM_pow*=QM_val;
322  factor = QM_pow * pVal;
323  }
324  //this scales the gradient
325  factor *= (scaling_value * get_negate_flag());
326 
327  // computes Objective Function value \sum_{i=1}^{N_v} |q_i|^P
328  // possibly scaled by 1/num
329  OF_val += (scaling_value * QM_pow * QM_val);
330  // For each free vertex around the vertex (and the vertex itself if free) ...
331  for (i=0; i < vert_num_free_vtces ; ++i) {
332  // ... computes p*q^{p-1}*grad(q) ...
333  grad_vec[i] *= factor;
334  // ... and accumulates it in the objective function gradient.
335  grad[pd.get_vertex_index(vert_free_vtces[i])] += grad_vec[i];
336  }
337  }
338  }
339 
340  OF_val *= get_negate_flag();
341 
342  return true;
343 
344 }
345 
346 
369  MsqHessian &hessian,
370  Vector3D *const &grad,
371  double &OF_val,
372  MsqError &err)
373 {
374  double scaling_value=1.0;
375 
376  MSQ_FUNCTION_TIMER( "LPtoPTemplate::compute_analytical_hessian" );
377 
378  MsqMeshEntity* elements = pd.get_element_array(err); MSQ_ERRZERO(err);
379  MsqVertex* vertices = pd.get_vertex_array(err); MSQ_ERRZERO(err);
380  size_t num_elems = pd.num_elements();
381  //if scaling divide by the number of elements.
382  if(dividingByN){
383  if(num_elems<=0) {
384  MSQ_SETERR(err)("LPtoP is attempting to divide by zero in analytical Hessian.",
386  return false;
387  }
388  scaling_value/=num_elems;
389  }
390 
391  size_t num_vertices = pd.num_vertices();
393  Matrix3D elem_outer_product;
395  double QM_val;
396  double fac1, fac2;
397  Matrix3D grad_outprod;
398  bool qm_bool;
399  QualityMetric* currentQM = get_quality_metric();
400 
401  MsqVertex* ele_free_vtces[MSQ_MAX_NUM_VERT_PER_ENT];
402  short i;
403  for (i=0; i<MSQ_MAX_NUM_VERT_PER_ENT; ++i) ele_free_vtces[i]=NULL;
404 
405  const size_t* vtx_indices;
406 
407  size_t e, v;
408  size_t nfve; // number of free vertices in element
409  short j,n;
410 
411  hessian.zero_out();
412  for (v=0; v<num_vertices; ++v) grad[v] = 0.;
413  OF_val = 0.;
414 
415  // Loops over all elements in the patch.
416  for (e=0; e<num_elems; ++e) {
417  short nve = elements[e].vertex_count();
418 
419  // Gets a list of free vertices in the element.
420  vtx_indices = elements[e].get_vertex_index_array();
421  nfve=0;
422  for (i=0; i<nve; ++i) {
423  if ( vertices[vtx_indices[i]].is_free_vertex() ) {
424  ele_free_vtces[nfve] = vertices + vtx_indices[i];
425  ++nfve;
426  }
427  }
428 
429  // Computes \nabla^2 Q(e). Only the free vertices will have non-zero entries.
430  qm_bool = currentQM->compute_element_hessian(pd,
431  elements+e, ele_free_vtces,
432  grad_vec, elem_hessian,
433  nfve, QM_val, err);
434  if (MSQ_CHKERR(err) || !qm_bool) return false;
435 
436 
437  // **** Computes Hessian ****
438  double QM_pow=1.;
439  if (pVal == 1) {
440  n=0;
441  for (i=0; i<nve; ++i) {
442  for (j=i; j<nve; ++j) {
443  //negate if necessary
444  elem_hessian[n] *= (scaling_value * get_negate_flag());
445  ++n;
446  }
447  }
448  hessian.accumulate_entries(pd, e, elem_hessian, err);
449  fac1 = 1;
450  }
451  else if (pVal >= 2) {
452  // Computes the coefficients:
453  QM_val = fabs(QM_val);
454  QM_pow = 1;
455  for (i=0; i<pVal-2; ++i)
456  QM_pow *= QM_val;
457  // 1 - computes p(p-1)Q(e)^{p-2}
458  fac2 = pVal* (pVal-1) * QM_pow;
459  // 2 - computes pQ(e)^{p-1}
460  QM_pow *= QM_val;
461  fac1 = pVal * QM_pow;
462 
463  //fac1 *= get_negate_flag();
464  //fac2 *= get_negate_flag();
465 
466  n=0;
467  for (i=0; i<nve; ++i) {
468  for (j=i; j<nve; ++j) {
469  if ( vertices[vtx_indices[i]].is_free_vertex() &&
470  vertices[vtx_indices[j]].is_free_vertex() ) {
471  // Computes \nabla Q(e) [\nabla Q(e)]^T
472  elem_outer_product.outer_product(grad_vec[i], grad_vec[j]);
473 
474  elem_outer_product *= fac2;
475  elem_hessian[n] *= fac1;
476  elem_hessian[n] += elem_outer_product;
477  } else {
478  // elem_outer_product is nul
479  elem_hessian[n] *= fac1;
480  }
481  //scale the hessian by the scaling factor
482  elem_hessian[n] *= (scaling_value * get_negate_flag());
483  ++n;
484  }
485  }
486 
487  hessian.accumulate_entries(pd, e, elem_hessian, err); MSQ_ERRZERO(err);
488 
489  } else {
490  MSQ_SETERR(err)(" invalid P value.", MsqError::INVALID_STATE);
491  return false;
492  }
493 
494 
495  // **** Computes Gradient ****
496 
497  // For each vertex in the element ...
498  for (i=0; i<nve; ++i) {
499  if ( vertices[vtx_indices[i]].is_free_vertex() ) {
500  // ... computes p*q^{p-1}*grad(q) ...
501  grad_vec[i] *= fac1*get_negate_flag();
502  // ... and accumulates it in the objective function gradient.
503  //also scale the gradient by the scaling factor
504  grad[vtx_indices[i]] += (scaling_value * grad_vec[i]);
505  }
506  }
507 
508  // **** computes Objective Function value \sum_{i=1}^{N_e} |q_i|^P ****
509  //and scale by 1/num if necessary
510  OF_val += (scaling_value * QM_pow * QM_val);
511 
512  }
513 
514  OF_val *= get_negate_flag();
515 
516  return true;
517 }
void set_gradient_type(GRADIENT_TYPE grad)
Set gradType to either NUMERICAL_GRADIENT or ANALYTICAL_GRADIENT.
virtual bool compute_analytical_hessian(PatchData &patch, MsqHessian &hessian, Vector3D *const &grad, double &OF_val, MsqError &err)
short pVal
The metric value entries are raised to the pVal power.
#define MSQ_ERRZERO(err)
Return zero/NULL on error.
void set_quality_metric(QualityMetric *qm)
Set the value of qMetric.
void accumulate_entries(PatchData &pd, const size_t &elem_index, Matrix3D *const &mat3d_array, MsqError &err)
double compute_function(double metric_values[], size_t total_num, MsqError &err)
int get_negate_flag()
Returns negateFlag.
bool compute_vertex_gradient(PatchData &pd, MsqVertex &vertex, MsqVertex *vertices[], Vector3D grad_vec[], int num_vtx, double &metric_value, MsqError &err)
Calls compute_vertex_numerical_gradient if gradType equals NUMERCIAL_GRADIENT. Calls compute_vertex_a...
Used to hold the error state and return it to the application.
Base class for concrete quality metrics.
virtual bool concrete_evaluate(PatchData &patch, double &fval, MsqError &err)
NT p1
MsqMeshEntity is the Mesquite object that stores information about the elements in the mesh...
Vector3D is the object that effeciently stores information about about three-deminsional vectors...
Vector3D is the object that effeciently stores the objective function Hessian each entry is a Matrix3...
const int MSQ_MAX_NUM_VERT_PER_ENT
Definition: Mesquite.hpp:120
every differentiable function should have an analytical gradient implemented.
virtual msq_std::list< QualityMetric * > get_quality_metric_list()
*********************************************************************Illinois Open Source License ****University of Illinois NCSA **Open Source License University of Illinois All rights reserved ****Developed free of to any person **obtaining a copy of this software and associated documentation to deal with the Software without including without limitation the rights to and or **sell copies of the and to permit persons to whom the **Software is furnished to do subject to the following this list of conditions and the following disclaimers ****Redistributions in binary form must reproduce the above **copyright this list of conditions and the following **disclaimers in the documentation and or other materials **provided with the distribution ****Neither the names of the Center for Simulation of Advanced the University of nor the names of its **contributors may be used to endorse or promote products derived **from this Software without specific prior written permission ****THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY **EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES **OF FITNESS FOR A PARTICULAR PURPOSE AND **NONINFRINGEMENT IN NO EVENT SHALL THE CONTRIBUTORS OR **COPYRIGHT HOLDERS BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN AN ACTION OF TORT OR **ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE **USE OR OTHER DEALINGS WITH THE SOFTWARE v
Definition: roccomf90.h:20
bool compute_element_hessian(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], Matrix3D hessian[], int num_free_vtx, double &metric_value, MsqError &err)
For MetricType == ELEMENT_BASED. Calls either compute_element_numerical_hessian() or compute_element_...
invalid function argument passed
size_t num_elements() const
number of elements in the Patch.
msq_stdc::size_t vertex_count() const
Returns the number of vertices in this element, based on its element type.
#define MSQ_CHKERR(err)
Mesquite&#39;s Error Checking macro.
3*3 Matric class, row-oriented, 0-based [i][j] indexing.
bool compute_element_gradient(PatchData &pd, MsqMeshEntity *element, MsqVertex *free_vtces[], Vector3D grad_vec[], int num_free_vtx, double &metric_value, MsqError &err)
For MetricType == ELEMENT_BASED. Calls either compute_element_numerical_gradient() or compute_element...
size_t get_vertex_index(MsqVertex *vertex)
#define MSQ_SETERR(err)
Macro to set error - use err.clear() to clear.
blockLoc i
Definition: read.cpp:79
void get_adjacent_vertex_indices(size_t vertex_index, msq_std::vector< size_t > &vert_indices, MsqError &err)
const NT & n
void set_negate_flag(int neg)
Set the value of ObjectiveFunction&#39;s negateFlag. Unless composite, concrete ObjectiveFunctions should...
size_t num_vertices() const
number of vertices in the patch.
virtual bool evaluate_element(PatchData &, MsqMeshEntity *, double &, MsqError &err)
Evaluate the metric for an element.
bool is_free_vertex() const
Returns true if vertex is ``free&#39;&#39;.
virtual bool evaluate_vertex(PatchData &, MsqVertex *, double &, MsqError &err)
Evaluate the metric for a vertex.
const MsqVertex * get_vertex_array(MsqError &err) const
Returns a pointer to the start of the vertex array.
j indices j
Definition: Indexing.h:6
object is in an invalid state
const msq_stdc::size_t * get_vertex_index_array() const
Very efficient retrieval of vertices indexes (corresponding to the PatchData vertex array)...
#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.
LPtoPTemplate(QualityMetric *, short, MsqError &)
MsqVertex is the Mesquite object that stores information about the vertices in the mesh...
virtual bool compute_analytical_gradient(PatchData &patch, Vector3D *const &grad, double &OF_val, MsqError &err, size_t array_size)
bool dividingByN
dividingByN is true if we are dividing the objective function by the number of metric values...