1 /*
2 XLiFE++ is an extended library of finite elements written in C++
3    Copyright (C) 2014  Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4 
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 /*!
18   \file GeomMapData.cpp
19   \authors D. Martin, E. Lunéville
20   \since 14 apr 2012
21   \date 23 may 2012
22 
23   \brief Implementation of xlifepp::GeomMapData functions
24 */
25 
26 #include "GeomMapData.hpp"
27 #include "GeomElement.hpp"
28 
29 namespace xlifepp
30 {
31 
32 //constructors
GeomMapData(const MeshElement * melt,const Point & x)33 GeomMapData::GeomMapData(const MeshElement* melt, const Point& x)
34   : geomElement_p(melt), currentPoint(x)
35 {
36   elementDim = geomElement_p->elementDim();
37   spaceDim = geomElement_p->spaceDim();
38   jacobianDeterminant = 0;
39   differentialElement=0;
40   metricTensorDeterminant=0;
41   jacobianMatrix.clear();           // to reset the size of vector to 0 (default 1x1)
42   inverseJacobianMatrix.clear();    // to reset the size of vector to 0 (default 1x1)
43   normalVector.clear();             // to reset the size of vector to 0 (default 1)
44   extdata=0;
45 }
46 
GeomMapData(const MeshElement * melt,std::vector<real_t>::const_iterator itp)47 GeomMapData::GeomMapData(const MeshElement* melt, std::vector<real_t>::const_iterator itp)
48   : geomElement_p(melt)
49 {
50   elementDim = geomElement_p->elementDim();
51   spaceDim = geomElement_p->spaceDim();
52   currentPoint = Point(itp, elementDim);
53   jacobianDeterminant=0;
54   differentialElement=0;
55   metricTensorDeterminant=0;
56   jacobianMatrix.clear();           // to reset the size of vector to 0 (default 1x1)
57   inverseJacobianMatrix.clear();    // to reset the size of vector to 0 (default 1x1)
58   normalVector.clear();             // to reset the size of vector to 0 (default 1)
59   extdata=0;
60 }
61 
GeomMapData(const MeshElement * melt)62 GeomMapData::GeomMapData(const MeshElement* melt)    //origin as point
63   : geomElement_p(melt)
64 {
65   elementDim = geomElement_p->elementDim();
66   spaceDim = geomElement_p->spaceDim();
67   currentPoint = Point(std::vector<real_t>(elementDim, 0.));
68   jacobianDeterminant = 0;
69   differentialElement=0;
70   metricTensorDeterminant=0;
71   jacobianMatrix.clear();           // to reset the size of vector to 0 (default 1x1)
72   inverseJacobianMatrix.clear();    // to reset the size of vector to 0 (default 1x1)
73   normalVector.clear();             // to reset the size of vector to 0 (default 1)
74   extdata=0;
75 }
76 
77 /*
78 --------------------------------------------------------------------------------
79   mapping a point from reference element onto geometric element point
80 --------------------------------------------------------------------------------
81 */
82 //mapping from ref. elt onto geom. elt. Element at a given point x
geomMap(const std::vector<real_t> & x,number_t side)83 Point GeomMapData::geomMap(const std::vector<real_t>& x, number_t side)
84 {
85   currentPoint = x;
86   //geomElement_p->refElement()->computeShapeValues(x.begin(), false);
87   ShapeValues shv = geomElement_p->refElement()->shapeValues;
88   geomElement_p->refElement()->computeShapeValues(x.begin(), shv, false);
89   return geomMap(shv, side);
90 }
91 
geomMap(std::vector<real_t>::const_iterator itx,number_t side)92 Point GeomMapData::geomMap(std::vector<real_t>::const_iterator itx, number_t side)
93 {
94   Point x(itx, geomElement_p->refElement()->dim());
95   return geomMap(x,side);
96 }
97 
geomMap(number_t side)98 Point GeomMapData::geomMap(number_t side)
99 {
100   return geomMap(geomElement_p->refElement()->shapeValues, side);
101 }
102 
103 //mapping from ref. elt onto geom. elt. Element (shape functions are given, thread safe)
104 // side = 0, transformation on whole element
105 // side > 0, transformation on side side of element of dimension reference_dim_
geomMap(const ShapeValues & shv,number_t side)106 Point GeomMapData::geomMap(const ShapeValues& shv, number_t side)
107 {
108   // spaceDim   : dimension of mapped point
109   // elementDim : dimension of reference point
110   Point pt(std::vector<real_t>(spaceDim, 0.));
111   Point::iterator it_pt = pt.begin(); //first coordinate of pt
112   std::vector<Point*>::const_iterator it_pb = geomElement_p->nodes.begin(), it_p; // iterator on geometric element point coordinates
113   std::vector<real_t>::const_iterator
114   it_wb = shv.w.begin(), // iterators on reference element shape functions at current reference point
115   it_we = shv.w.end(), it_w;
116 
117   if (side == 0)     //element map
118     {
119       for(dimen_t i = 0; i < spaceDim; i++, it_pt++)  // loop on coordinates
120         {
121           it_p = it_pb;  //first node (dof)
122           for(it_w = it_wb; it_w != it_we; it_w++, it_p++)  // loop on reference d.o.f (shape values)
123             { *it_pt += (**it_p)[i] **it_w; }
124         }
125     }
126   else  //side element map
127     {
128       std::vector<number_t>::const_iterator it_dofb = geomElement_p->refElement()->sideDofNumbers_[side - 1].begin(),
129                                             it_dofe = geomElement_p->refElement()->sideDofNumbers_[side - 1].end(), it_dof;
130       for (dimen_t i = 0; i < spaceDim; i++)   // loop on coordinates
131         {
132           it_w = it_wb;
133           for (it_dof = it_dofb; it_dof != it_dofe; it_dof++) // loop on reference side d.o.f
134             { *it_pt += (**(it_pb + *it_dof - 1))[i] **(it_w + *it_dof - 1); }
135         } // end for(dimen_t
136     } // end of else
137   return pt;
138 }
139 
140 /*!mapping from elt onto ref. elt. (inverse of GeomMap)
141   mapping may be non linear : order >1 or not simplicial element (quadrangle, hexahedron)
142   so to inverse it we have to use an iterative method (Newton for instance)
143     first step : initialize Newton's method with first order map say P_0=(JF1)^-1(P-F1(0))
144              if element is a 1 order simplicial element return P_0
145     second step: Newton's iteration P_k+1=P_k - JF(P_k)^-1(P-F(Pk))
146              stop if ||F(P_k+1)-X||< eps or ||P_k+1-P_k+1||< eps
147              stop also if the number of iteration k>50 (error)
148 */
geomMapInverse(const std::vector<real_t> & p,real_t eps,number_t maxIter)149 Point GeomMapData::geomMapInverse(const std::vector<real_t>& p, real_t eps, number_t maxIter)
150 {
151   //if (geomElement_p->isSimplex() && geomElement_p->order()==1)  //first order
152   if (geomElement_p->linearMap)  // linear map
153     {
154       if (inverseJacobianMatrix.size()==0) //compute it
155         {
156           if(jacobianMatrix.size()==0)
157             {
158               currentPoint = Point(std::vector<real_t>(elementDim,0.));
159               geomElement_p->refElement()->computeShapeValues(currentPoint.begin(), true);
160               computeJacobianMatrix();
161             }
162           invertJacobianMatrix();
163         }
164       Point q=geomMap(Point(std::vector<real_t>(elementDim,0.)));
165       Vector<real_t> qp = p - q;
166       return (inverseJacobianMatrix * qp);
167     }
168   else  //non linear map to inverse, to be improved
169     {
170       //create first order map using first order element
171       std::vector<MeshElement*> eltsP1=geomElement_p->splitP1();
172       GeomMapData gmd1(*eltsP1.begin(),p);
173       gmd1.computeJacobianMatrix();
174       gmd1.invertJacobianMatrix();
175       Point q=gmd1.geomMap(Point(std::vector<real_t>(p.size(),0.)));
176       Vector<real_t> qp = p - q;
177       if (geomElement_p->spaceDim()== geomElement_p->elementDim())
178         {
179           invertJacobianMatrix();
180           q=inverseJacobianMatrix * qp;
181         }
182       else //non square system, use least square method
183         {
184           if (inverseJacobianMatrix.size()==0) //compute it
185             {
186               currentPoint = p;
187               computeJacobianMatrix();
188             }
189           Matrix<real_t> Jt=transpose(jacobianMatrix);
190           q = inverse(Jt*jacobianMatrix)*(Jt*qp);
191         }
192 
193       //Newton algorithm
194       bool cont=true;
195       for (number_t k=0; k<maxIter && cont; k++)
196         {
197           qp = p - geomMap(q);
198           if (norminfty(qp)>eps)
199             {
200               currentPoint = q;
201               computeJacobianMatrix();
202               Vector<real_t> t;
203               if (geomElement_p->spaceDim()== geomElement_p->elementDim())
204                 {
205                   invertJacobianMatrix();
206                   t=inverseJacobianMatrix * qp;
207                 }
208               else //non square system, use least square method
209                 {
210                   Matrix<real_t> JtJ=transpose(jacobianMatrix) * jacobianMatrix;
211                   t = inverse(JtJ)*transpose(jacobianMatrix)*qp;
212                 }
213               if (norminfty(t)>eps) q+=Point(t);
214               else cont = false;
215             }
216           else cont=false;
217         }
218       std::vector<MeshElement*>::iterator ite=eltsP1.begin();
219       for (; ite!=eltsP1.end(); ite++) delete *ite;
220       return q;
221     }
222   return p;
223 }
224 
225 //Piola mapping from ref. elt onto geom. elt. Element (shape functions knowns)
piolaMap(number_t side)226 Point GeomMapData::piolaMap(number_t side)
227 {
228   error("not_yet_implemented", "GeomMapData::piolaMap");
229   return Point();
230 }
231 
232 /*! return the covariant Piola map matrix at current point : J^{-T}
233     when mapping from 1d->2d or 2d->3d the matrix J^{-T} is replace by J*(J{T}*J)^{-1}{T}
234     note : in that case invertJacobian() compute J*(J{T}*J)^{-1}
235     */
covariantPiolaMap(const Point & P)236 Matrix<real_t> GeomMapData::covariantPiolaMap(const Point& P)
237 {
238   if(P.size()!=0)
239     {
240       computeJacobianMatrix(P.begin());
241       invertJacobianMatrix();
242     }
243   else //use current point
244     {
245       if(jacobianMatrix.size()==0) computeJacobianMatrix();
246       if(inverseJacobianMatrix.size()==0) invertJacobianMatrix();
247     }
248   return transpose(inverseJacobianMatrix);
249 }
250 
251 /*! return the contravariant Piola map matrix at current point : J/|J|
252     when mapping from 1d->2d or 2d->3d the matrix J/|J| is replace by J/sqrt|Jt*J|
253     note : in that case computeJacobianDeterminant() compute sqrt|Jt*J|
254 */
contravariantPiolaMap(const Point & P)255 Matrix<real_t> GeomMapData::contravariantPiolaMap(const Point& P)
256 {
257   if(P.size()!=0) computeJacobianMatrix(P.begin());
258   else if(jacobianMatrix.size()==0) computeJacobianMatrix();//use current point
259   real_t j=computeJacobianDeterminant();
260   return jacobianMatrix/j;
261 }
262 
263 /*
264 --------------------------------------------------------------------------------
265   computes normal vector at a (boundary) point of element
266   assuming that jacobian matrix is up to date
267   only when space dimension = element dimension + 1
268   or        space dimension = element dimension + 2 (special process)
269 --------------------------------------------------------------------------------
270 */
computeNormalVector()271 void GeomMapData::computeNormalVector()
272 {
273   dimen_t sd=geomElement_p->spaceDim();   //space dimension
274   normalVector.resize(sd);
275   if (spaceDim == elementDim+1)
276     {
277       switch (spaceDim)
278         {
279         case 1:
280           normalVector[0] = 1.;
281           break;
282         case 2:
283           normalVector[0] = jacobianMatrix[1];
284           normalVector[1] = -jacobianMatrix[0];
285           break;
286         case 3:
287           normalVector[0] = jacobianMatrix[2] * jacobianMatrix[5] - jacobianMatrix[4] * jacobianMatrix[3];
288           normalVector[1] = jacobianMatrix[4] * jacobianMatrix[1] - jacobianMatrix[0] * jacobianMatrix[5];
289           normalVector[2] = jacobianMatrix[0] * jacobianMatrix[3] - jacobianMatrix[2] * jacobianMatrix[1];
290           break;
291         }
292       return;
293     }
294   where("GeomMapData::computeNormalVector()");
295   error("geoelt_space_mismatch_dims", elementDim+1, spaceDim);
296 }
297 
298 /*
299 --------------------------------------------------------------------------------
300   normalize normal vector into a outward unit normal vector
301 --------------------------------------------------------------------------------
302 */
normalize()303 void GeomMapData::normalize()
304 {
305   // normalize vector
306   real_t norm = 0.;
307   norm = inner_product(normalVector.begin(), normalVector.end(), normalVector.begin(), norm);
308   if (norm < theZeroThreshold) { error("is_null", words("norm")); }
309   norm = 1. / std::sqrt(norm);
310   if (geomElement_p->orientation < 0) { norm *= -1.; }
311   for (Vector<real_t>::iterator it = normalVector.begin(); it != normalVector.end(); it++)
312     { *it *= norm; }
313 }
314 
315 /*
316 --------------------------------------------------------------------------------
317   compute oriented unit normal vector, assuming jacobian matrix is update
318 --------------------------------------------------------------------------------
319 */
computeOutwardNormal()320 void GeomMapData::computeOutwardNormal()
321 {
322   computeNormalVector();
323   normalize();
324 }
325 
326 /*
327 --------------------------------------------------------------------------------
328   jacobianMatrix computes Jacobian Matrix at Reference Element point x
329     side = 0, jacobian matrix on whole element
330     side > 0, jacobian matrix on side of element of dimension reference_dim
331     spDim  : number of rows of jacobian matrix    (dim of geometric element points)
332     elDim :  number of columns of jacobian matrix (dim of reference element points)
333 --------------------------------------------------------------------------------
334 */
computeJacobianMatrix(const std::vector<real_t> & x,number_t side)335 void GeomMapData::computeJacobianMatrix(const std::vector<real_t>& x, number_t side)
336 {
337   currentPoint = x;
338   geomElement_p->refElement(side)->computeShapeValues(x.begin(), true);
339   computeJacobianMatrix(side);
340 }
341 
computeJacobianMatrix(std::vector<real_t>::const_iterator itx,number_t side)342 void GeomMapData::computeJacobianMatrix(std::vector<real_t>::const_iterator itx, number_t side)
343 {
344   currentPoint = Point(itx, geomElement_p->elementDim());
345   geomElement_p->refElement(side)->computeShapeValues(itx, true);
346   computeJacobianMatrix(side);
347 }
348 
349 // assuming that derivatives of shape functions at x are known and stored in RefElement.shapeValues
computeJacobianMatrix(number_t side)350 void GeomMapData::computeJacobianMatrix(number_t side)
351 {
352   computeJacobianMatrix(geomElement_p->refElement(side)->shapeValues, side);
353 }
354 
355 // assuming that derivatives of shape functions at x are given by shv
computeJacobianMatrix(const ShapeValues & shv,number_t side)356 void GeomMapData::computeJacobianMatrix(const ShapeValues& shv, number_t side)
357 {
358   if (geomElement_p->refElement()->shapeType() == _point)
359     {
360       jacobianMatrix.changesize(1,1,1.);
361       return;
362     }
363   //initialization
364   if (side > 0) { elementDim--; }
365   if (jacobianMatrix.size() != dimen_t(spaceDim * elementDim)) jacobianMatrix.changesize(spaceDim,elementDim);
366   //if(jacobianMatrix.size() != dimen_t(spaceDim * elementDim)) { jacobianMatrix = Matrix<real_t>(spaceDim, elementDim, 0.); }
367 
368   //iterator definitions
369   Matrix<real_t>::iterator it_jmb = jacobianMatrix.begin(), it_jm = it_jmb;        // iterators on matrix entries
370   std::vector<Point*>::const_iterator it_pb = geomElement_p->nodes.begin(), it_p;  // iterator on geometric element point coordinates
371   std::vector< std::vector<real_t> >::const_iterator
372   //it_svb = geomElement_p->refElement(side)->shapeValues.dw.begin(), it_sv; // iterators on reference element shape functions derivatives
373   it_svb = shv.dw.begin(), it_sv;                                            // iterators on reference element shape functions derivatives
374   std::vector<real_t>::const_iterator it_dw;
375 
376   if (side == 0)    //jacobian matrix on whole element
377     {
378       for (dimen_t i = 0; i < spaceDim; i++)    // loop on rows of jacobian matrix
379         {
380           it_sv=it_svb;
381           for (dimen_t j=0; j<elementDim; j++, ++it_sv, ++it_jm ) // loop on columns of jacobian matrix
382             {
383               *it_jm = 0.;             // iterator on geometric element point coordinates
384               it_p = it_pb;            // loop on reference d.o.f (associated shape function derivative)
385               for (it_dw = it_sv->begin(); it_dw != it_sv->end(); ++it_dw, ++it_p)
386                 *it_jm += (**it_p)[i] **it_dw;
387             }
388         } // end for(dimen_t
389     } // end of if(Side
390 
391   else  //jacobian matrix on side
392     {
393       //std::vector< std::vector<real_t> >::const_iterator it_sve = geomElement_p->refElement(side)->shapeValues.dw.end();
394       std::vector< std::vector<real_t> >::const_iterator it_sve = shv.dw.end();
395       //travel dofs on side
396       std::vector<number_t>::const_iterator it_dofb = geomElement_p->refElement()->sideDofNumbers_[side - 1].begin(), it_dof;
397       for (dimen_t i = 0; i < spaceDim; i++)   // loop on rows of jacobian matrix
398         {
399           for (it_sv = it_svb; it_sv != it_sve; it_sv++, it_jm++)    // loop on columns of jacobian matrix
400             {
401               *it_jm = 0.;
402               it_dof = it_dofb;      //begin of dof numbers
403               for (it_dw = it_sv->begin(); it_dw != it_sv->end(); it_dw++, it_dof++)
404                 {
405                   it_p = it_pb + *it_dof - 1;     // node on side
406                   *it_jm += (**it_p)[i] **it_dw;  // update jacobian coefficient
407                 }
408             }
409         } // end for(dimen_t
410     } // end of else
411 }
412 
413 /*
414 --------------------------------------------------------------------------------------
415   jacobianDeterminant computes Jacobian determinant, jacobianMatrix has to be computed
416 --------------------------------------------------------------------------------------
417 */
computeJacobianDeterminant()418 real_t GeomMapData::computeJacobianDeterminant()
419 {
420   if (spaceDim==elementDim) //standard jacobian
421     {
422       switch (spaceDim)
423         {
424         case 1:
425           jacobianDeterminant = jacobianMatrix[0];
426           break;
427         case 2:
428           jacobianDeterminant = jacobianMatrix[0] * jacobianMatrix[3] - jacobianMatrix[1] * jacobianMatrix[2];
429           break;
430         case 3:
431           jacobianDeterminant = jacobianMatrix[0] * (jacobianMatrix[4] * jacobianMatrix[8] - jacobianMatrix[5] * jacobianMatrix[7])
432                                 + jacobianMatrix[1] * (jacobianMatrix[5] * jacobianMatrix[6] - jacobianMatrix[3] * jacobianMatrix[8])
433                                 + jacobianMatrix[2] * (jacobianMatrix[3] * jacobianMatrix[7] - jacobianMatrix[4] * jacobianMatrix[6]);
434           break;
435         default:
436           where("GeomMapData::computeJacobianDeterminant()");
437           error("dim_not_in_range", 1, 3);
438         }
439       differentialElement = std::abs(jacobianDeterminant);
440       return jacobianDeterminant;
441     }
442 
443   //case eltDim < spaceDim : choose as determinant the sqrt(abs(det(Jt*J))), determinant of the metric tensor
444   Matrix<real_t> JtJ = transpose(jacobianMatrix)*jacobianMatrix;
445   switch (elementDim)
446     {
447     case 1:
448       jacobianDeterminant = std::sqrt(std::abs(JtJ[0]));
449       break;
450     case 2:
451       jacobianDeterminant = std::sqrt(std::abs(JtJ[0] * JtJ[3] - JtJ[1] * JtJ[2]));
452       break;
453     default:
454       where("GeomMapData::computeJacobianDeterminant()");
455       error("dim_not_in_range", 1, 2);
456     }
457   computeDifferentialElement();
458   return jacobianDeterminant;
459 }
460 
461 /*
462 --------------------------------------------------------------------------------
463   invertJacobianMatrix inverts Jacobian Matrix !
464   note that this function also sets the jacobian determinant and the differential element
465   Jacobian may not be a square matrix (spdim x eldim matrix with spdim > eldim)
466   in that case the pseudo inverse (Jt * J)^-1 * Jt (eldim x spdim matrix) is returned
467   and the differential element is computed using computeDifferentialElement function
468 --------------------------------------------------------------------------------
469 */
invertJacobianMatrix()470 void GeomMapData::invertJacobianMatrix()
471 {
472   dimen_t elDim = jacobianMatrix.numberOfColumns();
473   if (jacobianMatrix.size() == 0) { error("geoelt_noJacobian"); } //compute jacobian matrix before
474   real_t det = 0.;
475   Matrix<real_t>& jm = jacobianMatrix, &invjm = inverseJacobianMatrix;
476   if (spaceDim == elDim)
477     {
478       if (invjm.size() != dimen_t(spaceDim * spaceDim)) { invjm = Matrix<real_t>(spaceDim, spaceDim, 0.); }
479 
480       switch (spaceDim)
481         {
482         case 1:
483           det = jm[0];
484           if (std::abs(det) < theZeroThreshold) { error("geoelt_nulldet", det, theZeroThreshold); }
485           invjm[0] = 1. / det;
486           break;
487         case 2:
488           det = jm[0] * jm[3] - jm[1] * jm[2];
489           if (std::abs(det) < theZeroThreshold) { error("geoelt_nulldet", det, theZeroThreshold); }
490           invjm[0] = jm[3] / det;
491           invjm[3] = jm[0] / det;
492           invjm[1] = -jm[1] / det;
493           invjm[2] = -jm[2] / det;
494           break;
495         case 3:
496           // set 1st column to signed cofactors of 1st row
497           invjm[0] = jm[4] * jm[8] - jm[5] * jm[7];
498           invjm[3] = jm[5] * jm[6] - jm[3] * jm[8];
499           invjm[6] = jm[3] * jm[7] - jm[4] * jm[6];
500           // compute determinant
501           det = jm[0] * invjm[0] + jm[1] * invjm[3] + jm[2] * invjm[6];
502           // singular matrix ?
503           if (std::abs(det) < theZeroThreshold) { error("geoelt_nulldet", det, theZeroThreshold); }
504           // divide 1st column by determinant
505           invjm[0] = invjm[0] / det;
506           invjm[3] = invjm[3] / det;
507           invjm[6] = invjm[6] / det;
508           // set 2nd column to signed cofactors of 2nd row divided by determinant
509           invjm[1] = (jm[2] * jm[7] - jm[1] * jm[8]) / det;
510           invjm[4] = (jm[0] * jm[8] - jm[2] * jm[6]) / det;
511           invjm[7] = (jm[1] * jm[6] - jm[0] * jm[7]) / det;
512           // set 3rd column to signed cofactors of 3rd row  divided by determinant
513           invjm[2] = (jm[1] * jm[5] - jm[2] * jm[4]) / det;
514           invjm[5] = (jm[2] * jm[3] - jm[0] * jm[5]) / det;
515           invjm[8] = (jm[0] * jm[4] - jm[1] * jm[3]) / det;
516           break;
517         }
518       jacobianDeterminant = det;
519       differentialElement = std::abs(det);
520     }
521   else  //non square jacobian, use pseudoinverse (Jt*J)^-1 * Jt (matrix eltdim x spdim)
522     {
523       Matrix<real_t> jmt=transpose(jm);
524       Matrix<real_t> jmtjm=jmt*jm;
525       inverseJacobianMatrix = inverse(jmtjm)*jmt;
526       switch (elementDim)
527         {
528         case 1:
529           jacobianDeterminant = std::sqrt(std::abs(jmtjm[0]));
530           break;
531         case 2:
532           jacobianDeterminant = std::sqrt(std::abs(jmtjm[0] * jmtjm[3] - jmtjm[1] * jmtjm[2]));
533           break;
534         default:
535           where("GeomMapData::invertJacobianDeterminant()");
536           error("dim_not_in_range", 1, 2);
537         }
538       computeDifferentialElement();  //compute the differential element
539     }
540 }
541 
542 /*
543 --------------------------------------------------------------------------------
544   differentialElement computation at the current point
545   used in computation of integrals over element
546 --------------------------------------------------------------------------------
547 */
548 //compute differential element assuming jacobian matrix and jacobian determinant are update
computeDifferentialElement()549 void GeomMapData::computeDifferentialElement()
550 {
551   dimen_t elDim = jacobianMatrix.numberOfColumns(); //in case of side of element, number of columns of jacobian is the side element dimension
552 
553   if (spaceDim == elDim)            // 3D volume integrals, 2D surface integrals, 1D line integrals
554     {
555       computeJacobianDeterminant();
556     }
557   else if (spaceDim == elDim + 1)  // 3d surface integrals (3D element face), 2D line integrals (2D element edge)
558     {
559       computeNormalVector();    // compute outward normal vector
560       differentialElement = std::sqrt(std::inner_product(normalVector.begin(), normalVector.end(),
561                                       normalVector.begin(), 0.));
562       normalize();              //normalize normal vector
563     }
564   else if (spaceDim == elDim + 2)   // 3d line integrals, compute length of tangent vector
565     {
566       differentialElement = std::sqrt(std::inner_product(jacobianMatrix.begin(), jacobianMatrix.end(),
567                                       jacobianMatrix.begin(), 0.));
568     }
569 }
570 
571 //compute differential element updating jacobian matrix and jacobian determinant
diffElement()572 real_t GeomMapData::diffElement()
573 {
574   computeJacobianMatrix();
575   if (spaceDim == elementDim)  //  Reference Element dimension is space dimension ('Volume Domain computation")
576     { invertJacobianMatrix(); }
577   else   //  Reference Element dimension is less than space dimension ('Side Domain computation")
578     {
579       computeDifferentialElement();
580       if(elementDim == spaceDim - 1) { normalize(); }
581     }
582   return differentialElement;
583 }
584 
585 //compute differential element on side, updating jacobian matrix and jacobian determinant
586 //and normalize the normal to side
diffElement(number_t side)587 real_t GeomMapData::diffElement(number_t side)
588 {
589   computeJacobianMatrix(side);
590   computeDifferentialElement();
591   if(jacobianMatrix.numberOfColumns() == geomElement_p->spaceDim() - 1) { normalize(); }
592   return differentialElement;
593 }
594 
595 /*
596 --------------------------------------------------------------------------------
597  compute metric tensor and its determinant for surface differential geometry
598  metric tensor is only defined for spDim=3 and elDim=2 : mt=J^tJ (matrix 2x2)
599 --------------------------------------------------------------------------------
600 */
computeMetricTensor()601 void GeomMapData::computeMetricTensor()
602 {
603   if (spaceDim != 3)  { error("3D_only","GeomMapData::computeMetricTensor"); }
604   if (elementDim != 2)  { error("geoelt_2D_only","GeomMapData::computeMetricTensor"); }
605   if (metricTensor.size() != 4) { metricTensor = Matrix<real_t>(2,2,0.); }
606   std::vector<real_t>::const_iterator it_jac = jacobianMatrix.begin();
607   std::vector<real_t>::iterator it_mt;
608   for (it_mt = metricTensor.begin(); it_mt != metricTensor.end(); it_mt++) { *it_mt = 0.; }
609   it_mt = metricTensor.begin();
610   for (dimen_t i = 0; i < spaceDim; i++)
611     {
612       *it_mt += *it_jac **it_jac;
613       *(it_mt + 1) += *(it_jac + 1) **it_jac++;
614       *(it_mt + 3) += *it_jac **it_jac++;
615     }
616   *(it_mt + 2) = *(it_mt + 1);
617   metricTensorDeterminant = *it_mt **(it_mt + 3) - *(it_mt + 1) **(it_mt + 2);
618 }
619 /*
620 --------------------------------------------------------------------------------
621  compute surface gradient gradS from 2D reference gradient (grad0, grad1)
622  (grad0, grad1)^t is reference gradient, gradS is output surface gradient
623     Compute z0 = mt^{-1} t0 and z1 = mt^{-1} t1
624      where t0, t1 are reference tangent vectors (columns of rectangular jacobian matrix)
625      and mt is the metric tensor : {mt}_ij = ti.tj
626     division by tensor matrix determinant is made further down in final linear combination
627  only 3D
628 --------------------------------------------------------------------------------
629 */
computeSurfaceGradient(real_t grad0,real_t grad1,std::vector<real_t> & gradS)630 void GeomMapData::computeSurfaceGradient(real_t grad0, real_t grad1, std::vector<real_t>& gradS)
631 {
632   std::vector<real_t> z0(spaceDim, 0.), z1(spaceDim, 0.);
633   std::vector<real_t>::iterator it_gs = gradS.begin(), it_mt = metricTensor.begin(),
634                                 it_jac = jacobianMatrix.begin(), it_z0 = z0.begin(), it_z1 = z1.begin();
635 
636   for (dimen_t i = 0; i < spaceDim; i++, it_jac += elementDim)
637     {
638       *it_z0++ = -*(it_mt + 1) **it_jac + *it_mt **(it_jac + 1);
639       *it_z1++ =  *(it_mt + 3) **it_jac - *(it_mt + 1) **(it_jac + 1);
640     }
641 
642   //gradS = grad0 z1 + grad1 z0
643   it_z0 = z0.begin();
644   it_z1 = z1.begin();
645   real_t a0 = grad0 / metricTensorDeterminant, a1 = grad1 / metricTensorDeterminant;
646   for (dimen_t i = 0; i < spaceDim; i++, it_z1++, it_z0++, it_gs++)
647     { *it_gs = a0 **it_z1 + a1 **it_z0; }
648 }
649 
650 /*
651 --------------------------------------------------------------------------------
652  print GeomMapadata
653 --------------------------------------------------------------------------------
654 */
print(std::ostream & os) const655 void GeomMapData::print(std::ostream& os) const
656 {
657   os<<"MeshElement pointer="<<geomElement_p;
658   if(theVerboseLevel>10) os<<" MeshElement : "<<(*geomElement_p)<<eol;
659   os<<"current point="<<currentPoint<<eol;
660   os<<"jacobianMatrix="<<jacobianMatrix<<eol;
661   os<<"jacobian Determinant="<<jacobianDeterminant<<eol;
662   os<<"differential element="<<differentialElement<<eol;
663   os<<"inverse jacobian Matrix="<< inverseJacobianMatrix<<eol;
664   os<<"normal vector="<<normalVector<<eol;
665   os<<"metric tensor="<<metricTensor<<eol;
666   os<<"metric tensor determinant="<<metricTensorDeterminant<<eol;
667 }
668 
operator <<(std::ostream & os,const GeomMapData & gmd)669 std::ostream& operator<<(std::ostream&os, const GeomMapData& gmd)
670 {
671   gmd.print(os);
672   return os;
673 }
674 
sideNV() const675 std::vector< Vector<real_t> >& GeomMapData::sideNV() const
676 {
677   if (sideNormalVectors.size()==0)
678     {
679       number_t ns=geomElement_p->numberOfSides();
680       sideNormalVectors.resize(ns);
681       for (number_t s=0; s<ns; s++)
682         {
683           sideNormalVectors[s]=geomElement_p->normalVector(s+1);
684           sideNormalVectors[s]/=norm2(sideNormalVectors[s]);
685         }
686     }
687   return sideNormalVectors;
688 }
689 
690 } // end of namespace xlifepp
691