mergePatchPairs.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) 2023-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 "mergePatchPairs.H"
27 #include "fvMesh.H"
28 #include "polyPatchIntersection.H"
29 #include "polyTopoChange.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
36 }
37 
38 
39 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 
41 Foam::label Foam::mergePatchPairs::findPatchIndex(const word& patchName) const
42 {
43  label patchIndex = mesh_.boundaryMesh().findIndex(patchName);
44 
45  if (patchIndex == -1)
46  {
48  << "Cannot find patch " << patchName << exit(FatalError);
49  }
50 
51  return patchIndex;
52 }
53 
54 
55 Foam::Pair<Foam::label> Foam::mergePatchPairs::findPatchIndices
56 (
57  const Pair<word>& patchNamePair
58 ) const
59 {
60  return Pair<label>
61  {
62  findPatchIndex(patchNamePair.first()),
63  findPatchIndex(patchNamePair.second())
64  };
65 }
66 
67 
68 Foam::List<Foam::Pair<Foam::label>> Foam::mergePatchPairs::patchPairs
69 (
70  const List<Pair<word>>& patchNamePairs
71 ) const
72 {
73  List<Pair<label>> patchPairs(patchNamePairs.size());
74 
75  forAll(patchNamePairs, pairi)
76  {
77  patchPairs[pairi] = findPatchIndices(patchNamePairs[pairi]);
78  }
79 
80  return patchPairs;
81 }
82 
83 
84 void Foam::mergePatchPairs::removePoints
85 (
86  polyTopoChange& meshMod,
87  const List<Pair<label>>& patchPairs
88 ) const
89 {
90  boolList removedPoints(mesh_.nPoints(), false);
91 
92  forAll(patchPairs, ppi)
93  {
94  UIndirectList<bool>
95  (
96  removedPoints,
97  mesh_.boundaryMesh()[patchPairs[ppi].first()].meshPoints()
98  ) = true;
99 
100  UIndirectList<bool>
101  (
102  removedPoints,
103  mesh_.boundaryMesh()[patchPairs[ppi].second()].meshPoints()
104  ) = true;
105  }
106 
107  forAll(removedPoints, pi)
108  {
109  if (removedPoints[pi])
110  {
111  meshMod.removePoint(pi, -1);
112  }
113  }
114 }
115 
116 
117 void Foam::mergePatchPairs::addPoints
118 (
119  polyTopoChange& meshMod,
120  const polyPatchIntersection& intersection
121 ) const
122 {
123  const pointField& intersectionPoints = intersection.points();
124  newPoints_.setSize(intersectionPoints.size(), -1);
125 
126  forAll(intersectionPoints, pi)
127  {
128  const label pointi = meshMod.addPoint
129  (
130  intersectionPoints[pi],
131  -1,
132  false
133  );
134 
135  if (debug)
136  {
137  Info<< "Adding point "
138  << pointi << " "
139  << intersectionPoints[pi]
140  << endl;
141  }
142 
143  newPoints_[pi] = pointi;
144  }
145 }
146 
147 
148 void Foam::mergePatchPairs::removeFaces
149 (
150  polyTopoChange& meshMod,
151  const polyPatchIntersection& intersection
152 ) const
153 {
154  const polyPatch& srcPatch = intersection.srcPatch();
155  const polyPatch& tgtPatch = intersection.tgtPatch();
156 
157  // Remove existing source face
158  forAll(srcPatch, fi)
159  {
160  meshMod.removeFace(srcPatch.start() + fi, -1);
161  }
162 
163  // Remove existing target face
164  forAll(tgtPatch, fi)
165  {
166  meshMod.removeFace(tgtPatch.start() + fi, -1);
167  }
168 }
169 
170 
171 Foam::face Foam::mergePatchPairs::mapFace(const face& f) const
172 {
173  face newFace(f);
174 
175  forAll(newFace, fpi)
176  {
177  newFace[fpi] = newPoints_[newFace[fpi]];
178  }
179 
180  return newFace;
181 }
182 
183 
184 void Foam::mergePatchPairs::addFaces
185 (
186  polyTopoChange& meshMod,
187  const polyPatchIntersection& intersection
188 ) const
189 {
190  const faceList& faces = intersection.faces();
191  const DynamicList<label>& faceSrcFaces = intersection.faceSrcFaces();
192  const DynamicList<label>& faceTgtFaces = intersection.faceTgtFaces();
193 
194  const label srcPatchi = intersection.srcPatch().index();
195  const label srcPatchStart = intersection.srcPatch().start();
196 
197  const label tgtPatchi = intersection.tgtPatch().index();
198  const label tgtPatchStart = intersection.tgtPatch().start();
199 
200  forAll(faces, fi)
201  {
202  const face f = mapFace(faces[fi]);
203 
204  if (faceSrcFaces[fi] != -1 && faceTgtFaces[fi] != -1)
205  {
206  const label srcFacei = srcPatchStart + faceSrcFaces[fi];
207  const label tgtFacei = tgtPatchStart + faceTgtFaces[fi];
208 
209  const label srcOwn = mesh_.faceOwner()[srcFacei];
210  const label tgtOwn = mesh_.faceOwner()[tgtFacei];
211 
212  if (srcOwn < tgtOwn)
213  {
214  meshMod.addFace
215  (
216  f, // Face to add
217  srcOwn, // Owner cell
218  tgtOwn, // Neighbour cell
219  srcFacei, // Master face index
220  false, // Flip
221  -1 // Patch index
222  );
223 
224  if (debug)
225  {
226  Info<< "Adding internal face " << f
227  << " owner celli:" << srcOwn
228  << " neighbour celli:" << tgtOwn << endl;
229  }
230  }
231  else
232  {
233  meshMod.addFace
234  (
235  f.reverseFace(), // Face to add
236  tgtOwn, // Owner cell
237  srcOwn, // Neighbour cell
238  tgtFacei, // Master face index
239  false, // Flip
240  -1 // Patch index
241  );
242 
243  if (debug)
244  {
245  Info<< "Adding internal face " << f
246  << " owner celli:" << tgtOwn
247  << " neighbour celli:" << srcOwn << endl;
248  }
249  }
250  }
251  else if (faceSrcFaces[fi] != -1 && faceTgtFaces[fi] == -1)
252  {
253  const label srcFacei = srcPatchStart + faceSrcFaces[fi];
254  const label srcOwn = mesh_.faceOwner()[srcFacei];
255 
256  meshMod.addFace
257  (
258  f, // Face to add
259  srcOwn, // Owner cell
260  -1, // Neighbour cell
261  srcFacei, // Master face index
262  false, // Flip
263  srcPatchi // Patch index
264  );
265 
266  if (debug)
267  {
268  Info<< "Adding patch face " << f
269  << " owner celli:" << srcOwn
270  << " patchi:" << srcPatchi << endl;
271  }
272  }
273  else if (faceSrcFaces[fi] == -1 && faceTgtFaces[fi] != -1)
274  {
275  const label tgtFacei = tgtPatchStart + faceTgtFaces[fi];
276  const label tgtOwn = mesh_.faceOwner()[tgtFacei];
277 
278  meshMod.addFace
279  (
280  f.reverseFace(), // Face to add
281  tgtOwn, // Owner cell
282  -1, // Neighbour cell
283  tgtFacei, // Master face index
284  false, // Flip
285  tgtPatchi // Patch index
286  );
287 
288  if (debug)
289  {
290  Info<< "Adding patch face " << f
291  << " owner celli:" << tgtOwn
292  << " patchi:" << tgtPatchi << endl;
293  }
294  }
295  else
296  {
298  << "Both faceSrcFaces and faceTgtFaces are -1 for face " << fi
299  << exit(FatalError);
300  }
301  }
302 }
303 
304 
305 void Foam::mergePatchPairs::addEdgeAddedPoints
306 (
307  HashTable<labelList, edge, Hash<edge>>& edgeAddedPoints,
308  const primitivePatch& patch,
309  const List<DynamicList<label>>& patchEdgeAddedPoints
310 ) const
311 {
312  const edgeList& patchEdges = patch.edges();
313  const labelList& pmp = patch.meshPoints();
314 
315  forAll(patchEdgeAddedPoints, ei)
316  {
317  if (patchEdgeAddedPoints[ei].size())
318  {
319  labelList newEdgePoints(patchEdgeAddedPoints[ei].size());
320 
321  forAll(newEdgePoints, npi)
322  {
323  newEdgePoints[npi] = newPoints_[patchEdgeAddedPoints[ei][npi]];
324  }
325 
326  edgeAddedPoints.insert
327  (
328  edge(pmp[patchEdges[ei].start()], pmp[patchEdges[ei].end()]),
329  newEdgePoints
330  );
331  }
332  }
333 }
334 
335 
336 void Foam::mergePatchPairs::updatePoints
337 (
338  labelList& pointMap,
339  const primitivePatch& patch,
340  const labelList& pointPoints
341 ) const
342 {
343  const labelList& pmp = patch.meshPoints();
344 
345  forAll(pointPoints, ppi)
346  {
347  pointMap[pmp[ppi]] = newPoints_[pointPoints[ppi]];
348  }
349 }
350 
351 
352 void Foam::mergePatchPairs::modifyFaces
353 (
354  polyTopoChange& meshMod,
355  const polyPatchIntersection& intersection
356 ) const
357 {
358  HashTable<labelList, edge, Hash<edge>> edgeAddedPoints;
359  addEdgeAddedPoints
360  (
361  edgeAddedPoints,
362  intersection.srcPatch(),
363  intersection.srcEdgePoints()
364  );
365  addEdgeAddedPoints
366  (
367  edgeAddedPoints,
368  intersection.tgtPatch(),
369  intersection.tgtEdgePoints()
370  );
371 
372  labelList pointMap(identityMap(mesh_.nPoints()));
373  updatePoints
374  (
375  pointMap,
376  intersection.srcPatch(),
377  intersection.srcPointPoints()
378  );
379  updatePoints
380  (
381  pointMap,
382  intersection.tgtPatch(),
383  intersection.tgtPointPoints()
384  );
385 
386  DynamicList<label> modifiedFace;
387 
388  const faceList& meshFaces = mesh_.faces();
389 
390  forAll(meshFaces, fi)
391  {
392  if (meshMod.faceRemoved(fi))
393  {
394  continue;
395  }
396 
397  const face& f = meshFaces[fi];
398 
399  bool addNext = true;
400  bool modified = false;
401 
402  forAll(f, pi)
403  {
404  const edge e(f[pi], f[f.fcIndex(pi)]);
405 
406  const HashTable<labelList, edge, Hash<edge>>::const_iterator iter =
407  edgeAddedPoints.find(e);
408 
409  if (iter != edgeAddedPoints.end())
410  {
411  const labelList& addedPoints = iter();
412 
413  if (edge::compare(e, iter.key()) == 1)
414  {
415  forAll(addedPoints, i)
416  {
417  if
418  (
419  !modifiedFace.size()
420  || modifiedFace[modifiedFace.size() - 1]
421  != addedPoints[i]
422  )
423  {
424  modifiedFace.append(addedPoints[i]);
425  }
426  }
427  }
428  else
429  {
430  forAllReverse(addedPoints, i)
431  {
432  if
433  (
434  !modifiedFace.size()
435  || modifiedFace[modifiedFace.size() - 1]
436  != addedPoints[i]
437  )
438  {
439  modifiedFace.append(addedPoints[i]);
440  }
441  }
442  }
443 
444  if (f[f.fcIndex(pi)] == f[0])
445  {
446  // modifiedFace.first() = modifiedFace.last();
447  // modifiedFace.setSize(modifiedFace.size() - 1);
448  modifiedFace.erase(modifiedFace.begin());
449  }
450 
451  addNext = false;
452  modified = true;
453  }
454  else
455  {
456  if (addNext)
457  {
458  modifiedFace.append(pointMap[f[pi]]);
459  }
460  else
461  {
462  addNext = true;
463  }
464  }
465  }
466 
467  // Update points of point-connected faces if necessary
468  if (!modified)
469  {
470  forAll(f, pi)
471  {
472  if (pointMap[f[pi]] != f[pi])
473  {
474  if (!modified)
475  {
476  modifiedFace = f;
477  modified = true;
478  }
479 
480  modifiedFace[pi] = pointMap[f[pi]];
481  }
482  }
483  }
484 
485  if (modified)
486  {
487  if (mesh_.isInternalFace(fi))
488  {
489  if (debug)
490  {
491  Info<< "Modifying internal face " << fi
492  << " newface:" << modifiedFace
493  << " oldFace:" << f
494  << " centre:" << mesh_.faceCentres()[fi]
495  << " owner:" << mesh_.faceOwner()[fi]
496  << " neighbour:" << mesh_.faceNeighbour()[fi]
497  << endl;
498  }
499 
500  meshMod.modifyFace
501  (
502  face(modifiedFace), // Modified face
503  fi, // index of face being modified
504  mesh_.faceOwner()[fi], // Owner cell
505  mesh_.faceNeighbour()[fi], // Neighbour cell
506  false, // Face flip
507  -1 // Patch index
508  );
509  }
510  else
511  {
512  if (debug)
513  {
514  Info<< "Modifying boundary face " << fi
515  << " newface:" << modifiedFace
516  << " oldFace:" << f
517  << " centre:" << mesh_.faceCentres()[fi]
518  << " owner:" << mesh_.faceOwner()[fi]
519  << " patch:" << mesh_.boundaryMesh().whichPatch(fi)
520  << endl;
521  }
522 
523  meshMod.modifyFace
524  (
525  face(modifiedFace), // Modified face
526  fi, // index of face being modified
527  mesh_.faceOwner()[fi], // Owner cell
528  -1, // Neighbour cell
529  false, // Face flip
530  mesh_.boundaryMesh().whichPatch(fi) // Patch index
531  );
532  }
533  }
534 
535  modifiedFace.clear();
536  }
537 }
538 
539 
540 void Foam::mergePatchPairs::intersectPatchPair
541 (
542  polyTopoChange& meshMod,
543  const polyPatch& srcPatch,
544  const polyPatch& tgtPatch
545 ) const
546 {
547  polyPatchIntersection intersection(srcPatch, tgtPatch, snapTol_);
548  removeFaces(meshMod, intersection);
549  addPoints(meshMod, intersection);
550  addFaces(meshMod, intersection);
551  modifyFaces(meshMod, intersection);
552 }
553 
554 
555 Foam::autoPtr<Foam::polyTopoChangeMap> Foam::mergePatchPairs::merge
556 (
557  const List<Pair<label>>& patchPairs
558 ) const
559 {
560  // Construct the mesh modifier for merging patch-pairs
561  polyTopoChange meshMod(mesh_);
562 
563  removePoints(meshMod, patchPairs);
564 
565  // Accumulate the mesh modifications for merging the patch-pairs
566  forAll(patchPairs, ppi)
567  {
568  // Intersect patch-pair and update the mesh modifier
569  intersectPatchPair
570  (
571  meshMod,
572  mesh_.boundaryMesh()[patchPairs[ppi].first()],
573  mesh_.boundaryMesh()[patchPairs[ppi].second()]
574  );
575  }
576 
577  // Change mesh and return map
578  return meshMod.changeMesh(mesh_);
579 }
580 
581 
582 bool Foam::mergePatchPairs::connected
583 (
584  boolList& patchPoints,
585  const label patchi
586 ) const
587 {
588  const labelList& pmp = mesh_.boundaryMesh()[patchi].meshPoints();
589 
590  forAll(pmp, pi)
591  {
592  if (patchPoints[pmp[pi]])
593  {
594  return true;
595  }
596 
597  patchPoints[pmp[pi]] = true;
598  }
599 
600  return false;
601 }
602 
603 
604 template<class Mesh>
605 inline void Foam::mergePatchPairs::merge
606 (
607  Mesh& mesh,
608  const List<Pair<word>>& patchPairNames
609 ) const
610 {
611  const List<Pair<label>> patchPairs(this->patchPairs(patchPairNames));
612 
613  bool connected = false;
614 
615  if (patchPairs.size() > 1)
616  {
617  boolList patchPoints(mesh_.nPoints(), false);
618 
619  forAll(patchPairs, ppi)
620  {
621  if
622  (
623  this->connected(patchPoints, patchPairs[ppi].first())
624  || this->connected(patchPoints, patchPairs[ppi].second())
625  )
626  {
627  connected = true;
628  break;
629  }
630  }
631  }
632 
633  if (connected)
634  {
635  // Merge patch-pairs and update fields
636  forAll(patchPairNames, ppi)
637  {
638  Info<< "Merging patch pair " << patchPairNames[ppi] << endl;
639 
640  mesh.topoChange
641  (
642  merge(List<Pair<label>>(patchPairs[ppi]))
643  );
644  }
645  }
646  else
647  {
648  Info<< "Merging patch pairs " << patchPairNames << endl;
649 
650  mesh.topoChange(merge(patchPairs));
651  }
652 
653  // Find the stitched patches that are now zero-sized
654  labelHashSet zeroSizedMergedPatches;
655 
656  forAll(patchPairs, ppi)
657  {
658  if (mesh.boundaryMesh()[patchPairs[ppi].first()].size() == 0)
659  {
660  zeroSizedMergedPatches.insert(patchPairs[ppi].first());
661  }
662 
663  if (mesh.boundaryMesh()[patchPairs[ppi].second()].size() == 0)
664  {
665  zeroSizedMergedPatches.insert(patchPairs[ppi].second());
666  }
667  }
668 
669  // Create a list of the remaining patch old patch labels
670  labelList remainingPatches
671  (
672  mesh.boundaryMesh().size() - zeroSizedMergedPatches.size()
673  );
674 
675  label rpi = 0;
676  forAll(mesh.boundaryMesh(), patchi)
677  {
678  if (!zeroSizedMergedPatches.found(patchi))
679  {
680  remainingPatches[rpi++] = patchi;
681  }
682  }
683 
684  // Remove the zero-sized stitched patches
685  mesh_.reorderPatches(remainingPatches, true);
686 }
687 
688 
689 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
690 
692 (
693  polyMesh& mesh,
694  const List<Pair<word>>& patchPairNames,
695  const scalar snapTol
696 )
697 :
698  mesh_(mesh),
699  snapTol_(snapTol)
700 {
701  // Merge patch-pairs and update fields
702  merge(mesh, patchPairNames);
703 }
704 
705 
707 (
708  fvMesh& mesh,
709  const List<Pair<word>>& patchPairNames,
710  const scalar snapTol
711 )
712 :
713  mesh_(mesh),
714  snapTol_(snapTol)
715 {
716  // Merge patch-pairs and update fields
717  merge(mesh, patchPairNames);
718 }
719 
720 
721 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:446
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void setSize(const label)
Reset size of List.
Definition: List.C:281
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: Pair.H:65
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
static int compare(const edge &, const edge &)
Compare edges.
Definition: edgeI.H:36
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:99
Class to stitch mesh by merging patch-pairs.
mergePatchPairs(polyMesh &mesh, const List< Pair< word >> &patchPairNames, const scalar snapTol)
label findIndex(const word &patchName) const
Find patch index given a name.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:404
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
messageStream Info
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
defineDebugSwitch(mergePatchPairs, 0)
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
Addressing for a faceList slice.
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:213
error FatalError
List< edge > edgeList
Definition: edgeList.H:38
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
List< face > faceList
Definition: faceListFwd.H:41
labelList f(nPoints)