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