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 kraftche@cae.wisc.edu
26
27 ***************************************************************** */
28 /*!
29 \file QualityMetric.cpp
30 \brief
31
32 \author Michael Brewer
33 \author Thomas Leurent
34 \date 2002-05-14
35 \author Jason Kraftcheck
36 \date 2006-04-20
37 */
38
39 #include "QualityMetric.hpp"
40 #include "MsqVertex.hpp"
41 #include "PatchData.hpp"
42
43 namespace MBMesquite {
44
initialize_queue(MeshDomainAssoc *,const Settings *,MsqError &)45 void QualityMetric::initialize_queue( MeshDomainAssoc* ,
46 const Settings* ,
47 MsqError& )
48 {}
49
get_single_pass(PatchData & pd,std::vector<size_t> & handles,bool free_vertices_only,MsqError & err)50 void QualityMetric::get_single_pass( PatchData& pd,
51 std::vector<size_t>& handles,
52 bool free_vertices_only,
53 MsqError& err )
54 {
55 get_evaluations( pd, handles, free_vertices_only, err );
56 }
57
58
59 static inline
get_delta_C(const PatchData & pd,const std::vector<size_t> & indices,MsqError & err)60 double get_delta_C( const PatchData& pd,
61 const std::vector<size_t>& indices,
62 MsqError& err )
63 {
64 if (indices.empty()) {
65 MSQ_SETERR(err)(MsqError::INVALID_ARG);
66 return 0.0;
67 }
68
69 std::vector<size_t>::const_iterator beg, iter, iter2, end;
70
71 std::vector<size_t> tmp_vect;
72 if (indices.size() == 1u) {
73 pd.get_adjacent_vertex_indices( indices.front(), tmp_vect, err );
74 MSQ_ERRZERO(err);
75 assert(!tmp_vect.empty());
76 tmp_vect.push_back( indices.front() );
77 beg = tmp_vect.begin();
78 end = tmp_vect.end();
79 }
80 else {
81 beg = indices.begin();
82 end = indices.end();
83 }
84
85 double min_dist_sqr = HUGE_VAL, sum_dist_sqr = 0.0;
86 for (iter = beg; iter != end; ++iter) {
87 for (iter2 = iter+1; iter2 != end; ++iter2) {
88 Vector3D diff = pd.vertex_by_index(*iter);
89 diff -= pd.vertex_by_index(*iter2);
90 double dist_sqr = diff % diff;
91 if (dist_sqr < min_dist_sqr)
92 min_dist_sqr = dist_sqr;
93 sum_dist_sqr += dist_sqr;
94 }
95 }
96
97 return 3e-6*sqrt(min_dist_sqr) + 5e-7*sqrt(sum_dist_sqr/(end-beg));
98 }
99
100
evaluate_with_gradient(PatchData & pd,size_t handle,double & value,std::vector<size_t> & indices,std::vector<Vector3D> & gradient,MsqError & err)101 bool QualityMetric::evaluate_with_gradient( PatchData& pd,
102 size_t handle,
103 double& value,
104 std::vector<size_t>& indices,
105 std::vector<Vector3D>& gradient,
106 MsqError& err )
107 {
108 indices.clear();
109 bool valid = evaluate_with_indices( pd, handle, value, indices, err);
110 if (MSQ_CHKERR(err) || !valid)
111 return false;
112 if (indices.empty())
113 return true;
114
115 // get initial pertubation amount
116 double delta_C = finiteDiffEps;
117 if (!haveFiniteDiffEps) {
118 delta_C = get_delta_C( pd, indices, err ); MSQ_ERRZERO(err);
119 if (keepFiniteDiffEps) {
120 finiteDiffEps = delta_C;
121 haveFiniteDiffEps = true;
122 }
123 }
124 const double delta_inv_C = 1.0/delta_C;
125 const int reduction_limit = 15;
126
127 gradient.resize( indices.size() );
128 for (size_t v=0; v<indices.size(); ++v)
129 {
130 const Vector3D pos = pd.vertex_by_index(indices[v]);
131
132 /* gradient in the x, y, z direction */
133 for (int j=0;j<3;++j)
134 {
135 double delta = delta_C;
136 double delta_inv = delta_inv_C;
137 double metric_value;
138 Vector3D delta_v( 0, 0, 0 );
139
140 //perturb the node and calculate gradient. The while loop is a
141 //safety net to make sure the epsilon perturbation does not take
142 //the element out of the feasible region.
143 int counter = 0;
144 for (;;) {
145 // perturb the coordinates of the free vertex in the j direction
146 // by delta
147 delta_v[j] = delta;
148 pd.set_vertex_coordinates( pos+delta_v, indices[v], err ); MSQ_ERRZERO(err);
149
150 //compute the function at the perturbed point location
151 valid = evaluate( pd, handle, metric_value, err);
152 if (!MSQ_CHKERR(err) && valid)
153 break;
154
155 if (++counter >= reduction_limit) {
156 MSQ_SETERR(err)("Perturbing vertex by delta caused an inverted element.",
157 MsqError::INTERNAL_ERROR);
158 return false;
159 }
160
161 delta*=0.1;
162 delta_inv*=10.;
163 }
164 // put the coordinates back where they belong
165 pd.set_vertex_coordinates( pos, indices[v], err );
166 // compute the numerical gradient
167 gradient[v][j] = (metric_value - value) * delta_inv;
168 } // for(j)
169 } // for(indices)
170 return true;
171 }
172
173
evaluate_with_Hessian(PatchData & pd,size_t handle,double & value,std::vector<size_t> & indices,std::vector<Vector3D> & gradient,std::vector<Matrix3D> & Hessian,MsqError & err)174 bool QualityMetric::evaluate_with_Hessian( PatchData& pd,
175 size_t handle,
176 double& value,
177 std::vector<size_t>& indices,
178 std::vector<Vector3D>& gradient,
179 std::vector<Matrix3D>& Hessian,
180 MsqError& err )
181 {
182 indices.clear();
183 gradient.clear();
184 keepFiniteDiffEps = true;
185 bool valid = evaluate_with_gradient( pd, handle, value, indices, gradient, err );
186 keepFiniteDiffEps = false;
187 if (MSQ_CHKERR(err) || !valid) {
188 haveFiniteDiffEps = false;
189 return false;
190 }
191 if (indices.empty()){
192 haveFiniteDiffEps = false;
193 return true;
194 }
195
196 // get initial pertubation amount
197 double delta_C;
198 if (haveFiniteDiffEps) {
199 delta_C = finiteDiffEps;
200 }
201 else {
202 delta_C = get_delta_C( pd, indices, err ); MSQ_ERRZERO(err);
203 }
204 assert(delta_C < 1e30);
205 const double delta_inv_C = 1.0/delta_C;
206 const int reduction_limit = 15;
207
208 std::vector<Vector3D> temp_gradient( indices.size() );
209 const int num_hess = indices.size() * (indices.size() + 1) / 2;
210 Hessian.resize( num_hess );
211
212 for (unsigned v = 0; v < indices.size(); ++v) {
213 const Vector3D pos = pd.vertex_by_index(indices[v]);
214 for (int j = 0; j < 3; ++j ) { // x, y, and z
215 double delta = delta_C;
216 double delta_inv = delta_inv_C;
217 double metric_value;
218 Vector3D delta_v(0,0,0);
219
220 // find finite difference for gradient
221 int counter = 0;
222 for (;;) {
223 delta_v[j] = delta;
224 pd.set_vertex_coordinates( pos+delta_v, indices[v], err ); MSQ_ERRZERO(err);
225 valid = evaluate_with_gradient( pd, handle, metric_value, indices, temp_gradient, err );
226 if (!MSQ_CHKERR(err) && valid)
227 break;
228
229 if (++counter >= reduction_limit) {
230 MSQ_SETERR(err)("Algorithm did not successfully compute element's "
231 "Hessian.\n",MsqError::INTERNAL_ERROR);
232 haveFiniteDiffEps = false;
233 return false;
234 }
235
236 delta *= 0.1;
237 delta_inv *= 10.0;
238 }
239 pd.set_vertex_coordinates( pos, indices[v], err ); MSQ_ERRZERO(err);
240
241 //compute the numerical Hessian
242 for (unsigned w = 0; w <= v; ++w) {
243 //finite difference to get some entries of the Hessian
244 Vector3D fd( temp_gradient[w] );
245 fd -= gradient[w];
246 fd *= delta_inv;
247 // For the block at position w,v in a matrix, we need the corresponding index
248 // (mat_index) in a 1D array containing only upper triangular blocks.
249 unsigned sum_w = w*(w+1)/2; // 1+2+3+...+w
250 unsigned mat_index = w*indices.size() + v - sum_w;
251 Hessian[mat_index][0][j] = fd[0];
252 Hessian[mat_index][1][j] = fd[1];
253 Hessian[mat_index][2][j] = fd[2];
254 }
255 } // for(j)
256 } // for(indices)
257 haveFiniteDiffEps = false;
258 return true;
259 }
260
evaluate_with_Hessian_diagonal(PatchData & pd,size_t handle,double & value,std::vector<size_t> & indices,std::vector<Vector3D> & gradient,std::vector<SymMatrix3D> & Hessian_diagonal,MsqError & err)261 bool QualityMetric::evaluate_with_Hessian_diagonal( PatchData& pd,
262 size_t handle,
263 double& value,
264 std::vector<size_t>& indices,
265 std::vector<Vector3D>& gradient,
266 std::vector<SymMatrix3D>& Hessian_diagonal,
267 MsqError& err )
268 {
269 bool rval = evaluate_with_Hessian( pd, handle, value, indices, gradient, tmpHess, err );
270 if (MSQ_CHKERR(err) || !rval)
271 return rval;
272 size_t s = indices.size();
273 Hessian_diagonal.resize( s );
274 std::vector<Matrix3D>::const_iterator h = tmpHess.begin();
275 for (size_t i = 0; i < indices.size(); ++i) {
276 Hessian_diagonal[i] = h->upper();
277 h += s--;
278 }
279 return rval;
280 }
281
282
fixed_vertex_bitmap(PatchData & pd,const MsqMeshEntity * elem,std::vector<size_t> & indices)283 uint32_t QualityMetric::fixed_vertex_bitmap( PatchData& pd,
284 const MsqMeshEntity* elem,
285 std::vector<size_t>& indices )
286 {
287 indices.clear();
288 uint32_t result = ~(uint32_t)0;
289 unsigned num_vtx = elem->vertex_count();
290 const size_t* vertices = elem->get_vertex_index_array();
291 indices.clear();
292 for (unsigned i = 0; i < num_vtx; ++i) {
293 if (vertices[i] < pd.num_free_vertices()) {
294 indices.push_back( vertices[i] );
295 result &= ~(uint32_t)(1<<i);
296 }
297 }
298 return result;
299 }
300
301
remove_fixed_gradients(EntityTopology elem_type,uint32_t fixed,std::vector<Vector3D> & grads)302 void QualityMetric::remove_fixed_gradients( EntityTopology elem_type,
303 uint32_t fixed,
304 std::vector<Vector3D>& grads )
305 {
306 const unsigned num_vertex = TopologyInfo::corners( elem_type );
307 unsigned r, w;
308 for (r = 0; r < num_vertex && !(fixed & (1<<r)); ++r);
309 for (w = r++; r < num_vertex; ++r) {
310 if (!(fixed & (1<<r))) {
311 grads[w] = grads[r];
312 ++w;
313 }
314 }
315 grads.resize(w);
316 }
317
remove_fixed_diagonals(EntityTopology type,uint32_t fixed,std::vector<Vector3D> & grads,std::vector<SymMatrix3D> & diags)318 void QualityMetric::remove_fixed_diagonals( EntityTopology type,
319 uint32_t fixed,
320 std::vector<Vector3D>& grads,
321 std::vector<SymMatrix3D>& diags )
322 {
323 const unsigned num_vertex = TopologyInfo::corners( type );
324 unsigned r, w;
325 for (r = 0; r < num_vertex && !(fixed & (1<<r)); ++r);
326 for (w = r++; r < num_vertex; ++r) {
327 if (!(fixed & (1<<r))) {
328 grads[w] = grads[r];
329 diags[w] = diags[r];
330 ++w;
331 }
332 }
333 grads.resize(w);
334 diags.resize(w);
335 }
336
remove_fixed_hessians(EntityTopology elem_type,uint32_t fixed,std::vector<Matrix3D> & hessians)337 void QualityMetric::remove_fixed_hessians( EntityTopology elem_type,
338 uint32_t fixed,
339 std::vector<Matrix3D>& hessians )
340 {
341 const unsigned num_vertex = TopologyInfo::corners( elem_type );
342 unsigned r, c, i = 0, w = 0;
343 for (r = 0; r < num_vertex; ++r) {
344 if (fixed & (1<<r)) {
345 i += num_vertex - r;
346 continue;
347 }
348 for (c = r; c < num_vertex; ++c) {
349 if (!(fixed & (1<<c))) {
350 hessians[w] = hessians[i];
351 ++w;
352 }
353 ++i;
354 }
355 }
356 hessians.resize(w);
357 }
358
weighted_average_metrics(const double coef[],const double metric_values[],const int & num_values,MsqError &)359 double QualityMetric::weighted_average_metrics(const double coef[],
360 const double metric_values[],
361 const int& num_values,
362 MsqError &/*err*/)
363 {
364 //MSQ_MAX needs to be made global?
365 //double MSQ_MAX=1e10;
366 double total_value=0.0;
367 int i=0;
368 //if no values, return zero
369 if (num_values<=0){
370 return 0.0;
371 }
372
373 for (i=0;i<num_values;++i){
374 total_value += coef[i]*metric_values[i];
375 }
376 total_value /= (double) num_values;
377
378 return total_value;
379 }
380
381 } // namespace MBMesquite
382