meshToMesh.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) 2012-2022 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 "meshToMesh.H"
27 #include "Time.H"
28 #include "globalIndex.H"
29 #include "meshToMeshMethod.H"
30 #include "processorPolyPatch.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36  defineTypeNameAndDebug(meshToMesh, 0);
37 }
38 
39 
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
41 
42 template<>
43 void Foam::meshToMesh::mapAndOpSrcToTgt
44 (
45  const AMIInterpolation& AMI,
46  const Field<scalar>& srcField,
47  Field<scalar>& tgtField
48 ) const
49 {}
50 
51 
52 template<>
53 void Foam::meshToMesh::mapAndOpSrcToTgt
54 (
55  const AMIInterpolation& AMI,
56  const Field<vector>& srcField,
57  Field<vector>& tgtField
58 ) const
59 {}
60 
61 
62 template<>
63 void Foam::meshToMesh::mapAndOpSrcToTgt
64 (
65  const AMIInterpolation& AMI,
66  const Field<sphericalTensor>& srcField,
67  Field<sphericalTensor>& tgtField
68 ) const
69 {}
70 
71 
72 template<>
73 void Foam::meshToMesh::mapAndOpSrcToTgt
74 (
75  const AMIInterpolation& AMI,
76  const Field<symmTensor>& srcField,
77  Field<symmTensor>& tgtField
78 ) const
79 {}
80 
81 
82 template<>
83 void Foam::meshToMesh::mapAndOpSrcToTgt
84 (
85  const AMIInterpolation& AMI,
86  const Field<tensor>& srcField,
87  Field<tensor>& tgtField
88 ) const
89 {}
90 
91 
92 template<>
93 void Foam::meshToMesh::mapAndOpTgtToSrc
94 (
95  const AMIInterpolation& AMI,
96  Field<scalar>& srcField,
97  const Field<scalar>& tgtField
98 ) const
99 {}
100 
101 
102 template<>
103 void Foam::meshToMesh::mapAndOpTgtToSrc
104 (
105  const AMIInterpolation& AMI,
106  Field<vector>& srcField,
107  const Field<vector>& tgtField
108 ) const
109 {}
110 
111 
112 template<>
113 void Foam::meshToMesh::mapAndOpTgtToSrc
114 (
115  const AMIInterpolation& AMI,
116  Field<sphericalTensor>& srcField,
117  const Field<sphericalTensor>& tgtField
118 ) const
119 {}
120 
121 
122 template<>
123 void Foam::meshToMesh::mapAndOpTgtToSrc
124 (
125  const AMIInterpolation& AMI,
126  Field<symmTensor>& srcField,
127  const Field<symmTensor>& tgtField
128 ) const
129 {}
130 
131 
132 template<>
133 void Foam::meshToMesh::mapAndOpTgtToSrc
134 (
135  const AMIInterpolation& AMI,
136  Field<tensor>& srcField,
137  const Field<tensor>& tgtField
138 ) const
139 {}
140 
141 
142 Foam::labelList Foam::meshToMesh::maskCells
143 (
144  const polyMesh& src,
145  const polyMesh& tgt
146 ) const
147 {
148  boundBox intersectBb
149  (
150  max(src.bounds().min(), tgt.bounds().min()),
151  min(src.bounds().max(), tgt.bounds().max())
152  );
153 
154  intersectBb.inflate(0.01);
155 
156  const cellList& srcCells = src.cells();
157  const faceList& srcFaces = src.faces();
158  const pointField& srcPts = src.points();
159 
161  forAll(srcCells, srcI)
162  {
163  boundBox cellBb(srcCells[srcI].points(srcFaces, srcPts), false);
164  if (intersectBb.overlaps(cellBb))
165  {
166  cells.append(srcI);
167  }
168  }
169 
170  if (debug)
171  {
172  Pout<< "participating source mesh cells: " << cells.size() << endl;
173  }
174 
175  return move(cells);
176 }
177 
178 
179 void Foam::meshToMesh::normaliseWeights
180 (
181  const word& descriptor,
182  const labelListList& addr,
183  scalarListList& wght
184 ) const
185 {
186  const label nCell = returnReduce(wght.size(), sumOp<label>());
187 
188  if (nCell > 0)
189  {
190  forAll(wght, celli)
191  {
192  scalarList& w = wght[celli];
193  scalar s = sum(w);
194 
195  forAll(w, i)
196  {
197  // note: normalise by s instead of cell volume since
198  // 1-to-1 methods duplicate contributions in parallel
199  w[i] /= s;
200  }
201  }
202  }
203 }
204 
205 
206 Foam::word Foam::meshToMesh::calcAddressing
207 (
208  const word& methodName,
209  const polyMesh& src,
210  const polyMesh& tgt
211 )
212 {
213  autoPtr<meshToMeshMethod> methodPtr
214  (
216  (
217  methodName,
218  src,
219  tgt
220  )
221  );
222 
223  methodPtr->calculate
224  (
225  srcToTgtCellAddr_,
226  srcToTgtCellWght_,
227  tgtToSrcCellAddr_,
228  tgtToSrcCellWght_
229  );
230 
231  V_ = methodPtr->V();
232 
233  if (debug)
234  {
235  methodPtr->writeConnectivity(src, tgt, srcToTgtCellAddr_);
236  }
237 
238  return methodPtr->AMImethod();
239 }
240 
241 
242 Foam::word Foam::meshToMesh::calculate(const word& methodName)
243 {
244  Info<< "Creating mesh-to-mesh addressing for " << srcRegion_.name()
245  << " and " << tgtRegion_.name() << " regions using "
246  << methodName << endl;
247 
248  singleMeshProc_ = calcDistribution(srcRegion_, tgtRegion_);
249 
250  word amiMethod;
251 
252  if (singleMeshProc_ == -1)
253  {
254  // create global indexing for src and tgt meshes
255  globalIndex globalSrcCells(srcRegion_.nCells());
256  globalIndex globalTgtCells(tgtRegion_.nCells());
257 
258  // Create processor map of overlapping cells. This map gets
259  // (possibly remote) cells from the tgt mesh such that they (together)
260  // cover all of the src mesh
261  autoPtr<distributionMap> mapPtr = calcProcMap(srcRegion_, tgtRegion_);
262  const distributionMap& map = mapPtr();
263 
264  pointField newTgtPoints;
265  faceList newTgtFaces;
266  labelList newTgtFaceOwners;
267  labelList newTgtFaceNeighbours;
268  labelList newTgtCellIDs;
269 
270  distributeAndMergeCells
271  (
272  map,
273  tgtRegion_,
274  globalTgtCells,
275  newTgtPoints,
276  newTgtFaces,
277  newTgtFaceOwners,
278  newTgtFaceNeighbours,
279  newTgtCellIDs
280  );
281 
282 
283  // create a new target mesh
284  polyMesh newTgt
285  (
286  IOobject
287  (
288  "newTgt." + Foam::name(Pstream::myProcNo()),
289  tgtRegion_.time().timeName(),
290  tgtRegion_.time(),
292  ),
293  move(newTgtPoints),
294  move(newTgtFaces),
295  move(newTgtFaceOwners),
296  move(newTgtFaceNeighbours),
297  false // no parallel comms
298  );
299 
300  // create some dummy patch info
302  patches[0] = new polyPatch
303  (
304  "defaultFaces",
305  newTgt.nFaces() - newTgt.nInternalFaces(),
306  newTgt.nInternalFaces(),
307  0,
308  newTgt.boundaryMesh(),
309  word::null
310  );
311 
312  newTgt.addPatches(patches);
313 
314  // force calculation of tet-base points used for point-in-cell
315  (void)newTgt.tetBasePtIs();
316 
317  // force construction of cell tree
318 // (void)newTgt.cellTree();
319 
320  if (debug)
321  {
322  Pout<< "Created newTgt mesh:" << nl
323  << " old cells = " << tgtRegion_.nCells()
324  << ", new cells = " << newTgt.nCells() << nl
325  << " old faces = " << tgtRegion_.nFaces()
326  << ", new faces = " << newTgt.nFaces() << endl;
327 
328  if (debug > 1)
329  {
330  Pout<< "Writing newTgt mesh: " << newTgt.name() << endl;
331  newTgt.write();
332  }
333  }
334 
335  amiMethod = calcAddressing(methodName, srcRegion_, newTgt);
336 
337  // per source cell the target cell address in newTgt mesh
338  forAll(srcToTgtCellAddr_, i)
339  {
340  labelList& addressing = srcToTgtCellAddr_[i];
341  forAll(addressing, addrI)
342  {
343  addressing[addrI] = newTgtCellIDs[addressing[addrI]];
344  }
345  }
346 
347  // convert target addresses in newTgtMesh into global cell numbering
348  forAll(tgtToSrcCellAddr_, i)
349  {
350  labelList& addressing = tgtToSrcCellAddr_[i];
351  forAll(addressing, addrI)
352  {
353  addressing[addrI] = globalSrcCells.toGlobal(addressing[addrI]);
354  }
355  }
356 
357  // set up as a reverse distribute
359  (
361  List<labelPair>(),
362  tgtRegion_.nCells(),
363  map.constructMap(),
364  false,
365  map.subMap(),
366  false,
367  tgtToSrcCellAddr_,
369  flipOp(),
370  labelList()
371  );
372 
373  // set up as a reverse distribute
375  (
377  List<labelPair>(),
378  tgtRegion_.nCells(),
379  map.constructMap(),
380  false,
381  map.subMap(),
382  false,
383  tgtToSrcCellWght_,
385  flipOp(),
386  scalarList()
387  );
388 
389  // weights normalisation
390  normaliseWeights
391  (
392  "source",
393  srcToTgtCellAddr_,
394  srcToTgtCellWght_
395  );
396 
397  normaliseWeights
398  (
399  "target",
400  tgtToSrcCellAddr_,
401  tgtToSrcCellWght_
402  );
403 
404  // cache maps and reset addresses
405  List<Map<label>> cMap;
406  srcMapPtr_.reset
407  (
408  new distributionMap(globalSrcCells, tgtToSrcCellAddr_, cMap)
409  );
410  tgtMapPtr_.reset
411  (
412  new distributionMap(globalTgtCells, srcToTgtCellAddr_, cMap)
413  );
414 
415  // collect volume intersection contributions
416  reduce(V_, sumOp<scalar>());
417  }
418  else
419  {
420  amiMethod = calcAddressing(methodName, srcRegion_, tgtRegion_);
421 
422  normaliseWeights
423  (
424  "source",
425  srcToTgtCellAddr_,
426  srcToTgtCellWght_
427  );
428 
429  normaliseWeights
430  (
431  "target",
432  tgtToSrcCellAddr_,
433  tgtToSrcCellWght_
434  );
435  }
436 
437  Info<< " Overlap volume: " << V_ << endl;
438 
439  return amiMethod;
440 }
441 
442 
443 void Foam::meshToMesh::calculatePatchAMIs(const word& AMIMethodName)
444 {
445  if (!patchAMIs_.empty())
446  {
448  << "patch AMI already calculated"
449  << exit(FatalError);
450  }
451 
452  patchAMIs_.setSize(srcPatchID_.size());
453 
454  forAll(srcPatchID_, i)
455  {
456  label srcPatchi = srcPatchID_[i];
457  label tgtPatchi = tgtPatchID_[i];
458 
459  const polyPatch& srcPP = srcRegion_.boundaryMesh()[srcPatchi];
460  const polyPatch& tgtPP = tgtRegion_.boundaryMesh()[tgtPatchi];
461 
462  Info<< "Creating AMI between source patch " << srcPP.name()
463  << " and target patch " << tgtPP.name()
464  << " using " << AMIMethodName
465  << endl;
466 
467  Info<< incrIndent;
468 
469  patchAMIs_.set
470  (
471  i,
472  new AMIInterpolation
473  (
474  srcPP,
475  tgtPP,
477  false,
478  AMIMethodName,
479  -1,
480  true // flip target patch since patch normals are aligned
481  )
482  );
483 
484  Info<< decrIndent;
485  }
486 }
487 
488 
489 void Foam::meshToMesh::constructNoCuttingPatches
490 (
491  const word& methodName,
492  const bool interpAllPatches
493 )
494 {
495  if (interpAllPatches)
496  {
497  const polyBoundaryMesh& srcBM = srcRegion_.boundaryMesh();
498  const polyBoundaryMesh& tgtBM = tgtRegion_.boundaryMesh();
499 
500  DynamicList<label> srcPatchID(srcBM.size());
501  DynamicList<label> tgtPatchID(tgtBM.size());
502  forAll(srcBM, patchi)
503  {
504  const polyPatch& pp = srcBM[patchi];
505 
506  // We want to map all the global patches, including constraint
507  // patches (since they might have mappable properties, e.g.
508  // jumpCyclic). We'll fix the value afterwards.
509  if (!isA<processorPolyPatch>(pp))
510  {
511  srcPatchID.append(pp.index());
512 
513  label tgtPatchi = tgtBM.findPatchID(pp.name());
514 
515  if (tgtPatchi != -1)
516  {
517  tgtPatchID.append(tgtPatchi);
518  }
519  else
520  {
522  << "Source patch " << pp.name()
523  << " not found in target mesh. "
524  << "Available target patches are " << tgtBM.names()
525  << exit(FatalError);
526  }
527  }
528  }
529 
530  srcPatchID_.transfer(srcPatchID);
531  tgtPatchID_.transfer(tgtPatchID);
532  }
533 
534  // calculate volume addressing and weights
535  const word amiMethod = calculate(methodName);
536 
537  // calculate patch addressing and weights
538  calculatePatchAMIs(amiMethod);
539 }
540 
541 
542 void Foam::meshToMesh::constructFromCuttingPatches
543 (
544  const word& methodName,
545  const HashTable<word>& patchMap,
546  const wordList& cuttingPatches
547 )
548 {
549  srcPatchID_.setSize(patchMap.size());
550  tgtPatchID_.setSize(patchMap.size());
551 
552  label i = 0;
553  forAllConstIter(HashTable<word>, patchMap, iter)
554  {
555  const word& tgtPatchName = iter.key();
556  const word& srcPatchName = iter();
557 
558  const polyPatch& srcPatch = srcRegion_.boundaryMesh()[srcPatchName];
559  const polyPatch& tgtPatch = tgtRegion_.boundaryMesh()[tgtPatchName];
560 
561  srcPatchID_[i] = srcPatch.index();
562  tgtPatchID_[i] = tgtPatch.index();
563  i++;
564  }
565 
566  // calculate volume addressing and weights
567  const word amiMethod = calculate(methodName);
568 
569  // calculate patch addressing and weights
570  calculatePatchAMIs(amiMethod);
571 
572  // set IDs of cutting patches on target mesh
573  cuttingPatches_.setSize(cuttingPatches.size());
574  forAll(cuttingPatches_, i)
575  {
576  const word& patchName = cuttingPatches[i];
577  cuttingPatches_[i] = tgtRegion_.boundaryMesh().findPatchID(patchName);
578  }
579 }
580 
581 
582 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
583 
585 (
586  const polyMesh& src,
587  const polyMesh& tgt,
588  const word& methodName,
589  bool interpAllPatches
590 )
591 :
592  srcRegion_(src),
593  tgtRegion_(tgt),
594  srcPatchID_(),
595  tgtPatchID_(),
596  patchAMIs_(),
597  cuttingPatches_(),
598  srcToTgtCellAddr_(),
599  tgtToSrcCellAddr_(),
600  srcToTgtCellWght_(),
601  tgtToSrcCellWght_(),
602  V_(0.0),
603  singleMeshProc_(-1),
604  srcMapPtr_(nullptr),
605  tgtMapPtr_(nullptr)
606 {
607  constructNoCuttingPatches(methodName, interpAllPatches);
608 }
609 
610 
612 (
613  const polyMesh& src,
614  const polyMesh& tgt,
615  const word& methodName,
616  const HashTable<word>& patchMap,
617  const wordList& cuttingPatches
618 )
619 :
620  srcRegion_(src),
621  tgtRegion_(tgt),
622  srcPatchID_(),
623  tgtPatchID_(),
624  patchAMIs_(),
625  cuttingPatches_(),
626  srcToTgtCellAddr_(),
627  tgtToSrcCellAddr_(),
628  srcToTgtCellWght_(),
629  tgtToSrcCellWght_(),
630  V_(0.0),
631  singleMeshProc_(-1),
632  srcMapPtr_(nullptr),
633  tgtMapPtr_(nullptr)
634 {
635  constructFromCuttingPatches
636  (
637  methodName,
638  patchMap,
639  cuttingPatches
640  );
641 }
642 
643 
644 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
645 
647 {}
648 
649 
650 // ************************************************************************* //
const fvPatchList & patches
static void distribute(const Pstream::commsTypes commsType, const List< labelPair > &schedule, const label constructSize, const labelListList &subMap, const bool subHasFlip, const labelListList &constructMap, const bool constructHasFlip, List< T > &, const negateOp &negOp, const int tag=UPstream::msgType())
Distribute data. Note:schedule only used for.
Class containing functor to negate primitives. Dummy for all other types.
Definition: flipOp.H:50
bool overlaps(const boundBox &) const
Overlaps/touches boundingBox?
Definition: boundBoxI.H:120
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:82
void append(T *)
Append an element at the end of the list.
Definition: PtrListI.H:39
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
virtual Ostream & write(const char)=0
Write character.
const word & name() const
Return name.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
const polyBoundaryMesh & boundaryMesh() const
Return boundaryMesh reference.
Definition: polyPatch.C:297
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Plus op for FixedList<scalar>
label findPatchID(const word &patchName) const
Find patch index given a name.
scalar V() const
Return const access to the overlap volume.
const labelListList & constructMap() const
From subsetted data to new reconstructed data.
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:58
const cellList & cells() const
const labelListList & subMap() const
From subsetted data back to original data.
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
void writeConnectivity(const polyMesh &mesh1, const polyMesh &mesh2, const labelListList &mesh1ToMesh2Addr) const
Write the connectivity (debugging)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
virtual void calculate(labelListList &srcToTgtAddr, scalarListList &srcToTgtWght, labelListList &tgtToTgtAddr, scalarListList &tgtToTgtWght)=0
Calculate addressing and weights.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1211
label calculate(const fvMesh &mesh, const labelHashSet &patchIDs, const scalar minFaceFraction, GeometricField< scalar, PatchField, GeoMesh > &distance)
Calculate distance data from patches.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const cellShapeList & cells
const pointField & points
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
A class for handling words, derived from string.
Definition: word.H:59
wordList names() const
Return a list of patch names.
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
static const word null
An empty word.
Definition: word.H:77
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
List< label > labelList
A List of labels.
Definition: labelList.H:56
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1224
An STL-conforming hash table.
Definition: HashTable.H:61
Foam::polyBoundaryMesh.
void inflate(const scalar s)
Inflate box by factor*mag(span) in all dimensions.
Definition: boundBox.C:210
static const char nl
Definition: Ostream.H:260
defineTypeNameAndDebug(combustionModel, 0)
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:235
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
meshToMesh(const polyMesh &src, const polyMesh &tgt, const word &methodName, const bool interpAllPatches=true)
Construct from source and target meshes, generic mapping methods.
Definition: meshToMesh.C:585
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
const point & max() const
Maximum point defining the bounding box.
Definition: boundBoxI.H:60
const boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:459
Class containing processor-to-processor mapping information.
label patchi
virtual ~meshToMesh()
Destructor.
Definition: meshToMesh.C:646
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
virtual const word & AMImethod() const =0
Return the corresponding AMI method for patch interpolation.
label index() const
Return the index of this patch in the boundaryMesh.
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
messageStream Info
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
const point & min() const
Minimum point defining the bounding box.
Definition: boundBoxI.H:54
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:228
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:98
static autoPtr< meshToMeshMethod > New(const word &methodName, const polyMesh &src, const polyMesh &tgt)
Selector.
Namespace for OpenFOAM.