PRAgMaTIc  master
MetricTensor.h
Go to the documentation of this file.
1 /* Copyright (C) 2010 Imperial College London and others.
2  *
3  * Please see the AUTHORS file in the main source directory for a
4  * full list of copyright holders.
5  *
6  * Gerard Gorman
7  * Applied Modelling and Computation Group
8  * Department of Earth Science and Engineering
9  * Imperial College London
10  *
11  * g.gorman@imperial.ac.uk
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above
19  * copyright notice, this list of conditions and the following
20  * disclaimer in the documentation and/or other materials provided
21  * with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
32  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
34  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #ifndef METRICTENSOR_H
39 #define METRICTENSOR_H
40 
41 #include <iostream>
42 
43 #include <Eigen/Core>
44 #include <Eigen/Dense>
45 
46 #include "PragmaticMinis.h"
47 
48 template<typename treal_t, int dim> class MetricTensor;
49 template<typename treal_t, int dim>
50  std::ostream& operator<<(std::ostream& out, const MetricTensor<treal_t,dim>& in);
51 
66 template<typename treal_t, int dim> class MetricTensor{
67 public:
70 
73 
88  MetricTensor(const treal_t *metric){
89  set_metric(metric);
90  }
91 
96  *this = metric;
97  }
98 
103  for(size_t i=0; i<(dim==2?3:6); i++)
104  _metric[i] = metric._metric[i];
105  return *this;
106  }
107 
111  void get_metric(treal_t *metric){
112  for(size_t i=0; i<(dim==2?3:6); i++)
113  metric[i] = _metric[i];
114  }
115 
117  const treal_t* get_metric() const{
118  return _metric;
119  }
120 
135  void set_metric(const treal_t* metric){
136  for(size_t i=0; i<(dim==2?3:6); i++)
137  _metric[i] = metric[i];
138 
139  positive_definiteness(_metric);
140  }
141 
142  // Enforce positive definiteness
143  static void positive_definiteness(treal_t* metric){
144  Eigen::Matrix<treal_t, dim, dim> M;
145 
146  if(dim==2){
147  M << metric[0]+DBL_EPSILON, metric[1],
148  metric[1], metric[2]+DBL_EPSILON;
149  }else if(dim==3){
150  M << metric[0]+DBL_EPSILON, metric[1], metric[2],
151  metric[1], metric[3]+DBL_EPSILON, metric[4],
152  metric[2], metric[4], metric[5]+DBL_EPSILON;
153  }
154 
155  if(M.isZero())
156  return;
157 
158  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver(M);
159 
160  Eigen::Matrix<treal_t, dim, 1> evalues = solver.eigenvalues().real().cwise().abs();
161  Eigen::Matrix<treal_t, dim, dim> evectors = solver.eigenvectors().real();
162  Eigen::Matrix<treal_t, dim, dim> Mp = evectors*evalues.asDiagonal()*evectors.transpose();
163 
164  if(dim==2){
165  metric[0] = Mp[0];
166  metric[1] = Mp[1];
167  metric[2] = Mp[3];
168  }else if(dim==3){
169  metric[0] = Mp[0];
170  metric[1] = Mp[1];
171  metric[2] = Mp[2];
172  metric[3] = Mp[4];
173  metric[4] = Mp[5];
174  metric[5] = Mp[8];
175  }
176 
177  return;
178  }
179 
186  void constrain(const treal_t* M_in, bool perserved_small_edges=true){
187  for(size_t i=0; i<(dim==2?3:6); i++){
188  if(pragmatic_isnan(M_in[i])){
189  std::cerr<<"WARNING: encountered NAN in "<<__FILE__<<", "<<__LINE__<<std::endl;
190  return;
191  }
192  }
193 
194  MetricTensor<treal_t,dim> metric(M_in);
195 
196  // Make the tensor with the smallest aspect ratio the reference space Mr.
197  const treal_t *Mr=_metric, *Mi=metric._metric;
198  Eigen::Matrix<treal_t, dim, dim> M1;
199  if(dim==2)
200  M1 << _metric[0], _metric[1],
201  _metric[1], _metric[2];
202  else if(dim==3){
203  M1[0] = _metric[0]; M1[1] = _metric[1]; M1[2] = _metric[2];
204  M1[3] = _metric[1]; M1[4] = _metric[3]; M1[5] = _metric[4];
205  M1[6] = _metric[2]; M1[7] = _metric[4]; M1[8] = _metric[5];
206  }
207 
208  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver1(M1);
209  Eigen::Matrix<treal_t, dim, 1> evalues1 = solver1.eigenvalues().real().cwise().abs();
210 
211  treal_t aspect_r;
212  if(dim==2){
213  aspect_r = std::min(evalues1[0], evalues1[1])/
214  std::max(evalues1[0], evalues1[1]);
215 
216  // Just replace metric if it is foobar
217  if(!std::isnormal(aspect_r)){
218  for(int i=0;i<3;i++)
219  _metric[i] = M_in[i];
220  return;
221  }
222  }
223  else if(dim==3)
224  aspect_r = std::min(std::min(evalues1[0], evalues1[1]), evalues1[2])/
225  std::max(std::max(evalues1[0], evalues1[1]), evalues1[2]);
226 
227  Eigen::Matrix<treal_t, dim, dim> M2;
228  if(dim==2)
229  M2 << metric._metric[0], metric._metric[1],
230  metric._metric[1], metric._metric[2];
231  else if(dim==3){
232  M2[0] = metric._metric[0]; M2[1] = metric._metric[1]; M2[2] = metric._metric[2];
233  M2[3] = metric._metric[1]; M2[4] = metric._metric[3]; M2[5] = metric._metric[4];
234  M2[6] = metric._metric[2]; M2[7] = metric._metric[4]; M2[8] = metric._metric[5];
235  }
236 
237  // The input matrix could be zero if there is zero curvature in the local solution.
238  if(M2.isZero())
239  return;
240 
241  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver2(M2);
242  Eigen::Matrix<treal_t, dim, 1> evalues2 = solver2.eigenvalues().real().cwise().abs();
243 
244  treal_t aspect_i;
245  if(dim==2)
246  aspect_i = std::min(evalues2[0], evalues2[1])/
247  std::max(evalues2[0], evalues2[1]);
248  else if (dim==3)
249  aspect_i = std::min(std::min(evalues2[0], evalues2[1]), evalues2[2])/
250  std::max(std::max(evalues2[0], evalues2[1]), evalues2[2]);
251 
252  if(aspect_i>aspect_r){
253  Mi=_metric;
254  Mr=metric._metric;
255  }
256 
257  // Map Mi to the reference space where Mr==I
258  if(dim==2)
259  M1 << Mr[0], Mr[1],
260  Mr[1], Mr[2];
261  else if(dim==3)
262  M1 << Mr[0], Mr[1], Mr[2],
263  Mr[1], Mr[3], Mr[4],
264  Mr[2], Mr[4], Mr[5];
265 
266  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver(M1);
267  Eigen::Matrix<treal_t, dim, dim> F =
268  solver.eigenvalues().real().cwise().abs().cwise().sqrt().asDiagonal()*
269  solver.eigenvectors().real();
270 
271  if(dim==2)
272  M2 << Mi[0], Mi[1],
273  Mi[1], Mi[2];
274  else if(dim==3)
275  M2 << Mi[0], Mi[1], Mi[2],
276  Mi[1], Mi[3], Mi[4],
277  Mi[2], Mi[4], Mi[5];
278 
279  Eigen::Matrix<treal_t, dim, dim> M = F.inverse().transpose()*M2*F.inverse();
280 
281  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver3(M);
282  Eigen::Matrix<treal_t, dim, 1> evalues = solver3.eigenvalues().real().cwise().abs();
283  Eigen::Matrix<treal_t, dim, dim> evectors = solver3.eigenvectors().real();
284 
285  if(perserved_small_edges)
286  for(size_t i=0; i<dim; i++)
287  evalues[i] = std::max((treal_t) 1.0, evalues[i]);
288  else
289  for(size_t i=0; i<dim; i++)
290  evalues[i] = std::min((treal_t) 1.0, evalues[i]);
291 
292  Eigen::Matrix<treal_t, dim, dim> Mc = F.transpose()*evectors*evalues.asDiagonal()*evectors.transpose()*F;
293 
294  if(dim==2){
295  _metric[0] = Mc[0];
296  _metric[1] = Mc[1];
297  _metric[2] = Mc[3];
298  } else if(dim==3){
299  _metric[0] = Mc[0];
300  _metric[1] = Mc[1];
301  _metric[2] = Mc[2];
302  _metric[3] = Mc[4];
303  _metric[4] = Mc[5];
304  _metric[5] = Mc[8];
305  }
306 
307  return;
308  }
309 
313  void limit_aspect_ratio(treal_t max_ratio){
314  Eigen::Matrix<treal_t, dim, dim> M1;
315  if(dim==2)
316  M1 << _metric[0], _metric[1],
317  _metric[1], _metric[2];
318  else if(dim==3){
319  M1[0] = _metric[0]; M1[1] = _metric[1]; M1[2] = _metric[2];
320  M1[3] = _metric[1]; M1[4] = _metric[3]; M1[5] = _metric[4];
321  M1[6] = _metric[2]; M1[7] = _metric[4]; M1[8] = _metric[5];
322  }
323 
324  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver1(M1);
325 
326  Eigen::Matrix<treal_t, dim, 1> evalues = solver1.eigenvalues().real().cwise().abs();
327  Eigen::Matrix<treal_t, dim, dim> evectors = solver1.eigenvectors().real();
328 
329  if(dim==2){
330  if(evalues[0]<evalues[1]){
331  evalues[0] = std::max(evalues[0], evalues[1]/(max_ratio*max_ratio));
332  }else{
333  evalues[1] = std::max(evalues[1], evalues[0]/(max_ratio*max_ratio));
334  }
335  }else{
336  treal_t max_eigenvalue = std::max(evalues[0], std::max(evalues[1], evalues[2]));
337  treal_t min_eigenvalue = max_eigenvalue/(max_ratio*max_ratio);
338 
339  for(int i=0;i<dim;i++)
340  evalues[i] = std::max(evalues[i], min_eigenvalue);
341  }
342 
343  Eigen::Matrix<treal_t, dim, dim> Mc = evectors*evalues.asDiagonal()*evectors.transpose();
344 
345  if(dim==2){
346  _metric[0] = Mc[0];
347  _metric[1] = Mc[1];
348  _metric[2] = Mc[3];
349  } else if(dim==3){
350  _metric[0] = Mc[0];
351  _metric[1] = Mc[1];
352  _metric[2] = Mc[2];
353  _metric[3] = Mc[4];
354  _metric[4] = Mc[5];
355  _metric[5] = Mc[8];
356  }
357 
358  return;
359  }
360 
363  friend std::ostream& operator<< <>(std::ostream& out, const MetricTensor<treal_t,dim>& metric);
364 
365  void scale(treal_t scale_factor){
366  for(size_t i=0; i<(dim==2?3:6); i++)
367  _metric[i] *= scale_factor;
368  }
369 
370  treal_t average_length() const{
371  treal_t D[dim];
372  treal_t V[dim*dim];
373 
374  eigen_decomp(D, V);
375 
376  treal_t result;
377 
378  if(dim==2){
379  treal_t l0 = sqrt(1.0/D[0]);
380  treal_t l1 = sqrt(1.0/D[1]);
381  result = (l0+l1)*0.5;
382  }else if(dim==3){
383  treal_t l0 = sqrt(1.0/D[0]);
384  treal_t l1 = sqrt(1.0/D[1]);
385  treal_t l2 = sqrt(1.0/D[2]);
386  result = (l0+l1+l2)/3.0;
387  }
388 
389  return result;
390  }
391 
392  treal_t max_length() const{
393  treal_t D[dim];
394  treal_t V[dim*dim];
395 
396  eigen_decomp(D, V);
397 
398  treal_t min_d;
399 
400  if(dim==2)
401  min_d = std::min(D[0], D[1]);
402  else if(dim==3)
403  min_d = std::min(std::min(D[0], D[1]), D[2]);
404 
405  return sqrt(1.0/min_d); // ie, the max
406  }
407 
408  double min_length() const{
409  treal_t D[dim];
410  treal_t V[dim*dim];
411 
412  eigen_decomp(D, V);
413 
414  treal_t max_d;
415 
416  if(dim==2)
417  max_d = std::max(D[0], D[1]);
418  else if(dim==3)
419  max_d = std::max(std::max(D[0], D[1]), D[2]);
420 
421  return sqrt(1.0/max_d); // ie, the min
422  }
423 
424  void eigen_decomp(treal_t* eigenvalues, treal_t* eigenvectors) const{
425  Eigen::Matrix<treal_t, dim, dim> M;
426  if(dim==2)
427  M << _metric[0], _metric[1],
428  _metric[1], _metric[2];
429  else if(dim==3)
430  M << _metric[0], _metric[1], _metric[2],
431  _metric[1], _metric[3], _metric[4],
432  _metric[2], _metric[4], _metric[5];
433 
434  if(M.isZero()){
435  for(size_t i=0; i<dim; i++)
436  eigenvalues[i] = 0.0;
437 
438  for(size_t i=0; i<dim*dim; i++)
439  eigenvectors[i] = 0.0;
440  }else{
441  Eigen::EigenSolver< Eigen::Matrix<treal_t, dim, dim> > solver(M);
442 
443  Eigen::Matrix<treal_t, dim, 1> evalues = solver.eigenvalues().real().cwise().abs();
444  Eigen::Matrix<treal_t, dim, dim> evectors = solver.eigenvectors().real();
445 
446  for(size_t i=0; i<dim; i++)
447  eigenvalues[i] = evalues[i];
448 
449  Eigen::Matrix<treal_t, dim, dim> Mp = evectors.transpose();
450  for(size_t i=0; i<dim*dim; i++)
451  eigenvectors[i] = Mp[i];
452  }
453  }
454 
455  void eigen_undecomp(const treal_t* D, const treal_t* V){
456  // Insure eigenvalues are positive
457  treal_t eigenvalues[dim];
458  for(size_t i=0; i<dim; i++)
459  eigenvalues[i] = fabs(D[i]);
460 
461  treal_t M[dim*dim];
462  for(size_t i=0; i<dim; i++){
463  for(size_t j=0; j<dim; j++){
464  int ii = (i*dim) + j;
465  M[ii] = 0.0;
466  for(size_t k=0; k<dim; k++)
467  M[ii]+=eigenvalues[k]*V[k*dim+i]*V[k*dim+j];
468  }
469  }
470 
471  if(dim==2){
472  _metric[0] = M[0];
473  _metric[1] = M[1];
474  _metric[2] = M[3];
475  }else if(dim==3){
476  _metric[0] = M[0];
477  _metric[1] = M[1];
478  _metric[2] = M[2];
479  _metric[3] = M[4];
480  _metric[4] = M[5];
481  _metric[5] = M[8];
482  }
483  }
484 
485 private:
486  treal_t _metric[dim==2?3:(dim==3?6:-1)];
487 };
488 
489 template<typename treal_t, int dim>
490 std::ostream& operator<<(std::ostream& out, const MetricTensor<treal_t,dim>& in){
491  if(dim==2)
492  out << in._metric[0] << " " << in._metric[1] << std::endl
493  << in._metric[1] << " " << in._metric[2] << std::endl;
494  else if(dim==3)
495  out << in._metric[0] << " " << in._metric[1] << " " << in._metric[2] << std::endl
496  << in._metric[1] << " " << in._metric[3] << " " << in._metric[4] << std::endl
497  << in._metric[2] << " " << in._metric[4] << " " << in._metric[5] << std::endl;
498 
499  return out;
500 }
501 
502 #endif
symmetric metric tensor class.
Definition: MetricTensor.h:48
void limit_aspect_ratio(treal_t max_ratio)
Definition: MetricTensor.h:313
treal_t max_length() const
Definition: MetricTensor.h:392
MetricTensor()
Default constructor.
Definition: MetricTensor.h:69
void eigen_undecomp(const treal_t *D, const treal_t *V)
Definition: MetricTensor.h:455
const MetricTensor & operator=(const MetricTensor< treal_t, dim > &metric)
Definition: MetricTensor.h:102
MetricTensor(const MetricTensor< treal_t, dim > &metric)
Definition: MetricTensor.h:95
treal_t average_length() const
Definition: MetricTensor.h:370
static void positive_definiteness(treal_t *metric)
Definition: MetricTensor.h:143
void eigen_decomp(treal_t *eigenvalues, treal_t *eigenvectors) const
Definition: MetricTensor.h:424
void get_metric(treal_t *metric)
Definition: MetricTensor.h:111
~MetricTensor()
Default destructor.
Definition: MetricTensor.h:72
void set_metric(const treal_t *metric)
Definition: MetricTensor.h:135
#define pragmatic_isnan
double min_length() const
Definition: MetricTensor.h:408
MetricTensor(const treal_t *metric)
Definition: MetricTensor.h:88
const treal_t * get_metric() const
Give const pointer to metric tensor.
Definition: MetricTensor.h:117
void scale(treal_t scale_factor)
Definition: MetricTensor.h:365
void constrain(const treal_t *M_in, bool perserved_small_edges=true)
Definition: MetricTensor.h:186