meshRefinementBaffles.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-2020 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 "meshRefinement.H"
27 #include "fvMesh.H"
28 #include "syncTools.H"
29 #include "Time.H"
30 #include "refinementSurfaces.H"
31 #include "pointSet.H"
32 #include "faceSet.H"
33 #include "indirectPrimitivePatch.H"
34 #include "polyTopoChange.H"
35 #include "meshTools.H"
36 #include "polyModifyFace.H"
37 #include "polyModifyCell.H"
38 #include "polyAddFace.H"
39 #include "polyRemoveFace.H"
40 #include "polyAddPoint.H"
41 #include "localPointRegion.H"
42 #include "duplicatePoints.H"
43 #include "OFstream.H"
44 #include "regionSplit.H"
45 #include "removeCells.H"
46 #include "unitConversion.H"
47 #include "OBJstream.H"
48 #include "patchFaceOrientation.H"
49 #include "PatchEdgeFaceWave.H"
50 #include "patchEdgeFaceRegion.H"
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
54 Foam::label Foam::meshRefinement::createBaffle
55 (
56  const label facei,
57  const label ownPatch,
58  const label neiPatch,
59  polyTopoChange& meshMod
60 ) const
61 {
62  const face& f = mesh_.faces()[facei];
63  label zoneID = mesh_.faceZones().whichZone(facei);
64  bool zoneFlip = false;
65 
66  if (zoneID >= 0)
67  {
68  const faceZone& fZone = mesh_.faceZones()[zoneID];
69  zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
70  }
71 
72  meshMod.setAction
73  (
74  polyModifyFace
75  (
76  f, // modified face
77  facei, // label of face
78  mesh_.faceOwner()[facei], // owner
79  -1, // neighbour
80  false, // face flip
81  ownPatch, // patch for face
82  false, // remove from zone
83  zoneID, // zone for face
84  zoneFlip // face flip in zone
85  )
86  );
87 
88 
89  label dupFacei = -1;
90 
91  if (mesh_.isInternalFace(facei))
92  {
93  if (neiPatch == -1)
94  {
96  << "No neighbour patch for internal face " << facei
97  << " fc:" << mesh_.faceCentres()[facei]
98  << " ownPatch:" << ownPatch << abort(FatalError);
99  }
100 
101  bool reverseFlip = false;
102  if (zoneID >= 0)
103  {
104  reverseFlip = !zoneFlip;
105  }
106 
107  dupFacei = meshMod.setAction
108  (
109  polyAddFace
110  (
111  f.reverseFace(), // modified face
112  mesh_.faceNeighbour()[facei],// owner
113  -1, // neighbour
114  -1, // masterPointID
115  -1, // masterEdgeID
116  facei, // masterFaceID,
117  true, // face flip
118  neiPatch, // patch for face
119  zoneID, // zone for face
120  reverseFlip // face flip in zone
121  )
122  );
123  }
124  return dupFacei;
125 }
126 
127 
128 void Foam::meshRefinement::getBafflePatches
129 (
130  const labelList& globalToMasterPatch,
131  const labelList& neiLevel,
132  const pointField& neiCc,
133  labelList& ownPatch,
134  labelList& neiPatch
135 ) const
136 {
137  autoPtr<OFstream> str;
138  label vertI = 0;
139  if (debug&OBJINTERSECTIONS)
140  {
141  mkDir(mesh_.time().path()/timeName());
142  str.reset
143  (
144  new OFstream
145  (
146  mesh_.time().path()/timeName()/"intersections.obj"
147  )
148  );
149 
150  Pout<< "getBafflePatches : Writing surface intersections to file "
151  << str().name() << nl << endl;
152  }
153 
154  const pointField& cellCentres = mesh_.cellCentres();
155 
156  // Surfaces that need to be baffled
157  const labelList surfacesToBaffle
158  (
160  );
161 
162  ownPatch.setSize(mesh_.nFaces());
163  ownPatch = -1;
164  neiPatch.setSize(mesh_.nFaces());
165  neiPatch = -1;
166 
167 
168  // Collect candidate faces
169  // ~~~~~~~~~~~~~~~~~~~~~~~
170 
171  labelList testFaces(intersectedFaces());
172 
173  // Collect segments
174  // ~~~~~~~~~~~~~~~~
175 
176  pointField start(testFaces.size());
177  pointField end(testFaces.size());
178 
179  forAll(testFaces, i)
180  {
181  label facei = testFaces[i];
182 
183  label own = mesh_.faceOwner()[facei];
184 
185  if (mesh_.isInternalFace(facei))
186  {
187  start[i] = cellCentres[own];
188  end[i] = cellCentres[mesh_.faceNeighbour()[facei]];
189  }
190  else
191  {
192  start[i] = cellCentres[own];
193  end[i] = neiCc[facei-mesh_.nInternalFaces()];
194  }
195  }
196 
197  // Extend segments a bit
198  {
199  const vectorField smallVec(rootSmall*(end-start));
200  start -= smallVec;
201  end += smallVec;
202  }
203 
204 
205  // Do test for intersections
206  // ~~~~~~~~~~~~~~~~~~~~~~~~~
207  labelList surface1;
208  List<pointIndexHit> hit1;
209  labelList region1;
210  labelList surface2;
211  List<pointIndexHit> hit2;
212  labelList region2;
213  surfaces_.findNearestIntersection
214  (
215  surfacesToBaffle,
216  start,
217  end,
218 
219  surface1,
220  hit1,
221  region1,
222 
223  surface2,
224  hit2,
225  region2
226  );
227 
228  forAll(testFaces, i)
229  {
230  label facei = testFaces[i];
231 
232  if (hit1[i].hit() && hit2[i].hit())
233  {
234  if (str.valid())
235  {
236  meshTools::writeOBJ(str(), start[i]);
237  vertI++;
238  meshTools::writeOBJ(str(), hit1[i].rawPoint());
239  vertI++;
240  meshTools::writeOBJ(str(), hit2[i].rawPoint());
241  vertI++;
242  meshTools::writeOBJ(str(), end[i]);
243  vertI++;
244  str()<< "l " << vertI-3 << ' ' << vertI-2 << nl;
245  str()<< "l " << vertI-2 << ' ' << vertI-1 << nl;
246  str()<< "l " << vertI-1 << ' ' << vertI << nl;
247  }
248 
249  // Pick up the patches
250  ownPatch[facei] = globalToMasterPatch
251  [
252  surfaces_.globalRegion(surface1[i], region1[i])
253  ];
254  neiPatch[facei] = globalToMasterPatch
255  [
256  surfaces_.globalRegion(surface2[i], region2[i])
257  ];
258 
259  if (ownPatch[facei] == -1 || neiPatch[facei] == -1)
260  {
262  << "problem." << abort(FatalError);
263  }
264  }
265  }
266 
267  // No need to parallel sync since intersection data (surfaceIndex_ etc.)
268  // already guaranteed to be synced...
269  // However:
270  // - owncc and neicc are reversed on different procs so might pick
271  // up different regions reversed? No problem. Neighbour on one processor
272  // might not be owner on the other processor but the neighbour is
273  // not used when creating baffles from proc faces.
274  // - tolerances issues occasionally crop up.
275  syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
276  syncTools::syncFaceList(mesh_, neiPatch, maxEqOp<label>());
277 }
278 
279 
280 Foam::Map<Foam::labelPair> Foam::meshRefinement::getZoneBafflePatches
281 (
282  const bool allowBoundary,
283  const labelList& globalToMasterPatch,
284  const labelList& globalToSlavePatch
285 ) const
286 {
287  Map<labelPair> bafflePatch(mesh_.nFaces()/1000);
288 
289  const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
290  const faceZoneMesh& fZones = mesh_.faceZones();
291 
292  forAll(surfZones, surfI)
293  {
294  const word& faceZoneName = surfZones[surfI].faceZoneName();
295 
296  if (faceZoneName.size())
297  {
298  // Get zone
299  label zoneI = fZones.findZoneID(faceZoneName);
300 
301  const faceZone& fZone = fZones[zoneI];
302 
303  // Get patch allocated for zone
304  label globalRegionI = surfaces_.globalRegion(surfI, 0);
305  labelPair zPatches
306  (
307  globalToMasterPatch[globalRegionI],
308  globalToSlavePatch[globalRegionI]
309  );
310 
311  Info<< "For zone " << fZone.name() << " found patches "
312  << mesh_.boundaryMesh()[zPatches[0]].name() << " and "
313  << mesh_.boundaryMesh()[zPatches[1]].name()
314  << endl;
315 
316  forAll(fZone, i)
317  {
318  label facei = fZone[i];
319 
320  if (allowBoundary || mesh_.isInternalFace(facei))
321  {
322  labelPair patches = zPatches;
323  if (fZone.flipMap()[i])
324  {
325  patches = reverse(patches);
326  }
327 
328  if (!bafflePatch.insert(facei, patches))
329  {
331  << "Face " << facei
332  << " fc:" << mesh_.faceCentres()[facei]
333  << " in zone " << fZone.name()
334  << " is in multiple zones!"
335  << abort(FatalError);
336  }
337  }
338  }
339  }
340  }
341  return bafflePatch;
342 }
343 
344 
346 (
347  const labelList& ownPatch,
348  const labelList& neiPatch
349 )
350 {
351  if
352  (
353  ownPatch.size() != mesh_.nFaces()
354  || neiPatch.size() != mesh_.nFaces()
355  )
356  {
358  << "Illegal size :"
359  << " ownPatch:" << ownPatch.size()
360  << " neiPatch:" << neiPatch.size()
361  << ". Should be number of faces:" << mesh_.nFaces()
362  << abort(FatalError);
363  }
364 
365  if (debug)
366  {
367  labelList syncedOwnPatch(ownPatch);
368  syncTools::syncFaceList(mesh_, syncedOwnPatch, maxEqOp<label>());
369  labelList syncedNeiPatch(neiPatch);
370  syncTools::syncFaceList(mesh_, syncedNeiPatch, maxEqOp<label>());
371 
372  forAll(syncedOwnPatch, facei)
373  {
374  if
375  (
376  (ownPatch[facei] == -1 && syncedOwnPatch[facei] != -1)
377  || (neiPatch[facei] == -1 && syncedNeiPatch[facei] != -1)
378  )
379  {
381  << "Non synchronised at face:" << facei
382  << " on patch:" << mesh_.boundaryMesh().whichPatch(facei)
383  << " fc:" << mesh_.faceCentres()[facei] << endl
384  << "ownPatch:" << ownPatch[facei]
385  << " syncedOwnPatch:" << syncedOwnPatch[facei]
386  << " neiPatch:" << neiPatch[facei]
387  << " syncedNeiPatch:" << syncedNeiPatch[facei]
388  << abort(FatalError);
389  }
390  }
391  }
392 
393  // Topochange container
394  polyTopoChange meshMod(mesh_);
395 
396  label nBaffles = 0;
397 
398  forAll(ownPatch, facei)
399  {
400  if (ownPatch[facei] != -1)
401  {
402  // Create baffle or repatch face. Return label of inserted baffle
403  // face.
404  createBaffle
405  (
406  facei,
407  ownPatch[facei], // owner side patch
408  neiPatch[facei], // neighbour side patch
409  meshMod
410  );
411  nBaffles++;
412  }
413  }
414 
415  mesh_.clearOut();
416 
417  // Change the mesh (no inflation, parallel sync)
418  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
419 
420  // Update fields
421  mesh_.updateMesh(map);
422 
423  // Move mesh if in inflation mode
424  if (map().hasMotionPoints())
425  {
426  mesh_.movePoints(map().preMotionPoints());
427  }
428  else
429  {
430  // Delete mesh volumes.
431  mesh_.clearOut();
432  }
433 
434 
435  // Reset the instance for if in overwrite mode
436  mesh_.setInstance(timeName());
437 
438  //- Redo the intersections on the newly create baffle faces. Note that
439  // this changes also the cell centre positions.
440  faceSet baffledFacesSet(mesh_, "baffledFacesSet", 2*nBaffles);
441 
442  const labelList& reverseFaceMap = map().reverseFaceMap();
443  const labelList& faceMap = map().faceMap();
444 
445  // Pick up owner side of baffle
446  forAll(ownPatch, oldFacei)
447  {
448  label facei = reverseFaceMap[oldFacei];
449 
450  if (ownPatch[oldFacei] != -1 && facei >= 0)
451  {
452  const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[facei]];
453 
454  forAll(ownFaces, i)
455  {
456  baffledFacesSet.insert(ownFaces[i]);
457  }
458  }
459  }
460  // Pick up neighbour side of baffle (added faces)
461  forAll(faceMap, facei)
462  {
463  label oldFacei = faceMap[facei];
464 
465  if (oldFacei >= 0 && reverseFaceMap[oldFacei] != facei)
466  {
467  const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[facei]];
468 
469  forAll(ownFaces, i)
470  {
471  baffledFacesSet.insert(ownFaces[i]);
472  }
473  }
474  }
475  baffledFacesSet.sync(mesh_);
476 
477  updateMesh(map, baffledFacesSet.toc());
478 
479  return map;
480 }
481 
482 
484 {
485  const faceZoneMesh& fZones = mesh_.faceZones();
486 
487  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
488 
489  forAll(pbm, patchi)
490  {
491  const polyPatch& pp = pbm[patchi];
492 
493  if (isA<processorPolyPatch>(pp))
494  {
495  forAll(pp, i)
496  {
497  label facei = pp.start()+i;
498  label zoneI = fZones.whichZone(facei);
499 
500  if (zoneI != -1)
501  {
503  << "face:" << facei << " on patch " << pp.name()
504  << " is in zone " << fZones[zoneI].name()
505  << exit(FatalError);
506  }
507  }
508  }
509  }
510 }
511 
512 
514 (
515  const labelList& globalToMasterPatch,
516  const labelList& globalToSlavePatch,
517  List<labelPair>& baffles
518 )
519 {
520  const labelList zonedSurfaces
521  (
523  );
524 
526 
527  // No need to sync; all processors will have all same zonedSurfaces.
528  if (zonedSurfaces.size())
529  {
530  // Split internal faces on interface surfaces
531  Info<< "Converting zoned faces into baffles ..." << endl;
532 
533  // Get faces (internal only) to be baffled. Map from face to patch
534  // label.
535  Map<labelPair> faceToPatch
536  (
537  getZoneBafflePatches
538  (
539  false,
540  globalToMasterPatch,
541  globalToSlavePatch
542  )
543  );
544 
545  label nZoneFaces = returnReduce(faceToPatch.size(), sumOp<label>());
546  if (nZoneFaces > 0)
547  {
548  // Convert into labelLists
549  labelList ownPatch(mesh_.nFaces(), -1);
550  labelList neiPatch(mesh_.nFaces(), -1);
551  forAllConstIter(Map<labelPair>, faceToPatch, iter)
552  {
553  ownPatch[iter.key()] = iter().first();
554  neiPatch[iter.key()] = iter().second();
555  }
556 
557  // Create baffles. both sides same patch.
558  map = createBaffles(ownPatch, neiPatch);
559 
560  // Get pairs of faces created.
561  // Just loop over faceMap and store baffle if we encounter a slave
562  // face.
563 
564  baffles.setSize(faceToPatch.size());
565  label baffleI = 0;
566 
567  const labelList& faceMap = map().faceMap();
568  const labelList& reverseFaceMap = map().reverseFaceMap();
569 
570  forAll(faceMap, facei)
571  {
572  label oldFacei = faceMap[facei];
573 
574  // Does face originate from face-to-patch
575  Map<labelPair>::const_iterator iter = faceToPatch.find
576  (
577  oldFacei
578  );
579 
580  if (iter != faceToPatch.end())
581  {
582  label masterFacei = reverseFaceMap[oldFacei];
583  if (facei != masterFacei)
584  {
585  baffles[baffleI++] = labelPair(masterFacei, facei);
586  }
587  }
588  }
589 
590  if (baffleI != faceToPatch.size())
591  {
593  << "Had " << faceToPatch.size() << " patches to create "
594  << " but encountered " << baffleI
595  << " slave faces originating from patcheable faces."
596  << abort(FatalError);
597  }
598 
599  if (debug&MESH)
600  {
601  const_cast<Time&>(mesh_.time())++;
602  Pout<< "Writing zone-baffled mesh to time " << timeName()
603  << endl;
604  write
605  (
606  debugType(debug),
608  mesh_.time().path()/"baffles"
609  );
610  }
611  }
612  Info<< "Created " << nZoneFaces << " baffles in = "
613  << mesh_.time().cpuTimeIncrement() << " s\n" << nl << endl;
614  }
615  return map;
616 }
617 
618 
619 Foam::List<Foam::labelPair> Foam::meshRefinement::freeStandingBaffles
620 (
621  const List<labelPair>& couples,
622  const scalar planarAngle
623 ) const
624 {
625  // Done by counting the number of baffles faces per mesh edge. If edge
626  // has 2 boundary faces and both are baffle faces it is the edge of a baffle
627  // region.
628 
629  // All duplicate faces on edge of the patch are to be merged.
630  // So we count for all edges of duplicate faces how many duplicate
631  // faces use them.
632  labelList nBafflesPerEdge(mesh_.nEdges(), 0);
633 
634 
635  // This algorithm is quite tricky. We don't want to use edgeFaces and
636  // also want it to run in parallel so it is now an algorithm over
637  // all (boundary) faces instead.
638  // We want to pick up any edges that are only used by the baffle
639  // or internal faces but not by any other boundary faces. So
640  // - increment count on an edge by 1 if it is used by any (uncoupled)
641  // boundary face.
642  // - increment count on an edge by 1000000 if it is used by a baffle face
643  // - sum in parallel
644  //
645  // So now any edge that is used by baffle faces only will have the
646  // value 2*1000000+2*1.
647 
648 
649  const label baffleValue = 1000000;
650 
651 
652  // Count number of boundary faces per edge
653  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
654 
655  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
656 
657  forAll(patches, patchi)
658  {
659  const polyPatch& pp = patches[patchi];
660 
661  // Count number of boundary faces. Discard coupled boundary faces.
662  if (!pp.coupled())
663  {
664  label facei = pp.start();
665 
666  forAll(pp, i)
667  {
668  const labelList& fEdges = mesh_.faceEdges(facei);
669 
670  forAll(fEdges, fEdgeI)
671  {
672  nBafflesPerEdge[fEdges[fEdgeI]]++;
673  }
674  facei++;
675  }
676  }
677  }
678 
679 
680  DynamicList<label> fe0;
681  DynamicList<label> fe1;
682 
683 
684  // Count number of duplicate boundary faces per edge
685  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
686 
687  forAll(couples, i)
688  {
689  {
690  label f0 = couples[i].first();
691  const labelList& fEdges0 = mesh_.faceEdges(f0, fe0);
692  forAll(fEdges0, fEdgeI)
693  {
694  nBafflesPerEdge[fEdges0[fEdgeI]] += baffleValue;
695  }
696  }
697 
698  {
699  label f1 = couples[i].second();
700  const labelList& fEdges1 = mesh_.faceEdges(f1, fe1);
701  forAll(fEdges1, fEdgeI)
702  {
703  nBafflesPerEdge[fEdges1[fEdgeI]] += baffleValue;
704  }
705  }
706  }
707 
708  // Add nBaffles on shared edges
710  (
711  mesh_,
712  nBafflesPerEdge,
713  plusEqOp<label>(), // in-place add
714  label(0) // initial value
715  );
716 
717 
718  // Baffles which are not next to other boundaries and baffles will have
719  // nBafflesPerEdge value 2*baffleValue+2*1 (from 2 boundary faces which
720  // are both baffle faces)
721 
722  List<labelPair> filteredCouples(couples.size());
723  label filterI = 0;
724 
725  forAll(couples, i)
726  {
727  const labelPair& couple = couples[i];
728 
729  if
730  (
731  patches.whichPatch(couple.first())
732  == patches.whichPatch(couple.second())
733  )
734  {
735  const labelList& fEdges = mesh_.faceEdges(couple.first());
736 
737  forAll(fEdges, fEdgeI)
738  {
739  label edgeI = fEdges[fEdgeI];
740 
741  if (nBafflesPerEdge[edgeI] == 2*baffleValue+2*1)
742  {
743  filteredCouples[filterI++] = couple;
744  break;
745  }
746  }
747  }
748  }
749  filteredCouples.setSize(filterI);
750 
751 
752  label nFiltered = returnReduce(filteredCouples.size(), sumOp<label>());
753 
754  Info<< "freeStandingBaffles : detected "
755  << nFiltered
756  << " free-standing baffles out of "
757  << returnReduce(couples.size(), sumOp<label>())
758  << nl << endl;
759 
760 
761  if (nFiltered > 0)
762  {
763  // Collect segments
764  // ~~~~~~~~~~~~~~~~
765 
766  pointField start(filteredCouples.size());
767  pointField end(filteredCouples.size());
768 
769  const pointField& cellCentres = mesh_.cellCentres();
770 
771  forAll(filteredCouples, i)
772  {
773  const labelPair& couple = filteredCouples[i];
774  start[i] = cellCentres[mesh_.faceOwner()[couple.first()]];
775  end[i] = cellCentres[mesh_.faceOwner()[couple.second()]];
776  }
777 
778  // Extend segments a bit
779  {
780  const vectorField smallVec(rootSmall*(end-start));
781  start -= smallVec;
782  end += smallVec;
783  }
784 
785 
786  // Do test for intersections
787  // ~~~~~~~~~~~~~~~~~~~~~~~~~
788  labelList surface1;
789  List<pointIndexHit> hit1;
790  labelList region1;
791  vectorField normal1;
792 
793  labelList surface2;
794  List<pointIndexHit> hit2;
795  labelList region2;
796  vectorField normal2;
797 
798  surfaces_.findNearestIntersection
799  (
800  identity(surfaces_.surfaces().size()),
801  start,
802  end,
803 
804  surface1,
805  hit1,
806  region1,
807  normal1,
808 
809  surface2,
810  hit2,
811  region2,
812  normal2
813  );
814 
815  // mkDir(mesh_.time().path()/timeName());
816  // OBJstream str
817  //(
818  // mesh_.time().path()/timeName()/"flatBaffles.obj"
819  //);
820 
821  const scalar planarAngleCos = Foam::cos(degToRad(planarAngle));
822 
823  label filterI = 0;
824  forAll(filteredCouples, i)
825  {
826  const labelPair& couple = filteredCouples[i];
827 
828  if
829  (
830  hit1[i].hit()
831  && hit2[i].hit()
832  && (
833  surface1[i] != surface2[i]
834  || hit1[i].index() != hit2[i].index()
835  )
836  )
837  {
838  // Two different hits. Check angle.
839  // str.write
840  //(
841  // linePointRef(hit1[i].hitPoint(), hit2[i].hitPoint()),
842  // normal1[i],
843  // normal2[i]
844  //);
845 
846  if ((normal1[i]&normal2[i]) > planarAngleCos)
847  {
848  // Both normals aligned
849  vector n = end[i]-start[i];
850  scalar magN = mag(n);
851  if (magN > vSmall)
852  {
853  filteredCouples[filterI++] = couple;
854  }
855  }
856  }
857  else if (hit1[i].hit() || hit2[i].hit())
858  {
859  // Single hit. Do not include in freestanding baffles.
860  }
861  }
862 
863  filteredCouples.setSize(filterI);
864 
865  Info<< "freeStandingBaffles : detected "
866  << returnReduce(filterI, sumOp<label>())
867  << " planar (within " << planarAngle
868  << " degrees) free-standing baffles out of "
869  << nFiltered
870  << nl << endl;
871  }
872 
873  return filteredCouples;
874 }
875 
876 
878 (
879  const List<labelPair>& couples
880 )
881 {
882  // Mesh change engine
883  polyTopoChange meshMod(mesh_);
884 
885  const faceList& faces = mesh_.faces();
886  const labelList& faceOwner = mesh_.faceOwner();
887  const faceZoneMesh& faceZones = mesh_.faceZones();
888 
889  forAll(couples, i)
890  {
891  label face0 = couples[i].first();
892  label face1 = couples[i].second();
893 
894  // face1 < 0 signals a coupled face that has been converted to baffle.
895 
896  label own0 = faceOwner[face0];
897  label own1 = faceOwner[face1];
898 
899  if (face1 < 0 || own0 < own1)
900  {
901  // Use face0 as the new internal face.
902  label zoneID = faceZones.whichZone(face0);
903  bool zoneFlip = false;
904 
905  if (zoneID >= 0)
906  {
907  const faceZone& fZone = faceZones[zoneID];
908  zoneFlip = fZone.flipMap()[fZone.whichFace(face0)];
909  }
910 
911  label nei = (face1 < 0 ? -1 : own1);
912 
913  meshMod.setAction(polyRemoveFace(face1));
914  meshMod.setAction
915  (
917  (
918  faces[face0], // modified face
919  face0, // label of face being modified
920  own0, // owner
921  nei, // neighbour
922  false, // face flip
923  -1, // patch for face
924  false, // remove from zone
925  zoneID, // zone for face
926  zoneFlip // face flip in zone
927  )
928  );
929  }
930  else
931  {
932  // Use face1 as the new internal face.
933  label zoneID = faceZones.whichZone(face1);
934  bool zoneFlip = false;
935 
936  if (zoneID >= 0)
937  {
938  const faceZone& fZone = faceZones[zoneID];
939  zoneFlip = fZone.flipMap()[fZone.whichFace(face1)];
940  }
941 
942  meshMod.setAction(polyRemoveFace(face0));
943  meshMod.setAction
944  (
946  (
947  faces[face1], // modified face
948  face1, // label of face being modified
949  own1, // owner
950  own0, // neighbour
951  false, // face flip
952  -1, // patch for face
953  false, // remove from zone
954  zoneID, // zone for face
955  zoneFlip // face flip in zone
956  )
957  );
958  }
959  }
960 
961  mesh_.clearOut();
962 
963  // Change the mesh (no inflation)
964  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
965 
966  // Update fields
967  mesh_.updateMesh(map);
968 
969  // Move mesh (since morphing does not do this)
970  if (map().hasMotionPoints())
971  {
972  mesh_.movePoints(map().preMotionPoints());
973  }
974  else
975  {
976  // Delete mesh volumes.
977  mesh_.clearOut();
978  }
979 
980  // Reset the instance for if in overwrite mode
981  mesh_.setInstance(timeName());
982 
983  // Update intersections. Recalculate intersections on merged faces since
984  // this seems to give problems? Note: should not be necessary since
985  // baffles preserve intersections from when they were created.
986  labelList newExposedFaces(2*couples.size());
987  label newI = 0;
988 
989  forAll(couples, i)
990  {
991  label newFace0 = map().reverseFaceMap()[couples[i].first()];
992  if (newFace0 != -1)
993  {
994  newExposedFaces[newI++] = newFace0;
995  }
996 
997  label newFace1 = map().reverseFaceMap()[couples[i].second()];
998  if (newFace1 != -1)
999  {
1000  newExposedFaces[newI++] = newFace1;
1001  }
1002  }
1003  newExposedFaces.setSize(newI);
1004  updateMesh(map, newExposedFaces);
1005 
1006  return map;
1007 }
1008 
1009 
1010 // Finds region per cell for cells inside closed named surfaces
1011 void Foam::meshRefinement::findCellZoneGeometric
1012 (
1013  const pointField& neiCc,
1014  const labelList& closedNamedSurfaces, // indices of closed surfaces
1015  labelList& namedSurfaceIndex, // per face index of named surface
1016  const labelList& surfaceToCellZone, // cell zone index per surface
1017 
1018  labelList& cellToZone
1019 ) const
1020 {
1021  const pointField& cellCentres = mesh_.cellCentres();
1022  const labelList& faceOwner = mesh_.faceOwner();
1023  const labelList& faceNeighbour = mesh_.faceNeighbour();
1024 
1025  // Check if cell centre is inside
1026  labelList insideSurfaces;
1027  surfaces_.findInside
1028  (
1029  closedNamedSurfaces,
1030  cellCentres,
1031  insideSurfaces
1032  );
1033 
1034  forAll(insideSurfaces, celli)
1035  {
1036  if (cellToZone[celli] == -2)
1037  {
1038  label surfI = insideSurfaces[celli];
1039 
1040  if (surfI != -1)
1041  {
1042  cellToZone[celli] = surfaceToCellZone[surfI];
1043  }
1044  }
1045  }
1046 
1047 
1048  // Some cells with cell centres close to surface might have
1049  // had been put into wrong surface. Recheck with perturbed cell centre.
1050 
1051 
1052  // 1. Collect points
1053 
1054  // Count points to test.
1055  label nCandidates = 0;
1056  forAll(namedSurfaceIndex, facei)
1057  {
1058  label surfI = namedSurfaceIndex[facei];
1059 
1060  if (surfI != -1)
1061  {
1062  if (mesh_.isInternalFace(facei))
1063  {
1064  nCandidates += 2;
1065  }
1066  else
1067  {
1068  nCandidates += 1;
1069  }
1070  }
1071  }
1072 
1073  // Collect points.
1074  pointField candidatePoints(nCandidates);
1075  nCandidates = 0;
1076  forAll(namedSurfaceIndex, facei)
1077  {
1078  label surfI = namedSurfaceIndex[facei];
1079 
1080  if (surfI != -1)
1081  {
1082  label own = faceOwner[facei];
1083  const point& ownCc = cellCentres[own];
1084 
1085  if (mesh_.isInternalFace(facei))
1086  {
1087  label nei = faceNeighbour[facei];
1088  const point& neiCc = cellCentres[nei];
1089  // Perturbed cc
1090  const vector d = 1e-4*(neiCc - ownCc);
1091  candidatePoints[nCandidates++] = ownCc-d;
1092  candidatePoints[nCandidates++] = neiCc+d;
1093  }
1094  else
1095  {
1096  // const point& neiFc = mesh_.faceCentres()[facei];
1097  const point& neiFc = neiCc[facei-mesh_.nInternalFaces()];
1098 
1099  // Perturbed cc
1100  const vector d = 1e-4*(neiFc - ownCc);
1101  candidatePoints[nCandidates++] = ownCc-d;
1102  }
1103  }
1104  }
1105 
1106 
1107  // 2. Test points for inside
1108 
1109  surfaces_.findInside
1110  (
1111  closedNamedSurfaces,
1112  candidatePoints,
1113  insideSurfaces
1114  );
1115 
1116 
1117  // 3. Update zone information
1118 
1119  nCandidates = 0;
1120  forAll(namedSurfaceIndex, facei)
1121  {
1122  label surfI = namedSurfaceIndex[facei];
1123 
1124  if (surfI != -1)
1125  {
1126  label own = faceOwner[facei];
1127 
1128  if (mesh_.isInternalFace(facei))
1129  {
1130  label ownSurfI = insideSurfaces[nCandidates++];
1131  if (ownSurfI != -1)
1132  {
1133  cellToZone[own] = surfaceToCellZone[ownSurfI];
1134  }
1135 
1136  label neiSurfI = insideSurfaces[nCandidates++];
1137  if (neiSurfI != -1)
1138  {
1139  label nei = faceNeighbour[facei];
1140 
1141  cellToZone[nei] = surfaceToCellZone[neiSurfI];
1142  }
1143  }
1144  else
1145  {
1146  label ownSurfI = insideSurfaces[nCandidates++];
1147  if (ownSurfI != -1)
1148  {
1149  cellToZone[own] = surfaceToCellZone[ownSurfI];
1150  }
1151  }
1152  }
1153  }
1154 
1155 
1156  // Adapt the namedSurfaceIndex
1157  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
1158  // for if any cells were not completely covered.
1159 
1160  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1161  {
1162  label ownZone = cellToZone[mesh_.faceOwner()[facei]];
1163  label neiZone = cellToZone[mesh_.faceNeighbour()[facei]];
1164 
1165  if (namedSurfaceIndex[facei] == -1 && (ownZone != neiZone))
1166  {
1167  // Give face the zone of max cell zone
1168  namedSurfaceIndex[facei] = findIndex
1169  (
1170  surfaceToCellZone,
1171  max(ownZone, neiZone)
1172  );
1173  }
1174  }
1175 
1176  labelList neiCellZone(mesh_.nFaces()-mesh_.nInternalFaces());
1177  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1178 
1179  forAll(patches, patchi)
1180  {
1181  const polyPatch& pp = patches[patchi];
1182 
1183  if (pp.coupled())
1184  {
1185  forAll(pp, i)
1186  {
1187  label facei = pp.start()+i;
1188  label ownZone = cellToZone[mesh_.faceOwner()[facei]];
1189  neiCellZone[facei-mesh_.nInternalFaces()] = ownZone;
1190  }
1191  }
1192  }
1193  syncTools::swapBoundaryFaceList(mesh_, neiCellZone);
1194 
1195  forAll(patches, patchi)
1196  {
1197  const polyPatch& pp = patches[patchi];
1198 
1199  if (pp.coupled())
1200  {
1201  forAll(pp, i)
1202  {
1203  label facei = pp.start()+i;
1204  label ownZone = cellToZone[mesh_.faceOwner()[facei]];
1205  label neiZone = neiCellZone[facei-mesh_.nInternalFaces()];
1206 
1207  if (namedSurfaceIndex[facei] == -1 && (ownZone != neiZone))
1208  {
1209  // Give face the max cell zone
1210  namedSurfaceIndex[facei] = findIndex
1211  (
1212  surfaceToCellZone,
1213  max(ownZone, neiZone)
1214  );
1215  }
1216  }
1217  }
1218  }
1219 
1220  // Sync
1221  syncTools::syncFaceList(mesh_, namedSurfaceIndex, maxEqOp<label>());
1222 }
1223 
1224 
1225 void Foam::meshRefinement::findCellZoneInsideWalk
1226 (
1227  const labelList& locationSurfaces, // indices of surfaces with inside point
1228  const labelList& namedSurfaceIndex, // per face index of named surface
1229  const labelList& surfaceToCellZone, // cell zone index per surface
1230 
1231  labelList& cellToZone
1232 ) const
1233 {
1234  // Analyse regions. Reuse regionsplit
1235  boolList blockedFace(mesh_.nFaces());
1236  // selectSeparatedCoupledFaces(blockedFace);
1237 
1238  forAll(namedSurfaceIndex, facei)
1239  {
1240  if (namedSurfaceIndex[facei] == -1)
1241  {
1242  blockedFace[facei] = false;
1243  }
1244  else
1245  {
1246  blockedFace[facei] = true;
1247  }
1248  }
1249  // No need to sync since namedSurfaceIndex already is synced
1250 
1251  // Set region per cell based on walking
1252  regionSplit cellRegion(mesh_, blockedFace);
1253  blockedFace.clear();
1254 
1255 
1256  // Force calculation of face decomposition (used in findCell)
1257  (void)mesh_.tetBasePtIs();
1258 
1259  const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
1260 
1261  // For all locationSurface find the cell
1262  forAll(locationSurfaces, i)
1263  {
1264  label surfI = locationSurfaces[i];
1265 
1266  const point& insidePoint = surfZones[surfI].zoneInsidePoint();
1267 
1268  Info<< "For surface " << surfaces_.names()[surfI]
1269  << " finding inside point " << insidePoint
1270  << endl;
1271 
1272  // Find the region containing the insidePoint
1273  label keepRegionI = findRegion
1274  (
1275  mesh_,
1276  cellRegion,
1277  mergeDistance_*vector(1,1,1),
1278  insidePoint
1279  );
1280 
1281  Info<< "For surface " << surfaces_.names()[surfI]
1282  << " found point " << insidePoint
1283  << " in global region " << keepRegionI
1284  << " out of " << cellRegion.nRegions() << " regions." << endl;
1285 
1286  if (keepRegionI == -1)
1287  {
1289  << "Point " << insidePoint
1290  << " is not inside the mesh." << nl
1291  << "Bounding box of the mesh:" << mesh_.bounds()
1292  << exit(FatalError);
1293  }
1294 
1295  // Set all cells with this region
1296  forAll(cellRegion, celli)
1297  {
1298  if (cellRegion[celli] == keepRegionI)
1299  {
1300  if (cellToZone[celli] == -2)
1301  {
1302  cellToZone[celli] = surfaceToCellZone[surfI];
1303  }
1304  else if (cellToZone[celli] != surfaceToCellZone[surfI])
1305  {
1307  << "Cell " << celli
1308  << " at " << mesh_.cellCentres()[celli]
1309  << " is inside surface " << surfaces_.names()[surfI]
1310  << " but already marked as being in zone "
1311  << cellToZone[celli] << endl
1312  << "This can happen if your surfaces are not"
1313  << " (sufficiently) closed."
1314  << endl;
1315  }
1316  }
1317  }
1318  }
1319 }
1320 
1321 
1322 bool Foam::meshRefinement::calcRegionToZone
1323 (
1324  const label surfZoneI,
1325  const label ownRegion,
1326  const label neiRegion,
1327 
1328  labelList& regionToCellZone
1329 ) const
1330 {
1331  bool changed = false;
1332 
1333  // Check whether in between different regions
1334  if (ownRegion != neiRegion)
1335  {
1336  // Jump. Change one of the sides to my type.
1337 
1338  // 1. Interface between my type and unset region.
1339  // Set region to keepRegion
1340 
1341  if (regionToCellZone[ownRegion] == -2)
1342  {
1343  if (regionToCellZone[neiRegion] == surfZoneI)
1344  {
1345  // Face between unset and my region. Put unset
1346  // region into keepRegion
1347  regionToCellZone[ownRegion] = -1;
1348  changed = true;
1349  }
1350  else if (regionToCellZone[neiRegion] != -2)
1351  {
1352  // Face between unset and other region.
1353  // Put unset region into my region
1354  regionToCellZone[ownRegion] = surfZoneI;
1355  changed = true;
1356  }
1357  }
1358  else if (regionToCellZone[neiRegion] == -2)
1359  {
1360  if (regionToCellZone[ownRegion] == surfZoneI)
1361  {
1362  // Face between unset and my region. Put unset
1363  // region into keepRegion
1364  regionToCellZone[neiRegion] = -1;
1365  changed = true;
1366  }
1367  else if (regionToCellZone[ownRegion] != -2)
1368  {
1369  // Face between unset and other region.
1370  // Put unset region into my region
1371  regionToCellZone[neiRegion] = surfZoneI;
1372  changed = true;
1373  }
1374  }
1375  }
1376  return changed;
1377 }
1378 
1379 
1380 void Foam::meshRefinement::findCellZoneTopo
1381 (
1382  const point& keepPoint,
1383  const labelList& namedSurfaceIndex,
1384  const labelList& surfaceToCellZone,
1385  labelList& cellToZone
1386 ) const
1387 {
1388  // Assumes:
1389  // - region containing keepPoint does not go into a cellZone
1390  // - all other regions can be found by crossing faces marked in
1391  // namedSurfaceIndex.
1392 
1393  // Analyse regions. Reuse regionsplit
1394  boolList blockedFace(mesh_.nFaces());
1395 
1396  forAll(namedSurfaceIndex, facei)
1397  {
1398  if (namedSurfaceIndex[facei] == -1)
1399  {
1400  blockedFace[facei] = false;
1401  }
1402  else
1403  {
1404  blockedFace[facei] = true;
1405  }
1406  }
1407  // No need to sync since namedSurfaceIndex already is synced
1408 
1409  // Set region per cell based on walking
1410  regionSplit cellRegion(mesh_, blockedFace);
1411  blockedFace.clear();
1412 
1413  // Per mesh region the zone the cell should be put in.
1414  // -2 : not analysed yet
1415  // -1 : keepPoint region. Not put into any cellzone.
1416  // >= 0 : index of cellZone
1417  labelList regionToCellZone(cellRegion.nRegions(), -2);
1418 
1419  // See which cells already are set in the cellToZone (from geometric
1420  // searching) and use these to take over their zones.
1421  // Note: could be improved to count number of cells per region.
1422  forAll(cellToZone, celli)
1423  {
1424  if (cellToZone[celli] != -2)
1425  {
1426  regionToCellZone[cellRegion[celli]] = cellToZone[celli];
1427  }
1428  }
1429 
1430 
1431  // Find the region containing the keepPoint
1432  label keepRegionI = findRegion
1433  (
1434  mesh_,
1435  cellRegion,
1436  mergeDistance_*vector(1,1,1),
1437  keepPoint
1438  );
1439 
1440  Info<< "Found point " << keepPoint
1441  << " in global region " << keepRegionI
1442  << " out of " << cellRegion.nRegions() << " regions." << endl;
1443 
1444  if (keepRegionI == -1)
1445  {
1447  << "Point " << keepPoint
1448  << " is not inside the mesh." << nl
1449  << "Bounding box of the mesh:" << mesh_.bounds()
1450  << exit(FatalError);
1451  }
1452 
1453  // Mark default region with zone -1.
1454  if (regionToCellZone[keepRegionI] == -2)
1455  {
1456  regionToCellZone[keepRegionI] = -1;
1457  }
1458 
1459 
1460  // Find correspondence between cell zone and surface
1461  // by changing cell zone every time we cross a surface.
1462  while (true)
1463  {
1464  // Synchronise regionToCellZone.
1465  // Note:
1466  // - region numbers are identical on all processors
1467  // - keepRegion is identical ,,
1468  // - cellZones are identical ,,
1469  // This done at top of loop to account for geometric matching
1470  // not being synchronised.
1471  Pstream::listCombineGather(regionToCellZone, maxEqOp<label>());
1472  Pstream::listCombineScatter(regionToCellZone);
1473 
1474 
1475  bool changed = false;
1476 
1477  // Internal faces
1478 
1479  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1480  {
1481  label surfI = namedSurfaceIndex[facei];
1482 
1483  // Connected even if no cellZone defined for surface
1484  if (surfI != -1)
1485  {
1486  // Calculate region to zone from cellRegions on either side
1487  // of internal face.
1488  bool changedCell = calcRegionToZone
1489  (
1490  surfaceToCellZone[surfI],
1491  cellRegion[mesh_.faceOwner()[facei]],
1492  cellRegion[mesh_.faceNeighbour()[facei]],
1493  regionToCellZone
1494  );
1495 
1496  changed = changed | changedCell;
1497  }
1498  }
1499 
1500  // Boundary faces
1501 
1502  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1503 
1504  // Get coupled neighbour cellRegion
1505  labelList neiCellRegion(mesh_.nFaces()-mesh_.nInternalFaces());
1506  forAll(patches, patchi)
1507  {
1508  const polyPatch& pp = patches[patchi];
1509 
1510  if (pp.coupled())
1511  {
1512  forAll(pp, i)
1513  {
1514  label facei = pp.start()+i;
1515  neiCellRegion[facei-mesh_.nInternalFaces()] =
1516  cellRegion[mesh_.faceOwner()[facei]];
1517  }
1518  }
1519  }
1520  syncTools::swapBoundaryFaceList(mesh_, neiCellRegion);
1521 
1522  // Calculate region to zone from cellRegions on either side of coupled
1523  // face.
1524  forAll(patches, patchi)
1525  {
1526  const polyPatch& pp = patches[patchi];
1527 
1528  if (pp.coupled())
1529  {
1530  forAll(pp, i)
1531  {
1532  label facei = pp.start()+i;
1533 
1534  label surfI = namedSurfaceIndex[facei];
1535 
1536  // Connected even if no cellZone defined for surface
1537  if (surfI != -1)
1538  {
1539  bool changedCell = calcRegionToZone
1540  (
1541  surfaceToCellZone[surfI],
1542  cellRegion[mesh_.faceOwner()[facei]],
1543  neiCellRegion[facei-mesh_.nInternalFaces()],
1544  regionToCellZone
1545  );
1546 
1547  changed = changed | changedCell;
1548  }
1549  }
1550  }
1551  }
1552 
1553  if (!returnReduce(changed, orOp<bool>()))
1554  {
1555  break;
1556  }
1557  }
1558 
1559 
1560  forAll(regionToCellZone, regionI)
1561  {
1562  label zoneI = regionToCellZone[regionI];
1563 
1564  if (zoneI == -2)
1565  {
1567  << "For region " << regionI << " haven't set cell zone."
1568  << exit(FatalError);
1569  }
1570  }
1571 
1572  if (debug)
1573  {
1574  forAll(regionToCellZone, regionI)
1575  {
1576  Pout<< "Region " << regionI
1577  << " becomes cellZone:" << regionToCellZone[regionI]
1578  << endl;
1579  }
1580  }
1581 
1582  // Rework into cellToZone
1583  forAll(cellToZone, celli)
1584  {
1585  cellToZone[celli] = regionToCellZone[cellRegion[celli]];
1586  }
1587 }
1588 
1589 
1590 void Foam::meshRefinement::makeConsistentFaceIndex
1591 (
1592  const labelList& cellToZone,
1593  labelList& namedSurfaceIndex
1594 ) const
1595 {
1596  const labelList& faceOwner = mesh_.faceOwner();
1597  const labelList& faceNeighbour = mesh_.faceNeighbour();
1598 
1599  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1600  {
1601  label ownZone = cellToZone[faceOwner[facei]];
1602  label neiZone = cellToZone[faceNeighbour[facei]];
1603 
1604  if (ownZone == neiZone && namedSurfaceIndex[facei] != -1)
1605  {
1606  namedSurfaceIndex[facei] = -1;
1607  }
1608  else if (ownZone != neiZone && namedSurfaceIndex[facei] == -1)
1609  {
1611  << "Different cell zones on either side of face " << facei
1612  << " at " << mesh_.faceCentres()[facei]
1613  << " but face not marked with a surface."
1614  << abort(FatalError);
1615  }
1616  }
1617 
1618  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1619 
1620  // Get coupled neighbour cellZone
1621  labelList neiCellZone(mesh_.nFaces()-mesh_.nInternalFaces());
1622  forAll(patches, patchi)
1623  {
1624  const polyPatch& pp = patches[patchi];
1625 
1626  if (pp.coupled())
1627  {
1628  forAll(pp, i)
1629  {
1630  label facei = pp.start()+i;
1631  neiCellZone[facei-mesh_.nInternalFaces()] =
1632  cellToZone[mesh_.faceOwner()[facei]];
1633  }
1634  }
1635  }
1636  syncTools::swapBoundaryFaceList(mesh_, neiCellZone);
1637 
1638  // Use coupled cellZone to do check
1639  forAll(patches, patchi)
1640  {
1641  const polyPatch& pp = patches[patchi];
1642 
1643  if (pp.coupled())
1644  {
1645  forAll(pp, i)
1646  {
1647  label facei = pp.start()+i;
1648 
1649  label ownZone = cellToZone[faceOwner[facei]];
1650  label neiZone = neiCellZone[facei-mesh_.nInternalFaces()];
1651 
1652  if (ownZone == neiZone && namedSurfaceIndex[facei] != -1)
1653  {
1654  namedSurfaceIndex[facei] = -1;
1655  }
1656  else if (ownZone != neiZone && namedSurfaceIndex[facei] == -1)
1657  {
1659  << "Different cell zones on either side of face "
1660  << facei << " at " << mesh_.faceCentres()[facei]
1661  << " but face not marked with a surface."
1662  << abort(FatalError);
1663  }
1664  }
1665  }
1666  else
1667  {
1668  // Unzonify boundary faces
1669  forAll(pp, i)
1670  {
1671  label facei = pp.start()+i;
1672  namedSurfaceIndex[facei] = -1;
1673  }
1674  }
1675  }
1676 }
1677 
1678 
1679 void Foam::meshRefinement::handleSnapProblems
1680 (
1681  const snapParameters& snapParams,
1682  const bool useTopologicalSnapDetection,
1683  const bool removeEdgeConnectedCells,
1684  const scalarField& perpendicularAngle,
1685  const dictionary& motionDict,
1686  Time& runTime,
1687  const labelList& globalToMasterPatch,
1688  const labelList& globalToSlavePatch
1689 )
1690 {
1691  Info<< nl
1692  << "Introducing baffles to block off problem cells" << nl
1693  << "----------------------------------------------" << nl
1694  << endl;
1695 
1696  labelList facePatch;
1697  if (useTopologicalSnapDetection)
1698  {
1699  facePatch = markFacesOnProblemCells
1700  (
1701  motionDict,
1702  removeEdgeConnectedCells,
1703  perpendicularAngle,
1704  globalToMasterPatch
1705  );
1706  }
1707  else
1708  {
1709  facePatch = markFacesOnProblemCellsGeometric(snapParams, motionDict);
1710  }
1711  Info<< "Analyzed problem cells in = "
1712  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1713 
1714  if (debug&MESH)
1715  {
1716  faceSet problemFaces(mesh_, "problemFaces", mesh_.nFaces()/100);
1717 
1718  forAll(facePatch, facei)
1719  {
1720  if (facePatch[facei] != -1)
1721  {
1722  problemFaces.insert(facei);
1723  }
1724  }
1725  problemFaces.instance() = timeName();
1726  Pout<< "Dumping " << problemFaces.size()
1727  << " problem faces to " << problemFaces.objectPath() << endl;
1728  problemFaces.write();
1729  }
1730 
1731  Info<< "Introducing baffles to delete problem cells." << nl << endl;
1732 
1733  if (debug)
1734  {
1735  runTime++;
1736  }
1737 
1738  // Create baffles with same owner and neighbour for now.
1739  createBaffles(facePatch, facePatch);
1740 
1741  if (debug)
1742  {
1743  // Debug:test all is still synced across proc patches
1744  checkData();
1745  }
1746  Info<< "Created baffles in = "
1747  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1748 
1749  printMeshInfo(debug, "After introducing baffles");
1750 
1751  if (debug&MESH)
1752  {
1753  Pout<< "Writing extra baffled mesh to time "
1754  << timeName() << endl;
1755  write
1756  (
1757  debugType(debug),
1759  runTime.path()/"extraBaffles"
1760  );
1761  Pout<< "Dumped debug data in = "
1762  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
1763  }
1764 }
1765 
1766 
1767 Foam::labelList Foam::meshRefinement::freeStandingBaffleFaces
1768 (
1769  const labelList& faceToZone,
1770  const labelList& cellToZone,
1771  const labelList& neiCellZone
1772 ) const
1773 {
1774  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
1775  const labelList& faceOwner = mesh_.faceOwner();
1776  const labelList& faceNeighbour = mesh_.faceNeighbour();
1777 
1778 
1779  // We want to pick up the faces to orient. These faces come in
1780  // two variants:
1781  // - faces originating from stand-alone faceZones
1782  // (these will most likely have no cellZone on either side so
1783  // ownZone and neiZone both -1)
1784  // - sticky-up faces originating from a 'bulge' in a outside of
1785  // a cellZone. These will have the same cellZone on either side.
1786  // How to orient these is not really clearly defined so do them
1787  // same as stand-alone faceZone faces for now. (Normally these will
1788  // already have been removed by the 'allowFreeStandingZoneFaces=false'
1789  // default setting)
1790 
1791  // Note that argument neiCellZone will have -1 on uncoupled boundaries.
1792 
1793  DynamicList<label> faceLabels(mesh_.nFaces()/100);
1794 
1795  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1796  {
1797  if (faceToZone[facei] != -1)
1798  {
1799  // Free standing baffle?
1800  label ownZone = cellToZone[faceOwner[facei]];
1801  label neiZone = cellToZone[faceNeighbour[facei]];
1802  if (ownZone == neiZone)
1803  {
1804  faceLabels.append(facei);
1805  }
1806  }
1807  }
1808  forAll(patches, patchi)
1809  {
1810  const polyPatch& pp = patches[patchi];
1811 
1812  forAll(pp, i)
1813  {
1814  label facei = pp.start()+i;
1815  if (faceToZone[facei] != -1)
1816  {
1817  // Free standing baffle?
1818  label ownZone = cellToZone[faceOwner[facei]];
1819  label neiZone = neiCellZone[facei-mesh_.nInternalFaces()];
1820  if (ownZone == neiZone)
1821  {
1822  faceLabels.append(facei);
1823  }
1824  }
1825  }
1826  }
1827  return faceLabels.shrink();
1828 }
1829 
1830 
1831 void Foam::meshRefinement::calcPatchNumMasterFaces
1832 (
1833  const PackedBoolList& isMasterFace,
1834  const indirectPrimitivePatch& patch,
1835  labelList& nMasterFacesPerEdge
1836 ) const
1837 {
1838  // Number of (master)faces per edge
1839  nMasterFacesPerEdge.setSize(patch.nEdges());
1840  nMasterFacesPerEdge = 0;
1841 
1842  forAll(patch.addressing(), facei)
1843  {
1844  const label meshFacei = patch.addressing()[facei];
1845 
1846  if (isMasterFace[meshFacei])
1847  {
1848  const labelList& fEdges = patch.faceEdges()[facei];
1849  forAll(fEdges, fEdgeI)
1850  {
1851  nMasterFacesPerEdge[fEdges[fEdgeI]]++;
1852  }
1853  }
1854  }
1855 
1857  (
1858  mesh_,
1859  patch.meshEdges(mesh_.edges(), mesh_.pointEdges()),
1860  nMasterFacesPerEdge,
1861  plusEqOp<label>(),
1862  label(0)
1863  );
1864 }
1865 
1866 
1867 Foam::label Foam::meshRefinement::markPatchZones
1868 (
1869  const indirectPrimitivePatch& patch,
1870  const labelList& nMasterFacesPerEdge,
1871  labelList& faceToZone
1872 ) const
1873 {
1874  List<patchEdgeFaceRegion> allEdgeInfo(patch.nEdges());
1875  List<patchEdgeFaceRegion> allFaceInfo(patch.size());
1876 
1877 
1878  // Protect all non-manifold edges
1879  {
1880  label nProtected = 0;
1881 
1882  forAll(nMasterFacesPerEdge, edgeI)
1883  {
1884  if (nMasterFacesPerEdge[edgeI] > 2)
1885  {
1886  allEdgeInfo[edgeI] = -2;
1887  nProtected++;
1888  }
1889  }
1890  // Info<< "Protected from visiting "
1891  // << returnReduce(nProtected, sumOp<label>())
1892  // << " non-manifold edges" << nl << endl;
1893  }
1894 
1895 
1896  // Hand out zones
1897 
1898  DynamicList<label> changedEdges;
1900 
1901  const scalar tol = PatchEdgeFaceWave
1902  <
1905  >::propagationTol();
1906 
1907  int dummyTrackData;
1908 
1909  const globalIndex globalFaces(patch.size());
1910 
1911  label facei = 0;
1912 
1913  label currentZoneI = 0;
1914 
1915  while (true)
1916  {
1917  // Pick an unset face
1918  label globalSeed = labelMax;
1919  for (; facei < allFaceInfo.size(); facei++)
1920  {
1921  if (!allFaceInfo[facei].valid(dummyTrackData))
1922  {
1923  globalSeed = globalFaces.toGlobal(facei);
1924  break;
1925  }
1926  }
1927 
1928  reduce(globalSeed, minOp<label>());
1929 
1930  if (globalSeed == labelMax)
1931  {
1932  break;
1933  }
1934 
1935  label proci = globalFaces.whichProcID(globalSeed);
1936  label seedFacei = globalFaces.toLocal(proci, globalSeed);
1937 
1938  // Info<< "Seeding zone " << currentZoneI
1939  // << " from processor " << proci << " face " << seedFacei
1940  // << endl;
1941 
1942  if (proci == Pstream::myProcNo())
1943  {
1944  patchEdgeFaceRegion& faceInfo = allFaceInfo[seedFacei];
1945 
1946 
1947  // Set face
1948  faceInfo = currentZoneI;
1949 
1950  // .. and seed its edges
1951  const labelList& fEdges = patch.faceEdges()[seedFacei];
1952  forAll(fEdges, fEdgeI)
1953  {
1954  label edgeI = fEdges[fEdgeI];
1955 
1956  patchEdgeFaceRegion& edgeInfo = allEdgeInfo[edgeI];
1957 
1958  if
1959  (
1960  edgeInfo.updateEdge<int>
1961  (
1962  mesh_,
1963  patch,
1964  edgeI,
1965  seedFacei,
1966  faceInfo,
1967  tol,
1968  dummyTrackData
1969  )
1970  )
1971  {
1972  changedEdges.append(edgeI);
1973  changedInfo.append(edgeInfo);
1974  }
1975  }
1976  }
1977 
1978 
1979  if (returnReduce(changedEdges.size(), sumOp<label>()) == 0)
1980  {
1981  break;
1982  }
1983 
1984 
1985  // Walk
1987  <
1990  > calc
1991  (
1992  mesh_,
1993  patch,
1994  changedEdges,
1995  changedInfo,
1996  allEdgeInfo,
1997  allFaceInfo,
1998  returnReduce(patch.nEdges(), sumOp<label>())
1999  );
2000 
2001  currentZoneI++;
2002  }
2003 
2004 
2005  faceToZone.setSize(patch.size());
2006  forAll(allFaceInfo, facei)
2007  {
2008  if (!allFaceInfo[facei].valid(dummyTrackData))
2009  {
2011  << "Problem: unvisited face " << facei
2012  << " at " << patch.faceCentres()[facei]
2013  << exit(FatalError);
2014  }
2015  faceToZone[facei] = allFaceInfo[facei].region();
2016  }
2017 
2018  return currentZoneI;
2019 }
2020 
2021 
2022 void Foam::meshRefinement::consistentOrientation
2023 (
2024  const PackedBoolList& isMasterFace,
2025  const indirectPrimitivePatch& patch,
2026  const labelList& nMasterFacesPerEdge,
2027  const labelList& faceToZone,
2028  const Map<label>& zoneToOrientation,
2029  boolList& meshFlipMap
2030 ) const
2031 {
2032  const polyBoundaryMesh& bm = mesh_.boundaryMesh();
2033 
2034  // Data on all edges and faces
2035  List<patchFaceOrientation> allEdgeInfo(patch.nEdges());
2036  List<patchFaceOrientation> allFaceInfo(patch.size());
2037 
2038  // Make sure we don't walk through
2039  // - slaves of coupled faces
2040  // - non-manifold edges
2041  {
2042  label nProtected = 0;
2043 
2044  forAll(patch.addressing(), facei)
2045  {
2046  const label meshFacei = patch.addressing()[facei];
2047  const label patchi = bm.whichPatch(meshFacei);
2048 
2049  if
2050  (
2051  patchi != -1
2052  && bm[patchi].coupled()
2053  && !isMasterFace[meshFacei]
2054  )
2055  {
2056  // Slave side. Mark so doesn't get visited.
2057  allFaceInfo[facei] = orientedSurface::NOFLIP;
2058  nProtected++;
2059  }
2060  }
2061  // Info<< "Protected from visiting "
2062  // << returnReduce(nProtected, sumOp<label>())
2063  // << " slaves of coupled faces" << nl << endl;
2064  }
2065  {
2066  label nProtected = 0;
2067 
2068  forAll(nMasterFacesPerEdge, edgeI)
2069  {
2070  if (nMasterFacesPerEdge[edgeI] > 2)
2071  {
2072  allEdgeInfo[edgeI] = orientedSurface::NOFLIP;
2073  nProtected++;
2074  }
2075  }
2076 
2077  Info<< "Protected from visiting "
2078  << returnReduce(nProtected, sumOp<label>())
2079  << " non-manifold edges" << nl << endl;
2080  }
2081 
2082 
2083 
2084  DynamicList<label> changedEdges;
2086 
2087  const scalar tol = PatchEdgeFaceWave
2088  <
2091  >::propagationTol();
2092 
2093  int dummyTrackData;
2094 
2095  globalIndex globalFaces(patch.size());
2096 
2097  while (true)
2098  {
2099  // Pick an unset face
2100  label globalSeed = labelMax;
2101  forAll(allFaceInfo, facei)
2102  {
2103  if (allFaceInfo[facei] == orientedSurface::UNVISITED)
2104  {
2105  globalSeed = globalFaces.toGlobal(facei);
2106  break;
2107  }
2108  }
2109 
2110  reduce(globalSeed, minOp<label>());
2111 
2112  if (globalSeed == labelMax)
2113  {
2114  break;
2115  }
2116 
2117  label proci = globalFaces.whichProcID(globalSeed);
2118  label seedFacei = globalFaces.toLocal(proci, globalSeed);
2119 
2120  // Info<< "Seeding from processor " << proci << " face " << seedFacei
2121  // << endl;
2122 
2123  if (proci == Pstream::myProcNo())
2124  {
2125  // Determine orientation of seedFace
2126 
2127  patchFaceOrientation& faceInfo = allFaceInfo[seedFacei];
2128 
2129  // Start off with correct orientation
2130  faceInfo = orientedSurface::NOFLIP;
2131 
2132  if (zoneToOrientation[faceToZone[seedFacei]] < 0)
2133  {
2134  faceInfo.flip();
2135  }
2136 
2137 
2138  const labelList& fEdges = patch.faceEdges()[seedFacei];
2139  forAll(fEdges, fEdgeI)
2140  {
2141  label edgeI = fEdges[fEdgeI];
2142 
2143  patchFaceOrientation& edgeInfo = allEdgeInfo[edgeI];
2144 
2145  if
2146  (
2147  edgeInfo.updateEdge<int>
2148  (
2149  mesh_,
2150  patch,
2151  edgeI,
2152  seedFacei,
2153  faceInfo,
2154  tol,
2155  dummyTrackData
2156  )
2157  )
2158  {
2159  changedEdges.append(edgeI);
2160  changedInfo.append(edgeInfo);
2161  }
2162  }
2163  }
2164 
2165 
2166  if (returnReduce(changedEdges.size(), sumOp<label>()) == 0)
2167  {
2168  break;
2169  }
2170 
2171 
2172 
2173  // Walk
2175  <
2178  > calc
2179  (
2180  mesh_,
2181  patch,
2182  changedEdges,
2183  changedInfo,
2184  allEdgeInfo,
2185  allFaceInfo,
2186  returnReduce(patch.nEdges(), sumOp<label>())
2187  );
2188  }
2189 
2190 
2191  // Push master zone info over to slave (since slave faces never visited)
2192  {
2193  labelList neiStatus
2194  (
2195  mesh_.nFaces()-mesh_.nInternalFaces(),
2197  );
2198 
2199  forAll(patch.addressing(), i)
2200  {
2201  const label meshFacei = patch.addressing()[i];
2202  if (!mesh_.isInternalFace(meshFacei))
2203  {
2204  neiStatus[meshFacei-mesh_.nInternalFaces()] =
2205  allFaceInfo[i].flipStatus();
2206  }
2207  }
2208  syncTools::swapBoundaryFaceList(mesh_, neiStatus);
2209 
2210  forAll(patch.addressing(), i)
2211  {
2212  const label meshFacei = patch.addressing()[i];
2213  const label patchi = bm.whichPatch(meshFacei);
2214 
2215  if
2216  (
2217  patchi != -1
2218  && bm[patchi].coupled()
2219  && !isMasterFace[meshFacei]
2220  )
2221  {
2222  // Slave side. Take flipped from neighbour
2223  label bFacei = meshFacei-mesh_.nInternalFaces();
2224 
2225  if (neiStatus[bFacei] == orientedSurface::NOFLIP)
2226  {
2227  allFaceInfo[i] = orientedSurface::FLIP;
2228  }
2229  else if (neiStatus[bFacei] == orientedSurface::FLIP)
2230  {
2231  allFaceInfo[i] = orientedSurface::NOFLIP;
2232  }
2233  else
2234  {
2236  << "Incorrect status for face " << meshFacei
2237  << abort(FatalError);
2238  }
2239  }
2240  }
2241  }
2242 
2243 
2244  // Convert to meshFlipMap and adapt faceZones
2245 
2246  meshFlipMap.setSize(mesh_.nFaces());
2247  meshFlipMap = false;
2248 
2249  forAll(allFaceInfo, facei)
2250  {
2251  label meshFacei = patch.addressing()[facei];
2252 
2253  if (allFaceInfo[facei] == orientedSurface::NOFLIP)
2254  {
2255  meshFlipMap[meshFacei] = false;
2256  }
2257  else if (allFaceInfo[facei] == orientedSurface::FLIP)
2258  {
2259  meshFlipMap[meshFacei] = true;
2260  }
2261  else
2262  {
2264  << "Problem : unvisited face " << facei
2265  << " centre:" << mesh_.faceCentres()[meshFacei]
2266  << abort(FatalError);
2267  }
2268  }
2269 }
2270 
2271 
2272 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2273 
2276  const bool doHandleSnapProblems,
2277  const snapParameters& snapParams,
2278  const bool useTopologicalSnapDetection,
2279  const bool removeEdgeConnectedCells,
2280  const scalarField& perpendicularAngle,
2281  const bool mergeFreeStanding,
2282  const scalar planarAngle,
2283  const dictionary& motionDict,
2284  Time& runTime,
2285  const labelList& globalToMasterPatch,
2286  const labelList& globalToSlavePatch,
2287  const point& keepPoint
2288 )
2289 {
2290  // Introduce baffles
2291  // ~~~~~~~~~~~~~~~~~
2292 
2293  // Split the mesh along internal faces wherever there is a pierce between
2294  // two cell centres.
2295 
2296  Info<< "Introducing baffles for "
2298  << " faces that are intersected by the surface." << nl << endl;
2299 
2300  // Swap neighbouring cell centres and cell level
2301  labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2302  pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2303  calcNeighbourData(neiLevel, neiCc);
2304 
2305  labelList ownPatch, neiPatch;
2306  getBafflePatches
2307  (
2308  globalToMasterPatch,
2309  neiLevel,
2310  neiCc,
2311 
2312  ownPatch,
2313  neiPatch
2314  );
2315 
2316  createBaffles(ownPatch, neiPatch);
2317 
2318  if (debug)
2319  {
2320  // Debug:test all is still synced across proc patches
2321  checkData();
2322  }
2323 
2324  Info<< "Created baffles in = "
2325  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
2326 
2327  printMeshInfo(debug, "After introducing baffles");
2328 
2329  if (debug&MESH)
2330  {
2331  Pout<< "Writing baffled mesh to time " << timeName()
2332  << endl;
2333  write
2334  (
2335  debugType(debug),
2337  runTime.path()/"baffles"
2338  );
2339  Pout<< "Dumped debug data in = "
2340  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
2341  }
2342 
2343 
2344  // Introduce baffles to delete problem cells
2345  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2346 
2347  // Create some additional baffles where we want surface cells removed.
2348 
2349  if (doHandleSnapProblems)
2350  {
2351  handleSnapProblems
2352  (
2353  snapParams,
2354  useTopologicalSnapDetection,
2355  removeEdgeConnectedCells,
2356  perpendicularAngle,
2357  motionDict,
2358  runTime,
2359  globalToMasterPatch,
2360  globalToSlavePatch
2361  );
2362  }
2363 
2364 
2365  // Select part of mesh
2366  // ~~~~~~~~~~~~~~~~~~~
2367 
2368  Info<< nl
2369  << "Remove unreachable sections of mesh" << nl
2370  << "-----------------------------------" << nl
2371  << endl;
2372 
2373  if (debug)
2374  {
2375  runTime++;
2376  }
2377 
2378  splitMeshRegions(globalToMasterPatch, globalToSlavePatch, keepPoint);
2379 
2380  if (debug)
2381  {
2382  // Debug:test all is still synced across proc patches
2383  checkData();
2384  }
2385  Info<< "Split mesh in = "
2386  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
2387 
2388  printMeshInfo(debug, "After subsetting");
2389 
2390  if (debug&MESH)
2391  {
2392  Pout<< "Writing subsetted mesh to time " << timeName()
2393  << endl;
2394  write
2395  (
2396  debugType(debug),
2398  runTime.path()/timeName()
2399  );
2400  Pout<< "Dumped debug data in = "
2401  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
2402  }
2403 
2404 
2405  // Merge baffles
2406  // ~~~~~~~~~~~~~
2407 
2408  if (mergeFreeStanding)
2409  {
2410  Info<< nl
2411  << "Merge free-standing baffles" << nl
2412  << "---------------------------" << nl
2413  << endl;
2414 
2415 
2416  // List of pairs of freestanding baffle faces.
2417  List<labelPair> couples
2418  (
2419  freeStandingBaffles // filter out freestanding baffles
2420  (
2422  planarAngle
2423  )
2424  );
2425 
2426  label nCouples = couples.size();
2427  reduce(nCouples, sumOp<label>());
2428 
2429  Info<< "Detected free-standing baffles : " << nCouples << endl;
2430 
2431  if (nCouples > 0)
2432  {
2433  // Actually merge baffles. Note: not exactly parallellized. Should
2434  // convert baffle faces into processor faces if they resulted
2435  // from them.
2436  mergeBaffles(couples);
2437 
2438  // Detect any problem cells resulting from merging of baffles
2439  // and delete them
2440  handleSnapProblems
2441  (
2442  snapParams,
2443  useTopologicalSnapDetection,
2444  removeEdgeConnectedCells,
2445  perpendicularAngle,
2446  motionDict,
2447  runTime,
2448  globalToMasterPatch,
2449  globalToSlavePatch
2450  );
2451 
2452  if (debug)
2453  {
2454  // Debug:test all is still synced across proc patches
2455  checkData();
2456  }
2457  }
2458  Info<< "Merged free-standing baffles in = "
2459  << runTime.cpuTimeIncrement() << " s\n" << nl << endl;
2460  }
2461 }
2462 
2463 
2466  const label nBufferLayers,
2467  const labelList& globalToMasterPatch,
2468  const labelList& globalToSlavePatch,
2469  const point& keepPoint
2470 )
2471 {
2472  // Determine patches to put intersections into
2473  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2474 
2475  // Swap neighbouring cell centres and cell level
2476  labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2477  pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2478  calcNeighbourData(neiLevel, neiCc);
2479 
2480  labelList ownPatch, neiPatch;
2481  getBafflePatches
2482  (
2483  globalToMasterPatch,
2484  neiLevel,
2485  neiCc,
2486 
2487  ownPatch,
2488  neiPatch
2489  );
2490 
2491  // Analyse regions. Reuse regionsplit
2492  boolList blockedFace(mesh_.nFaces(), false);
2493 
2494  forAll(ownPatch, facei)
2495  {
2496  if (ownPatch[facei] != -1 || neiPatch[facei] != -1)
2497  {
2498  blockedFace[facei] = true;
2499  }
2500  }
2501  syncTools::syncFaceList(mesh_, blockedFace, orEqOp<bool>());
2502 
2503  // Set region per cell based on walking
2504  regionSplit cellRegion(mesh_, blockedFace);
2505  blockedFace.clear();
2506 
2507  // Find the region containing the keepPoint
2508  const label keepRegionI = findRegion
2509  (
2510  mesh_,
2511  cellRegion,
2512  mergeDistance_*vector(1,1,1),
2513  keepPoint
2514  );
2515 
2516  Info<< "Found point " << keepPoint
2517  << " in global region " << keepRegionI
2518  << " out of " << cellRegion.nRegions() << " regions." << endl;
2519 
2520  if (keepRegionI == -1)
2521  {
2523  << "Point " << keepPoint
2524  << " is not inside the mesh." << nl
2525  << "Bounding box of the mesh:" << mesh_.bounds()
2526  << exit(FatalError);
2527  }
2528 
2529 
2530  // Walk out nBufferlayers from region split
2531  // (modifies cellRegion, ownPatch)
2532  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2533  // Takes over face patch onto points and then back to faces and cells
2534  // (so cell-face-point walk)
2535 
2536  const labelList& faceOwner = mesh_.faceOwner();
2537  const labelList& faceNeighbour = mesh_.faceNeighbour();
2538 
2539  // Patch for exposed faces for lack of anything sensible.
2540  label defaultPatch = 0;
2541  if (globalToMasterPatch.size())
2542  {
2543  defaultPatch = globalToMasterPatch[0];
2544  }
2545 
2546  for (label i = 0; i < nBufferLayers; i++)
2547  {
2548  // 1. From cells (via faces) to points
2549 
2550  labelList pointBaffle(mesh_.nPoints(), -1);
2551 
2552  forAll(faceNeighbour, facei)
2553  {
2554  const face& f = mesh_.faces()[facei];
2555 
2556  label ownRegion = cellRegion[faceOwner[facei]];
2557  label neiRegion = cellRegion[faceNeighbour[facei]];
2558 
2559  if (ownRegion == keepRegionI && neiRegion != keepRegionI)
2560  {
2561  // Note max(..) since possibly regionSplit might have split
2562  // off extra unreachable parts of mesh. Note: or can this only
2563  // happen for boundary faces?
2564  forAll(f, fp)
2565  {
2566  pointBaffle[f[fp]] = max(defaultPatch, ownPatch[facei]);
2567  }
2568  }
2569  else if (ownRegion != keepRegionI && neiRegion == keepRegionI)
2570  {
2571  label newPatchi = neiPatch[facei];
2572  if (newPatchi == -1)
2573  {
2574  newPatchi = max(defaultPatch, ownPatch[facei]);
2575  }
2576  forAll(f, fp)
2577  {
2578  pointBaffle[f[fp]] = newPatchi;
2579  }
2580  }
2581  }
2582  for
2583  (
2584  label facei = mesh_.nInternalFaces();
2585  facei < mesh_.nFaces();
2586  facei++
2587  )
2588  {
2589  const face& f = mesh_.faces()[facei];
2590 
2591  label ownRegion = cellRegion[faceOwner[facei]];
2592 
2593  if (ownRegion == keepRegionI)
2594  {
2595  forAll(f, fp)
2596  {
2597  pointBaffle[f[fp]] = max(defaultPatch, ownPatch[facei]);
2598  }
2599  }
2600  }
2601 
2602  // Sync
2604  (
2605  mesh_,
2606  pointBaffle,
2607  maxEqOp<label>(),
2608  label(-1) // null value
2609  );
2610 
2611 
2612  // 2. From points back to faces
2613 
2614  const labelListList& pointFaces = mesh_.pointFaces();
2615 
2616  forAll(pointFaces, pointi)
2617  {
2618  if (pointBaffle[pointi] != -1)
2619  {
2620  const labelList& pFaces = pointFaces[pointi];
2621 
2622  forAll(pFaces, pFacei)
2623  {
2624  label facei = pFaces[pFacei];
2625 
2626  if (ownPatch[facei] == -1)
2627  {
2628  ownPatch[facei] = pointBaffle[pointi];
2629  }
2630  }
2631  }
2632  }
2633  syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
2634 
2635 
2636  // 3. From faces to cells (cellRegion) and back to faces (ownPatch)
2637 
2638  labelList newOwnPatch(ownPatch);
2639 
2640  forAll(ownPatch, facei)
2641  {
2642  if (ownPatch[facei] != -1)
2643  {
2644  label own = faceOwner[facei];
2645 
2646  if (cellRegion[own] != keepRegionI)
2647  {
2648  cellRegion[own] = keepRegionI;
2649 
2650  const cell& ownFaces = mesh_.cells()[own];
2651  forAll(ownFaces, j)
2652  {
2653  if (ownPatch[ownFaces[j]] == -1)
2654  {
2655  newOwnPatch[ownFaces[j]] = ownPatch[facei];
2656  }
2657  }
2658  }
2659  if (mesh_.isInternalFace(facei))
2660  {
2661  label nei = faceNeighbour[facei];
2662 
2663  if (cellRegion[nei] != keepRegionI)
2664  {
2665  cellRegion[nei] = keepRegionI;
2666 
2667  const cell& neiFaces = mesh_.cells()[nei];
2668  forAll(neiFaces, j)
2669  {
2670  if (ownPatch[neiFaces[j]] == -1)
2671  {
2672  newOwnPatch[neiFaces[j]] = ownPatch[facei];
2673  }
2674  }
2675  }
2676  }
2677  }
2678  }
2679 
2680  ownPatch.transfer(newOwnPatch);
2681 
2682  syncTools::syncFaceList(mesh_, ownPatch, maxEqOp<label>());
2683  }
2684 
2685 
2686 
2687  // Subset
2688  // ~~~~~~
2689 
2690  // Get cells to remove
2691  DynamicList<label> cellsToRemove(mesh_.nCells());
2692  forAll(cellRegion, celli)
2693  {
2694  if (cellRegion[celli] != keepRegionI)
2695  {
2696  cellsToRemove.append(celli);
2697  }
2698  }
2699  cellsToRemove.shrink();
2700 
2701  label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
2702  reduce(nCellsToKeep, sumOp<label>());
2703 
2704  Info<< "Keeping all cells in region " << keepRegionI
2705  << " containing point " << keepPoint << endl
2706  << "Selected for keeping : " << nCellsToKeep
2707  << " cells." << endl;
2708 
2709 
2710  // Remove cells
2711  removeCells cellRemover(mesh_);
2712 
2713  // Pick up patches for exposed faces
2714  labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
2715  labelList exposedPatches(exposedFaces.size());
2716 
2717  forAll(exposedFaces, i)
2718  {
2719  label facei = exposedFaces[i];
2720 
2721  if (ownPatch[facei] != -1)
2722  {
2723  exposedPatches[i] = ownPatch[facei];
2724  }
2725  else
2726  {
2728  << "For exposed face " << facei
2729  << " fc:" << mesh_.faceCentres()[facei]
2730  << " found no patch." << endl
2731  << " Taking patch " << defaultPatch
2732  << " instead." << endl;
2733  exposedPatches[i] = defaultPatch;
2734  }
2735  }
2736 
2737  return doRemoveCells
2738  (
2739  cellsToRemove,
2740  exposedFaces,
2741  exposedPatches,
2742  cellRemover
2743  );
2744 }
2745 
2746 
2749  const localPointRegion& regionSide
2750 )
2751 {
2752  // Topochange container
2753  polyTopoChange meshMod(mesh_);
2754 
2755  label nNonManifPoints = returnReduce
2756  (
2757  regionSide.meshPointMap().size(),
2758  sumOp<label>()
2759  );
2760 
2761  Info<< "dupNonManifoldPoints : Found : " << nNonManifPoints
2762  << " non-manifold points (out of "
2763  << mesh_.globalData().nTotalPoints()
2764  << ')' << endl;
2765 
2766  // Topo change engine
2767  duplicatePoints pointDuplicator(mesh_);
2768 
2769  // Insert changes into meshMod
2770  pointDuplicator.setRefinement(regionSide, meshMod);
2771 
2772  mesh_.clearOut();
2773 
2774  // Change the mesh (no inflation, parallel sync)
2775  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
2776 
2777  // Update fields
2778  mesh_.updateMesh(map);
2779 
2780  // Move mesh if in inflation mode
2781  if (map().hasMotionPoints())
2782  {
2783  mesh_.movePoints(map().preMotionPoints());
2784  }
2785  else
2786  {
2787  // Delete mesh volumes.
2788  mesh_.clearOut();
2789  }
2790 
2791  // Reset the instance for if in overwrite mode
2792  mesh_.setInstance(timeName());
2793 
2794  // Update intersections. Is mapping only (no faces created, positions stay
2795  // same) so no need to recalculate intersections.
2796  updateMesh(map, labelList(0));
2797 
2798  return map;
2799 }
2800 
2801 
2803 {
2804  // Analyse which points need to be duplicated
2805  localPointRegion regionSide(mesh_);
2806 
2807  return dupNonManifoldPoints(regionSide);
2808 }
2809 
2810 
2813  const point& keepPoint,
2814  const bool allowFreeStandingZoneFaces
2815 )
2816 {
2817  const PtrList<surfaceZonesInfo>& surfZones = surfaces_.surfZones();
2818 
2819  labelList namedSurfaces(surfaceZonesInfo::getNamedSurfaces(surfZones));
2820 
2821  forAll(namedSurfaces, i)
2822  {
2823  label surfI = namedSurfaces[i];
2824 
2825  Info<< "Surface : " << surfaces_.names()[surfI] << nl
2826  << " faceZone : " << surfZones[surfI].faceZoneName() << nl
2827  << " cellZone : " << surfZones[surfI].cellZoneName() << endl;
2828  }
2829 
2830 
2831  // Add zones to mesh
2832  labelList surfaceToFaceZone =
2834  (
2835  surfZones,
2836  namedSurfaces,
2837  mesh_
2838  );
2839 
2840  labelList surfaceToCellZone =
2842  (
2843  surfZones,
2844  namedSurfaces,
2845  mesh_
2846  );
2847 
2848 
2849  const pointField& cellCentres = mesh_.cellCentres();
2850  const labelList& faceOwner = mesh_.faceOwner();
2851  const labelList& faceNeighbour = mesh_.faceNeighbour();
2852  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2853 
2854 
2855  // Swap neighbouring cell centres and cell level
2856  labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2857  pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2858  calcNeighbourData(neiLevel, neiCc);
2859 
2860 
2861  // Mark faces intersecting zoned surfaces
2862  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2863 
2864 
2865  // Like surfaceIndex_ but only for named surfaces.
2866  labelList namedSurfaceIndex(mesh_.nFaces(), -1);
2867  PackedBoolList posOrientation(mesh_.nFaces());
2868 
2869  {
2870  // Statistics: number of faces per faceZone
2871  labelList nSurfFaces(surfZones.size(), 0);
2872 
2873  // Note: for all internal faces? internal + coupled?
2874  // Since zonify is run after baffling the surfaceIndex_ on baffles is
2875  // not synchronised across both baffle faces. Fortunately we don't
2876  // do zonify baffle faces anyway (they are normal boundary faces).
2877 
2878  // Collect candidate faces
2879  // ~~~~~~~~~~~~~~~~~~~~~~~
2880 
2881  labelList testFaces(intersectedFaces());
2882 
2883  // Collect segments
2884  // ~~~~~~~~~~~~~~~~
2885 
2886  pointField start(testFaces.size());
2887  pointField end(testFaces.size());
2888 
2889  forAll(testFaces, i)
2890  {
2891  label facei = testFaces[i];
2892 
2893  if (mesh_.isInternalFace(facei))
2894  {
2895  start[i] = cellCentres[faceOwner[facei]];
2896  end[i] = cellCentres[faceNeighbour[facei]];
2897  }
2898  else
2899  {
2900  start[i] = cellCentres[faceOwner[facei]];
2901  end[i] = neiCc[facei-mesh_.nInternalFaces()];
2902  }
2903  }
2904 
2905  // Extend segments a bit
2906  {
2907  const vectorField smallVec(rootSmall*(end-start));
2908  start -= smallVec;
2909  end += smallVec;
2910  }
2911 
2912 
2913  // Do test for intersections
2914  // ~~~~~~~~~~~~~~~~~~~~~~~~~
2915  // Note that we intersect all intersected faces again. Could reuse
2916  // the information already in surfaceIndex_.
2917 
2918  labelList surface1;
2919  List<pointIndexHit> hit1;
2920  vectorField normal1;
2921  labelList surface2;
2922  List<pointIndexHit> hit2;
2923  vectorField normal2;
2924  {
2925  labelList region1;
2926  labelList region2;
2927  surfaces_.findNearestIntersection
2928  (
2929  namedSurfaces,
2930  start,
2931  end,
2932 
2933  surface1,
2934  hit1,
2935  region1,
2936  normal1,
2937 
2938  surface2,
2939  hit2,
2940  region2,
2941  normal2
2942  );
2943  }
2944 
2945  forAll(testFaces, i)
2946  {
2947  label facei = testFaces[i];
2948  const vector& area = mesh_.faceAreas()[facei];
2949 
2950  if (surface1[i] != -1)
2951  {
2952  // If both hit should probably choose 'nearest'
2953  if
2954  (
2955  surface2[i] != -1
2956  && (
2957  magSqr(hit2[i].hitPoint())
2958  < magSqr(hit1[i].hitPoint())
2959  )
2960  )
2961  {
2962  namedSurfaceIndex[facei] = surface2[i];
2963  posOrientation[facei] = ((area&normal2[i]) > 0);
2964  nSurfFaces[surface2[i]]++;
2965  }
2966  else
2967  {
2968  namedSurfaceIndex[facei] = surface1[i];
2969  posOrientation[facei] = ((area&normal1[i]) > 0);
2970  nSurfFaces[surface1[i]]++;
2971  }
2972  }
2973  else if (surface2[i] != -1)
2974  {
2975  namedSurfaceIndex[facei] = surface2[i];
2976  posOrientation[facei] = ((area&normal2[i]) > 0);
2977  nSurfFaces[surface2[i]]++;
2978  }
2979  }
2980 
2981 
2982  // surfaceIndex might have different surfaces on both sides if
2983  // there happen to be a (obviously thin) surface with different
2984  // regions between the cell centres. If one is on a named surface
2985  // and the other is not this might give problems so sync.
2987  (
2988  mesh_,
2989  namedSurfaceIndex,
2990  maxEqOp<label>()
2991  );
2992 
2993  // Print a bit
2994  if (debug)
2995  {
2996  forAll(nSurfFaces, surfI)
2997  {
2998  Pout<< "Surface:"
2999  << surfaces_.names()[surfI]
3000  << " nZoneFaces:" << nSurfFaces[surfI] << nl;
3001  }
3002  Pout<< endl;
3003  }
3004  }
3005 
3006 
3007  // Put the cells into the correct zone
3008  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3009 
3010  // Zone per cell:
3011  // -2 : unset
3012  // -1 : not in any zone
3013  // >=0: zoneID
3014  labelList cellToZone(mesh_.nCells(), -2);
3015 
3016 
3017  // Set using geometric test
3018  // ~~~~~~~~~~~~~~~~~~~~~~~~
3019 
3020  // Closed surfaces with cellZone specified.
3021  labelList closedNamedSurfaces
3022  (
3024  (
3025  surfZones,
3026  surfaces_.geometry(),
3027  surfaces_.surfaces()
3028  )
3029  );
3030 
3031  if (closedNamedSurfaces.size())
3032  {
3033  Info<< "Found " << closedNamedSurfaces.size()
3034  << " closed, named surfaces. Assigning cells in/outside"
3035  << " these surfaces to the corresponding cellZone."
3036  << nl << endl;
3037 
3038  findCellZoneGeometric
3039  (
3040  neiCc,
3041  closedNamedSurfaces, // indices of closed surfaces
3042  namedSurfaceIndex, // per face index of named surface
3043  surfaceToCellZone, // cell zone index per surface
3044 
3045  cellToZone
3046  );
3047  }
3048 
3049 
3050  // Set using provided locations
3051  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3052 
3053  labelList locationSurfaces
3054  (
3056  );
3057 
3058  if (locationSurfaces.size())
3059  {
3060  Info<< "Found " << locationSurfaces.size()
3061  << " named surfaces with a provided inside point."
3062  << " Assigning cells inside these surfaces"
3063  << " to the corresponding cellZone."
3064  << nl << endl;
3065 
3066  findCellZoneInsideWalk
3067  (
3068  locationSurfaces, // indices of closed surfaces
3069  namedSurfaceIndex, // per face index of named surface
3070  surfaceToCellZone, // cell zone index per surface
3071 
3072  cellToZone
3073  );
3074  }
3075 
3076 
3077  // Set using walking
3078  // ~~~~~~~~~~~~~~~~~
3079 
3080  {
3081  Info<< "Walking from location-in-mesh " << keepPoint
3082  << " to assign cellZones "
3083  << "- crossing a faceZone face changes cellZone" << nl << endl;
3084 
3085  // Topological walk
3086  findCellZoneTopo
3087  (
3088  keepPoint,
3089  namedSurfaceIndex,
3090  surfaceToCellZone,
3091 
3092  cellToZone
3093  );
3094  }
3095 
3096 
3097  // Make sure namedSurfaceIndex is unset in between same cell cell zones.
3098  if (!allowFreeStandingZoneFaces)
3099  {
3100  Info<< "Only keeping zone faces in between different cellZones."
3101  << nl << endl;
3102 
3103  makeConsistentFaceIndex(cellToZone, namedSurfaceIndex);
3104  }
3105 
3106 
3107  //- Per face index of faceZone or -1
3108  labelList faceToZone(mesh_.nFaces(), -1);
3109 
3110  // Convert namedSurfaceIndex (index of named surfaces) to
3111  // actual faceZone index
3112 
3113  forAll(namedSurfaceIndex, facei)
3114  {
3115  label surfI = namedSurfaceIndex[facei];
3116  if (surfI != -1)
3117  {
3118  faceToZone[facei] = surfaceToFaceZone[surfI];
3119  }
3120  }
3121 
3122 
3123  // Topochange container
3124  polyTopoChange meshMod(mesh_);
3125 
3126 
3127 
3128  // Get coupled neighbour cellZone. Set to -1 on non-coupled patches.
3129  labelList neiCellZone;
3130  syncTools::swapBoundaryCellList(mesh_, cellToZone, neiCellZone);
3131  forAll(patches, patchi)
3132  {
3133  const polyPatch& pp = patches[patchi];
3134 
3135  if (!pp.coupled())
3136  {
3137  label bFacei = pp.start()-mesh_.nInternalFaces();
3138  forAll(pp, i)
3139  {
3140  neiCellZone[bFacei++] = -1;
3141  }
3142  }
3143  }
3144 
3145 
3146 
3147  // Get per face whether is it master (of a coupled set of faces)
3148  const PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
3149 
3150 
3151 
3152  // faceZones
3153  // ~~~~~~~~~
3154  // Faces on faceZones come in two variants:
3155  // - faces on the outside of a cellZone. They will be oriented to
3156  // point out of the maximum cellZone.
3157  // - free-standing faces. These will be oriented according to the
3158  // local surface normal. We do this in a two step algorithm:
3159  // - do a consistent orientation
3160  // - check number of faces with consistent orientation
3161  // - if <0 flip the whole patch
3162  boolList meshFlipMap(mesh_.nFaces(), false);
3163  {
3164  // Collect all data on zone faces without cellZones on either side.
3165  const indirectPrimitivePatch patch
3166  (
3168  (
3169  mesh_.faces(),
3170  freeStandingBaffleFaces
3171  (
3172  faceToZone,
3173  cellToZone,
3174  neiCellZone
3175  )
3176  ),
3177  mesh_.points()
3178  );
3179 
3180  label nFreeStanding = returnReduce(patch.size(), sumOp<label>());
3181  if (nFreeStanding > 0)
3182  {
3183  Info<< "Detected " << nFreeStanding << " free-standing zone faces"
3184  << endl;
3185 
3186  if (debug)
3187  {
3188  OBJstream str(mesh_.time().path()/"freeStanding.obj");
3189  str.write(patch.localFaces(), patch.localPoints(), false);
3190  }
3191 
3192 
3193  // Detect non-manifold edges
3194  labelList nMasterFacesPerEdge;
3195  calcPatchNumMasterFaces(isMasterFace, patch, nMasterFacesPerEdge);
3196 
3197  // Mark zones. Even a single original surface might create multiple
3198  // disconnected/non-manifold-connected zones
3199  labelList faceToConnectedZone;
3200  const label nZones = markPatchZones
3201  (
3202  patch,
3203  nMasterFacesPerEdge,
3204  faceToConnectedZone
3205  );
3206 
3207  Map<label> nPosOrientation(2*nZones);
3208  for (label zoneI = 0; zoneI < nZones; zoneI++)
3209  {
3210  nPosOrientation.insert(zoneI, 0);
3211  }
3212 
3213  // Make orientations consistent in a topological way. This just
3214  // checks the first face per zone for whether nPosOrientation
3215  // is negative (which it never is at this point)
3216  consistentOrientation
3217  (
3218  isMasterFace,
3219  patch,
3220  nMasterFacesPerEdge,
3221  faceToConnectedZone,
3222  nPosOrientation,
3223 
3224  meshFlipMap
3225  );
3226 
3227  // Count per region the number of orientations (taking the new
3228  // flipMap into account)
3229  forAll(patch.addressing(), facei)
3230  {
3231  label meshFacei = patch.addressing()[facei];
3232 
3233  if (isMasterFace[meshFacei])
3234  {
3235  label n = 1;
3236  if
3237  (
3238  bool(posOrientation[meshFacei])
3239  == meshFlipMap[meshFacei]
3240  )
3241  {
3242  n = -1;
3243  }
3244 
3245  nPosOrientation.find(faceToConnectedZone[facei])() += n;
3246  }
3247  }
3248  Pstream::mapCombineGather(nPosOrientation, plusEqOp<label>());
3249  Pstream::mapCombineScatter(nPosOrientation);
3250 
3251 
3252  Info<< "Split " << nFreeStanding << " free-standing zone faces"
3253  << " into " << nZones << " disconnected regions with size"
3254  << " (negative denotes wrong orientation) :"
3255  << endl;
3256 
3257  for (label zoneI = 0; zoneI < nZones; zoneI++)
3258  {
3259  Info<< " " << zoneI << "\t" << nPosOrientation[zoneI]
3260  << endl;
3261  }
3262  Info<< endl;
3263 
3264 
3265  // Reapply with new counts (in nPosOrientation). This will cause
3266  // zones with a negative count to be flipped.
3267  consistentOrientation
3268  (
3269  isMasterFace,
3270  patch,
3271  nMasterFacesPerEdge,
3272  faceToConnectedZone,
3273  nPosOrientation,
3274 
3275  meshFlipMap
3276  );
3277  }
3278  }
3279 
3280 
3281  // Put the faces into the correct zone
3282  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3283 
3284  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
3285  {
3286  label faceZoneI = faceToZone[facei];
3287 
3288  if (faceZoneI != -1)
3289  {
3290  // Orient face zone to have slave cells in max cell zone.
3291  // Note: logic to use flipMap should be consistent with logic
3292  // to pick up the freeStandingBaffleFaces!
3293 
3294  label ownZone = cellToZone[faceOwner[facei]];
3295  label neiZone = cellToZone[faceNeighbour[facei]];
3296 
3297  bool flip;
3298 
3299  if (ownZone == neiZone)
3300  {
3301  // free-standing face. Use geometrically derived orientation
3302  flip = meshFlipMap[facei];
3303  }
3304  else
3305  {
3306  flip =
3307  (
3308  ownZone == -1
3309  || (neiZone != -1 && ownZone > neiZone)
3310  );
3311  }
3312 
3313  meshMod.setAction
3314  (
3316  (
3317  mesh_.faces()[facei], // modified face
3318  facei, // label of face
3319  faceOwner[facei], // owner
3320  faceNeighbour[facei], // neighbour
3321  false, // face flip
3322  -1, // patch for face
3323  false, // remove from zone
3324  faceZoneI, // zone for face
3325  flip // face flip in zone
3326  )
3327  );
3328  }
3329  }
3330 
3331 
3332  // Set owner as no-flip
3333  forAll(patches, patchi)
3334  {
3335  const polyPatch& pp = patches[patchi];
3336 
3337  label facei = pp.start();
3338 
3339  forAll(pp, i)
3340  {
3341  label faceZoneI = faceToZone[facei];
3342 
3343  if (faceZoneI != -1)
3344  {
3345  label ownZone = cellToZone[faceOwner[facei]];
3346  label neiZone = neiCellZone[facei-mesh_.nInternalFaces()];
3347 
3348  bool flip;
3349 
3350  if (ownZone == neiZone)
3351  {
3352  // free-standing face. Use geometrically derived orientation
3353  flip = meshFlipMap[facei];
3354  }
3355  else
3356  {
3357  flip =
3358  (
3359  ownZone == -1
3360  || (neiZone != -1 && ownZone > neiZone)
3361  );
3362  }
3363 
3364  meshMod.setAction
3365  (
3367  (
3368  mesh_.faces()[facei], // modified face
3369  facei, // label of face
3370  faceOwner[facei], // owner
3371  -1, // neighbour
3372  false, // face flip
3373  patchi, // patch for face
3374  false, // remove from zone
3375  faceZoneI, // zone for face
3376  flip // face flip in zone
3377  )
3378  );
3379  }
3380  facei++;
3381  }
3382  }
3383 
3384 
3385  // Put the cells into the correct zone
3386  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3387 
3388  forAll(cellToZone, celli)
3389  {
3390  label zoneI = cellToZone[celli];
3391 
3392  if (zoneI >= 0)
3393  {
3394  meshMod.setAction
3395  (
3397  (
3398  celli,
3399  false, // removeFromZone
3400  zoneI
3401  )
3402  );
3403  }
3404  }
3405 
3406  mesh_.clearOut();
3407 
3408  // Change the mesh (no inflation, parallel sync)
3409  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh_, false, true);
3410 
3411  // Update fields
3412  mesh_.updateMesh(map);
3413 
3414  // Move mesh if in inflation mode
3415  if (map().hasMotionPoints())
3416  {
3417  mesh_.movePoints(map().preMotionPoints());
3418  }
3419  else
3420  {
3421  // Delete mesh volumes.
3422  mesh_.clearOut();
3423  }
3424 
3425  // Reset the instance for if in overwrite mode
3426  mesh_.setInstance(timeName());
3427 
3428  // Print some stats (note: zones are synchronised)
3429  if (mesh_.cellZones().size() > 0)
3430  {
3431  Info<< "CellZones:" << endl;
3432  forAll(mesh_.cellZones(), zoneI)
3433  {
3434  const cellZone& cz = mesh_.cellZones()[zoneI];
3435  Info<< " " << cz.name()
3436  << "\tsize:" << returnReduce(cz.size(), sumOp<label>())
3437  << endl;
3438  }
3439  Info<< endl;
3440  }
3441  if (mesh_.faceZones().size() > 0)
3442  {
3443  Info<< "FaceZones:" << endl;
3444  forAll(mesh_.faceZones(), zoneI)
3445  {
3446  const faceZone& fz = mesh_.faceZones()[zoneI];
3447  Info<< " " << fz.name()
3448  << "\tsize:" << returnReduce(fz.size(), sumOp<label>())
3449  << endl;
3450  }
3451  Info<< endl;
3452  }
3453 
3454  // None of the faces has changed, only the zones. Still...
3455  updateMesh(map, labelList());
3456 
3457  return map;
3458 }
3459 
3460 
3461 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:434
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:119
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:82
Class containing data for face removal.
void clearOut()
Clear all geometry and addressing.
Definition: fvMesh.C:240
void printMeshInfo(const bool, const string &) const
Print some mesh stats.
bool updateEdge(const polyMesh &mesh, const indirectPrimitivePatch &patch, const label edgeI, const label facei, const patchEdgeFaceRegion &faceInfo, const scalar tol, TrackingData &td)
Influence of face on edge.
ZoneMesh< faceZone, polyMesh > faceZoneMesh
A ZoneMesh with the type faceZone.
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
fileName path() const
Return path.
Definition: Time.H:266
void checkZoneFaces() const
Debug helper: check faceZones are not on processor patches.
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
const word & name() const
Return name.
const word & name() const
Return name.
Definition: IOobject.H:295
const labelList & surfaces() const
A list of face labels.
Definition: faceSet.H:48
An STL-conforming const_iterator.
Definition: HashTable.H:481
bool updateEdge(const polyMesh &mesh, const indirectPrimitivePatch &patch, const label edgeI, const label facei, const patchFaceOrientation &faceInfo, const scalar tol, TrackingData &td)
Influence of face on edge.
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:476
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Class describing modification of a face.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:112
label countHits() const
Count number of intersections (local)
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
const labelListList & faceEdges() const
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
const Field< PointType > & faceCentres() const
Return face centres for patch.
label nInternalFaces() const
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1175
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition: polyMesh.C:848
const labelListList & pointEdges() const
label nFaces() const
static label findRegion(const polyMesh &, const labelList &cellRegion, const vector &perturbVec, const point &p)
Find region point is in. Uses optional perturbation to re-test.
Wave propagation of information along patch. Every iteration information goes through one layer of fa...
Unit conversion functions.
label nTotalPoints() const
Return total number of points in decomposed mesh. Not.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
const boolList & flipMap() const
Return face flip map.
Definition: faceZone.H:248
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Given list of cells to remove insert all the topology changes.
Definition: removeCells.H:59
label nCells() const
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
autoPtr< mapPolyMesh > createZoneBaffles(const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, List< labelPair > &)
Create baffles for faces straddling zoned surfaces. Return.
autoPtr< mapPolyMesh > createBaffles(const labelList &ownPatch, const labelList &neiPatch)
Create baffle for every internal face where ownPatch != -1.
labelList intersectedFaces() const
Get faces with intersection.
static writeType writeLevel()
Get/set write level.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Transport of orientation for use in PatchEdgeFaceWave.
static labelList addCellZonesToMesh(const PtrList< surfaceZonesInfo > &surfList, const labelList &namedSurfaces, polyMesh &mesh)
void baffleAndSplitMesh(const bool handleSnapProblems, const snapParameters &snapParams, const bool useTopologicalSnapDetection, const bool removeEdgeConnectedCells, const scalarField &perpendicularAngle, const bool mergeFreeStanding, const scalar freeStandingAngle, const dictionary &motionDict, Time &runTime, const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const point &keepPoint)
Split off unreachable areas of mesh.
const cellList & cells() const
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:306
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
patches[0]
autoPtr< mapPolyMesh > splitMesh(const label nBufferLayers, const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const point &keepPoint)
Split off (with optional buffer layers) unreachable areas.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:239
virtual Ostream & write(const char)
Write character.
Definition: OBJstream.C:82
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
Foam::indirectPrimitivePatch.
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:108
T & first()
Return the first element of the list.
Definition: UListI.H:114
Class describing modification of a cell.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
const Map< label > & meshPointMap() const
Per point that is to be duplicated the local index.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
static PackedBoolList getMasterFaces(const polyMesh &)
Get per face whether it is uncoupled or a master of a.
Definition: syncTools.C:153
scalar f1
Definition: createFields.H:28
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
scalar degToRad(const scalar deg)
Conversion from degrees to radians.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
autoPtr< mapPolyMesh > splitMeshRegions(const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const point &keepPoint)
Split mesh. Keep part containing point.
Takes mesh with &#39;baffles&#39; (= boundary faces sharing points). Determines for selected points on bounda...
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1131
static void mapCombineScatter(const List< commsStruct > &comms, Container &Values, const int tag, const label comm)
Scatter data. Reverse of combineGather.
autoPtr< mapPolyMesh > mergeBaffles(const List< labelPair > &)
Merge baffles. Gets pairs of faces.
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const label &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:142
const searchableSurfaces & geometry() const
A list of faces which address into the list of points.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Duplicate points.
virtual void updateMesh(const mapPolyMesh &mpm)
Update mesh corresponding to the given map.
Definition: fvMesh.C:795
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:313
dimensionedScalar cos(const dimensionedScalar &ds)
static void syncEdgeList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh edges.
const cellZoneMesh & cellZones() const
Return cell zone mesh.
Definition: polyMesh.H:482
Simple container to keep together snap specific information.
double cpuTimeIncrement() const
Return CPU time (in seconds) since last call to cpuTimeIncrement()
Definition: cpuTime.C:74
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:177
Transport of region for use in PatchEdgeFaceWave.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1169
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
void flip()
Reverse orientation.
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1394
static const label labelMax
Definition: label.H:62
List< label > labelList
A List of labels.
Definition: labelList.H:56
const word & name() const
Return name.
Definition: zone.H:147
static void mapCombineGather(const List< commsStruct > &comms, Container &Values, const CombineOp &cop, const int tag, const label comm)
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1156
static labelList getInsidePointNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of surfaces with a cellZone that have &#39;insidePoint&#39;.
const PtrList< surfaceZonesInfo > & surfZones() const
const vectorField & cellCentres() const
static labelList getUnnamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of unnamed surfaces (surfaces without faceZoneName)
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
word timeName() const
Replacement for Time::timeName() : return oldInstance (if.
Foam::polyBoundaryMesh.
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
dimensioned< scalar > magSqr(const dimensioned< Type > &)
label nEdges() const
Return number of edges in patch.
void reverse(UList< T > &, const label n)
Definition: UListI.H:322
OFstream which keeps track of vertices.
Definition: OBJstream.H:53
static const char nl
Definition: Ostream.H:265
void checkData()
Debugging: check that all faces still obey start()>end()
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
A subset of mesh cells.
Definition: cellZone.H:61
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
void updateMesh(const mapPolyMesh &, const labelList &changedFaces)
Update for external change to mesh. changedFaces are in new mesh.
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:32
const Type & second() const
Return second.
Definition: Pair.H:99
label nEdges() const
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:221
virtual tmp< scalarField > movePoints(const pointField &)
Move points, returns volumes swept by faces in motion.
Definition: fvMesh.C:716
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const vectorField & faceCentres() const
static void syncFaceList(const polyMesh &mesh, UList< T > &l, const CombineOp &cop)
Synchronize values on all mesh faces.
Definition: syncTools.H:381
void setSize(const label)
Reset size of List.
Definition: List.C:281
const boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:440
autoPtr< mapPolyMesh > dupNonManifoldPoints()
Find boundary points that connect to more than one cell.
A bit-packed bool list.
const wordList & names() const
Names of surfaces.
label patchi
autoPtr< mapPolyMesh > zonify(const point &keepPoint, const bool allowFreeStandingZoneFaces)
Put faces/cells into zones according to surface specification.
#define WarningInFunction
Report a warning using Foam::Warning.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:70
labelList meshEdges(const edgeList &allEdges, const labelListList &cellEdges, const labelList &faceCells) const
Return labels of patch edges in the global edge list using.
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:56
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
const vectorField & faceAreas() const
Direct mesh changes based on v1.3 polyTopoChange syntax.
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:303
static labelList addFaceZonesToMesh(const PtrList< surfaceZonesInfo > &surfList, const labelList &namedSurfaces, polyMesh &mesh)
void setRefinement(const localPointRegion &regionSide, polyTopoChange &)
Play commands into polyTopoChange to duplicate points. Gets.
label globalRegion(const label surfI, const label regionI) const
From surface and region on surface to global region.
static void syncPointList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:201
static labelList getClosedNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList, const searchableSurfaces &allGeometry, const labelList &surfaces)
Get indices of surfaces with a cellZone that are closed and.
static labelList getNamedSurfaces(const PtrList< surfaceZonesInfo > &surfList)
Get indices of named surfaces (surfaces with faceZoneName)
messageStream Info
const labelListList & pointFaces() const
const labelListList & faceEdges() const
Return face-edge addressing.
dimensioned< scalar > mag(const dimensioned< Type > &)
label n
label nPoints() const
Field< vector > vectorField
Specialisation of Field<T> for vector.
void setSize(const label)
Dummy setSize function.
Definition: FixedListI.H:183
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
virtual Ostream & write(const token &)=0
Write next token to stream.
const doubleScalar e
Elementary charge.
Definition: doubleScalar.H:98
labelList getExposedFaces(const labelList &cellsToRemove) const
Get labels of exposed faces.
Definition: removeCells.C:73
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:430
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:64
List< Key > toc() const
Return the table of contents.
Definition: HashTable.C:202
virtual void sync(const polyMesh &mesh)
Sync faceSet across coupled patches.
Definition: faceSet.C:113
autoPtr< mapPolyMesh > changeMesh(polyMesh &mesh, const bool inflate, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
bool write() const
Write mesh and all data.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
void findNearestIntersection(const labelList &surfacesToTest, const pointField &start, const pointField &end, labelList &surface1, List< pointIndexHit > &hit1, labelList &region1, labelList &surface2, List< pointIndexHit > &hit2, labelList &region2) const
Find intersection nearest to the endpoints. surface1,2 are.
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=*(cellModeller::lookup("hex"));labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< small) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
const Type & first() const
Return first.
Definition: Pair.H:87
A List with indirect addressing.
Definition: IndirectList.H:101
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
A HashTable to objects of type <T> with a label key.
Definition: Map.H:49
void findInside(const labelList &surfacesToTest, const pointField &pt, labelList &insideSurfaces) const
Detect if a point is &#39;inside&#39; (closed) surfaces.
label setAction(const topoAction &action)
For compatibility with polyTopoChange: set topological action.