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