PrimitivePatchProjectPoints.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 Description
27  For every point on the patch find the closest face on the target side.
28  Return a target face label for each patch point
29 
30 \*---------------------------------------------------------------------------*/
31 
32 #include "boolList.H"
33 #include "PointHit.H"
34 #include "objectHit.H"
35 #include "bandCompression.H"
36 
37 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
38 
39 template
40 <
41  class Face,
42  template<class> class FaceList,
43  class PointField,
44  class PointType
45 >
46 template<class ToPatch>
50 (
51  const ToPatch& targetPatch,
52  const Field<PointType>& projectionDirection,
53  const intersection::algorithm alg,
54  const intersection::direction dir
55 ) const
56 {
57  // The current patch is slave, i.e. it is being projected onto the target
58 
59  if (projectionDirection.size() != nPoints())
60  {
62  << "Projection direction field does not correspond to "
63  << "patch points." << endl
64  << "Size: " << projectionDirection.size()
65  << " Number of points: " << nPoints()
66  << abort(FatalError);
67  }
68 
69  const labelList& slavePointOrder = localPointOrder();
70 
71  const labelList& slaveMeshPoints = meshPoints();
72 
73  // Result
74  List<objectHit> result(nPoints());
75 
76  const labelListList& masterFaceFaces = targetPatch.faceFaces();
77 
78  const ToPatch& masterFaces = targetPatch;
79 
80  const Field<PointType>& masterPoints = targetPatch.points();
81 
82  // Estimate face centre of target side
83  Field<PointType> masterFaceCentres(targetPatch.size());
84 
85  forAll(masterFaceCentres, facei)
86  {
87  masterFaceCentres[facei] =
88  average(masterFaces[facei].points(masterPoints));
89  }
90 
91  // Algorithm:
92  // Loop through all points of the slave side. For every point find the
93  // radius for the current contact face. If the contact point falls inside
94  // the face and the radius is smaller than for all neighbouring faces,
95  // the contact is found. If not, visit the neighbour closest to the
96  // calculated contact point. If a single master face is visited more than
97  // twice, initiate n-squared search.
98 
99  label curFace = 0;
100  label nNSquaredSearches = 0;
101 
102  forAll(slavePointOrder, pointi)
103  {
104  // Pick up slave point and direction
105  const label curLocalPointLabel = slavePointOrder[pointi];
106 
107  const PointType& curPoint =
108  points_[slaveMeshPoints[curLocalPointLabel]];
109 
110  const PointType& curProjectionDir =
111  projectionDirection[curLocalPointLabel];
112 
113  bool closer;
114 
115  boolList visitedTargetFace(targetPatch.size(), false);
116  bool doNSquaredSearch = false;
117 
118  bool foundEligible = false;
119 
120  scalar sqrDistance = GREAT;
121 
122  // Force the full search for the first point to ensure good
123  // starting face
124  if (pointi == 0)
125  {
126  doNSquaredSearch = true;
127  }
128  else
129  {
130  do
131  {
132  closer = false;
133  doNSquaredSearch = false;
134 
135  // Calculate intersection with curFace
136  PointHit<PointType> curHit =
137  masterFaces[curFace].ray
138  (
139  curPoint,
140  curProjectionDir,
141  masterPoints,
142  alg,
143  dir
144  );
145 
146  visitedTargetFace[curFace] = true;
147 
148  if (curHit.hit())
149  {
150  result[curLocalPointLabel] = objectHit(true, curFace);
151 
152  break;
153  }
154  else
155  {
156  // If a new miss is eligible, it is closer than
157  // any previous eligible miss (due to surface walk)
158 
159  // Only grab the miss if it is eligible
160  if (curHit.eligibleMiss())
161  {
162  foundEligible = true;
163  result[curLocalPointLabel] = objectHit(false, curFace);
164  }
165 
166  // Find the next likely face for intersection
167 
168  // Calculate the miss point on the plane of the
169  // face. This is cooked (illogical!) for fastest
170  // surface walk.
171  //
172  PointType missPlanePoint =
173  curPoint + curProjectionDir*curHit.distance();
174 
175  const labelList& masterNbrs = masterFaceFaces[curFace];
176 
177  sqrDistance =
178  magSqr(missPlanePoint - masterFaceCentres[curFace]);
179 
180  forAll(masterNbrs, nbrI)
181  {
182  if
183  (
184  magSqr
185  (
186  missPlanePoint
187  - masterFaceCentres[masterNbrs[nbrI]]
188  )
189  <= sqrDistance
190  )
191  {
192  closer = true;
193  curFace = masterNbrs[nbrI];
194  }
195  }
196 
197  if (visitedTargetFace[curFace])
198  {
199  // This face has already been visited.
200  // Execute n-squared search
201  doNSquaredSearch = true;
202  break;
203  }
204  }
205 
206  if (debug) Info<< ".";
207  } while (closer);
208  }
209 
210  if
211  (
212  doNSquaredSearch || !foundEligible
213  )
214  {
215  nNSquaredSearches++;
216 
217  if (debug)
218  {
219  Info<< "p " << curLocalPointLabel << ": ";
220  }
221 
222  result[curLocalPointLabel] = objectHit(false, -1);
223  scalar minDistance = GREAT;
224 
225  forAll(masterFaces, facei)
226  {
227  PointHit<PointType> curHit =
228  masterFaces[facei].ray
229  (
230  curPoint,
231  curProjectionDir,
232  masterPoints,
233  alg,
234  dir
235  );
236 
237  if (curHit.hit())
238  {
239  result[curLocalPointLabel] = objectHit(true, facei);
240  curFace = facei;
241 
242  break;
243  }
244  else if (curHit.eligibleMiss())
245  {
246  // Calculate min distance
247  scalar missDist =
248  Foam::mag(curHit.missPoint() - curPoint);
249 
250  if (missDist < minDistance)
251  {
252  minDistance = missDist;
253 
254  result[curLocalPointLabel] = objectHit(false, facei);
255  curFace = facei;
256  }
257  }
258  }
259 
260  if (debug)
261  {
262  Info<< result[curLocalPointLabel] << nl;
263  }
264  }
265  else
266  {
267  if (debug) Info<< "x";
268  }
269  }
270 
271  if (debug)
272  {
273  Info<< nl << "Executed " << nNSquaredSearches
274  << " n-squared searches out of total of "
275  << nPoints() << endl;
276  }
277 
278  return result;
279 }
280 
281 
282 template
283 <
284  class Face,
285  template<class> class FaceList,
286  class PointField,
287  class PointType
288 >
289 template<class ToPatch>
293 (
294  const ToPatch& targetPatch,
295  const Field<PointType>& projectionDirection,
296  const intersection::algorithm alg,
297  const intersection::direction dir
298 ) const
299 {
300  // The current patch is slave, i.e. it is being projected onto the target
301 
302  if (projectionDirection.size() != this->size())
303  {
305  << "Projection direction field does not correspond to patch faces."
306  << endl << "Size: " << projectionDirection.size()
307  << " Number of points: " << this->size()
308  << abort(FatalError);
309  }
310 
311  labelList slaveFaceOrder = bandCompression(faceFaces());
312 
313  // calculate master face centres
314  Field<PointType> masterFaceCentres(targetPatch.size());
315 
316  const labelListList& masterFaceFaces = targetPatch.faceFaces();
317 
318  const ToPatch& masterFaces = targetPatch;
319 
320  const typename ToPatch::PointFieldType& masterPoints = targetPatch.points();
321 
322  forAll(masterFaceCentres, facei)
323  {
324  masterFaceCentres[facei] =
325  masterFaces[facei].centre(masterPoints);
326  }
327 
328  // Result
329  List<objectHit> result(this->size());
330 
332  *this;
333 
334  const PointField& slaveGlobalPoints = points();
335 
336  // Algorithm:
337  // Loop through all points of the slave side. For every point find the
338  // radius for the current contact face. If the contact point falls inside
339  // the face and the radius is smaller than for all neighbouring faces,
340  // the contact is found. If not, visit the neighbour closest to the
341  // calculated contact point. If a single master face is visited more than
342  // twice, initiate n-squared search.
343 
344  label curFace = 0;
345  label nNSquaredSearches = 0;
346 
347  forAll(slaveFaceOrder, facei)
348  {
349  // pick up slave point and direction
350  const label curLocalFaceLabel = slaveFaceOrder[facei];
351 
352  const point& curFaceCentre =
353  slaveFaces[curLocalFaceLabel].centre(slaveGlobalPoints);
354 
355  const vector& curProjectionDir =
356  projectionDirection[curLocalFaceLabel];
357 
358  bool closer;
359 
360  boolList visitedTargetFace(targetPatch.size(), false);
361  bool doNSquaredSearch = false;
362 
363  bool foundEligible = false;
364 
365  scalar sqrDistance = GREAT;
366 
367  // Force the full search for the first point to ensure good
368  // starting face
369  if (facei == 0)
370  {
371  doNSquaredSearch = true;
372  }
373  else
374  {
375  do
376  {
377  closer = false;
378  doNSquaredSearch = false;
379 
380  // Calculate intersection with curFace
381  PointHit<PointType> curHit =
382  masterFaces[curFace].ray
383  (
384  curFaceCentre,
385  curProjectionDir,
386  masterPoints,
387  alg,
388  dir
389  );
390 
391  visitedTargetFace[curFace] = true;
392 
393  if (curHit.hit())
394  {
395  result[curLocalFaceLabel] = objectHit(true, curFace);
396 
397  break;
398  }
399  else
400  {
401  // If a new miss is eligible, it is closer than
402  // any previous eligible miss (due to surface walk)
403 
404  // Only grab the miss if it is eligible
405  if (curHit.eligibleMiss())
406  {
407  foundEligible = true;
408  result[curLocalFaceLabel] = objectHit(false, curFace);
409  }
410 
411  // Find the next likely face for intersection
412 
413  // Calculate the miss point. This is
414  // cooked (illogical!) for fastest surface walk.
415  //
416  PointType missPlanePoint =
417  curFaceCentre + curProjectionDir*curHit.distance();
418 
419  sqrDistance =
420  magSqr(missPlanePoint - masterFaceCentres[curFace]);
421 
422  const labelList& masterNbrs = masterFaceFaces[curFace];
423 
424  forAll(masterNbrs, nbrI)
425  {
426  if
427  (
428  magSqr
429  (
430  missPlanePoint
431  - masterFaceCentres[masterNbrs[nbrI]]
432  )
433  <= sqrDistance
434  )
435  {
436  closer = true;
437  curFace = masterNbrs[nbrI];
438  }
439  }
440 
441  if (visitedTargetFace[curFace])
442  {
443  // This face has already been visited.
444  // Execute n-squared search
445  doNSquaredSearch = true;
446  break;
447  }
448  }
449 
450  if (debug) Info<< ".";
451  } while (closer);
452  }
453 
454  if (doNSquaredSearch || !foundEligible)
455  {
456  nNSquaredSearches++;
457 
458  if (debug)
459  {
460  Info<< "p " << curLocalFaceLabel << ": ";
461  }
462 
463  result[curLocalFaceLabel] = objectHit(false, -1);
464  scalar minDistance = GREAT;
465 
466  forAll(masterFaces, facei)
467  {
468  PointHit<PointType> curHit =
469  masterFaces[facei].ray
470  (
471  curFaceCentre,
472  curProjectionDir,
473  masterPoints,
474  alg,
475  dir
476  );
477 
478  if (curHit.hit())
479  {
480  result[curLocalFaceLabel] = objectHit(true, facei);
481  curFace = facei;
482 
483  break;
484  }
485  else if (curHit.eligibleMiss())
486  {
487  // Calculate min distance
488  scalar missDist =
489  Foam::mag(curHit.missPoint() - curFaceCentre);
490 
491  if (missDist < minDistance)
492  {
493  minDistance = missDist;
494 
495  result[curLocalFaceLabel] = objectHit(false, facei);
496  curFace = facei;
497  }
498  }
499  }
500 
501  if (debug)
502  {
503  Info<< result[curLocalFaceLabel] << nl;
504  }
505  }
506  else
507  {
508  if (debug) Info<< "x";
509  }
510  }
511 
512  if (debug)
513  {
514  Info<< nl << "Executed " << nNSquaredSearches
515  << " n-squared searches out of total of "
516  << this->size() << endl;
517  }
518 
519  return result;
520 }
521 
522 
523 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::intersection::direction
direction
Definition: intersection.H:66
Foam::PrimitivePatch::projectFaceCentres
List< objectHit > projectFaceCentres(const ToPatch &targetPatch, const Field< PointType > &projectionDirection, const intersection::algorithm=intersection::FULL_RAY, const intersection::direction=intersection::VECTOR) const
Project vertices of patch onto another patch.
boolList.H
Foam::PointHit::hit
bool hit() const
Is there a hit.
Definition: PointHit.H:124
Foam::PrimitivePatch::projectPoints
List< objectHit > projectPoints(const ToPatch &targetPatch, const Field< PointType > &projectionDirection, const intersection::algorithm=intersection::FULL_RAY, const intersection::direction=intersection::VECTOR) const
Project vertices of patch onto another patch.
Foam::PointHit
This class describes the interaction of a face and a point. It carries the info of a successful hit a...
Definition: PointHit.H:53
Foam::bandCompression
labelList bandCompression(const labelListList &addressing)
Renumbers the addressing to reduce the band of the matrix.
Definition: bandCompression.C:44
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
objectHit.H
Foam::PointHit::distance
scalar distance() const
Return distance to hit.
Definition: PointHit.H:143
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:62
Foam::Field< PointType >
Foam::fac::average
tmp< GeometricField< Type, faPatchField, areaMesh > > average(const GeometricField< Type, faePatchField, edgeMesh > &ssf)
Area-weighted average a edgeField creating a areaField.
Definition: facAverage.C:47
Foam::PointHit::eligibleMiss
bool eligibleMiss() const
Is this an eligible miss.
Definition: PointHit.H:168
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::intersection::algorithm
algorithm
Definition: intersection.H:72
Foam::FatalError
error FatalError
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
bandCompression.H
The bandCompression function renumbers the addressing such that the band of the matrix is reduced....
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::Vector< scalar >
Foam::List< Foam::objectHit >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
points
const pointField & points
Definition: gmvOutputHeader.H:1
PointHit.H
Foam::objectHit
This class describes a combination of target object index and success flag.
Definition: objectHit.H:49
Foam::PointHit::missPoint
const Point & missPoint() const
Return miss point.
Definition: PointHit.H:149
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:90