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 GeomElement.cpp
19 \authors D.Martin, E. Lunéville, N. Kielbasiewicz
20 \since 14 apr 2012
21 \date 5 jul 2013
22
23 \brief Implementation of xlifepp::GeomElement classes and functionnalities
24 */
25
26 #include "GeomElement.hpp"
27 #include "Mesh.hpp"
28
29 namespace xlifepp
30 {
31
32 //===========================================================================
33 // GeomElement member functions and related external functions
34 //===========================================================================
35
36 //construct a plain element from ReferenceElement & space dimension
GeomElement(const Mesh * msh,const RefElement * ref,dimen_t d,number_t n)37 GeomElement::GeomElement(const Mesh* msh, const RefElement* ref, dimen_t d, number_t n)
38 : mesh_p(msh), number_(n), twin_p(0)
39 {
40 meshElement_p = new MeshElement(ref, d, n);
41 materialId=0; domainId=0;
42 theta=0; phi=0;
43 color=0; flag=0;
44 }
45
46 //construct a side element from GeomElement and a side number
GeomElement(GeomElement * parent,number_t sideNum,number_t index)47 GeomElement::GeomElement(GeomElement* parent, number_t sideNum, number_t index)
48 : number_(index), twin_p(0)
49 {
50 mesh_p = parent->mesh_p;
51 parentSides_.push_back(GeoNumPair(parent, sideNum));
52 meshElement_p = 0;
53 materialId=0; domainId=0;
54 theta=0; phi=0.;
55 color=0;flag=0;
56 }
57
58 //copy constructor
GeomElement(const GeomElement & ge)59 GeomElement::GeomElement(const GeomElement& ge)
60 {
61 meshElement_p = 0;
62 if(ge.meshElement_p != 0) { meshElement_p = new MeshElement(*ge.meshElement_p);}
63 if(ge.parentSides_.size() > 0) { parentSides_ = ge.parentSides_; }
64 number_ = ge.number_;
65 mesh_p = ge.mesh_p;
66 materialId = ge.materialId;
67 domainId=ge.domainId;
68 theta=ge.theta; phi=ge.phi;
69 color=ge.color;flag=ge.flag;
70 twin_p = ge.twin_p;
71 }
72
73 //assignment operator
operator =(const GeomElement & ge)74 GeomElement& GeomElement::operator=(const GeomElement& ge)
75 {
76 if(this == &ge) { return *this; }
77 if(meshElement_p != 0) { delete meshElement_p; }
78 meshElement_p = 0;
79 if(ge.meshElement_p != 0) { meshElement_p = new MeshElement(*ge.meshElement_p); }
80 parentSides_.clear();
81 if(ge.parentSides_.size() > 0) { parentSides_ = ge.parentSides_; }
82 number_ = ge.number_;
83 materialId = ge.materialId;
84 domainId=ge.domainId;
85 theta=ge.theta; phi=ge.phi;
86 color=ge.color; flag=ge.flag;
87 twin_p = ge.twin_p;
88 return *this;
89 }
90
91 //delete meshElement information
deleteMeshElement()92 void GeomElement::deleteMeshElement()
93 {
94 if(meshElement_p != 0) { delete meshElement_p; }
95 meshElement_p = 0;
96 }
97
98 //---------------------------------------------------------------------------
99 //build MeshElement structure for a side element if required
100 //---------------------------------------------------------------------------
buildSideMeshElement() const101 MeshElement* GeomElement::buildSideMeshElement() const
102 {
103 if(meshElement_p != 0) { return meshElement_p;} //already built
104 trace_p->push("GeomElement::buildSideMeshElement");
105
106 //new MeshElement
107 RefElement* ref = findRefElement(shapeType(), &refElement()->interpolation());
108 //meshElement_p = new MeshElement(ref, geomRefElement()->dim(), 1);
109 dimen_t dim=geomRefElement()->dim(); //case of mesh_p=0 (normally does not occur)
110 if(mesh_p!=0) { dim= mesh_p->spaceDim();}
111 meshElement_p = new MeshElement(ref,dim,1);
112 //set nodenumbers from sideDofNumbers of RefElement parent (assuming a Lagrange element)
113 GeomElement* parent = parentSides_[0].first;
114 number_t side = parentSides_[0].second;
115 if(parent->meshElement_p != 0) {
116 // set nodeNumbers and nodes
117 std::vector<number_t> locnum = parent->refElement()->sideDofNumbers_[side - 1]; //local node numbering on side
118 size_t lns = locnum.size();
119 meshElement_p->nodeNumbers.resize(lns);
120 meshElement_p->nodes.resize(lns);
121 for(number_t i = 0; i < lns; i++) {
122 meshElement_p->nodeNumbers[i] = parent->meshElement_p->nodeNumbers[locnum[i] - 1];
123 meshElement_p->nodes[i] = parent->meshElement_p->nodes[locnum[i] - 1];
124 }
125 // set vertexNumbers
126 const std::vector<number_t>& svn = parent->geomRefElement()->sideVertexNumbers()[side - 1];
127 for(number_t i = 0; i < svn.size(); i++)
128 { meshElement_p->vertexNumbers[i] = parent->meshElement_p->vertexNumber(svn[i]); }
129 //update measures
130 meshElement_p->computeMeasures();
131 //update linearMap flag
132 if(!meshElement_p->linearMap) meshElement_p->linearMap=meshElement_p->checkLinearMap();
133 trace_p->pop();
134 return meshElement_p;
135 }
136 // parent has no MeshElement structure, go to grand parent (case of a side of side, edge in 3D)
137 number_t sideOfSide = parent->parentSides_[0].second;
138 parent = parent->parentSides_[0].first;
139 if(parent->meshElement_p == 0) { error("geoelt_sosos", "GeomElement::buildSideMeshElement"); } //stop recursion of side of side
140 // set nodeNumbers and nodes
141 number_t sos = std::abs(parent->geomRefElement()->sideOfSideNumber(sideOfSide, side));
142 std::vector<number_t> locnum = parent->refElement()->sideOfSideDofNumbers_[sos - 1]; //local node numbering on side of side
143 size_t lns = locnum.size();
144 meshElement_p->nodeNumbers.resize(lns);
145 meshElement_p->nodes.resize(lns);
146 for(number_t i = 0; i < lns; i++) {
147 meshElement_p->nodeNumbers[i] = parent->meshElement_p->nodeNumbers[locnum[i] - 1];
148 meshElement_p->nodes[i] = parent->meshElement_p->nodes[locnum[i] - 1];
149 }
150 //set vertexNumbers
151 const std::vector<number_t>& svn = parent->geomRefElement()->sideOfSideVertexNumbers()[sos - 1];
152 for(number_t i = 0; i < svn.size(); i++) { meshElement_p->vertexNumbers[i] = parent->meshElement_p->vertexNumber(svn[i]); }
153 //update measures
154 meshElement_p->computeMeasures();
155 //update linearMap flag
156 if(!meshElement_p->linearMap) meshElement_p->linearMap=meshElement_p->checkLinearMap();
157
158 trace_p->pop();
159 return meshElement_p;
160 }
161
162 //---------------------------------------------------------------------------
163 // complex accessors
164 //---------------------------------------------------------------------------
165 //return i-th parent, return 0 if not a side element
parent(number_t i) const166 const GeomElement* GeomElement::parent(number_t i) const
167 {
168 if(i < parentSides_.size()) { return parentSides_[i].first; }
169 else { return 0; }
170 }
171
172 //return i-th parent and its side as a GeoNumPair, (0,0) if not a side element
parentSide(number_t i) const173 const GeoNumPair GeomElement::parentSide(number_t i) const
174 {
175 if(i < parentSides_.size()) { return parentSides_[i]; }
176 else { return GeoNumPair(static_cast<GeomElement*>(0), 0); }
177 }
178
179 //return first parent in a domain - not optimized
parentInDomain(const MeshDomain * mdom) const180 const GeomElement* GeomElement::parentInDomain(const MeshDomain* mdom) const
181 {
182 if(mdom==0) return parent(); //no domain return first parent
183 std::vector<GeoNumPair>::const_iterator itp=parentSides_.begin();
184 for(; itp!=parentSides_.end(); ++itp)
185 {
186 const GeomElement* gelt=itp->first;
187 std::vector<GeomElement*>::const_iterator itg=mdom->geomElements.begin(), itge=mdom->geomElements.end();
188 while(itg!=itge) //loop on domain elements - may be expansive
189 {
190 if(*itg==gelt) return gelt;
191 itg++;
192 }
193 }
194 return 0;
195 }
196
197 //return meshElement_p if not a null pointer
meshElement() const198 const MeshElement* GeomElement::meshElement() const
199 {
200 //if (meshElement_p == 0) { error("geoelt_not_meshelement"); }
201 return meshElement_p;
202 }
203
204 //return meshElement_p if not a null pointer (writable)
meshElement()205 MeshElement* GeomElement::meshElement()
206 {
207 //if (meshElement_p == 0) { error("geoelt_not_meshelement"); }
208 return meshElement_p;
209 }
210
211 //return space dimension of the element
elementDim() const212 dimen_t GeomElement::elementDim() const
213 {
214 if(parentSides_.size() > 0 && parentSides_[0].first->elementDim()==1) return 0; //case of a 0 dim element !!!
215 return geomRefElement()->dim();
216 }
217
218 //return space dimension, i.e nodes dimension
spaceDim() const219 dimen_t GeomElement::spaceDim() const
220 {
221 return mesh_p->spaceDim();
222 }
223
224 //return reference element if i=0 else refelement of side i
refElement(number_t i) const225 const RefElement* GeomElement::refElement(number_t i) const
226 {
227 if(meshElement_p != 0) { return meshElement_p->refElement(i); }
228 // side element with no MeshElement structure,
229 return parentSides_[0].first->refElement(parentSides_[0].second)->refElement(i);
230 }
231
232 // returns number of vertices of element
numberOfVertices() const233 number_t GeomElement::numberOfVertices() const
234 {
235 if(meshElement_p != 0) { return meshElement_p->vertexNumbers.size(); }
236 if(elementDim() < 1) { return 1; } // one vertex for a point element
237 return geomRefElement()->nbVertices();
238 }
239
240 // returns number of nodes of element
numberOfNodes() const241 number_t GeomElement::numberOfNodes() const
242 {
243 if(meshElement_p != 0) { return meshElement_p->nodes.size(); }
244 if(elementDim() < 1) { return 1; } //1 node for a point element
245 return refElement()->nbDofs(); //nb of dofs is the number of nodes for a Lagrange element
246 }
247
248 // returns number of sides (faces in 3D, edges in 2D)
numberOfSides() const249 number_t GeomElement::numberOfSides() const
250 {
251 if(meshElement_p != 0) {return meshElement_p->numberOfSides(); }
252 if(elementDim() < 1) { return 0; } //0 sides for a point element
253 return geomRefElement()->nbSides();
254 }
255
256 // returns number of side of sides (edges in 3D)
numberOfSideOfSides() const257 number_t GeomElement::numberOfSideOfSides() const
258 {
259 if(meshElement_p != 0) { return meshElement_p->numberOfSideOfSides(); }
260 if(elementDim() < 1) { return 0; } //0 sides of sides for a point element
261 return geomRefElement()->nbSideOfSides();
262 }
263
264 // return the shape type of element (i=0) and its sides (_segment, _triangle, ...)
shapeType(number_t i) const265 ShapeType GeomElement::shapeType(number_t i) const
266 {
267 if(meshElement_p != 0) { return meshElement_p->shapeType(i); }
268 return geomRefElement()->shapeType(i);
269 }
270
271 // return the global number of vertex i (i=1,...)
vertexNumber(number_t i) const272 number_t GeomElement::vertexNumber(number_t i) const
273 {
274 if(meshElement_p != 0) { return meshElement_p->vertexNumber(i); }
275 // is a side element, go to parent
276 GeomElement* parent = parentSides_[0].first;
277 number_t sideNum = parentSides_[0].second;
278 if(parent->meshElement_p != 0)
279 {
280 return parent->meshElement_p->vertexNumber(parent->meshElement_p->geomRefElement()->sideVertexNumbers()[sideNum - 1][i - 1]);
281 }
282
283 // is a side of side element, go to grandparent
284 number_t sideNumgp = parent->parentSides_[0].second;
285 parent = parent->parentSides_[0].first;
286 if(parent->meshElement_p == 0) { error("geoelt_sosos", "GeomElement::vertexNumber"); }
287 number_t s = std::abs(parent->meshElement_p->geomRefElement()->sideOfSideNumber(sideNum, sideNumgp)); //sideofside number
288 return parent->meshElement_p->vertexNumber(parent->meshElement_p->geomRefElement()->sideOfSideVertexNumbers()[s - 1][i - 1]);
289 }
290
291 // return the global number of node i (i=1,...)
nodeNumber(number_t i) const292 number_t GeomElement::nodeNumber(number_t i) const
293 {
294 if(meshElement_p != 0) { return meshElement_p->nodeNumbers[i-1]; }
295 // is a side element, go to parent
296 GeomElement* parent = parentSides_[0].first;
297 number_t sideNum = parentSides_[0].second;
298 if(parent->meshElement_p != 0)
299 {
300 return parent->meshElement_p->nodeNumber(parent->meshElement_p->refElement()->sideDofNumbers_[sideNum - 1][i - 1]);
301 }
302
303 // is a side of side element, go to grandparent
304 number_t sideNumgp = parent->parentSides_[0].second;
305 parent = parent->parentSides_[0].first;
306 if(parent->meshElement_p == 0) { error("geoelt_sosos", "GeomElement::nodeNumber"); }
307 number_t s = std::abs(parent->meshElement_p->geomRefElement()->sideOfSideNumber(sideNum, sideNumgp)); //sideofside number
308 return parent->meshElement_p->nodeNumber(parent->meshElement_p->refElement()->sideOfSideDofNumbers_[s - 1][i - 1]);
309 }
310
311 // return the global numbers of vertices (s=0) or the global numbers of vertices on side s
vertexNumbers(number_t s) const312 std::vector<number_t> GeomElement::vertexNumbers(number_t s) const
313 {
314 if(s == 0) //global numbers of vertices
315 {
316 if(meshElement_p != 0) { return meshElement_p->vertexNumbers; }
317 std::vector<number_t> vnum(numberOfVertices());
318 for(number_t i = 0; i < numberOfVertices(); i++) { vnum[i] = vertexNumber(i + 1); }
319 return vnum;
320 }
321 // global numbers of vertices on side s
322 std::vector<number_t> vnum = geomRefElement()->sideVertexNumbers()[s - 1];
323 for(number_t i = 0; i < vnum.size(); i++) { vnum[i] = vertexNumber(vnum[i]); }
324 return vnum;
325 }
326
327 // return the global numbers of nodes (s=0) or the global numbers of nodes on side s
nodeNumbers(number_t s) const328 std::vector<number_t> GeomElement::nodeNumbers(number_t s) const
329 {
330 if(s == 0) //global numbers of nodes
331 {
332 if(meshElement_p != 0) { return meshElement_p->nodeNumbers;}
333 std::vector<number_t> vnum(numberOfNodes());
334 for(number_t i = 0; i < numberOfNodes(); i++) {vnum[i] = nodeNumber(i + 1);}
335 return vnum;
336 }
337 // global numbers of vertices on side s
338 std::vector<number_t> vnum = refElement()->sideDofNumbers_[s - 1];
339 for(number_t i = 0; i < vnum.size(); i++) { vnum[i] = nodeNumber(vnum[i]); }
340 return vnum;
341 }
342
343 //utility to encode element or side element : ascending order vertices global numbers as string
encodeElement(number_t s) const344 string_t GeomElement::encodeElement(number_t s) const
345 {
346 string_t key = "";
347 std::vector<number_t> vnum = vertexNumbers(s);
348 std::sort(vnum.begin(), vnum.end());
349 for(number_t i = 0; i < vnum.size(); i++) { key += tostring(vnum[i]) + " "; }
350 return key;
351 }
352
353 //utility to encode element or side element : ascending order nodes global numbers as string
encodeElementNodes(number_t s) const354 string_t GeomElement::encodeElementNodes(number_t s) const
355 {
356 string_t key = "";
357 std::vector<number_t> vnum = nodeNumbers(s);
358 std::sort(vnum.begin(), vnum.end());
359 for(number_t i = 0; i < vnum.size(); i++) { key += tostring(vnum[i]) + " "; }
360 return key;
361 }
362
363 //! return measure of element if side_no = 0, measure of side number side_no > 0
measure(const number_t sideNo) const364 real_t GeomElement::measure(const number_t sideNo) const
365 {
366 if(meshElement_p!=0) return meshElement_p->measure(sideNo);
367 if(sideNo==0) return parentSides_[0].first->measure(parentSides_[0].second);
368 buildSideMeshElement();
369 return meshElement_p->measure(sideNo);
370 }
371
372 //! characteristic size of element (computed if not available)
size() const373 real_t GeomElement::size() const
374 {
375 if(meshElement_p!=0) return meshElement_p->size;
376 buildSideMeshElement();
377 return meshElement_p->size;
378 }
379
380 //! centroid of element (computed if not available)
center() const381 Point GeomElement::center() const
382 {
383 if(meshElement_p==0) buildSideMeshElement();
384 return meshElement_p->center();
385 }
386
387
388 //test if a point belongs to current geom element (use MeshElement::contains)
contains(const std::vector<real_t> & p)389 bool GeomElement::contains(const std::vector<real_t>& p)
390 {
391 if(meshElement_p==0) buildSideMeshElement();
392 return meshElement_p->contains(p);
393 }
394
395 //project a point to current geom element (use MeshElement::projection), h is the distance to element
projection(const std::vector<real_t> & p,real_t & h)396 Point GeomElement::projection(const std::vector<real_t>& p, real_t& h)
397 {
398 if(meshElement_p==0) buildSideMeshElement();
399 return meshElement_p->projection(p,h);
400 }
401
402 //adjacent element by the side s, do not work for side elements!
403 //Mesh::sides_ must have been constructed before
404 //return element and its side number if exists, else return (0,0)
elementSharingSide(number_t s) const405 GeoNumPair GeomElement::elementSharingSide(number_t s) const
406 {
407 if(isSideElement()) { error("geoelt_isside", "elementSharingSide"); }
408 if(mesh_p->sides().size() == 0) { error("geoelt_sidesnotbuilt", "elementOnSide", "sides"); }
409 const std::vector<GeoNumPair>& parSide = mesh_p->sides()[meshElement()->sideNumbers[s - 1] - 1]->parentSides();
410 if(parSide.size() > 0 && parSide[0].first != this) { return parSide[0]; }
411 if(parSide.size() > 1 && parSide[1].first != this) { return parSide[1]; }
412 return GeoNumPair(static_cast<GeomElement*>(0), 0);
413 }
414
415 //adjacent element by the side of side s, only in 3D, do not work for side elements!
416 //when obs=true, list of elements sharing only the side of side s
417 //Mesh::sideOfSides_ must have been constructed before
418 //return element and its side number if exists, else return void
elementsSharingSideOfSide(number_t s,bool obs) const419 std::vector<GeoNumPair> GeomElement::elementsSharingSideOfSide(number_t s, bool obs) const
420 {
421 if(isSideElement()) { error("geoelt_isside", "elementSharingSideOfSide"); }
422 if(mesh_p->sideOfSides().size() == 0) { error("geoelt_sidesnotbuilt", "elementSharingSideOfSide", "sideOfSides"); }
423 std::map<GeomElement*, number_t> elts;
424
425 const std::vector<GeoNumPair>& par = mesh_p->sideOfSides()[meshElement()->sideOfSideNumbers[s - 1] - 1]->parentSides();
426 std::vector<GeoNumPair>::const_iterator itpar, itgpar;
427 for(itpar = par.begin(); itpar != par.end(); itpar++)
428 {
429 GeomElement* pelt = itpar->first;
430 if(!pelt->isSideElement())
431 {
432 where("GeomElement::elementsSharingSideOfSide");
433 error("geoelt_notside"); // parent element is not a side element
434 }
435 for(itgpar = pelt->parentSides().begin(); itgpar != pelt->parentSides().end(); itgpar++) // add grandparents
436 {
437 if(itgpar->first != this && elts.find(itgpar->first) == elts.end()) { elts[itgpar->first] = itgpar->second; } // add new grand parent element
438 }
439 }
440
441 // if obs=true remove adjacent elements by side
442 if(obs)
443 {
444 for(number_t s = 1; s <= numberOfSides(); s++) { elts.erase(elementSharingSide(s).first); }
445 }
446
447 // copy map in result vector
448 std::map<GeomElement*, number_t>::iterator itm;
449 std::vector<GeoNumPair> res(elts.size());
450 std::vector<GeoNumPair>::iterator itres = res.begin();
451 for(itm = elts.begin(); itm != elts.end(); itm++, itres++) { *itres = GeoNumPair(itm->first, itm->second); }
452 return res;
453 }
454
455 //list of adjacent elements by the vertex v, do not work for side elements!
456 //when obv=true, list of elements sharing only the vertex v
457 //Mesh::vertexElements_ must have been constructed before
458 //return a vector of GeoNumPair, may be a void list if there is no adjacent element
elementsSharingVertex(number_t v,bool obv) const459 std::vector<GeoNumPair> GeomElement::elementsSharingVertex(number_t v, bool obv) const
460 {
461 if(isSideElement()) { error("geoelt_isside", "elementsOnVertex"); }
462 if(mesh_p->vertexElements().size() == 0) { error("geoelt_sidesnotbuilt", "elementsOnVertex", "vertexElement"); }
463 const std::vector<GeoNumPair>& elts = mesh_p->vertexElements()[vertexNumber(v) - 1]; //list of all elements sharing vertex v
464 std::vector<GeoNumPair> res(elts.size() - 1);
465 std::vector<GeoNumPair>::const_iterator itelts;
466 std::vector<GeoNumPair>::iterator itres = res.begin();
467 for(itelts = elts.begin(); itelts != elts.end(); itelts++)
468 {
469 if((*itelts).first != this) {*itres = *itelts; itres++;}
470 }
471 if(!obv) { return res; }
472
473 // if obv=true remove adjacent elements by side or side by side
474 std::map<GeomElement*, number_t> selts;
475 std::vector<GeoNumPair>::iterator itg;
476 for(number_t sos = 1; sos <= numberOfSideOfSides(); sos++)
477 {
478 std::vector<GeoNumPair> soselts = elementsSharingSideOfSide(sos); //elements sharing side of side sos
479 for(itg = soselts.begin(); itg != soselts.end(); itg++) { selts[itg->first] = itg->second; }
480 }
481 std::vector<GeoNumPair> res2;
482 for(itres = res.begin(); itres != res.end(); itres++)
483 {
484 if(selts.find(itres->first) == selts.end()) { res2.push_back(*itres); }
485 }
486 return res2;
487 }
488
489
490 // split mesh element in first order elements (P1) and return split elements in a list
splitP1() const491 std::vector<GeomElement*> GeomElement::splitP1() const
492 {
493 std::vector<GeomElement*> listel;
494 if(meshElement_p == 0)
495 {
496 warning("free_warning", "try to split a side element in GeomElement::split, nothing is done");
497 return listel;
498 }
499
500 if(meshElement_p->order() == 1 && meshElement_p->isSimplex()) //no new element, copy of pointer
501 {
502 GeomElement* geoelt= new GeomElement(*this);
503 listel.push_back(geoelt);
504 return listel;
505 }
506 // split element
507 std::vector<std::vector<number_t> > subeltnum=meshElement_p->refElement()->splitP1();
508 std::vector<std::vector<number_t> >::iterator ite;
509 Interpolation* intp=findInterpolation(_Lagrange, _standard, 1,_H1);
510 RefElement* refelt=0;
511 if(meshElement_p->elementDim()==1) refelt=findRefElement(_segment,intp);
512 if(meshElement_p->elementDim()==2) refelt=findRefElement(_triangle,intp);
513 if(meshElement_p->elementDim()==3) refelt=findRefElement(_tetrahedron,intp);
514 for(ite=subeltnum.begin(); ite!=subeltnum.end(); ite++)
515 {
516 GeomElement* geoelt= new GeomElement(0, refelt,mesh_p->spaceDim(), 0); //update later mesh pointer and number
517 listel.push_back(geoelt);
518 //update meshElement
519 MeshElement* melt=geoelt->meshElement_p;
520 melt->firstOrderParent_= meshElement_p;
521 number_t nbnodes=ite->size();
522 melt->nodeNumbers.resize(nbnodes);
523 melt->nodes.resize(nbnodes);
524 std::vector<number_t>::iterator itn, itk=melt->nodeNumbers.begin();
525 std::vector<Point*>::iterator itp=melt->nodes.begin();
526 for(std::vector<number_t>::iterator itn=ite->begin(); itn!=ite->end(); itn++,itk++,itp++)
527 {
528 *itk=meshElement_p->nodeNumbers[*itn-1];
529 *itp=meshElement_p->nodes[*itn-1];
530 }
531 melt->vertexNumbers=melt->nodeNumbers;
532 melt->computeMeasures();
533 melt->computeOrientation();
534 }
535 return listel;
536 }
537
538 /*
539 // split mesh element in first order elements of same shape and return split elements in a list
540 std::vector<GeomElement*> GeomElement::splitO1() const
541 {
542 std::vector<GeomElement*> listel;
543 if(meshElement_p == 0)
544 {
545 warning("free_warning", "try to split a side element in GeomElement::split, nothing is done");
546 return listel;
547 }
548 if(meshElement_p->order() == 1) //no new element, copy of pointer
549 {
550 GeomElement* geoelt= new GeomElement(*this);
551 listel.push_back(geoelt);
552 return listel;
553 }
554 // split element
555 std::vector<std::pair<ShapeType,std::vector<number_t> > > subeltnum = meshElement_p->refElement()->splitO1();
556 std::vector<std::pair<ShapeType,std::vector<number_t> > >::iterator ite;
557 Interpolation* intp=findInterpolation(_Lagrange, _standard, 1,_H1);
558 RefElement* refelt=0;
559 for(ite=subeltnum.begin(); ite!=subeltnum.end(); ite++)
560 {
561 refelt=findRefElement(ite->first,intp);
562 GeomElement* geoelt= new GeomElement(0, refelt,mesh_p->spaceDim(), 0); //update later mesh pointer and number
563 listel.push_back(geoelt);
564 //update meshElement
565 MeshElement* melt=geoelt->meshElement_p;
566 melt->firstOrderParent_= meshElement_p;
567 number_t nbnodes=(ite->second).size();
568 melt->nodeNumbers.resize(nbnodes);
569 melt->nodes.resize(nbnodes);
570 std::vector<number_t>::iterator itn, itk=melt->nodeNumbers.begin();
571 std::vector<Point*>::iterator itp=melt->nodes.begin();
572 for(std::vector<number_t>::iterator itn=(ite->second).begin(); itn!=(ite->second).end(); itn++,itk++,itp++)
573 {
574 *itk=meshElement_p->nodeNumbers[*itn-1];
575 *itp=meshElement_p->nodes[*itn-1];
576 }
577 melt->vertexNumbers=melt->nodeNumbers;
578 melt->computeMeasures();
579 melt->computeOrientation();
580 }
581 return listel;
582 }
583 */
584
585 //! return outward normal vector on side
normalVector(number_t s) const586 std::vector<real_t> GeomElement::normalVector(number_t s) const
587 {
588 if(meshElement_p==0) buildSideMeshElement();
589 return meshElement_p->normalVector(s);
590 }
591
592 //! return outward normal vector on side
tangentVector(number_t s) const593 std::vector<real_t> GeomElement::tangentVector(number_t s) const
594 {
595 if(meshElement_p==0) buildSideMeshElement();
596 return meshElement_p->tangentVector(s);
597 }
598
599 //---------------------------------------------------------------------------
600 //print utilities
601 //---------------------------------------------------------------------------
print(std::ostream & os) const602 void GeomElement::print(std::ostream& os) const
603 {
604 if(theVerboseLevel == 0) { return; }
605 if(meshElement_p != 0)
606 {
607 os << words("geometric element") << " " << number_ <<" (material "<<materialId<<", color "<<color<<") : " << (*meshElement_p);
608 if(theVerboseLevel < 2) return;
609
610 // print adjacent elements if possible
611 if(mesh_p != 0 && mesh_p->sides().size() > 0 && !isSideElement())
612 {
613 os << "\n " << words("adjacent elements") << " " << words("by side") << " :";
614 bool first=true;
615 for(number_t s = 1; s <= numberOfSides(); s++)
616 {
617 GeoNumPair g = elementSharingSide(s);
618 if(g.first != 0)
619 {
620 if(!first) os << ",";
621 else first = false;
622 os << " " << s << " -> " << g.first->number();
623 }
624 }
625 }
626 if(mesh_p != 0 && mesh_p->sideOfSides().size() > 0 && !isSideElement())
627 {
628 os << "\n " << words("adjacent elements") << " " << words("by side of side") << " :";
629 bool first = true;
630 for(number_t s = 1; s <= numberOfSideOfSides(); s++)
631 {
632 const std::vector<GeoNumPair> elts = elementsSharingSideOfSide(s);
633 if(elts.size() > 0)
634 {
635 if(!first) os << ",";
636 else first = false;
637 os << " " << s << "->";
638 for(number_t e = 0; e < elts.size(); e++) { os << " " << elts[e].first->number(); }
639 }
640 }
641 }
642 if(mesh_p != 0 && mesh_p->vertexElements().size() > 0 && !isSideElement())
643 {
644 os << "\n " << words("adjacent elements") << " " << words("by vertex") << " :";
645 bool first = true;
646 for(number_t v = 1; v <= numberOfVertices(); v++)
647 {
648 const std::vector<GeoNumPair> elts = elementsSharingVertex(v);
649 if(elts.size() > 0)
650 {
651 if(!first) os << ",";
652 else first = false;
653 os << " " << v << "->";
654 for(number_t e = 0; e < elts.size(); e++) { os << " " << elts[e].first->number(); }
655 }
656 }
657 }
658 }
659 if(isSideElement())
660 {
661 if (meshElement_p != 0) os << std::endl;
662 os << words("geometric side element") << " " << number_ << " : ";
663 for(number_t i = 0; i < parentSides_.size(); i++)
664 {
665 if (i > 0) { os << ", ";}
666 os << words("side") << " " << parentSides_[i].second
667 << " " << words("of element") << " " << parentSides_[i].first->number_;
668 if(theVerboseLevel > 2) { os << "\n " << (*parentSides_[i].first); }
669 }
670 }
671 }
672
673 //---------------------------------------------------------------------------
674 // external functions involving GeomElement
675 //---------------------------------------------------------------------------
676 //overload operators < and == to sort elements using STL vector sort method
operator ==(const GeomElement & x,const GeomElement & y)677 bool operator== (const GeomElement& x, const GeomElement& y)
678 { return (x.number() == y.number()); }
679
operator <(const GeomElement & x,const GeomElement & y)680 bool operator< (const GeomElement& x, const GeomElement& y)
681 { return x.number() < y.number(); }
682
683 //output stream operator <<
operator <<(std::ostream & os,const GeomElement & geo)684 std::ostream& operator<< (std::ostream& os, const GeomElement& geo)
685 {
686 geo.print(os);
687 return os;
688 }
689
690 /*! create an index of all sides of a list of elements
691 very similar to buildSides function except the fact that no new side element are created
692 do not clear current sideIndex !
693 */
createSideIndex(const std::vector<GeomElement * > & elements,std::map<string_t,std::vector<GeoNumPair>> & sideIndex)694 void createSideIndex(const std::vector<GeomElement*>& elements,
695 std::map<string_t,std::vector<GeoNumPair> >& sideIndex)
696 {
697 trace_p->push("createSideIndex of mesh");
698 std::vector<GeomElement*>::const_iterator itel=elements.begin();
699 for(; itel != elements.end(); itel++)
700 {
701 MeshElement* melt = (*itel)->meshElement();
702 std::map<string_t,std::vector<GeoNumPair> >::iterator itsn;
703 if(melt!=0 && melt->elementDim() == melt->spaceDim()) //plain element
704 if(!(*itel)->isSideElement()) //not side element
705 {
706 for(number_t s = 0; s < (*itel)->numberOfSides(); s++) // loop on element sides
707 {
708 string_t key = (*itel)->encodeElement(s + 1); // encode vertex numbers of side s
709 itsn = sideIndex.find(key); // search side in sideIndex map
710 if(itsn == sideIndex.end()) sideIndex[key]=std::vector<GeoNumPair>(1,GeoNumPair(*itel,s+1));
711 else sideIndex[key].push_back(GeoNumPair(*itel,s+1));
712 } // end for (number_t s
713 }// end if(!itel
714 } //end for (itel
715 trace_p->pop();
716 }
717
718 /*! create an index of all side elements in given side element list, do not clear current sideEltIndex !
719 */
createSideEltIndex(const std::vector<GeomElement * > & elements,std::map<string_t,GeomElement * > & sideEltIndex)720 void createSideEltIndex(const std::vector<GeomElement*>& elements, std::map<string_t, GeomElement* >& sideEltIndex)
721 {
722 trace_p->push("Mesh::createSideEltIndex");
723 std::map<string_t, GeomElement* >::iterator its;
724 std::vector<GeomElement*>::const_iterator itel=elements.begin();
725 for(; itel != elements.end(); itel++)
726 {
727 if((*itel)->isSideElement()) //side element
728 {
729 string_t key = (*itel)->encodeElement(); // encode vertex numbers of side s
730 its = sideEltIndex.find(key); // search side in sideEltIndex map
731 if(its == sideEltIndex.end()) sideEltIndex[key] = *itel; //insert sidelt in sideEltIndex map
732 }// end if(!itel
733 } //end for (itel
734 trace_p->pop();
735 }
736
737 //===========================================================================
738 // MeshElement member functions and related external functions
739 //===========================================================================
740 //default constructor
MeshElement()741 MeshElement::MeshElement()
742 : refElt_p(0), index_(0), spaceDim_(0) {orientation = 0; geomMapData_p = 0; firstOrderParent_=0; linearMap=true;}
743
744 //basic constructor
MeshElement(const RefElement * re,dimen_t sdim,number_t n)745 MeshElement::MeshElement(const RefElement* re, dimen_t sdim, number_t n)
746 : refElt_p(re), index_(n), spaceDim_(sdim)
747 {
748 orientation = 0;
749 geomMapData_p = 0;
750 firstOrderParent_=0;
751 // Create arrays for global numbering ...
752 const GeomRefElement* gre_p = refElt_p->geomRefElem_p;
753 nodes.resize(refElt_p->nbPts()); // ... of node pointers
754 nodeNumbers.resize(refElt_p->nbPts()); // ... of node numbers
755 vertexNumbers.resize(gre_p->nbVertices()); // ... of vertices
756 sideNumbers.resize(gre_p->nbSides()); // ... of sides (faces in 3D, edges in 2D)
757 sideOfSideNumbers.resize(gre_p->nbSideOfSides()); // ... of faces
758 measures.resize(1 + gre_p->nbSides(), 0.); // ... of measures
759 linearMap = (refElt_p->isSimplex()) && (refElt_p->order()<2);
760 }
761
762 //check if linear map is available, return true if it is
checkLinearMap() const763 bool MeshElement::checkLinearMap() const
764 {
765 if(nodes.size()==0) return false; //prevent undefined nodes definition
766 std::vector<Point*>::const_iterator itn=nodes.begin();
767 dimen_t dn=(*itn)->dim();
768 if(dn==0) return false; //prevent unfinished nodes definition, nodes vector allocated but not filled
769 itn++;
770 for(;itn!=nodes.end();++itn)
771 if((*itn)->dim()!=dn) return false; //prevent partial nodes definition, nodes vector allocated but not completely filled
772
773 //build linear map f(x,y,z)=0+x*A+y*B+z*C
774 std::vector<number_t> sns=refElt_p->geomRefElem_p->simplexNodes(); //node numbers (>=1) defining first simplex of ref element
775 number_t d=sns.size()-1;
776 Point O = *nodes[sns[0]-1];
777 Point A = *nodes[sns[1]-1]-O;
778 Point B,C;
779 if(d>1) B= *nodes[sns[2]-1]-O;
780 if(d>2) C= *nodes[sns[3]-1]-O;
781 //test f(ref_node_i)==node_i
782 real_t eps=characteristicSize()/1000;
783 number_t i=0;
784 std::vector<RefDof*>::const_iterator itd=refElt_p->refDofs.begin();
785 for(;itd!=refElt_p->refDofs.end();++itd,++i)
786 {
787 std::vector<real_t> Q=(*itd)->point();
788 Point P = O + Q[0]*A;
789 if(d>1) P += Q[1]*B;
790 if(d>2) P += Q[2]*C;
791 if(dist(P,*nodes[i])>eps) return false;
792 }
793 return true;
794 }
795
796 // update node pointers vector from Mesh::nodes and nodeNumbers
797 // do not use if nodeNumbers has not to be built
setNodes(std::vector<Point> & points)798 void MeshElement::setNodes(std::vector<Point>& points)
799 {
800 for(number_t i = 0; i < nodeNumbers.size(); i++) { nodes[i] = &points[nodeNumbers[i] - 1]; }
801 //update linearMap flag
802 if(!linearMap) linearMap=checkLinearMap();
803 }
804
805 // return the global numbers of vertices of element (s=0), of side s>0
verticesNumbers(number_t s) const806 std::vector<number_t> MeshElement::verticesNumbers(number_t s) const
807 {
808 if(s == 0) { return vertexNumbers; }
809 //global numbers of vertices on side s
810 std::vector<number_t> vnum = geomRefElement()->sideVertexNumbers()[s - 1];
811 for(number_t i = 0; i < vnum.size(); i++) { vnum[i] = vertexNumber(vnum[i]); }
812 return vnum;
813 }
814
815 /*
816 --------------------------------------------------------------------------------
817 set measure of elements and its side and set orientation (sign of the jacobioan)
818 --------------------------------------------------------------------------------
819 */
computeMeasures()820 void MeshElement::computeMeasures()
821 {
822 computeMeasure();
823 computeMeasureOfSides();
824 centroid = center();
825 size = characteristicSize();
826 }
827
828 //compute a characteristic size assuming measures of element and sides are up to date
829 // for simplex : diameter of the circumscribed ball
830 // other cases : max of length of segments joining two vertices
characteristicSize() const831 real_t MeshElement::characteristicSize() const
832 {
833 number_t nbv=0;
834 switch(shapeType())
835 {
836 case _point :
837 case _segment : return measures[0];
838 case _triangle : return measures[1]* measures[2]* measures[3]/(2*measures[0]); //circumscribed circle diameter
839 case _tetrahedron: //circumscribed sphere diameter
840 {
841 real_t a=pointDistance(*nodes[0], *nodes[1]), a1=pointDistance(*nodes[2], *nodes[3]);
842 real_t b=pointDistance(*nodes[1], *nodes[2]), b1=pointDistance(*nodes[0], *nodes[3]);
843 real_t c=pointDistance(*nodes[0], *nodes[2]), c1=pointDistance(*nodes[1], *nodes[3]);
844 real_t aa1=a*a1, bb1=b*b1, cc1=c*c1, p=(aa1+bb1+cc1)/2;
845 return std::sqrt(p*(p-aa1)*(p-bb1)*(p-cc1))/(3*measures[0]);
846 }
847 case _quadrangle : nbv=4; break;
848 case _prism : nbv=6; break;
849 case _hexahedron : nbv=8; break;
850 case _pyramid : nbv=5; break;
851 default:
852 error("geoelt_noshapetype", shapeType(), "MeshElement::characteristicSize");
853 break;
854 }
855
856 //max of all segments joining two vertices
857 real_t h=0;
858 for(number_t i=0; i<nbv; i++)
859 for(number_t j=i+1; j<nbv; j++)
860 h=std::max(h, pointDistance(*nodes[i], *nodes[j]));
861 return h;
862 }
863
864 /*compute measure of elements (length, area or volume of implied assembly of straight simplices)
865 Should be called only for Lagrange elements, assuming vertices are first points of nodes vector
866 */
computeMeasure()867 void MeshElement::computeMeasure()
868 {
869 switch(shapeType())
870 {
871 case _point:
872 measures[0] = 1.; // Dirac
873 break;
874 case _segment:
875 measures[0] = pointDistance(*nodes[0], *nodes[1]);
876 break;
877 case _triangle:
878 measures[0] = triangleArea(*nodes[0], *nodes[1], *nodes[2]);
879 break;
880 case _quadrangle:
881 measures[0] = triangleArea(*nodes[0], *nodes[1], *nodes[2])
882 + triangleArea(*nodes[0], *nodes[2], *nodes[3]);
883 break;
884 case _tetrahedron:
885 measures[0] = tetrahedronVolume(*nodes[0], *nodes[1], *nodes[2], *nodes[3]);
886 break;
887 case _prism:
888 measures[0] = tetrahedronVolume(*nodes[0], *nodes[1], *nodes[5], *nodes[2])
889 + tetrahedronVolume(*nodes[2], *nodes[3], *nodes[5], *nodes[4])
890 + tetrahedronVolume(*nodes[0], *nodes[2], *nodes[4], *nodes[3]);
891 break;
892 case _hexahedron:
893 measures[0] = tetrahedronVolume(*nodes[0], *nodes[2], *nodes[7], *nodes[3])
894 + tetrahedronVolume(*nodes[3], *nodes[4], *nodes[7], *nodes[6])
895 + tetrahedronVolume(*nodes[0], *nodes[3], *nodes[6], *nodes[4])
896 + tetrahedronVolume(*nodes[2], *nodes[0], *nodes[5], *nodes[1])
897 + tetrahedronVolume(*nodes[1], *nodes[6], *nodes[5], *nodes[4])
898 + tetrahedronVolume(*nodes[2], *nodes[1], *nodes[4], *nodes[6]);
899 break;
900 case _pyramid:
901 measures[0] = tetrahedronVolume(*nodes[0], *nodes[1], *nodes[2], *nodes[4])
902 + tetrahedronVolume(*nodes[1], *nodes[2], *nodes[3], *nodes[4]);
903 break;
904 default:
905 error("geoelt_noshapetype", shapeType(), "MeshElement::computeMeasure");
906 break;
907 }
908 }
909
910 /*compute measure of side of elements (length, area or volume of implied assembly of straight simplices)
911 Should be called only for Lagrange elements, assuming vertices are first points of nodes vector
912 */
computeMeasureOfSides()913 void MeshElement::computeMeasureOfSides()
914 {
915 for(number_t s = 1; s <= numberOfSides(); s++)
916 {
917 //vertex local numbers on side s
918 const std::vector<number_t>& vn = geomRefElement()->sideVertexNumbers()[s - 1];
919
920 switch(shapeType(s))
921 {
922 case _point :
923 measures[s] = 0.;
924 break;
925 case _segment:
926 measures[s] = pointDistance(*nodes[vn[0] - 1], *nodes[vn[1] - 1]);
927 break;
928 case _triangle:
929 measures[s] = triangleArea(*nodes[vn[0] - 1], *nodes[vn[1] - 1], *nodes[vn[2] - 1]);
930 break;
931 case _quadrangle:
932 measures[s] = triangleArea(*nodes[vn[0] - 1], *nodes[vn[1] - 1], *nodes[vn[2] - 1])
933 + triangleArea(*nodes[vn[2] - 1], *nodes[vn[3] - 1], *nodes[vn[0] - 1]);
934 break;
935 default: error("geoelt_noshapetype", shapeType(s), "MeshElement::computeMeasureOfSides");
936 break;
937 }
938 }
939 }
940
941 /*
942 --------------------------------------------------------------------------------
943 compute element orientation
944 if necessary, a GeomMapData object is created but it is deleted at the end
945 if a GeomMapData object already exists, it is not deleted
946 if jacobianMatrix does not exist it is created from element centroid and then cleared
947 NOTE : when domain is a manifold (elementDim()< spaceDim_)
948 the orientation is computed using a general process, see setOrientationManifold, setOrientationBoundary
949 --------------------------------------------------------------------------------
950 */
computeOrientation()951 void MeshElement::computeOrientation()
952 {
953 if(geomMapData_p == 0) {geomMapData_p = new GeomMapData(this);}
954 std::vector<real_t>::const_iterator itc = geomRefElement()->centroid();
955 std::vector<real_t> center(itc, itc + geomRefElement()->dim());
956 geomMapData_p->computeJacobianMatrix(center);
957 orientation=0;
958 if(elementDim()==spaceDim_)
959 orientation = geomMapData_p->computeJacobianDeterminant() > 0 ? 1 : -1;
960 }
961
962 /*! return the center of element based on vertices : sum_i vertex(i) / nb_vertex */
center() const963 Point MeshElement::center() const
964 {
965 Point G=*nodes[0];
966 number_t n=verticesNumbers().size();
967 for(number_t i=1; i<n; i++) G+= *nodes[i];
968 return G/=n;
969 }
970
971 /*! return outward normal vector on side s (edge in 2D, face in 3D)
972 normal is computed from vertices of side, exact only for 1 order element
973 Is not normalized !
974 if s=0 return the normal to element using the jacobian and the orientation
975 */
normalVector(number_t s) const976 std::vector<real_t> MeshElement::normalVector(number_t s) const
977 {
978 dimen_t edim = elementDim();
979 if(s>0) //normal vector to a side
980 {
981 switch(edim)
982 {
983 case 1 : //for consistancy
984 {
985 return std::vector<real_t>(1,1.);
986 }
987
988 case 2 : //general formula that not assumes that element "lives" in R2
989 {
990 number_t ss=s+1;
991 if(s==numberOfSides()) ss=1;
992 Point S12=vertexOnSide(2,s)-vertexOnSide(1,s), S13=vertexOnSide(2,ss)-vertexOnSide(1,s);
993 return (dot(S12,S13)/dot(S12,S12)*S12-S13);
994 }
995
996 case 3 : //use cross product
997 {
998 Point S12=vertexOnSide(2,s)-vertexOnSide(1,s), S23=vertexOnSide(3,s)-vertexOnSide(2,s);
999 Point T=vertexOppositeToSide(s)-vertexOnSide(1,s);
1000 Point n=cross3D(S12,S23);
1001 if(dot(T,n) > 0) return -n;
1002 return n;
1003 }
1004
1005 default :
1006 where("MeshElement::normalVector(Number)");
1007 error("index_out_of_range","dimension",1,3);
1008 }
1009 }
1010
1011 //normal vector to element (edim should be <=2)
1012 if(edim==spaceDim()) // it is not a manifold, return as normal vector (0,1) for a 1D element or (0,0,1) for a 2D element
1013 {
1014 std::vector<real_t> n(edim+1,0.);
1015 n[edim]=1.;
1016 return n;
1017 }
1018 //case of a manifold, use jacobian and orientation
1019 if(geomMapData_p==0) geomMapData_p = new GeomMapData(this);
1020 if(geomMapData_p->normalVector.size()==0)
1021 {
1022 if(geomMapData_p->jacobianMatrix.size()==0) geomMapData_p->computeJacobianMatrix(center());
1023 geomMapData_p->computeNormalVector(); // compute unnormalized normal vector
1024 if(orientation==0)
1025 {
1026 where("MeshElement::normalVector(Number)");
1027 error("is_null",words("orientation"));
1028 }
1029 geomMapData_p->normalize(); // normalize normal vector
1030 }
1031 return geomMapData_p->normalVector;
1032 }
1033
1034 /*! return tangent vector on edge e (side in 2D, side on side in 3D)
1035 tangent vector is computed from vertices of edge, exact only for 1 order element
1036 */
tangentVector(number_t e) const1037 std::vector<real_t> MeshElement::tangentVector(number_t e) const
1038 {
1039 switch(elementDim())
1040 {
1041 case 2 : return vertexOnSide(2,e)-vertexOnSide(1,e);
1042 case 3 : return vertexOnSideOfSide(2,e)-vertexOnSideOfSide(1,e);
1043 default :
1044 where("MeshElement::tangentVector(Number)");
1045 error("dim_not_in_range",2,3);
1046 }
1047 return std::vector<real_t>(); //fake return
1048 }
1049
1050 //--------------------------------------------------------------------------------
1051 /*! test if a point belongs to current mesh element
1052 if element is a simplex and is one order , we use the map from element to ref element
1053 else the element is split in P1 elements and test is performed on each P1 sub element
1054 The tolerance is chosen as size(element)/1000
1055 */
1056 //--------------------------------------------------------------------------------
contains(const std::vector<real_t> & p)1057 bool MeshElement::contains(const std::vector<real_t>& p)
1058 {
1059 bool inelt = false;
1060 real_t tol = measure();
1061 if(tol==0.) {computeMeasure(); tol = measure();}
1062 tol=std::max(measure()/1000, theTolerance);
1063 dimen_t edim=elementDim();
1064 if(order()==1 && isSimplex())
1065 {
1066 if(p.size()==edim) //use inverse map
1067 {
1068 GeomMapData gd(this,p);
1069 Point q=gd.geomMapInverse(p);
1070 return refElement()->geomRefElement()->contains(q, tol);
1071 }
1072 else //p.size > elementDim
1073 {
1074 real_t s=0;
1075 if(edim==1) //use cross product S1S2 x S1P to check if P belongs to the line containing segment
1076 {
1077 Point p01=*nodes[1]-*nodes[0], p0=p-*nodes[0];
1078 s=norm2(crossProduct(p01,p0));
1079 if(s>tol) return false;
1080 real_t a=dot(p01,p0)/norm2(p01);
1081 return (a>-tol && a<1+tol);
1082 }
1083 if(edim==2) //use mix product (S1S2 x S1S3).S1P to check if P belongs to the plane containing triangle
1084 {
1085 Point n10=*nodes[1]-*nodes[0], n20=*nodes[2]-*nodes[0], p0= p-*nodes[0];
1086 Point u=crossProduct(n10,n20);
1087 s=std::abs(dot(u,p0));
1088 if(s>tol) return false;
1089 //use barycentric coordinates
1090 real_t nu=dot(u,u);
1091 real_t a= dot(crossProduct(p0,n20),u)/ nu;
1092 if(a<-tol || a>1+tol) return false;
1093 real_t b= dot(crossProduct(n10,p0),u)/ nu;
1094 if(b<-tol || b>1+tol) return false;
1095 real_t c=1-a-b;
1096 if(c<-tol || c>1+tol) return false;
1097 return true;
1098 }
1099 //old method
1100 // GeomMapData gd(this,p);
1101 // Point q=gd.geomMapInverse(p);
1102 // return= refElement()->geomRefElement()->contains(q, tol);
1103 }
1104 }
1105 //split in P1 elements
1106 std::vector<MeshElement*> eltsP1=splitP1();
1107 std::vector<MeshElement*>::iterator ite=eltsP1.begin();
1108 for(; ite!=eltsP1.end(); ite++)
1109 {
1110 if(!inelt && (*ite)->contains(p)) inelt=true;
1111 delete *ite;
1112 }
1113 return inelt;
1114 }
1115
1116 // projection of a point onto a geometric element
projection(const std::vector<real_t> & p,real_t & h) const1117 Point MeshElement::projection(const std::vector<real_t>& p, real_t& h) const
1118 {
1119 dimen_t edim=elementDim();
1120 if(p.size()==edim) //use reference element
1121 {
1122 GeomMapData gd(this,p);
1123 Point q=gd.geomMapInverse(p);
1124 Point r=refElement()->geomRefElement()->projection(q,h);
1125 return gd.geomMap(r);
1126 }
1127
1128 // case p.size()>elementDim(), use projection on one order element
1129 // !!! has to be extended in future for element of order greater than 1 !!!
1130 switch(edim)
1131 {
1132 case 1 : //projection on a segment [S1 S2]
1133 return projectionOnSegment(p,*nodes[0],*nodes[1],h);
1134 case 2 :
1135 {
1136 if(isSimplex()) return projectionOnTriangle(p,*nodes[0],*nodes[1],*nodes[2],h); //projection on a triangle [S1 S2 S3]
1137 else //split element in triangles
1138 {
1139 std::vector<MeshElement*> eltsP1=splitP1();
1140 std::vector<MeshElement*>::iterator ite=eltsP1.begin();
1141 h=theRealMax;
1142 real_t he;
1143 Point q, qe;
1144 for(; ite!=eltsP1.end(); ++ite)
1145 {
1146 std::vector<Point*>& ns = (*ite)->nodes;
1147 qe = projectionOnTriangle(p,*ns[0],*ns[1],*ns[2],he);
1148 if(he<h) {h=he; q=qe;}
1149 delete *ite;
1150 }
1151 return q;
1152 }
1153 }
1154 default :
1155 where("MeshElement::projection(Vector<Real>, Real)");
1156 error("index_out_of_range","dimension", 1, 2);
1157 }
1158 return Point();// dummy return
1159 }
1160
1161 // split mesh element in first order elements (P1) and return split elements in a list
1162 // it is a "clone" of std::vector<GeomElement*> GeomElement::splitP1() const
splitP1() const1163 std::vector<MeshElement*> MeshElement::splitP1() const
1164 {
1165 std::vector<MeshElement*> listel;
1166
1167 if(order() == 1 && isSimplex()) //no new element, copy of MeshElement
1168 {
1169 listel.push_back(new MeshElement(*this));
1170 return listel;
1171 }
1172 // split element
1173 std::vector<std::vector<number_t> > subeltnum=refElement()->splitP1();
1174 std::vector<std::vector<number_t> >::iterator ite;
1175 Interpolation* intp=findInterpolation(_Lagrange, _standard, 1,_H1);
1176 RefElement* refelt=0;
1177 if(elementDim()==1) refelt=findRefElement(_segment,intp);
1178 if(elementDim()==2) refelt=findRefElement(_triangle,intp);
1179 if(elementDim()==3) refelt=findRefElement(_tetrahedron,intp);
1180 for(ite=subeltnum.begin(); ite!=subeltnum.end(); ite++)
1181 {
1182 MeshElement* melt= new MeshElement(refelt,spaceDim_, 0); //update later mesh pointer and number
1183 listel.push_back(melt);
1184 melt->firstOrderParent_= this;
1185 number_t nbnodes=ite->size();
1186 melt->nodeNumbers.resize(nbnodes);
1187 melt->nodes.resize(nbnodes);
1188 std::vector<number_t>::iterator itn, itk=melt->nodeNumbers.begin();
1189 std::vector<Point*>::iterator itp=melt->nodes.begin();
1190 for(std::vector<number_t>::iterator itn=ite->begin(); itn!=ite->end(); itn++,itk++,itp++)
1191 {
1192 *itk=nodeNumbers[*itn-1];
1193 *itp=nodes[*itn-1];
1194 }
1195 melt->vertexNumbers=melt->nodeNumbers;
1196 melt->computeMeasures();
1197 melt->computeOrientation();
1198 }
1199 return listel;
1200 }
1201
1202 //--------------------------------------------------------------------------------
1203 // prints Geom Element characteristics and point numbers to opened ostream or default print file
1204 //--------------------------------------------------------------------------------
1205
print(std::ostream & os) const1206 void MeshElement::print(std::ostream& os) const
1207 {
1208 if(theVerboseLevel == 0) { return; }
1209 os << refElt_p->name() << ", orientation " << std::showpos << orientation << std::noshowpos<<", ";
1210 if(!linearMap) os<<" non";
1211 os<<" linear map";
1212 if(measures.size() > 0) { os << ", measure = " << measures[0]; }
1213
1214 if(theVerboseLevel < 2) { return; }
1215
1216 std::vector<number_t>::const_iterator it;
1217 os << "\n " << words("nodes") << " : ";
1218 for(number_t n = 0; n < nodeNumbers.size(); n++)
1219 {
1220 os << nodeNumbers[n] << " ";
1221 if(theVerboseLevel > 2)
1222 {
1223 os << "-> " << (*nodes[n]);
1224 if(n != nodeNumbers.size() - 1) { os << ", "; }
1225 }
1226 }
1227
1228 os << "\n " << words("vertices") << " : ";
1229 if(vertexNumbers.size() > 0 && vertexNumbers[0] > 0)
1230 {
1231 for(number_t n = 0; n < vertexNumbers.size(); n++)
1232 {
1233 os << vertexNumbers[n] << " ";
1234 if(theVerboseLevel > 2)
1235 {
1236 os << "-> " << (*nodes[n]);
1237 if(n != vertexNumbers.size() - 1) { os << ", "; }
1238 }
1239 }
1240 }
1241 else { os << words("unset"); }
1242
1243 if(theVerboseLevel < 5) { return; }
1244 if(measures.size() > 1)
1245 {
1246 os << "\n " << words("measure of sides") << " =";
1247 for(dimen_t i = 0; i < numberOfSides(); i++) { os << " " << measures[i + 1]; }
1248 }
1249
1250 os << "\n " << words("sides") << " : ";
1251 if(sideNumbers.size() > 0 && sideNumbers[0] > 0)
1252 {
1253 for(number_t n = 0; n < sideNumbers.size(); n++) { os << sideNumbers[n] << " "; }
1254 }
1255 else { os << words("unset"); }
1256
1257 os << "\n " << words("sideOfSides") << " : ";
1258 if(sideOfSideNumbers.size() > 0 && sideOfSideNumbers[0] > 0)
1259 {
1260 for(it = sideOfSideNumbers.begin(); it != sideOfSideNumbers.end(); it++) { os << (*it) << " "; }
1261 }
1262 else { os << words("unset"); }
1263
1264 if(theVerboseLevel < 10000) return;
1265 os << "\n" << *(refElt_p);
1266 }
1267
operator <<(std::ostream & os,const MeshElement & me)1268 std::ostream& operator<< (std::ostream& os, const MeshElement& me)
1269 {
1270 me.print(os);
1271 return os;
1272 }
1273
1274 /*! distance from two MeshElement, assuming not intersection and using first order, i.e vertices
1275 under these assumptions
1276 dist(e1,e2)= min{dist(p1,p2), p1 in e1, p2 in e2}
1277 = min{dist(p1,p2), p1 any vertex of e1, p2 any vertex of e2}
1278 */
distance(const MeshElement & elt1,const MeshElement & elt2)1279 real_t distance(const MeshElement& elt1, const MeshElement& elt2)
1280 {
1281 real_t d = theRealMax;
1282 for(number_t i=1; i<=elt1.numberOfVertices(); i++)
1283 {
1284 Point & vi = elt1.vertex(i);
1285 for(number_t j=1; j<=elt2.numberOfVertices(); j++)
1286 {
1287 d=std::min(d,vi.distance(elt2.vertex(j)));
1288 if(d<=theTolerance) return 0.;
1289 }
1290 }
1291 return d;
1292 }
1293
1294
1295 //--------------------------------------------------------------------------------
1296 // area and volume of simplices
1297 //--------------------------------------------------------------------------------
triangleArea(const Point & p1,const Point & p2,const Point & p3)1298 real_t triangleArea(const Point& p1, const Point& p2, const Point& p3)
1299 { return 0.5 * norm(crossProduct(p2 - p1, p3 - p1)); }
1300
tetrahedronVolume(const Point & p1,const Point & p2,const Point & p3,const Point & p4)1301 real_t tetrahedronVolume(const Point& p1, const Point& p2, const Point& p3, const Point& p4)
1302 {
1303 std::vector<real_t> v = crossProduct(p1 - p4, p1 - p3);
1304 std::vector<real_t> w = p2 - p3;
1305 return std::abs(std::inner_product(v.begin(), v.end(), w.begin(), 0.)) / 6.;
1306 }
1307
1308 //--------------------------------------------------------------------------------
1309 // default GeomElement coloring rule
1310 //--------------------------------------------------------------------------------
1311 /*!
1312 the default GeomElement coloring rule is the following
1313 let np the number of strictly positive values (v_i) on the n vertices of the geomelement
1314 if(np>n/2) then color =1 else color =0
1315 for a triangle : color is 1 if at least 2 vertex values are >0
1316 for a quadrangle : color is 1 if at least 3 vertex values are >0
1317 for a tetrahedron : color is 1 if at least 3 vertex values are >0
1318 for a hexahedron : color is 1 if at least 5 vertex values are >0
1319
1320 gelt : geom element
1321 val : real values on vertices
1322
1323 */
defaultColoringRule(const GeomElement & gelt,const std::vector<real_t> & val)1324 real_t defaultColoringRule(const GeomElement& gelt, const std::vector<real_t>& val)
1325 {
1326 number_t np=0, n=std::min(val.size(),gelt.numberOfVertices());
1327 std::vector<real_t>::const_iterator itv=val.begin();
1328 for(number_t i=0; i<n; ++i, ++itv)
1329 if(*itv>0) np++;
1330 if(np>n/2) return 1;
1331 return 0;
1332 }
1333
1334
1335 } // end of namespace xlifepp
1336