mappedPatchBase.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "mappedPatchBase.H"
27 #include "SubField.H"
28 #include "Time.H"
29 #include "triPointRef.H"
30 #include "treeDataPoint.H"
31 #include "indexedOctree.H"
32 #include "globalIndex.H"
33 #include "RemoteData.H"
34 
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
40 
41  const scalar mappedPatchBase::defaultMatchTol_ = 1e-4;
42 }
43 
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
48 {
49  return patch_.primitivePatch::faceAreas();
50 }
51 
52 
54 {
55  return patch_.primitivePatch::faceCentres();
56 }
57 
58 
60 {
61  return patch_.localPoints();
62 }
63 
64 
66 {
67  return
68  nbrPatchIsMapped()
69  ? nbrMappedPatch().patchFaceAreas()
70  : tmp<vectorField>(nbrPolyPatch().primitivePatch::faceAreas());
71 }
72 
73 
75 {
76  return
77  nbrPatchIsMapped()
78  ? nbrMappedPatch().patchFaceCentres()
80 }
81 
82 
84 {
85  return
86  nbrPatchIsMapped()
87  ? nbrMappedPatch().patchLocalPoints()
88  : tmp<vectorField>(nbrPolyPatch().localPoints());
89 }
90 
91 
93 {
94  if (treeMapPtr_.valid())
95  {
97  << "Mapping already calculated" << exit(FatalError);
98  }
99 
100  if (sameUntransformedPatch())
101  {
103  << "Patch " << patch_.name() << " is mapping itself with no "
104  << "transform. Mapping data does not need to be constructed."
105  << exit(FatalError);
106  }
107 
108  // Calculate the transform as necessary
109  transform_ =
111  (
112  patch_.name(),
113  patchFaceCentres(),
114  patchFaceAreas(),
115  transform_,
116  nbrPolyPatch().name(),
117  nbrPatchFaceCentres(),
118  nbrPatchFaceAreas(),
119  nbrPatchIsMapped()
120  ? nbrMappedPatch().transform_
121  : cyclicTransform(false),
122  matchTol_,
123  true
124  );
125 
126  // Build the mapping
127  if (usingTree_)
128  {
129  const globalIndex patchGlobalIndex(patch_.size());
130 
131  // Find processor and cell/face indices of samples
132  labelList sampleGlobalPatchFaces, sampleIndices;
133  {
134  // Gather the sample points into a single globally indexed list
135  List<point> allPoints(patchGlobalIndex.size());
136  {
137  List<pointField> procSamplePoints(Pstream::nProcs());
138  procSamplePoints[Pstream::myProcNo()] =
139  transform_.transform().invTransformPosition
140  (
141  patchFaceCentres()
142  );
143  Pstream::gatherList(procSamplePoints);
144  Pstream::scatterList(procSamplePoints);
145 
146  forAll(procSamplePoints, proci)
147  {
148  forAll(procSamplePoints[proci], procSamplei)
149  {
150  allPoints
151  [
152  patchGlobalIndex.toGlobal(proci, procSamplei)
153  ] = procSamplePoints[proci][procSamplei];
154  }
155  }
156  }
157 
158  // List of possibly remote mapped faces
159  List<RemoteData<scalar>> allNearest(patchGlobalIndex.size());
160 
161  // Find nearest face opposite every face
162  if (nbrPolyPatch().empty())
163  {
164  forAll(allPoints, alli)
165  {
166  allNearest[alli].proci = -1;
167  allNearest[alli].elementi = -1;
168  allNearest[alli].data = Foam::sqr(great);
169  }
170  }
171  else
172  {
173  const pointField nbrPoints(nbrPatchFaceCentres());
174 
175  const treeBoundBox nbrPointsBb
176  (
177  treeBoundBox(nbrPoints).extend(1e-4)
178  );
179 
181  (
182  treeDataPoint(nbrPoints),
183  nbrPointsBb, // overall search domain
184  8, // maxLevel
185  10, // leafsize
186  3.0 // duplicity
187  );
188 
189  forAll(allPoints, alli)
190  {
191  const point& p = allPoints[alli];
192 
193  const pointIndexHit pih =
194  tree.findNearest(p, magSqr(nbrPointsBb.span()));
195 
196  if (pih.hit())
197  {
198  allNearest[alli].proci = Pstream::myProcNo();
199  allNearest[alli].elementi = pih.index();
200  allNearest[alli].data =
201  magSqr(nbrPoints[pih.index()] - p);
202  }
203  }
204  }
205 
206  // Find nearest. Combine on master.
208  (
209  allNearest,
211  );
212  Pstream::listCombineScatter(allNearest);
213 
214  // Determine the number of faces for which a nearest neighbouring
215  // face was not found (no reduction necessary as this is computed
216  // from synchronised data)
217  label nNotFound = 0;
218  forAll(allPoints, alli)
219  {
220  if (allNearest[alli].proci == -1)
221  {
222  nNotFound ++;
223  }
224  }
225 
226  // If any points were not found within cells then re-search for
227  // them using a nearest test, which should not fail. Warn that this
228  // is happening. If any points were not found for some other
229  // method, then fail.
230  if (nNotFound)
231  {
233  << "Mapping failed for " << nl
234  << " patch: " << patch_.name() << nl
235  << " neighbourRegion: " << nbrRegionName() << nl
236  << " neighbourPatch: " << nbrPatchName() << nl
237  << exit(FatalError);
238  }
239 
240  // Build lists of samples
241  DynamicList<label> samplePatchGlobalFacesDyn;
242  DynamicList<label> sampleIndicesDyn;
243  forAll(allNearest, alli)
244  {
245  if (allNearest[alli].proci == Pstream::myProcNo())
246  {
247  samplePatchGlobalFacesDyn.append(alli);
248  sampleIndicesDyn.append(allNearest[alli].elementi);
249  }
250  }
251  sampleGlobalPatchFaces.transfer(samplePatchGlobalFacesDyn);
252  sampleIndices.transfer(sampleIndicesDyn);
253  }
254 
255  // Construct distribution schedule
256  List<Map<label>> compactMap;
257  treeMapPtr_.reset
258  (
259  new distributionMap
260  (
261  patchGlobalIndex,
262  sampleGlobalPatchFaces,
263  compactMap
264  )
265  );
266  const labelList oldToNew(move(sampleGlobalPatchFaces));
267  const labelList oldSampleIndices(move(sampleIndices));
268 
269  // Construct input mapping for data to be distributed
270  treeNbrPatchFaceIndices_ = labelList(treeMapPtr_->constructSize(), -1);
271  UIndirectList<label>(treeNbrPatchFaceIndices_, oldToNew) =
272  oldSampleIndices;
273 
274  // Reverse the map. This means the map is "forward" when going from
275  // the neighbour patch to this patch, which is logical.
276  treeMapPtr_.reset
277  (
278  new distributionMap
279  (
280  patch_.size(),
281  move(treeMapPtr_->constructMap()),
282  move(treeMapPtr_->subMap())
283  )
284  );
285  }
286  else
287  {
288  if (patchToPatchIsValid_)
289  {
291  << "Patch-to-patch already calculated" << exit(FatalError);
292  }
293 
294  const pointField patchLocalPoints(this->patchLocalPoints());
295  const pointField nbrPatchLocalPoints(this->nbrPatchLocalPoints());
296 
297  const primitivePatch patch
298  (
299  SubList<face>(patch_.localFaces(), patch_.size()),
300  patchLocalPoints
301  );
302  const primitivePatch nbrPatch
303  (
304  SubList<face>(nbrPolyPatch().localFaces(), nbrPolyPatch().size()),
305  nbrPatchLocalPoints
306  );
307 
308  patchToPatchPtr_->update
309  (
310  patch,
311  patch.pointNormals(),
312  nbrPatch,
313  transform_.transform()
314  );
315 
316  patchToPatchIsValid_ = true;
317  }
318 }
319 
320 
321 // * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
322 
324 :
326  usingTree_(true),
327  treeMapPtr_(nullptr),
328  treeNbrPatchFaceIndices_(),
329  patchToPatchIsValid_(false),
330  patchToPatchPtr_(nullptr),
331  matchTol_(defaultMatchTol_),
332  reMapAfterMove_(true),
333  reMapNbr_(false)
334 {}
335 
336 
338 (
339  const polyPatch& pp,
340  const word& nbrRegionName,
341  const word& nbrPatchName,
343 )
344 :
345  mappedPatchBaseBase(pp, nbrRegionName, nbrPatchName, transform),
346  usingTree_(true),
347  treeMapPtr_(nullptr),
348  treeNbrPatchFaceIndices_(),
349  patchToPatchIsValid_(false),
350  patchToPatchPtr_(nullptr),
351  matchTol_(defaultMatchTol_),
352  reMapAfterMove_(true),
353  reMapNbr_(false)
354 {}
355 
356 
358 (
359  const polyPatch& pp,
360  const dictionary& dict,
361  const bool defaultTransformIsNone
362 )
363 :
364  mappedPatchBaseBase(pp, dict, defaultTransformIsNone),
365  usingTree_(!dict.found("method") && !dict.found("sampleMode")),
366  treeMapPtr_(nullptr),
367  treeNbrPatchFaceIndices_(),
368  patchToPatchIsValid_(false),
369  patchToPatchPtr_
370  (
371  !usingTree_
372  ? patchToPatch::New
373  (
374  dict.lookupBackwardsCompatible<word>({"method", "sampleMode"}),
375  false
376  ).ptr()
377  : nullptr
378  ),
379  matchTol_(dict.lookupOrDefault("matchTolerance", defaultMatchTol_)),
380  reMapAfterMove_(dict.lookupOrDefault<bool>("reMapAfterMove", true)),
381  reMapNbr_(false)
382 {}
383 
384 
386 (
387  const polyPatch& pp,
388  const mappedPatchBase& mpb
389 )
390 :
391  mappedPatchBaseBase(pp, mpb),
392  usingTree_(mpb.usingTree_),
393  treeMapPtr_(nullptr),
394  treeNbrPatchFaceIndices_(),
395  patchToPatchIsValid_(false),
396  patchToPatchPtr_
397  (
398  !usingTree_
399  ? patchToPatch::New(mpb.patchToPatchPtr_->type(), false).ptr()
400  : nullptr
401  ),
402  matchTol_(mpb.matchTol_),
403  reMapAfterMove_(mpb.reMapAfterMove_),
404  reMapNbr_(false)
405 {}
406 
407 
408 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
409 
411 {}
412 
413 
414 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
415 
417 (
418  const polyPatch& patch
419 )
420 {
421  if (!isA<mappedPatchBase>(patch))
422  {
424  << "Patch " << patch.name() << " is not of type "
425  << typeName << exit(FatalError);
426  }
427 
428  return refCast<const mappedPatchBase>(patch);
429 }
430 
431 
433 {
434  if (reMapAfterMove_)
435  {
436  treeMapPtr_.clear();
437  treeNbrPatchFaceIndices_.clear();
438  patchToPatchIsValid_ = false;
439  reMapNbr_ = true;
440  }
441 }
442 
443 
445 {
447 
448  if (!usingTree_)
449  {
450  writeEntry(os, "method", patchToPatchPtr_->type());
451  }
452 
453  writeEntryIfDifferent(os, "matchTolerance", defaultMatchTol_, matchTol_);
454 
455  writeEntryIfDifferent<bool>(os, "reMapAfterMove", true, reMapAfterMove_);
456 }
457 
458 
459 // ************************************************************************* //
bool found
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:54
label index() const
Return index.
bool hit() const
Is there a hit.
const Field< PointType > & pointNormals() const
Return point normals for patch.
const Field< PointType > & faceAreas() const
Return face areas for patch.
const Field< PointType > & faceCentres() const
Return face centres for patch.
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
A List obtained as a section of another List.
Definition: SubList.H:56
A List with indirect addressing.
Definition: UIndirectList.H:60
T * data()
Return a pointer to the first data element,.
Definition: UListI.H:149
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:90
Cyclic plane transformation.
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T, if not found return the given default.
Class containing processor-to-processor mapping information.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
label size() const
Global sum of localSizes.
Definition: globalIndexI.H:66
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
Non-pointer based hierarchical recursive searching.
Definition: indexedOctree.H:72
Base class for engines and poly patches which provide mapping between two poly patches.
const polyPatch & patch_
Patch to map to.
virtual void write(Ostream &) const
Write as a dictionary.
Engine and base class for poly patches which provides interpolative mapping between two globally conf...
tmp< pointField > nbrPatchLocalPoints() const
Get the local points for the neighbour patch.
static const mappedPatchBase & getMap(const polyPatch &patch)
Cast the given polyPatch to a mappedPatchBase. Handle errors.
virtual void write(Ostream &) const
Write as a dictionary.
virtual tmp< vectorField > patchFaceAreas() const
Get the face-areas for this patch.
virtual tmp< pointField > patchLocalPoints() const
Get the local points for this patch.
static const scalar defaultMatchTol_
Default Matching tolerance.
mappedPatchBase(const polyPatch &)
Construct from patch.
tmp< vectorField > nbrPatchFaceAreas() const
Get the face-areas for the neighbour patch.
tmp< pointField > nbrPatchFaceCentres() const
Get the face-centres for the neighbour patch.
virtual ~mappedPatchBase()
Destructor.
void calcMapping() const
Calculate mapping.
virtual tmp< pointField > patchFaceCentres() const
Get the face-centres for this patch.
virtual void clearOut()
Clear out data on mesh change.
const word & name() const
Return name.
Class to generate coupling geometry between two primitive patches.
Definition: patchToPatch.H:56
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
A class for managing temporary objects.
Definition: tmp.H:55
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:90
Holds (reference to) pointField. Encapsulation of data needed for octree searches....
Definition: treeDataPoint.H:60
A class for handling words, derived from string.
Definition: word.H:62
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
void writeEntryIfDifferent(Ostream &os, const word &entryName, const EntryType &value1, const EntryType &value2)
Helper function to write the keyword and entry only if the.
List< label > labelList
A List of labels.
Definition: labelList.H:56
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:59
dimensionedSymmTensor sqr(const dimensionedVector &dv)
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
void writeEntry(Ostream &os, const HashTable< T, Key, Hash > &ht)
Definition: HashTableIO.C:96
dimensionSet transform(const dimensionSet &)
Definition: dimensionSet.C:504
defineTypeNameAndDebug(combustionModel, 0)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
error FatalError
static const char nl
Definition: Ostream.H:266
dimensioned< scalar > magSqr(const dimensioned< Type > &)
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
dictionary dict
volScalarField & p
Operator to take smallest valid value.
Definition: RemoteData.H:94