advancingFrontAMI.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) 2013-2016 OpenFOAM Foundation
9  Copyright (C) 2015-2020 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 \*---------------------------------------------------------------------------*/
28 
29 #include "advancingFrontAMI.H"
30 #include "meshTools.H"
31 #include "mapDistribute.H"
32 #include "unitConversion.H"
33 
34 #include "findNearestMaskedOp.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40  defineTypeNameAndDebug(advancingFrontAMI, 0);
41 }
42 
43 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
44 
46 {
47  const auto& src = srcPatch();
48  const auto& tgt = tgtPatch();
49 
50  if (debug && (!src.size() || !tgt.size()))
51  {
52  Pout<< "AMI: Patches not on processor: Source faces = "
53  << src.size() << ", target faces = " << tgt.size()
54  << endl;
55  }
56 
57 
58  if (requireMatch_)
59  {
60  const scalar maxBoundsError = 0.05;
61 
62  // Check bounds of source and target
63  boundBox bbSrc(src.points(), src.meshPoints(), true);
64  boundBox bbTgt(tgt.points(), tgt.meshPoints(), true);
65 
66  boundBox bbTgtInf(bbTgt);
67  bbTgtInf.inflate(maxBoundsError);
68 
69  if (!bbTgtInf.contains(bbSrc))
70  {
72  << "Source and target patch bounding boxes are not similar"
73  << nl
74  << " source box span : " << bbSrc.span() << nl
75  << " target box span : " << bbTgt.span() << nl
76  << " source box : " << bbSrc << nl
77  << " target box : " << bbTgt << nl
78  << " inflated target box : " << bbTgtInf << endl;
79  }
80  }
81 }
82 
83 
85 {
86  // Create processor map of extended cells. This map gets (possibly
87  // remote) cells from the src mesh such that they (together) cover
88  // all of tgt
89  extendedTgtMapPtr_.reset(calcProcMap(srcPatch0(), tgtPatch0()));
90  const mapDistribute& map = extendedTgtMapPtr_();
91 
92  // Original faces from tgtPatch
93  // Note: in globalIndexing since might be remote
94  globalIndex globalTgtFaces(tgtPatch0().size());
95  distributeAndMergePatches
96  (
97  map,
98  tgtPatch0(),
99  globalTgtFaces,
100  extendedTgtFaces_,
101  extendedTgtPoints_,
102  extendedTgtFaceIDs_
103  );
104 
105  // Create a representation of the tgt patch that is extended to overlap
106  // the src patch
107  extendedTgtPatchPtr_.reset
108  (
110  (
111  SubList<face>(extendedTgtFaces_),
112  extendedTgtPoints_
113  )
114  );
115 }
116 
117 
118 bool Foam::advancingFrontAMI::initialiseWalk(label& srcFacei, label& tgtFacei)
119 {
120  const auto& src = this->srcPatch();
121  const auto& tgt = this->tgtPatch();
122 
123  bool foundFace = false;
124 
125  // Check that patch sizes are valid
126  if (!src.size())
127  {
128  return foundFace;
129  }
130  else if (!tgt.size())
131  {
133  << src.size() << " source faces but no target faces" << endl;
134 
135  return foundFace;
136  }
137 
138  // Reset the octree
139  treePtr_.reset(createTree(tgt));
140 
141  // Find initial face match using brute force/octree search
142  if ((srcFacei == -1) || (tgtFacei == -1))
143  {
144  srcFacei = 0;
145  tgtFacei = 0;
146  forAll(src, facei)
147  {
148  tgtFacei = findTargetFace(facei);
149  if (tgtFacei >= 0)
150  {
151  srcFacei = facei;
152  foundFace = true;
153  break;
154  }
155  }
156 
157  if (!foundFace)
158  {
159  if (requireMatch_)
160  {
162  << "Unable to find initial target face"
163  << abort(FatalError);
164  }
165 
166  return foundFace;
167  }
168  }
169 
170  if (debug)
171  {
172  Pout<< "AMI: initial target face = " << tgtFacei << endl;
173  }
174 
175  return true;
176 }
177 
178 
180 (
181  const scalar area,
182  const face& f1,
183  const face& f2,
184  const pointField& f1Points,
185  const pointField& f2Points
186 ) const
187 {
188  static label count = 1;
189 
190  const pointField f1pts = f1.points(f1Points);
191  const pointField f2pts = f2.points(f2Points);
192 
193  Pout<< "Face intersection area (" << count << "):" << nl
194  << " f1 face = " << f1 << nl
195  << " f1 pts = " << f1pts << nl
196  << " f2 face = " << f2 << nl
197  << " f2 pts = " << f2pts << nl
198  << " area = " << area
199  << endl;
200 
201  OFstream os("areas" + name(count) + ".obj");
202 
203  for (const point& pt : f1pts)
204  {
205  meshTools::writeOBJ(os, pt);
206  }
207  os<< "l";
208  forAll(f1pts, i)
209  {
210  os<< " " << i + 1;
211  }
212  os<< " 1" << endl;
213 
214  for (const point& pt : f2pts)
215  {
216  meshTools::writeOBJ(os, pt);
217  }
218  os<< "l";
219  const label n = f1pts.size();
220  forAll(f2pts, i)
221  {
222  os<< " " << n + i + 1;
223  }
224  os<< " " << n + 1 << endl;
225 
226  ++count;
227 }
228 
229 
231 (
232  const label srcFacei,
233  const UList<label>& excludeFaces,
234  const label srcFacePti
235 ) const
236 {
237  const auto& src = srcPatch();
238 
239  label targetFacei = -1;
240 
241  const pointField& srcPts = src.points();
242  const face& srcFace = src[srcFacei];
243 
244  findNearestMaskedOp<primitivePatch> fnOp(*treePtr_, excludeFaces);
245 
246  const boundBox bb(srcPts, srcFace, false);
247 
248  const point srcPt =
249  srcFacePti == -1 ? bb.centre() : srcPts[srcFace[srcFacePti]];
250 
251  const pointIndexHit sample =
252  treePtr_->findNearest(srcPt, magSqr(bb.max() - bb.centre()), fnOp);
253 
254  if (sample.hit())
255  {
256  targetFacei = sample.index();
257 
258  if (debug)
259  {
260  Pout<< "Source point = " << srcPt << ", Sample point = "
261  << sample.hitPoint() << ", Sample index = " << sample.index()
262  << endl;
263  }
264  }
265 
266  return targetFacei;
267 }
268 
269 
271 (
272  const label facei,
273  const primitivePatch& patch,
274  const DynamicList<label>& visitedFaces,
275  DynamicList<label>& faceIDs
276 ) const
277 {
278  static const scalar thetaCos = Foam::cos(degToRad(89.0));
279 
280  const labelList& nbrFaces = patch.faceFaces()[facei];
281 
282  // Filter out faces already visited from face neighbours
283  for (const label nbrFacei : nbrFaces)
284  {
285  // Prevent addition of face if it is not on the same plane-ish
286  if (!visitedFaces.found(nbrFacei) && !faceIDs.found(nbrFacei))
287  {
288  const vector& n1 = patch.faceNormals()[facei];
289  const vector& n2 = patch.faceNormals()[nbrFacei];
290 
291  const scalar cosI = n1 & n2;
292 
293  if (cosI > thetaCos)
294  {
295  faceIDs.append(nbrFacei);
296  }
297  }
298  }
299 }
300 
301 
303 (
304  const primitivePatch& patch,
305  List<DynamicList<face>>& tris,
306  List<scalar>& magSf
307 ) const
308 {
309  const pointField& points = patch.points();
310  tris.setSize(patch.size());
311  magSf.setSize(patch.size());
312 
313  // Using methods that index into existing points
314  forAll(patch, facei)
315  {
316  tris[facei].clear();
317 
318  switch (triMode_)
319  {
321  {
322  faceAreaIntersect::triangleFan(patch[facei], tris[facei]);
323  break;
324  }
326  {
327  patch[facei].triangles(points, tris[facei]);
328  break;
329  }
330  }
331 
332  const DynamicList<face>& triFaces = tris[facei];
333  magSf[facei] = 0;
334  for (const face& f : triFaces)
335  {
336  magSf[facei] +=
338  (
339  points[f[0]],
340  points[f[1]],
341  points[f[2]]
342  ).mag();
343  }
344  }
345 }
346 
347 
349 {
350  if (!requireMatch_ && distributed())
351  {
352  scalarList newTgtMagSf(std::move(tgtMagSf_));
353 
354  // Assign default sizes. Override selected values with calculated
355  // values. This is to support ACMI where some of the target faces
356  // are never used (so never get sent over and hence never assigned
357  // to)
358  tgtMagSf_ = tgtPatch0().magFaceAreas();
359 
360  for (const labelList& smap : this->extendedTgtMapPtr_->subMap())
361  {
362  UIndirectList<scalar>(tgtMagSf_, smap) =
363  UIndirectList<scalar>(newTgtMagSf, smap);
364  }
365  }
366 }
367 
368 
369 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
370 
372 (
373  const dictionary& dict,
374  const bool reverseTarget
375 )
376 :
377  AMIInterpolation(dict, reverseTarget),
378  srcTris_(),
379  tgtTris_(),
380  extendedTgtPatchPtr_(nullptr),
381  extendedTgtFaces_(),
382  extendedTgtPoints_(),
383  extendedTgtFaceIDs_(),
384  extendedTgtMapPtr_(nullptr),
385  srcNonOverlap_(),
386  triMode_
387  (
389  (
390  "triMode",
391  dict,
393  )
394  )
395 {}
396 
397 
399 (
400  const bool requireMatch,
401  const bool reverseTarget,
402  const scalar lowWeightCorrection,
404 )
405 :
406  AMIInterpolation(requireMatch, reverseTarget, lowWeightCorrection),
407  srcTris_(),
408  tgtTris_(),
409  extendedTgtPatchPtr_(nullptr),
410  extendedTgtFaces_(),
411  extendedTgtPoints_(),
412  extendedTgtFaceIDs_(),
413  extendedTgtMapPtr_(nullptr),
414  srcNonOverlap_(),
415  triMode_(triMode)
416 {}
417 
418 
420 :
421  AMIInterpolation(ami),
422  srcTris_(),
423  tgtTris_(),
424  extendedTgtPatchPtr_(nullptr),
425  extendedTgtFaces_(),
426  extendedTgtPoints_(),
427  extendedTgtFaceIDs_(),
428  extendedTgtMapPtr_(nullptr),
429  srcNonOverlap_(),
430  triMode_(ami.triMode_)
431 {}
432 
433 
434 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
435 
437 (
438  const primitivePatch& srcPatch,
439  const primitivePatch& tgtPatch,
440  const autoPtr<searchableSurface>& surfPtr
441 )
442 {
443  if (AMIInterpolation::calculate(srcPatch, tgtPatch, surfPtr))
444  {
445  // Create a representation of the target patch that covers the source
446  // patch
447  if (distributed())
448  {
449  createExtendedTgtPatch();
450  }
451 
452  const auto& src = this->srcPatch();
453  const auto& tgt = this->tgtPatch();
454 
455  // Initialise area magnitudes
456  srcMagSf_.setSize(src.size(), 1.0);
457  tgtMagSf_.setSize(tgt.size(), 1.0);
458 
459  // Source and target patch triangulations
460  triangulatePatch(src, srcTris_, srcMagSf_);
461  triangulatePatch(tgt, tgtTris_, tgtMagSf_);
462 
463  checkPatches();
464 
465  // Set initial sizes for weights and addressing - must be done even if
466  // returns false below
467  srcAddress_.setSize(src.size());
468  srcWeights_.setSize(src.size());
469  tgtAddress_.setSize(tgt.size());
470  tgtWeights_.setSize(tgt.size());
471 
472  return true;
473  }
474 
475  return false;
476 }
477 
478 
479 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
meshTools.H
Foam::AMIInterpolation::calculate
virtual bool calculate(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const autoPtr< searchableSurface > &surfPtr=nullptr)
Update addressing, weights and (optional) centroids.
Definition: AMIInterpolation.C:734
Foam::advancingFrontAMI::triangulatePatch
void triangulatePatch(const primitivePatch &patch, List< DynamicList< face >> &tris, List< scalar > &magSf) const
Helper function to decompose a patch.
Definition: advancingFrontAMI.C:303
Foam::advancingFrontAMI::initialiseWalk
bool initialiseWalk(label &srcFacei, label &tgtFacei)
Initialise walk and return true if all ok.
Definition: advancingFrontAMI.C:118
Foam::faceAreaIntersect::triangulationMode
triangulationMode
Definition: faceAreaIntersect.H:63
Foam::DynamicList< label >
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
Foam::SubList
A List obtained as a section of another List.
Definition: SubList.H:54
Foam::advancingFrontAMI::nonConformalCorrection
virtual void nonConformalCorrection()
Correction for non-conformal interpolations, e.g. for ACMI.
Definition: advancingFrontAMI.C:348
unitConversion.H
Unit conversion functions.
Foam::advancingFrontAMI::calculate
virtual bool calculate(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const autoPtr< searchableSurface > &surfPtr=nullptr)
Update addressing, weights and (optional) centroids.
Definition: advancingFrontAMI.C:437
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:97
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::advancingFrontAMI::appendNbrFaces
void appendNbrFaces(const label facei, const primitivePatch &patch, const DynamicList< label > &visitedFaces, DynamicList< label > &faceIDs) const
Add faces neighbouring facei to the ID list.
Definition: advancingFrontAMI.C:271
Foam::faceAreaIntersect::triangulationModeNames_
static const Enum< triangulationMode > triangulationModeNames_
Definition: faceAreaIntersect.H:69
Foam::advancingFrontAMI::checkPatches
void checkPatches() const
Check AMI patch coupling.
Definition: advancingFrontAMI.C:45
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::PointIndexHit
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:52
Foam::Field< vector >
Foam::AMIInterpolation::requireMatch_
bool requireMatch_
Definition: AMIInterpolation.H:97
Foam::boundBox::centre
point centre() const
The centre (midpoint) of the bounding box.
Definition: boundBoxI.H:115
Foam::advancingFrontAMI::createExtendedTgtPatch
void createExtendedTgtPatch()
Create a map that extends tgtPatch so that it covers srcPatch.
Definition: advancingFrontAMI.C:84
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
Foam::mapDistribute
Class containing processor-to-processor mapping information.
Definition: mapDistribute.H:163
findNearestMaskedOp.H
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
os
OBJstream os(runTime.globalPath()/outputName)
Foam::faceAreaIntersect::tmFan
Definition: faceAreaIntersect.H:65
Foam::advancingFrontAMI::findTargetFace
label findTargetFace(const label srcFacei, const UList< label > &excludeFaces=UList< label >::null(), const label srcFacePti=-1) const
Definition: advancingFrontAMI.C:231
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::degToRad
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Definition: unitConversion.H:48
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
Foam::autoPtr
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: HashPtrTable.H:53
Foam::advancingFrontAMI::writeIntersectionOBJ
void writeIntersectionOBJ(const scalar area, const face &f1, const face &f2, const pointField &f1Points, const pointField &f2Points) const
Write triangle intersection to OBJ file.
Definition: advancingFrontAMI.C:180
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::nl
constexpr char nl
Definition: Ostream.H:404
mapDistribute.H
f
labelList f(nPoints)
Foam::foamVersion::patch
const std::string patch
OpenFOAM patch number as a std::string.
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::Vector< scalar >
Foam::List< label >
advancingFrontAMI.H
Foam::AMIInterpolation
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
Definition: AMIInterpolation.H:79
Foam::UList< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::face::points
pointField points(const UList< point > &pts) const
Return the points corresponding to this face.
Definition: faceI.H:87
Foam::advancingFrontAMI
Base class for Arbitrary Mesh Interface (AMI) methods.
Definition: advancingFrontAMI.H:55
Foam::fieldTypes::area
const wordList area
Standard area field types (scalar, vector, tensor, etc)
Foam::boundBox
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::advancingFrontAMI::srcPatch
const primitivePatch & srcPatch() const
Return const access to the source patch.
Definition: advancingFrontAMII.H:28
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::findNearestMaskedOp
Definition: findNearestMaskedOp.H:8
Foam::advancingFrontAMI::tgtPatch
const primitivePatch & tgtPatch() const
Return const access to the target patch.
Definition: advancingFrontAMII.H:41
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::advancingFrontAMI::advancingFrontAMI
advancingFrontAMI(const dictionary &dict, const bool reverseTarget)
Construct from components.
Definition: advancingFrontAMI.C:372
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
Foam::faceAreaIntersect::triangleFan
static void triangleFan(const face &f, DynamicList< face > &faces)
Decompose face into triangle fan.
Definition: faceAreaIntersectI.H:32
Foam::triPointRef
triangle< point, const point & > triPointRef
A triangle using referred points.
Definition: triangle.H:71
Foam::faceAreaIntersect::tmMesh
Definition: faceAreaIntersect.H:66
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:79
sample
Minimal example by using system/controlDict.functions:
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:265