Line |
Branch |
Exec |
Source |
1 |
|
|
// ______ ______ _ _ _____ ______ |
2 |
|
|
// | ____| ____| | (_)/ ____| | ____| |
3 |
|
|
// | |__ | |__ | | _| (___ ___| |__ |
4 |
|
|
// | __| | __| | | | |\___ \ / __| __| |
5 |
|
|
// | | | |____| |____| |____) | (__| |____ |
6 |
|
|
// |_| |______|______|_|_____/ \___|______| |
7 |
|
|
// Finite Elements for Life Sciences and Engineering |
8 |
|
|
// |
9 |
|
|
// License: LGL2.1 License |
10 |
|
|
// FELiScE default license: LICENSE in root folder |
11 |
|
|
// |
12 |
|
|
// Main authors: J. Foulon & J-F. Gerbeau & V. Martin |
13 |
|
|
// |
14 |
|
|
|
15 |
|
|
// System includes |
16 |
|
|
|
17 |
|
|
// External includes |
18 |
|
|
|
19 |
|
|
// Project includes |
20 |
|
|
#include "Geometry/surfaceInterpolator.hpp" |
21 |
|
|
#include "Geometry/point.hpp" |
22 |
|
|
#include "Geometry/geo_utilities.hpp" |
23 |
|
|
#include "Tools/math_utilities.hpp" |
24 |
|
|
|
25 |
|
|
namespace felisce { |
26 |
|
|
//default parameter for alternate labels: an empty std::vector. |
27 |
|
✗ |
void SurfaceInterpolator::buildInterpolator( PetscMatrix& interpolator, |
28 |
|
|
const std::vector< std::pair< Point*, felInt > >& pointsAndCorrespondingSurfLabel, |
29 |
|
|
const std::vector<int> rowNumbering, |
30 |
|
|
const Variable& var, felInt ivar, std::size_t iBD ) { |
31 |
|
✗ |
std::vector<int> alternativeLabels; |
32 |
|
✗ |
std::string logFile="logFile"; |
33 |
|
✗ |
this->buildInterpolator( interpolator, |
34 |
|
|
pointsAndCorrespondingSurfLabel, |
35 |
|
|
rowNumbering, |
36 |
|
|
var,ivar,iBD, |
37 |
|
|
alternativeLabels, |
38 |
|
|
logFile); |
39 |
|
|
} |
40 |
|
|
|
41 |
|
|
namespace { |
42 |
|
✗ |
void printLog(std::ostream& log, int id, Point* thePoint, Point& pointProjection, double distance) { |
43 |
|
✗ |
log<<id<<'\t'; |
44 |
|
✗ |
thePoint->printWithTab(log); |
45 |
|
✗ |
log<<'\t'; |
46 |
|
✗ |
pointProjection.printWithTab(log); |
47 |
|
✗ |
log<<'\t'<<distance<<std::endl; |
48 |
|
|
} |
49 |
|
|
} |
50 |
|
|
|
51 |
|
|
/* |
52 |
|
|
* Let f_1 be a finite-element function defined on the surface on the current domain (1). |
53 |
|
|
* f_1(x) = sum_j phi_{1,j}(x) f_{1,j} |
54 |
|
|
* where phi_{1,j} are the basis function of the surface. |
55 |
|
|
* |
56 |
|
|
* We want to pass this information to another domain (2) that share a surface, but has not conforming mesh. |
57 |
|
|
* |
58 |
|
|
* f_2(x) = sum_i phi_{2,i}(x) f_{2,i} |
59 |
|
|
* where f_{2,i} = f_1(x_i), x_i are the points coming from the second domain. |
60 |
|
|
* f_{2,i}=f_1(x_i) = sum_j phi_{1,j}(x_i) f_{1,j}. |
61 |
|
|
* |
62 |
|
|
* From this we get the matrix representation of the relationship between the two finite-element representation. |
63 |
|
|
* f_{2,i}= A_{i,j} f_{1,j} |
64 |
|
|
* where A_{i,j} = phi_{1,j}(x_i) is the interpolator that we want to build in this function! |
65 |
|
|
* |
66 |
|
|
* A will be parallel with respect to the column! |
67 |
|
|
*/ |
68 |
|
✗ |
void SurfaceInterpolator::buildInterpolator( PetscMatrix& interpolator, |
69 |
|
|
const std::vector< std::pair< Point*, felInt > >& pointsAndCorrespondingSurfLabel, |
70 |
|
|
const std::vector<int> rowNumbering, |
71 |
|
|
const Variable& var, felInt ivar, std::size_t iBD, |
72 |
|
|
const std::vector<int> alternativeLabels, std::string logFile) |
73 |
|
|
{ |
74 |
|
✗ |
if ( MpiInfo::rankProc() == 0 ) { |
75 |
|
✗ |
std::ofstream log; |
76 |
|
✗ |
log.open(logFile.c_str()); |
77 |
|
|
// First we extract the information. |
78 |
|
|
// the points in pointsAndCorrespondingSurfLabel are the x_i. |
79 |
|
|
|
80 |
|
|
// Warning: if the x_i belongs to more than one label, it does not matter. |
81 |
|
|
// in fact, we assume that the edges of the surface are geometrically conforming. Which means that they can have, as 1D manifolds, different finite-element |
82 |
|
|
// representation, but they overlap. |
83 |
|
|
|
84 |
|
|
// Number of points coming from the other mesh. |
85 |
|
✗ |
felInt nPoints = pointsAndCorrespondingSurfLabel.size(); // physical points that can support more than one dofs. Think about std::vector variables. |
86 |
|
✗ |
if ( nPoints == 0 ) |
87 |
|
✗ |
FEL_ERROR("Zero points in surface interpolator."); |
88 |
|
|
// Number of dofs of the other mesh, which is also the number of rows |
89 |
|
✗ |
m_nrows[iBD] = rowNumbering.size(); |
90 |
|
|
// We assume that all the points support the same number of dofs |
91 |
|
✗ |
FEL_ASSERT( m_nrows[iBD] % nPoints == 0 ); |
92 |
|
|
// We compute this number |
93 |
|
✗ |
felInt nComp = m_nrows[iBD]/nPoints; // 1 if we are passing scalars, 2 or 3 if we are passing vectors |
94 |
|
|
|
95 |
|
|
// We first save the interpolator in this data structure |
96 |
|
|
// We assume that rowNumbering contains all and only the numbers from 0 to m_nrows-1; |
97 |
|
✗ |
std::vector< std::vector < std::pair < /*column numbering*/ felInt, /*value*/ double > > > temporaryInterpolator; |
98 |
|
✗ |
temporaryInterpolator.resize(m_nrows[iBD]); |
99 |
|
|
|
100 |
|
|
// eltType will be used in the loop to distinguish between triangles and quadrangles |
101 |
|
|
// previousEltType will be used to store the previous value of eltType and check if it has changed |
102 |
|
|
// It is initialized to Tetra4 because Tetra4 can not be an element of the boundary, the idea is to std::set this element type to "NULL" |
103 |
|
✗ |
ElementType eltType, previousEltType=GeometricMeshRegion::Tetra4; |
104 |
|
|
// Vector to store vertex of the current element |
105 |
|
✗ |
std::vector< Point*> elemPoint; |
106 |
|
|
// Curvilinear finite element on the boundary, to access basis functions |
107 |
|
✗ |
CurvilinearFiniteElement* currentFe=nullptr; |
108 |
|
|
// Number of degrees of freedom of the current element |
109 |
|
✗ |
felInt nDofEle = 0; |
110 |
|
|
// Global index of the element |
111 |
|
|
felInt ielSupportDof; |
112 |
|
|
// Id of the column |
113 |
|
|
felInt idColumn; |
114 |
|
|
// Auxiliary vectors to temporary store the values of the matrix |
115 |
|
✗ |
std::vector<double> values; |
116 |
|
|
// projected point |
117 |
|
✗ |
Point pointProjection(0.0); |
118 |
|
|
|
119 |
|
✗ |
int idForLog = 0; //0 inside elem, 1 inside elem alternative lab, 2 edge, 3 point 4 not found |
120 |
|
|
|
121 |
|
✗ |
const int iMesh = var.idMesh(); |
122 |
|
|
|
123 |
|
|
// For each x_i |
124 |
|
✗ |
int pointNotFound(0); |
125 |
|
✗ |
int foundInsideAnElement(0), foundInsideAnElementAltLab(0), foundInEdge(0),foundInPoint(0); |
126 |
|
✗ |
for ( std::size_t cPoint(0); cPoint< (std::size_t) nPoints; ++cPoint) { |
127 |
|
|
|
128 |
|
|
// 1) IDENTIFY THE ELEMENT, ON THIS MESH, CLOSEST TO THE POINT. |
129 |
|
✗ |
std::map<int,double> iel2ScoreByEdge; |
130 |
|
✗ |
double pointDistance(1.e20); |
131 |
|
✗ |
int idOfElOfClosestPoint,ielSupportDofByType(0); |
132 |
|
|
int notFound; |
133 |
|
✗ |
Point* thePoint = pointsAndCorrespondingSurfLabel[cPoint].first; |
134 |
|
|
// 1a) check if the projection can be done on a triangle on the given label. |
135 |
|
|
// at the same time, best point and best edges are computed for the current label |
136 |
|
✗ |
notFound = getClosestSurfaceElement(thePoint, /* [in] the point*/ |
137 |
|
✗ |
pointsAndCorrespondingSurfLabel[cPoint].second,/* [in] the surface label where to look for*/ |
138 |
|
|
eltType, /* [out] type of the element */ |
139 |
|
|
elemPoint, /* [out] verteces of the element */ |
140 |
|
|
pointProjection, /* [out] the projection of the given point on the element*/ |
141 |
|
|
ielSupportDof, /* [out] the id of the element*/ |
142 |
|
|
iel2ScoreByEdge, /* [out] updated std::unordered_map from ielByType to the best edge score*/ |
143 |
|
|
pointDistance, /* [out] updated best distance from a point of the mesh*/ |
144 |
|
|
idOfElOfClosestPoint); /* [out] updated id of the closest point of the mesh*/ |
145 |
|
✗ |
foundInsideAnElement += (1-notFound); |
146 |
|
✗ |
if ( ! notFound ) { |
147 |
|
✗ |
idForLog=0; |
148 |
|
|
} |
149 |
|
✗ |
if ( notFound ) { |
150 |
|
|
// 1b) check if the projection can be done on a triangle on the other possible labels. |
151 |
|
|
// at the same time, best point and best edges are possibily updated for the current label |
152 |
|
✗ |
for ( std::size_t iL(0); iL<alternativeLabels.size() && notFound; ++iL ) { |
153 |
|
✗ |
if ( alternativeLabels[iL] != pointsAndCorrespondingSurfLabel[cPoint].second ) { |
154 |
|
✗ |
notFound = getClosestSurfaceElement(thePoint, /* [in] the point*/ |
155 |
|
✗ |
alternativeLabels[iL],/* [in] the surface label where to look for*/ |
156 |
|
|
eltType, /* [out] type of the element */ |
157 |
|
|
elemPoint, /* [out] verteces of the element */ |
158 |
|
|
pointProjection,/* [out] the projection of the given point on the element*/ |
159 |
|
|
ielSupportDof,iel2ScoreByEdge,pointDistance,idOfElOfClosestPoint); /* [out] the id of the element*/ |
160 |
|
✗ |
foundInsideAnElementAltLab+= (1-notFound); |
161 |
|
✗ |
if ( ! notFound ) { |
162 |
|
✗ |
idForLog=1; |
163 |
|
|
} |
164 |
|
|
} |
165 |
|
|
} |
166 |
|
|
// 1c) It was not possible to project it on a triangle, we have to project it either on an edge or on a point |
167 |
|
✗ |
if ( notFound ) { |
168 |
|
|
// 1d) we look for the best edge |
169 |
|
✗ |
double best=100; |
170 |
|
✗ |
for ( auto it = iel2ScoreByEdge.begin(); it != iel2ScoreByEdge.end(); ++it ) { |
171 |
|
✗ |
if ( it->second < best ) { |
172 |
|
✗ |
ielSupportDofByType = it->first; |
173 |
|
✗ |
best = it->second; |
174 |
|
|
} |
175 |
|
|
} |
176 |
|
|
// 1e) we check if it is better to project on a point instead |
177 |
|
✗ |
if ( best > pointDistance ) { |
178 |
|
✗ |
foundInPoint++; |
179 |
|
✗ |
ielSupportDofByType = idOfElOfClosestPoint; |
180 |
|
✗ |
idForLog=3; |
181 |
|
|
} else { |
182 |
|
✗ |
foundInEdge++; |
183 |
|
✗ |
idForLog=2; |
184 |
|
|
} |
185 |
|
|
// We hope the eltType of the element is the same on all the alternative labels..todo!! |
186 |
|
✗ |
ElementType eltType2 = getETandAssert2D(m_pb->mesh(iMesh)->intRefToEnum().at(pointsAndCorrespondingSurfLabel[cPoint].second)); |
187 |
|
✗ |
ielSupportDof=0;//very important |
188 |
|
✗ |
m_pb->mesh(iMesh)->getIdElemFromTypeElemAndIdByType(eltType,ielSupportDofByType,ielSupportDof); |
189 |
|
✗ |
std::vector<int> elemIdPoint( GeometricMeshRegion::m_numPointsPerElt[eltType2] ); |
190 |
|
✗ |
elemPoint.resize( GeometricMeshRegion::m_numPointsPerElt[eltType2] ); |
191 |
|
|
|
192 |
|
✗ |
m_pb->mesh(iMesh)->getOneElement(eltType2, ielSupportDofByType, elemIdPoint, 0); |
193 |
|
|
|
194 |
|
✗ |
for (int iPoint = 0; iPoint < GeometricMeshRegion::m_numPointsPerElt[eltType2]; iPoint++) { |
195 |
|
✗ |
elemPoint[iPoint] = &m_pb->mesh(iMesh)->listPoints()[elemIdPoint[iPoint]]; |
196 |
|
|
} |
197 |
|
|
|
198 |
|
✗ |
if ( best > pointDistance ) {//case of the point |
199 |
|
✗ |
projectOnBestPoint ( elemPoint,thePoint,pointProjection); |
200 |
|
|
} else {//case of the edge |
201 |
|
✗ |
projectOnBestEdge ( elemPoint,thePoint,pointProjection); |
202 |
|
|
} |
203 |
|
|
} |
204 |
|
|
} |
205 |
|
|
// Final assert! |
206 |
|
✗ |
double projectionDistance = thePoint->dist(pointProjection); |
207 |
|
✗ |
double epsAssert(0.1);//TODO |
208 |
|
✗ |
if ( projectionDistance > epsAssert ) { |
209 |
|
✗ |
std::cout<<"=========================The point is quite far from the projection."<<std::endl; |
210 |
|
✗ |
idForLog=4; |
211 |
|
✗ |
pointNotFound++; |
212 |
|
|
} |
213 |
|
✗ |
printLog(log, idForLog, thePoint, pointProjection, projectionDistance); |
214 |
|
|
// 2) IF NEEDED, INITIALIZATION OF THE CURVILINEAR FINITE ELEMENT |
215 |
|
✗ |
if ( eltType != previousEltType ) { |
216 |
|
✗ |
if ( currentFe ) |
217 |
|
✗ |
delete currentFe; |
218 |
|
|
|
219 |
|
|
// Get standard information for the element |
220 |
|
✗ |
int typeOfFiniteElement = var.finiteElementType(); |
221 |
|
✗ |
const GeoElement* geoEle = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second; |
222 |
|
✗ |
const RefElement* refEle = geoEle->defineFiniteEle(eltType,typeOfFiniteElement, *m_pb->mesh(iMesh)); |
223 |
|
|
|
224 |
|
|
// Initialization |
225 |
|
✗ |
currentFe = new CurvilinearFiniteElement(*refEle,*geoEle,var.degreeOfExactness()); |
226 |
|
|
|
227 |
|
✗ |
nDofEle= currentFe->numDof(); |
228 |
|
✗ |
values.resize(nDofEle); |
229 |
|
|
|
230 |
|
|
// Update of previous type of element |
231 |
|
✗ |
previousEltType=eltType; |
232 |
|
|
} |
233 |
|
|
|
234 |
|
|
// 3) UPDATE OF THE BASIS FUNCTIONS IN CURVILINEAR FINITE ELEMENT |
235 |
|
✗ |
currentFe->updateMeas(0,elemPoint); |
236 |
|
|
|
237 |
|
|
// 4) EVALUATION OF THE BASIS FUNCTION IN THE POINT |
238 |
|
✗ |
currentFe->evaluateBasisFunctionsInPoint(&pointProjection,values); |
239 |
|
|
|
240 |
|
|
// 5) FILLING THE DATA STRUCTURE |
241 |
|
✗ |
for ( std::size_t iComp(0); iComp < static_cast<std::size_t>(nComp); ++iComp ) { |
242 |
|
✗ |
for ( std::size_t iDof(0); iDof < static_cast<std::size_t>(nDofEle); ++iDof ) { |
243 |
|
|
// get the global application numbering volume |
244 |
|
✗ |
m_pb->dof().loc2glob(ielSupportDof,iDof,ivar,iComp, idColumn); |
245 |
|
|
// Tranforming it into globalPetscOrdering volume |
246 |
|
✗ |
AOApplicationToPetsc(m_pb->ao(), 1, & idColumn); |
247 |
|
|
// Moving to global application ordering bd |
248 |
|
✗ |
idColumn = m_dofBD[iBD]->petscVol2ApplicationBD( idColumn ); |
249 |
|
|
// Saving the values in the temporary interpolator matrix |
250 |
|
✗ |
temporaryInterpolator[ rowNumbering[ cPoint*nComp + iComp ] ].push_back( std::make_pair( idColumn, values[iDof] ) ); |
251 |
|
|
} |
252 |
|
|
} |
253 |
|
|
} |
254 |
|
✗ |
this->checkInterpolatorStatistics(foundInsideAnElement, foundInsideAnElementAltLab, foundInEdge, foundInPoint, pointNotFound, nPoints ); |
255 |
|
|
|
256 |
|
|
// 6) Build the pattern and the data in csr format |
257 |
|
✗ |
std::vector<felInt> icsr(m_nrows[iBD]+1); |
258 |
|
✗ |
std::vector<felInt> jcsr; |
259 |
|
✗ |
std::vector<double> data; |
260 |
|
✗ |
icsr[0]=0; |
261 |
|
✗ |
for ( felInt iRow(0); iRow< m_nrows[iBD]; ++iRow ) { |
262 |
|
✗ |
icsr[iRow+1]=icsr[iRow] + temporaryInterpolator[iRow].size(); |
263 |
|
✗ |
if ( temporaryInterpolator[iRow].size () > 5 ) |
264 |
|
✗ |
std::cout<<"iRow: "<<iRow<<" size "<<temporaryInterpolator[iRow].size()<<std::endl; |
265 |
|
✗ |
for ( std::size_t j(0); j<temporaryInterpolator[iRow].size(); ++j) { |
266 |
|
✗ |
jcsr.push_back(temporaryInterpolator[iRow][j].first); |
267 |
|
✗ |
data.push_back(temporaryInterpolator[iRow][j].second); |
268 |
|
|
} |
269 |
|
|
} |
270 |
|
|
// 7) Allocating the matrix |
271 |
|
✗ |
std::vector<felInt> nnz( m_nrows[iBD] ); |
272 |
|
✗ |
for ( std::size_t nRow = 0; nRow < (std::size_t) m_nrows[iBD]; nRow++ ) { |
273 |
|
✗ |
nnz[nRow] = icsr[nRow+1]-icsr[nRow]; |
274 |
|
|
} |
275 |
|
✗ |
m_ncols[iBD] = m_dofBD[iBD]->numGlobalDofInterface(); |
276 |
|
✗ |
interpolator.createSeqAIJ(MPI_COMM_SELF, m_nrows[iBD], m_ncols[iBD], 0, nnz.data()); |
277 |
|
✗ |
interpolator.setOption(MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE); |
278 |
|
✗ |
interpolator.setFromOptions(); |
279 |
|
✗ |
for ( felInt iRow(0); iRow< m_nrows[iBD]; ++iRow ) { |
280 |
|
✗ |
interpolator.setValues(1,&iRow,nnz[iRow],&jcsr[icsr[iRow]],&data[icsr[iRow]],INSERT_VALUES); |
281 |
|
|
} |
282 |
|
✗ |
interpolator.assembly(MAT_FINAL_ASSEMBLY); |
283 |
|
|
}//endif |
284 |
|
|
} |
285 |
|
|
|
286 |
|
✗ |
void SurfaceInterpolator::writeInterfaceFile(felInt iunknown, felInt numComp, std::string filename, std::string folder, std::size_t iBD) const |
287 |
|
|
{ |
288 |
|
✗ |
if ( MpiInfo::rankProc() == 0 ) { |
289 |
|
|
//All the infos are in dofBD |
290 |
|
✗ |
m_dofBD[iBD]->writeSurfaceInterpolatorFile(iunknown,numComp,filename,folder); |
291 |
|
|
} |
292 |
|
|
} |
293 |
|
|
|
294 |
|
✗ |
void SurfaceInterpolator::readInterfaceFile( std::string filename, std::vector< std::pair< Point*, felInt > >& pointsAndCorrespondingSurfLabel, std::vector<int>& rowNumbering, std::string folder) |
295 |
|
|
{ |
296 |
|
✗ |
if ( MpiInfo::rankProc() == 0 ) { |
297 |
|
|
|
298 |
|
|
// 0) Make sure we got empty output variable |
299 |
|
✗ |
pointsAndCorrespondingSurfLabel.clear(); |
300 |
|
✗ |
rowNumbering.clear(); |
301 |
|
|
|
302 |
|
|
// 1) Opening the file |
303 |
|
✗ |
std::stringstream fname; |
304 |
|
✗ |
fname<<folder<<"/"<<filename; |
305 |
|
✗ |
std::ifstream iFile; |
306 |
|
✗ |
iFile.open(fname.str().c_str()); |
307 |
|
✗ |
if ( ! iFile.good() ) { |
308 |
|
✗ |
iFile.close(); |
309 |
|
✗ |
std::cout<<fname.str()<<std::endl; |
310 |
|
✗ |
FEL_ERROR("Problem in opening the file"); |
311 |
|
|
} |
312 |
|
|
// 2) Get the number of points in the file |
313 |
|
|
felInt nPoints; |
314 |
|
✗ |
iFile>>nPoints; |
315 |
|
✗ |
if ( FelisceParam::verbose() > 2 ) { |
316 |
|
✗ |
std::cout<<"Found "<<nPoints<<" points in "<<fname.str().c_str()<<std::endl; |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
// 3) Temporary variable declaration |
320 |
|
|
// Number of components |
321 |
|
|
felInt nComp; |
322 |
|
|
// The pointer to the Point |
323 |
|
|
Point* newPoint; |
324 |
|
|
// The surface label |
325 |
|
|
felInt label; |
326 |
|
|
// The if of the dof |
327 |
|
|
felInt id; |
328 |
|
|
|
329 |
|
|
// 4) Reading |
330 |
|
✗ |
for ( int curPoint(0); curPoint<nPoints; ++curPoint) { |
331 |
|
|
// get the number of components |
332 |
|
✗ |
iFile>>nComp; |
333 |
|
|
|
334 |
|
|
// get the point |
335 |
|
✗ |
newPoint = new Point; |
336 |
|
✗ |
iFile>>newPoint->x(); |
337 |
|
✗ |
iFile>>newPoint->y(); |
338 |
|
✗ |
iFile>>newPoint->z(); |
339 |
|
|
|
340 |
|
|
// get the label |
341 |
|
✗ |
iFile>>label; |
342 |
|
|
|
343 |
|
|
// verify label correctness, TODO improve this check |
344 |
|
|
// especially in case 1 label is mapped into more labels or viceversa. |
345 |
|
✗ |
if ( FelisceParam::instance().withCVG ) { |
346 |
|
✗ |
int otherLabel=label; |
347 |
|
✗ |
FEL_ASSERT( FelisceParam::instance().interfaceLabels.size() == FelisceParam::instance().correspondingInterfaceLabels.size() ); |
348 |
|
✗ |
for ( std::size_t k(0); k<FelisceParam::instance().interfaceLabels.size(); ++k) { |
349 |
|
✗ |
if ( FelisceParam::instance().correspondingInterfaceLabels[k] == otherLabel ) { |
350 |
|
✗ |
label = FelisceParam::instance().interfaceLabels[k]; |
351 |
|
|
} |
352 |
|
|
} |
353 |
|
|
} |
354 |
|
|
// save point and label in data structure |
355 |
|
✗ |
pointsAndCorrespondingSurfLabel.emplace_back(newPoint,label); |
356 |
|
|
|
357 |
|
|
// get the id and save them |
358 |
|
✗ |
for ( int iComp(0); iComp<nComp; ++iComp) { |
359 |
|
✗ |
iFile>>id; |
360 |
|
✗ |
rowNumbering.push_back(id); |
361 |
|
|
} |
362 |
|
|
} |
363 |
|
|
} |
364 |
|
|
} |
365 |
|
|
|
366 |
|
✗ |
void SurfaceInterpolator::checkInterpolatorStatistics(int foundInsideAnElement, int foundInsideAnElementAltLab, int foundInEdge, int foundInPoint, int pointNotFound, int nPoints ) const |
367 |
|
|
{ |
368 |
|
✗ |
if ( FelisceParam::verbose() > 1 ) { |
369 |
|
✗ |
std::stringstream msg; |
370 |
|
✗ |
double percentageInsideElement = (double) foundInsideAnElement / (double) nPoints; |
371 |
|
✗ |
double percentageInsideElementAltLab = (double) foundInsideAnElementAltLab / (double) nPoints; |
372 |
|
✗ |
double percentageEdge = (double) foundInEdge / (double) nPoints; |
373 |
|
✗ |
double percentagePoint= (double) foundInPoint / (double) nPoints; |
374 |
|
|
|
375 |
|
✗ |
int prec = 2; |
376 |
|
✗ |
int oldPrec=std::cout.precision(); |
377 |
|
✗ |
if ( percentageInsideElement*100 < 0.01 ) |
378 |
|
✗ |
prec = 4; |
379 |
|
✗ |
else if (percentageInsideElement*100 > 1 ) |
380 |
|
✗ |
prec=oldPrec; |
381 |
|
✗ |
std::cout<<"Points projected on an element: "<<foundInsideAnElement<<"/" |
382 |
|
|
<<nPoints<<", percentage=" |
383 |
|
✗ |
<<std::setprecision(prec) <<percentageInsideElement*100 |
384 |
|
✗ |
<<std::setprecision(oldPrec) <<"%"<<std::endl; |
385 |
|
✗ |
if ( percentageInsideElement*100 < 0.01 ) |
386 |
|
✗ |
prec = 4; |
387 |
|
✗ |
else if (percentageInsideElement*100 > 1 ) |
388 |
|
✗ |
prec=oldPrec; |
389 |
|
✗ |
std::cout<<"Points projected on an element on a different label than the one specified: "<<foundInsideAnElementAltLab<<"/" |
390 |
|
|
<<nPoints<<", percentage=" |
391 |
|
✗ |
<<std::setprecision(prec) <<percentageInsideElementAltLab*100 |
392 |
|
✗ |
<<std::setprecision(oldPrec) <<"%"<<std::endl; |
393 |
|
|
|
394 |
|
✗ |
if ( percentageEdge*100 < 0.01 ) |
395 |
|
✗ |
prec = 4; |
396 |
|
✗ |
std::cout<<"Points projected on an edge: "<<foundInEdge<<"/" |
397 |
|
|
<<nPoints<<", percentage=" |
398 |
|
✗ |
<<std::setprecision(prec) <<percentageEdge*100 |
399 |
|
✗ |
<<std::setprecision(oldPrec) <<"%"<<std::endl; |
400 |
|
✗ |
if ( percentagePoint*100 < 0.01 ) |
401 |
|
✗ |
prec = 4; |
402 |
|
✗ |
std::cout<<"Points projected on the closest point: "<<foundInPoint<<"/" |
403 |
|
|
<<nPoints<<", percentage=" |
404 |
|
✗ |
<<std::setprecision(prec) <<percentagePoint*100 |
405 |
|
✗ |
<<std::setprecision(oldPrec) <<"%"<<std::endl; |
406 |
|
|
} |
407 |
|
✗ |
if ( pointNotFound > 0 ) { |
408 |
|
✗ |
std::stringstream msg; |
409 |
|
✗ |
double percentage = (double) pointNotFound/ (double) nPoints; |
410 |
|
✗ |
int prec = 2; |
411 |
|
✗ |
int oldPrec=std::cout.precision(); |
412 |
|
✗ |
if ( percentage*100 < 0.01 ) |
413 |
|
✗ |
prec = 4; |
414 |
|
✗ |
msg<<"For "<<pointNotFound<<" point(s) the algorithm (total nb of points=" |
415 |
|
|
<<nPoints<<", percentage=" |
416 |
|
✗ |
<<std::setprecision(prec) <<percentage*100 |
417 |
|
✗ |
<<std::setprecision(oldPrec) <<"%), with threshold " |
418 |
|
✗ |
<<FelisceParam::instance().interpolatorThreshold<<", was not able to find an element containing the point projection."<<std::endl; |
419 |
|
✗ |
FEL_ERROR(msg.str().c_str()); |
420 |
|
|
} |
421 |
|
|
} |
422 |
|
|
|
423 |
|
✗ |
void SurfaceInterpolator::initializeSurfaceInterpolator() |
424 |
|
|
{ |
425 |
|
✗ |
std::vector<Point*> elemPoint; |
426 |
|
✗ |
std::vector<felInt> elemIdPoint; |
427 |
|
|
// Counter, necessary to compute the id of element by type; |
428 |
|
|
felInt numElementPerEltType; |
429 |
|
|
|
430 |
|
|
// For each type of element present on the boundary: i.e. triangles, quadrangles |
431 |
|
✗ |
for (std::size_t cElemType = 0; cElemType < m_mesh->bagElementTypeDomainBoundary().size(); ++cElemType) { |
432 |
|
✗ |
ElementType eltType = m_mesh->bagElementTypeDomainBoundary()[cElemType]; |
433 |
|
✗ |
elemPoint.resize(GeometricMeshRegion::m_numPointsPerElt[eltType]); |
434 |
|
✗ |
elemIdPoint.resize(GeometricMeshRegion::m_numPointsPerElt[eltType]); |
435 |
|
✗ |
numElementPerEltType=0; |
436 |
|
|
// We loop over the associated labels |
437 |
|
✗ |
for (auto itLabelMesh = m_mesh->intRefToBegEndMaps[eltType].begin(); itLabelMesh != m_mesh->intRefToBegEndMaps[eltType].end(); itLabelMesh++) { |
438 |
|
|
// We get the label |
439 |
|
✗ |
felInt cLabel = itLabelMesh->first; |
440 |
|
|
// We get the number of elements present on this label |
441 |
|
✗ |
felInt numElemsPerLabel = itLabelMesh->second.second; |
442 |
|
|
// For each of this element... |
443 |
|
✗ |
for ( felInt iel = 0; iel < numElemsPerLabel; iel++) { |
444 |
|
|
// Even in the case of P2, I just need the verteces of the element. |
445 |
|
|
// The reason is that I need them to find the element in the future! |
446 |
|
|
// Than of course, the interpolation will depend on the type of finite-element |
447 |
|
|
// used. |
448 |
|
✗ |
m_mesh->getOneElement(eltType, numElementPerEltType+iel, elemIdPoint, 0); |
449 |
|
✗ |
for (int iPoint = 0; iPoint < GeometricMeshRegion::m_numPointsPerElt[eltType]; iPoint++) { |
450 |
|
✗ |
elemPoint[iPoint]= &m_mesh->listPoints()[elemIdPoint[iPoint]]; |
451 |
|
|
// For each point we save the index of the elements of the part of the star |
452 |
|
|
// on this label. |
453 |
|
✗ |
m_surfLabelAndIdPoint2Star[cLabel][elemIdPoint[iPoint]].push_back(numElementPerEltType+iel); // this is an index local to this proc, pay attention when going parallel |
454 |
|
✗ |
m_surfLab2SetOfPointsAndIds[cLabel].insert(std::make_pair(elemPoint[iPoint],elemIdPoint[iPoint])); |
455 |
|
|
} |
456 |
|
|
} |
457 |
|
✗ |
numElementPerEltType+=numElemsPerLabel; |
458 |
|
|
} |
459 |
|
|
} |
460 |
|
✗ |
m_surfaceInterpolatorInitialized = true; |
461 |
|
|
} |
462 |
|
|
|
463 |
|
✗ |
int SurfaceInterpolator::getClosestSurfaceElement( |
464 |
|
|
Point* thePoint, |
465 |
|
|
felInt surfaceLabel, |
466 |
|
|
ElementType& eltTypeReturn, |
467 |
|
|
std::vector<Point*>& elemPointReturn, |
468 |
|
|
Point& projection, |
469 |
|
|
felInt& ielSupportDof, |
470 |
|
|
std::map<int,double>& iel2ScoreByEdge, |
471 |
|
|
double& distance, |
472 |
|
|
int& idElOfClosestPoint |
473 |
|
|
) |
474 |
|
|
{ |
475 |
|
✗ |
if ( ! m_surfaceInterpolatorInitialized ) { |
476 |
|
✗ |
FEL_ERROR("You have to call initializeSurfaceInterpolator"); |
477 |
|
|
} |
478 |
|
✗ |
if ( FelisceParam::verbose() > 2 ) { |
479 |
|
✗ |
std::cout<<"Point to be projected: "; thePoint->print(10); |
480 |
|
|
} |
481 |
|
|
|
482 |
|
|
// We extract the std::set of points and the corresponding ids for this label |
483 |
|
✗ |
auto setOfPointsAndIds = m_surfLab2SetOfPointsAndIds.at(surfaceLabel); |
484 |
|
|
|
485 |
|
|
// We start looking for the closest point |
486 |
|
|
Point* closest; |
487 |
|
|
double curDist; |
488 |
|
✗ |
felInt curIdClosestPoint = closestPoint( setOfPointsAndIds, thePoint, closest, curDist ); |
489 |
|
✗ |
if ( curDist < distance ) { |
490 |
|
✗ |
distance = curDist; |
491 |
|
✗ |
std::vector<felInt> star = m_surfLabelAndIdPoint2Star.at(surfaceLabel).at(curIdClosestPoint); |
492 |
|
✗ |
idElOfClosestPoint = star[0]; |
493 |
|
|
} |
494 |
|
✗ |
if ( FelisceParam::verbose() > 2 ) { |
495 |
|
✗ |
std::cout<<"The closest point on label "<<surfaceLabel<<" is: "; closest->print(10); |
496 |
|
|
} |
497 |
|
✗ |
int depth(0); |
498 |
|
|
double score; |
499 |
|
✗ |
return lookIntoStar(curIdClosestPoint, surfaceLabel, thePoint, eltTypeReturn, elemPointReturn, projection, ielSupportDof, depth, score,iel2ScoreByEdge); |
500 |
|
|
} |
501 |
|
|
|
502 |
|
✗ |
int SurfaceInterpolator::lookIntoStar( |
503 |
|
|
int idClosestPoint, |
504 |
|
|
int surfaceLabel, |
505 |
|
|
Point* thePoint, |
506 |
|
|
ElementType & eltTypeReturn, |
507 |
|
|
std::vector<Point*>& elemPointReturn, |
508 |
|
|
Point& projection, felInt& ielSupportDof, |
509 |
|
|
felInt& depth, |
510 |
|
|
double& minScore, |
511 |
|
|
std::map<int,double>& iel2distFromEdge |
512 |
|
|
) |
513 |
|
|
{ |
514 |
|
|
// We start looking for the closest element |
515 |
|
✗ |
felInt idClosestElement=-1; |
516 |
|
|
// Points of the element |
517 |
|
✗ |
std::vector<Point*> elemPoint; |
518 |
|
|
// ..and corresponding ids. |
519 |
|
✗ |
std::vector<felInt> elemIdPoint; |
520 |
|
|
|
521 |
|
|
// We assume that the closest element is in the star of this point |
522 |
|
|
// We extract the star |
523 |
|
✗ |
std::vector<felInt> star = m_surfLabelAndIdPoint2Star.at(surfaceLabel).at(idClosestPoint); |
524 |
|
|
// We loop over its element, until we find the closest one |
525 |
|
✗ |
const std::size_t star_size = star.size(); |
526 |
|
✗ |
if ( FelisceParam::verbose() > 2 ) { |
527 |
|
✗ |
std::cout<<"Size of the star: "<<star_size<<std::endl; |
528 |
|
|
} |
529 |
|
✗ |
std::vector<double> alpha(star_size); |
530 |
|
✗ |
std::vector<double> beta(star_size); |
531 |
|
✗ |
for( std::size_t k(0); k<star_size && idClosestElement<0; ++k) { |
532 |
|
|
// ==================EXTRACTING ELEMENT INFORMATION==================== // |
533 |
|
|
// We get the type of element |
534 |
|
✗ |
ElementType eltType=getETandAssert2D(m_mesh->intRefToEnum().at(surfaceLabel)); |
535 |
|
|
// ..and we resize this two vectors accoringly |
536 |
|
✗ |
elemPoint.resize(GeometricMeshRegion::m_numPointsPerElt[eltType]); |
537 |
|
✗ |
elemIdPoint.resize(GeometricMeshRegion::m_numPointsPerElt[eltType]); |
538 |
|
|
// We extract the element and its points |
539 |
|
✗ |
m_mesh->getOneElement(eltType, star[k], elemIdPoint, 0); |
540 |
|
|
// We assume that we have only triangles or quadrangles |
541 |
|
✗ |
FEL_ASSERT(elemIdPoint.size()>=3 && elemIdPoint.size()<=4); |
542 |
|
|
|
543 |
|
|
// We get the pointers of the points trough their ids |
544 |
|
✗ |
for (int iPoint = 0; iPoint < GeometricMeshRegion::m_numPointsPerElt[eltType]; iPoint++) { |
545 |
|
✗ |
elemPoint[iPoint] = &m_mesh->listPoints()[elemIdPoint[iPoint]]; |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
// ==================PLANE PROJETION=================================== // |
549 |
|
✗ |
projectOnElementPlane(elemPoint,thePoint,projection); |
550 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) { |
551 |
|
✗ |
std::cout<<" its idByType: "<<star[k]<<std::endl; |
552 |
|
✗ |
std::cout<<" its position in the star: "<<k<<std::endl; |
553 |
|
✗ |
std::cout<<" its points: "<<std::endl; |
554 |
|
✗ |
for ( int iPoint = 0; iPoint < GeometricMeshRegion::m_numPointsPerElt[eltType]; iPoint++) { |
555 |
|
✗ |
elemPoint[iPoint]->print(10); |
556 |
|
|
} |
557 |
|
✗ |
std::cout<<"TheProjection "; |
558 |
|
✗ |
projection.print(10); |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
// ==================CHECK IF THE THE PROJECTION BELONGS TO THE ELEMENT AND COMPUTE BEST EDGE DISTANCE==================== // |
562 |
|
✗ |
bool pointInElement=false; |
563 |
|
✗ |
if ( elemPoint.size() == 3 ) { |
564 |
|
✗ |
double edgeDist=1e20; |
565 |
|
✗ |
pointInElement = checkTriangle(projection,elemPoint,alpha[k],beta[k],thePoint,edgeDist); |
566 |
|
|
// saving bestEdge information |
567 |
|
✗ |
iel2distFromEdge[star[k]]=edgeDist; |
568 |
|
✗ |
} else if ( elemPoint.size() == 4 ) { |
569 |
|
✗ |
double edgeDist=1.e20; |
570 |
|
✗ |
pointInElement = checkQuadrangle(projection,elemPoint,alpha[k],beta[k],thePoint,edgeDist); |
571 |
|
|
// saving bestEdge information |
572 |
|
✗ |
iel2distFromEdge[star[k]]=edgeDist; |
573 |
|
|
} |
574 |
|
|
// We check if the projection is inside or outside the element. |
575 |
|
✗ |
if ( pointInElement ) { |
576 |
|
|
// The correct element has been found |
577 |
|
✗ |
idClosestElement = star[k]; |
578 |
|
✗ |
ielSupportDof=0; |
579 |
|
✗ |
m_mesh->getIdElemFromTypeElemAndIdByType(eltType,idClosestElement,ielSupportDof); |
580 |
|
✗ |
eltTypeReturn = eltType; |
581 |
|
✗ |
elemPointReturn = elemPoint; |
582 |
|
✗ |
if ( FelisceParam::verbose() > 2 ) { |
583 |
|
✗ |
std::cout<<" its idByType: "<<idClosestElement<<std::endl; |
584 |
|
✗ |
std::cout<<" its position in the star: "<<k<<std::endl; |
585 |
|
✗ |
std::cout<<" its points: "<<std::endl; |
586 |
|
✗ |
for ( int iPoint = 0; iPoint < GeometricMeshRegion::m_numPointsPerElt[eltType]; iPoint++) { |
587 |
|
✗ |
elemPoint[iPoint]->print(10); |
588 |
|
|
} |
589 |
|
✗ |
std::cout<<"TheProjection "; projection.print(10); |
590 |
|
|
} |
591 |
|
|
} |
592 |
|
|
} |
593 |
|
|
// If found it so simply we just skip all this part and return 0 (success); |
594 |
|
|
// If we have not found it |
595 |
|
✗ |
if (idClosestElement<0) { |
596 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) { |
597 |
|
✗ |
std::cout<<"Point: "; |
598 |
|
✗ |
thePoint->print(10); |
599 |
|
|
} |
600 |
|
|
// We compute the score of each element in the star! |
601 |
|
✗ |
minScore=1e20; |
602 |
|
✗ |
for ( std::size_t k(0); k<star.size(); ++k ) { |
603 |
|
✗ |
double score=computeScore(alpha[k],beta[k]); |
604 |
|
✗ |
if ( score < minScore) { |
605 |
|
✗ |
minScore = score; |
606 |
|
✗ |
idClosestElement = star[k]; |
607 |
|
|
} |
608 |
|
|
} |
609 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) |
610 |
|
✗ |
std::cout<<"SPECIAL CASE OF GET CLOSEST SURFACE ELEMENT: Score of current star: "<<minScore<<std::endl; |
611 |
|
|
|
612 |
|
|
// For now this element is our best! |
613 |
|
|
// We extract the return parameters |
614 |
|
✗ |
ElementType eltType=getETandAssert2D(m_mesh->intRefToEnum().at(surfaceLabel)); |
615 |
|
✗ |
eltTypeReturn = eltType; |
616 |
|
✗ |
ielSupportDof=0; |
617 |
|
✗ |
m_mesh->getIdElemFromTypeElemAndIdByType(eltType,idClosestElement,ielSupportDof); |
618 |
|
✗ |
m_mesh->getOneElement(eltType, idClosestElement, elemIdPoint, 0); |
619 |
|
|
|
620 |
|
✗ |
elemPointReturn.resize( GeometricMeshRegion::m_numPointsPerElt[eltType] ); |
621 |
|
✗ |
for (int iPoint = 0; iPoint < GeometricMeshRegion::m_numPointsPerElt[eltType]; iPoint++) { |
622 |
|
✗ |
elemPointReturn[iPoint] = &m_mesh->listPoints()[elemIdPoint[iPoint]]; |
623 |
|
|
} |
624 |
|
|
|
625 |
|
|
// We also look into the adjacent stars. |
626 |
|
✗ |
if ( depth >= FelisceParam::instance().maxDepth ) { |
627 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) |
628 |
|
✗ |
std::cout<<"Max depth reached, iterations concluded"<<std::endl; |
629 |
|
|
} else { |
630 |
|
✗ |
depth++; |
631 |
|
|
int result; |
632 |
|
✗ |
double score=100; |
633 |
|
|
ElementType eltTypeReturnTmp; |
634 |
|
✗ |
std::vector<Point*> elemPointReturnTmp; |
635 |
|
✗ |
Point projectionTmp(0.0); |
636 |
|
|
felInt ielSupportDofTmp; |
637 |
|
|
// I look in the other stars close to this element. |
638 |
|
✗ |
for ( std::size_t k(0); k<elemIdPoint.size(); ++k) { |
639 |
|
|
// I skip the current star. |
640 |
|
✗ |
if ( elemIdPoint[k] != idClosestPoint ) { |
641 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) |
642 |
|
✗ |
std::cout<<"Descending into the star of point number "<<k<<std::endl; |
643 |
|
✗ |
result = this->lookIntoStar(/*where to look*/elemIdPoint[k], surfaceLabel, thePoint, eltTypeReturnTmp, elemPointReturnTmp, projectionTmp, ielSupportDofTmp, depth , score, iel2distFromEdge ); |
644 |
|
|
// We found it in this star! |
645 |
|
✗ |
if ( result == 0 ) { |
646 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) |
647 |
|
✗ |
std::cout<<"found it in the current star!"<<std::endl; |
648 |
|
|
// We do not go any further! we update the parameters and return success. |
649 |
|
✗ |
eltTypeReturn = eltTypeReturnTmp; |
650 |
|
✗ |
elemPointReturn = elemPointReturnTmp; |
651 |
|
✗ |
projection = projectionTmp; |
652 |
|
✗ |
ielSupportDof = ielSupportDofTmp; |
653 |
|
✗ |
return 0;//success |
654 |
|
|
} else { |
655 |
|
|
// We have not found it, but maybe we found something slightly better |
656 |
|
|
|
657 |
|
|
// is this better than what we have? |
658 |
|
|
// if not we ignore it |
659 |
|
✗ |
if ( score < minScore ) { |
660 |
|
✗ |
if ( FelisceParam::verbose() > 3 ) |
661 |
|
✗ |
std::cout<<"Not found, but score improved!"<<std::endl; |
662 |
|
✗ |
minScore = score; |
663 |
|
|
//update current best |
664 |
|
✗ |
eltTypeReturn = eltTypeReturnTmp; |
665 |
|
✗ |
elemPointReturn = elemPointReturnTmp; |
666 |
|
✗ |
projection = projectionTmp; |
667 |
|
✗ |
ielSupportDof = ielSupportDofTmp; |
668 |
|
|
} |
669 |
|
|
} |
670 |
|
|
} |
671 |
|
|
} |
672 |
|
|
} |
673 |
|
✗ |
return 1; // not found |
674 |
|
|
} else { |
675 |
|
|
//standard result |
676 |
|
✗ |
return 0; // found |
677 |
|
|
} |
678 |
|
|
} |
679 |
|
|
|
680 |
|
✗ |
void SurfaceInterpolator::displayDataForSurfaceInterpolator() |
681 |
|
|
{ |
682 |
|
|
int rank; |
683 |
|
|
int numproc; |
684 |
|
✗ |
MPI_Comm_rank(PETSC_COMM_WORLD, &rank); |
685 |
|
✗ |
MPI_Comm_size(PETSC_COMM_WORLD, &numproc); |
686 |
|
|
|
687 |
|
✗ |
for ( int cProc(0); cProc<numproc; ++cProc ) { |
688 |
|
✗ |
if( rank == cProc ) { |
689 |
|
✗ |
std::cout << "---------- Proc numero: " << rank << std::endl; |
690 |
|
✗ |
for (auto i = m_surfLab2SetOfPointsAndIds.begin(); i != m_surfLab2SetOfPointsAndIds.end(); ++i) { |
691 |
|
✗ |
std::cout << "----- " << "Label: " << i->first << std::endl; |
692 |
|
✗ |
for (auto j = i->second.begin(); j != i->second.end(); ++j) { |
693 |
|
✗ |
std::cout << "P: "; j->first->print(10); |
694 |
|
✗ |
std::cout << "--> Number of Elements in the star: " << m_surfLabelAndIdPoint2Star[i->first][j->second].size() << std::endl; |
695 |
|
✗ |
std::cout << "----> Elements ids: "; |
696 |
|
✗ |
for(std::size_t k = 0; k < m_surfLabelAndIdPoint2Star[i->first][j->second].size(); ++k) |
697 |
|
✗ |
std::cout << m_surfLabelAndIdPoint2Star[i->first][j->second][k] << " "; |
698 |
|
✗ |
std::cout << std::endl; |
699 |
|
|
} |
700 |
|
|
} |
701 |
|
|
} |
702 |
|
✗ |
MPI_Barrier(MpiInfo::petscComm()); |
703 |
|
|
} |
704 |
|
|
} |
705 |
|
|
|
706 |
|
✗ |
GeometricMeshRegion::ElementType SurfaceInterpolator::getETandAssert2D(std::set<ElementType> setOfET){ |
707 |
|
✗ |
int nTypeElPerLab(0); |
708 |
|
✗ |
ElementType eltType = static_cast<ElementType>(0); |
709 |
|
✗ |
for ( std::set<ElementType>::iterator et=setOfET.begin(); |
710 |
|
✗ |
et!=setOfET.end(); |
711 |
|
✗ |
++et ) { |
712 |
|
✗ |
int first3DElement = 12; //TODO! |
713 |
|
✗ |
int first2DElement = 4; //TODO! |
714 |
|
✗ |
ElementType eltType2 = *et; |
715 |
|
✗ |
if( (int) eltType2 < first3DElement && (int)eltType2 >= first2DElement ) { |
716 |
|
✗ |
nTypeElPerLab++; |
717 |
|
✗ |
eltType=*et; |
718 |
|
|
} |
719 |
|
|
} |
720 |
|
|
// We assume that each label can have only one type of element. |
721 |
|
✗ |
FEL_ASSERT(nTypeElPerLab==1); |
722 |
|
✗ |
FEL_ASSERT(eltType!=0); |
723 |
|
✗ |
return eltType; |
724 |
|
|
} |
725 |
|
|
|
726 |
|
|
|
727 |
|
|
|
728 |
|
|
|
729 |
|
|
|
730 |
|
|
|
731 |
|
✗ |
bool SurfaceInterpolator::isPointInTriangle(const double* A,const double* B,const double* C,const double* D, double& alpha, double& beta) |
732 |
|
|
{ |
733 |
|
|
|
734 |
|
|
double V1[3],V2[3],H[3]; |
735 |
|
|
|
736 |
|
✗ |
V1[0]=B[0]-A[0]; |
737 |
|
✗ |
V1[1]=B[1]-A[1]; |
738 |
|
✗ |
V1[2]=B[2]-A[2]; |
739 |
|
|
|
740 |
|
✗ |
V2[0]=C[0]-A[0]; |
741 |
|
✗ |
V2[1]=C[1]-A[1]; |
742 |
|
✗ |
V2[2]=C[2]-A[2]; |
743 |
|
|
|
744 |
|
✗ |
H[0]=D[0]-A[0]; |
745 |
|
✗ |
H[1]=D[1]-A[1]; |
746 |
|
✗ |
H[2]=D[2]-A[2]; |
747 |
|
|
|
748 |
|
|
double det,det1,det2; |
749 |
|
✗ |
det = V1[0]*V2[1] - V2[0]*V1[1]; |
750 |
|
✗ |
det1 = V1[0]*V2[2] - V2[0]*V1[2]; |
751 |
|
✗ |
det2 = V1[1]*V2[2] - V2[1]*V1[2]; |
752 |
|
|
double fdet,fdet1,fdet2; |
753 |
|
✗ |
fdet=std::fabs(det); |
754 |
|
✗ |
fdet1=std::fabs(det1); |
755 |
|
✗ |
fdet2=std::fabs(det2); |
756 |
|
|
|
757 |
|
✗ |
alpha = -1; |
758 |
|
✗ |
beta = -1; |
759 |
|
✗ |
if ( fdet> fdet1 && fdet > fdet2 ) { |
760 |
|
✗ |
alpha=(V2[1]*H[0] - V2[0]*H[1])/det; |
761 |
|
✗ |
beta =(V1[0]*H[1] - V1[1]*H[0])/det; |
762 |
|
✗ |
} else if ( fdet1> fdet && fdet1 > fdet2 ){ |
763 |
|
✗ |
alpha=(V2[2]*H[0] - V2[0]*H[2])/det1; |
764 |
|
✗ |
beta =(V1[0]*H[2] - V1[2]*H[0])/det1; |
765 |
|
✗ |
} else if ( fdet2> fdet && fdet2 > fdet1 ){ |
766 |
|
✗ |
alpha=(V2[2]*H[1] - V2[1]*H[2])/det2; |
767 |
|
✗ |
beta =(V1[1]*H[2] - V1[2]*H[1])/det2; |
768 |
|
|
} |
769 |
|
✗ |
double eps = FelisceParam::instance().interpolatorThreshold; |
770 |
|
✗ |
return alpha>=-eps && beta >= -eps && alpha+beta<=1+eps; |
771 |
|
|
} |
772 |
|
|
|
773 |
|
✗ |
void SurfaceInterpolator::checkEdge(const double *p0,const double *p1,Point* thePoint,double& bestDistance) |
774 |
|
|
{ |
775 |
|
|
double distance,t; |
776 |
|
✗ |
bool inside = isPointInEdgeAndIfYesHowFar( p0, p1, thePoint->coor(), distance, t); |
777 |
|
✗ |
if ( inside && distance < bestDistance ) { |
778 |
|
✗ |
bestDistance = distance; |
779 |
|
|
} |
780 |
|
|
} |
781 |
|
|
|
782 |
|
✗ |
bool SurfaceInterpolator::checkTriangle( const Point& projection, const std::vector<Point*>& elemPoint, double& alpha, double& beta, Point* thePoint, double& bestEdgeDistance ) |
783 |
|
|
{ |
784 |
|
|
// Check if it is in the triangle |
785 |
|
✗ |
bool pointInElement(false); |
786 |
|
✗ |
pointInElement = isPointInTriangle(elemPoint[0]->coor(),elemPoint[1]->coor(),elemPoint[2]->coor(),projection.coor(),alpha,beta); |
787 |
|
✗ |
if ( pointInElement ){ |
788 |
|
✗ |
return pointInElement; //no need to check the edges; |
789 |
|
|
} |
790 |
|
✗ |
checkEdge(elemPoint[0]->coor(),elemPoint[1]->coor(),thePoint,bestEdgeDistance); |
791 |
|
✗ |
checkEdge(elemPoint[1]->coor(),elemPoint[2]->coor(),thePoint,bestEdgeDistance); |
792 |
|
✗ |
checkEdge(elemPoint[2]->coor(),elemPoint[0]->coor(),thePoint,bestEdgeDistance); |
793 |
|
✗ |
return pointInElement; |
794 |
|
|
} |
795 |
|
|
|
796 |
|
✗ |
bool SurfaceInterpolator::checkQuadrangle( const Point& projection, const std::vector<Point*>& elemPoint, double& alpha, double& beta, Point* thePoint, double& bestEdgeDistance ) |
797 |
|
|
{ |
798 |
|
✗ |
bool pointInElement(false); |
799 |
|
|
double alphaTmp,betaTmp, bestScore; |
800 |
|
✗ |
bestScore=1e20; |
801 |
|
✗ |
pointInElement = isPointInTriangle(elemPoint[0]->coor(),elemPoint[1]->coor(),elemPoint[2]->coor(),projection.coor(),alphaTmp,betaTmp); |
802 |
|
✗ |
updateBestScore(alphaTmp,betaTmp,bestScore,alpha,beta); |
803 |
|
✗ |
pointInElement = isPointInTriangle(elemPoint[1]->coor(),elemPoint[2]->coor(),elemPoint[3]->coor(),projection.coor(),alphaTmp,betaTmp) || pointInElement; |
804 |
|
✗ |
updateBestScore(alphaTmp,betaTmp,bestScore,alpha,beta); |
805 |
|
✗ |
pointInElement = isPointInTriangle(elemPoint[2]->coor(),elemPoint[3]->coor(),elemPoint[0]->coor(),projection.coor(),alphaTmp,betaTmp) || pointInElement; |
806 |
|
✗ |
updateBestScore(alphaTmp,betaTmp,bestScore,alpha,beta); |
807 |
|
✗ |
pointInElement = isPointInTriangle(elemPoint[3]->coor(),elemPoint[0]->coor(),elemPoint[1]->coor(),projection.coor(),alphaTmp,betaTmp) || pointInElement; |
808 |
|
✗ |
updateBestScore(alphaTmp,betaTmp,bestScore,alpha,beta); |
809 |
|
✗ |
if ( pointInElement ){ |
810 |
|
✗ |
return pointInElement; //no need to check the edges; |
811 |
|
|
} |
812 |
|
✗ |
checkEdge(elemPoint[0]->coor(),elemPoint[1]->coor(),thePoint,bestEdgeDistance); |
813 |
|
✗ |
checkEdge(elemPoint[1]->coor(),elemPoint[2]->coor(),thePoint,bestEdgeDistance); |
814 |
|
✗ |
checkEdge(elemPoint[2]->coor(),elemPoint[3]->coor(),thePoint,bestEdgeDistance); |
815 |
|
✗ |
checkEdge(elemPoint[3]->coor(),elemPoint[0]->coor(),thePoint,bestEdgeDistance); |
816 |
|
✗ |
return pointInElement; |
817 |
|
|
} |
818 |
|
|
|
819 |
|
✗ |
bool SurfaceInterpolator::isPointInEdgeAndIfYesHowFar( const double *p0,const double *p1,const double* thePoint,double& distance, double&t) |
820 |
|
|
{ |
821 |
|
✗ |
projectOnEdge(p0,p1,thePoint,t); |
822 |
|
✗ |
double eps = FelisceParam::instance().interpolatorThreshold; |
823 |
|
✗ |
if ( t < 1 + eps && t > -eps ) { |
824 |
|
✗ |
double dist(0); |
825 |
|
✗ |
for ( int i(0); i<3; ++i ) { |
826 |
|
✗ |
dist += ((1-t)*p0[i] +t*p1[i]-thePoint[i])*((1-t)*p0[i] +t*p1[i]-thePoint[i]); |
827 |
|
|
} |
828 |
|
✗ |
distance = std::sqrt(dist); |
829 |
|
✗ |
return true; |
830 |
|
|
} else { |
831 |
|
✗ |
distance = 1.e10; |
832 |
|
✗ |
return false; |
833 |
|
|
} |
834 |
|
|
} |
835 |
|
|
|
836 |
|
|
// elemPoint [in] points defining the plane, only the first three are used |
837 |
|
|
// thePoint [in] the point to be projected |
838 |
|
|
// projection [out] the projection of this point on the plane |
839 |
|
✗ |
void SurfaceInterpolator::projectOnElementPlane( const std::vector<Point*>& elemPoint, Point* thePoint, Point& projection ) |
840 |
|
|
{ |
841 |
|
|
Point normal; // Normal to the element plane |
842 |
|
✗ |
MathUtilities::CrossProduct(normal.getCoor(), (*elemPoint[0] - *elemPoint[1]).getCoor(), (*elemPoint[0] - *elemPoint[2]).getCoor()); |
843 |
|
|
|
844 |
|
✗ |
double nnorm = normal.norm(); |
845 |
|
✗ |
for( int coor(0); coor<3; coor++) { |
846 |
|
✗ |
normal.coor(coor)/=nnorm; |
847 |
|
|
} |
848 |
|
|
// We compute the intercept of the plane containing the element |
849 |
|
✗ |
double intercept = (*elemPoint[0]) * normal; |
850 |
|
|
|
851 |
|
|
// P_proj = P + s*normal |
852 |
|
|
// We compute s, by imposing that P_proj is on the plane. |
853 |
|
✗ |
double s = intercept - (*thePoint) * normal; |
854 |
|
✗ |
projection = s * normal + (*thePoint); |
855 |
|
|
} |
856 |
|
|
|
857 |
|
✗ |
void SurfaceInterpolator::projectOnEdge(const double *p0,const double *p1,const double* thePoint, double& t) |
858 |
|
|
{ |
859 |
|
✗ |
double denom(0); |
860 |
|
✗ |
double num(0); |
861 |
|
✗ |
for ( int i(0); i<3; ++i ) { |
862 |
|
✗ |
num += - p0[i]*p1[i]-thePoint[i]*p0[i]+thePoint[i]*p1[i] + p0[i]*p0[i]; |
863 |
|
✗ |
denom += -2*p0[i]*p1[i] +p1[i]*p1[i] + p0[i]*p0[i]; |
864 |
|
|
} |
865 |
|
✗ |
t = num/denom; |
866 |
|
|
} |
867 |
|
|
|
868 |
|
✗ |
void SurfaceInterpolator::projectOnBestEdge(const std::vector<Point*>& elemPoint, Point* thePoint, Point& projection) |
869 |
|
|
{ |
870 |
|
✗ |
double bestDist(1e20),bestT(0.0),bestEdgeA(0.0),bestEdgeB(0.0); |
871 |
|
|
double d,t; |
872 |
|
✗ |
for (std::size_t iPoint(0); iPoint < elemPoint.size(); iPoint++) { |
873 |
|
|
// We assume that the point describing the element are in an order such that |
874 |
|
|
// the edges are described by consecutive points |
875 |
|
✗ |
isPointInEdgeAndIfYesHowFar(elemPoint[iPoint]->coor(),elemPoint[( iPoint + 1 ) % elemPoint.size() ]->coor(),thePoint->coor(), d,t); |
876 |
|
✗ |
if ( d < bestDist ) { |
877 |
|
✗ |
bestDist = d; |
878 |
|
✗ |
bestT = t; |
879 |
|
✗ |
bestEdgeA = iPoint; |
880 |
|
✗ |
bestEdgeB = (iPoint+1)%elemPoint.size(); |
881 |
|
|
} |
882 |
|
|
} |
883 |
|
✗ |
for( int coor(0); coor<3; coor++) { |
884 |
|
✗ |
projection.coor()[coor] = (1-bestT)*elemPoint[bestEdgeA]->coor()[coor]+bestT*elemPoint[bestEdgeB]->coor()[coor]; |
885 |
|
|
} |
886 |
|
|
} |
887 |
|
|
|
888 |
|
✗ |
void SurfaceInterpolator::projectOnBestPoint(const std::vector<Point*>& elemPoint, Point* thePoint, Point& projection) |
889 |
|
|
{ |
890 |
|
✗ |
double best=1e20; |
891 |
|
✗ |
for (std::size_t iPoint = 0; iPoint < elemPoint.size(); iPoint++) { |
892 |
|
✗ |
double dist = elemPoint[iPoint]->dist( *thePoint); |
893 |
|
✗ |
if ( dist<best ) { |
894 |
|
✗ |
best=dist; |
895 |
|
✗ |
projection=*elemPoint[iPoint]; |
896 |
|
|
} |
897 |
|
|
} |
898 |
|
|
} |
899 |
|
|
|
900 |
|
✗ |
double SurfaceInterpolator::computeScore(double alpha, double beta) |
901 |
|
|
{ |
902 |
|
✗ |
double score(0); |
903 |
|
✗ |
if ( alpha < 0 ) score += -alpha; |
904 |
|
✗ |
if ( alpha > 1 ) score += alpha-1; |
905 |
|
✗ |
if ( beta < 0 ) score += -beta; |
906 |
|
✗ |
if ( beta > 1 ) score += beta-1; |
907 |
|
✗ |
if ( alpha+beta < 0 ) score += -(alpha+beta); |
908 |
|
✗ |
if ( alpha+beta > 1 ) score += alpha+beta-1; |
909 |
|
✗ |
return score; |
910 |
|
|
} |
911 |
|
|
|
912 |
|
✗ |
void SurfaceInterpolator::updateBestScore( double alpha, double beta, double& bestScore, double& alphabest, double& betabest) |
913 |
|
|
{ |
914 |
|
✗ |
double score = computeScore(alpha,beta); |
915 |
|
✗ |
if( score < bestScore ) { |
916 |
|
✗ |
bestScore = score; |
917 |
|
✗ |
alphabest = alpha; |
918 |
|
✗ |
betabest = beta; |
919 |
|
|
} |
920 |
|
|
} |
921 |
|
|
|
922 |
|
✗ |
int SurfaceInterpolator::closestPoint(const std::set< std::pair< Point*, felInt > >& setOfPointsAndIds, const Point* thePoint, Point*& closest, double& distance) |
923 |
|
|
{ |
924 |
|
|
// We start looking for the closest point |
925 |
|
✗ |
felInt idClosestPoint=-1; |
926 |
|
✗ |
double dist(0), distMin=1.e30; |
927 |
|
|
// We compute the distance between each point and our point |
928 |
|
✗ |
for(auto cPoint=setOfPointsAndIds.begin(); |
929 |
|
✗ |
cPoint!=setOfPointsAndIds.end(); ++cPoint ) { |
930 |
|
|
// Distance |
931 |
|
✗ |
dist = 0; |
932 |
|
✗ |
for( int coor(0); coor<3; coor++) { |
933 |
|
✗ |
dist += std::pow((thePoint->coor(coor)-cPoint->first->coor(coor)),2); |
934 |
|
|
} |
935 |
|
|
// Check if it is closer than the previous best |
936 |
|
✗ |
if ( dist < distMin ) { |
937 |
|
✗ |
distMin=dist; |
938 |
|
✗ |
idClosestPoint=cPoint->second; |
939 |
|
✗ |
closest = cPoint->first; |
940 |
|
|
} |
941 |
|
|
} |
942 |
|
✗ |
distance = std::sqrt(distMin); |
943 |
|
✗ |
return idClosestPoint; |
944 |
|
|
} |
945 |
|
|
|
946 |
|
|
} |
947 |
|
|
|
948 |
|
|
|