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