meshRefinement.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-2026 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 "volFields.H"
28 #include "syncTools.H"
29 #include "Time.H"
30 #include "refinementHistory.H"
31 #include "refinementSurfaces.H"
32 #include "refinementFeatures.H"
33 #include "decompositionMethod.H"
34 #include "regionSplit.H"
35 #include "fvMeshDistribute.H"
36 #include "indirectPrimitivePatch.H"
37 #include "polyTopoChange.H"
38 #include "removeCells.H"
39 #include "polyDistributionMap.H"
40 #include "localPointRegion.H"
41 #include "pointMesh.H"
42 #include "pointFields.H"
43 #include "slipPointPatchFields.H"
47 #include "processorPointPatch.H"
48 #include "globalIndex.H"
49 #include "meshTools.H"
50 #include "OFstream.H"
51 #include "geometric.H"
52 #include "randomGenerator.H"
53 #include "searchableSurfaceList.H"
54 #include "meshSearch.H"
55 #include "fvMeshTools.H"
56 
57 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
58 
59 namespace Foam
60 {
62 }
63 
66 {
67  "mesh",
68  "intersections",
69  "featureSeeds",
70  "attraction",
71  "layerInfo"
72 };
73 
76 {
77  "layerInfo"
78 };
79 
82 {
83  "mesh",
84  "noRefinement",
85  "scalarLevels",
86  "layerSets",
87  "layerFields"
88 };
89 
90 Foam::meshRefinement::writeType Foam::meshRefinement::writeLevel_;
91 
92 Foam::meshRefinement::outputType Foam::meshRefinement::outputLevel_;
93 
94 
95 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
96 
97 void Foam::meshRefinement::calcNeighbourData
98 (
99  labelList& neiLevel,
100  pointField& neiCc
101 ) const
102 {
103  const labelList& cellLevel = meshCutter_.cellLevel();
104  const pointField& cellCentres = mesh_.cellCentres();
105 
106  const label nBoundaryFaces = mesh_.nFaces() - mesh_.nInternalFaces();
107 
108  if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
109  {
111  << nBoundaryFaces << " neiLevel:" << neiLevel.size()
112  << abort(FatalError);
113  }
114 
115  const polyBoundaryMesh& patches = mesh_.poly().boundary();
116 
117  labelHashSet addedPatchIDSet(meshedPatches());
118 
120  {
121  const polyPatch& pp = patches[patchi];
122 
123  const labelUList& faceCells = pp.faceCells();
124  const vectorField::subField faceCentres = pp.faceCentres();
125  const vectorField::subField faceAreas = pp.faceAreas();
126 
127  label bFacei = pp.start() - mesh_.nInternalFaces();
128 
129  if (pp.coupled())
130  {
131  forAll(faceCells, i)
132  {
133  neiLevel[bFacei] = cellLevel[faceCells[i]];
134  neiCc[bFacei] = cellCentres[faceCells[i]];
135  bFacei++;
136  }
137  }
138  else if (addedPatchIDSet.found(patchi))
139  {
140  // Face was introduced from cell-cell intersection. Try to
141  // reconstruct other side cell(centre). Three possibilities:
142  // - cells same size.
143  // - preserved cell smaller. Not handled.
144  // - preserved cell larger.
145  forAll(faceCells, i)
146  {
147  // Extrapolate the face centre.
148  const vector fn = faceAreas[i]/(mag(faceAreas[i]) + vSmall);
149 
150  const label own = faceCells[i];
151  const label ownLevel = cellLevel[own];
152  const label faceLevel = meshCutter_.faceLevel(pp.start() + i);
153 
154  // Normal distance from face centre to cell centre
155  scalar d = ((faceCentres[i] - cellCentres[own]) & fn);
156  if (faceLevel > ownLevel)
157  {
158  // Other cell more refined. Adjust normal distance
159  d *= 0.5;
160  }
161  neiLevel[bFacei] = faceLevel;
162  // Calculate other cell centre by extrapolation
163  neiCc[bFacei] = faceCentres[i] + d*fn;
164  bFacei++;
165  }
166  }
167  else
168  {
169  forAll(faceCells, i)
170  {
171  neiLevel[bFacei] = cellLevel[faceCells[i]];
172  neiCc[bFacei] = faceCentres[i];
173  bFacei++;
174  }
175  }
176  }
177 
178  // Swap coupled boundaries. Apply separation to cc since is coordinate.
180  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
181 }
182 
183 
184 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
185 {
186  const pointField& cellCentres = mesh_.cellCentres();
187 
188  // Stats on edges to test. Count proc faces only once.
189  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
190 
191  {
192  label nMasterFaces = 0;
193  forAll(isMasterFace, facei)
194  {
195  if (isMasterFace.get(facei) == 1)
196  {
197  nMasterFaces++;
198  }
199  }
200  reduce(nMasterFaces, sumOp<label>());
201 
202  label nChangedFaces = 0;
203  forAll(changedFaces, i)
204  {
205  if (isMasterFace.get(changedFaces[i]) == 1)
206  {
207  nChangedFaces++;
208  }
209  }
210  reduce(nChangedFaces, sumOp<label>());
211 
212  Info<< "Edge intersection testing:" << nl
213  << " Number of edges : " << nMasterFaces << nl
214  << " Number of edges to retest : " << nChangedFaces
215  << endl;
216  }
217 
218 
219  // Get boundary face centre and level. Coupled aware.
220  labelList neiLevel(mesh_.nFaces() - mesh_.nInternalFaces());
221  pointField neiCc(mesh_.nFaces() - mesh_.nInternalFaces());
222  calcNeighbourData(neiLevel, neiCc);
223 
224  // Collect segments we want to test for
225  pointField start(changedFaces.size());
226  pointField end(changedFaces.size());
227 
228  forAll(changedFaces, i)
229  {
230  const label facei = changedFaces[i];
231  const label own = mesh_.faceOwner()[facei];
232 
233  start[i] = cellCentres[own];
234  if (mesh_.isInternalFace(facei))
235  {
236  end[i] = cellCentres[mesh_.faceNeighbour()[facei]];
237  }
238  else
239  {
240  end[i] = neiCc[facei-mesh_.nInternalFaces()];
241  }
242  }
243 
244  // Extend segments a bit
245  {
246  const vectorField smallVec(rootSmall*(end-start));
247  start -= smallVec;
248  end += smallVec;
249  }
250 
251 
252  // Do tests in one go
253  labelList surfaceHit;
254  {
255  labelList surfaceLevel;
256  surfaces_.findHigherIntersection
257  (
258  start,
259  end,
260  labelList(start.size(), -1), // accept any intersection
261  surfaceHit,
262  surfaceLevel
263  );
264  }
265 
266  // Keep just surface hit
267  forAll(surfaceHit, i)
268  {
269  surfaceIndex_[changedFaces[i]] = surfaceHit[i];
270  }
271 
272  // Make sure both sides have same information. This should be
273  // case in general since same vectors but just to make sure.
274  syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>());
275 
276  const label nHits = countHits();
277  const label nTotHits = returnReduce(nHits, sumOp<label>());
278 
279  Info<< " Number of intersected edges : " << nTotHits << endl;
280 
281  // Set files to same time as mesh
282  setInstance(mesh_.facesInstance());
283 }
284 
285 
287 (
288  const string& msg,
289  const polyMesh& mesh,
290  const List<scalar>& fld
291 )
292 {
293  if (fld.size() != mesh.nPoints())
294  {
296  << msg << endl
297  << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
298  << abort(FatalError);
299  }
300 
301  Pout<< "Checking field " << msg << endl;
302  scalarField minFld(fld);
304  (
305  mesh,
306  minFld,
307  minEqOp<scalar>(),
308  great
309  );
310  scalarField maxFld(fld);
312  (
313  mesh,
314  maxFld,
315  maxEqOp<scalar>(),
316  -great
317  );
318  forAll(minFld, pointi)
319  {
320  const scalar& minVal = minFld[pointi];
321  const scalar& maxVal = maxFld[pointi];
322  if (mag(minVal-maxVal) > small)
323  {
324  Pout<< msg << " at:" << mesh.points()[pointi] << nl
325  << " minFld:" << minVal << nl
326  << " maxFld:" << maxVal << nl
327  << endl;
328  }
329  }
330 }
331 
332 
334 (
335  const string& msg,
336  const polyMesh& mesh,
337  const List<point>& fld
338 )
339 {
340  if (fld.size() != mesh.nPoints())
341  {
343  << msg << endl
344  << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
345  << abort(FatalError);
346  }
347 
348  Pout<< "Checking field " << msg << endl;
349  pointField minFld(fld);
351  (
352  mesh,
353  minFld,
355  point(great, great, great)
356  );
357  pointField maxFld(fld);
359  (
360  mesh,
361  maxFld,
364  );
365  forAll(minFld, pointi)
366  {
367  const point& minVal = minFld[pointi];
368  const point& maxVal = maxFld[pointi];
369  if (mag(minVal-maxVal) > small)
370  {
371  Pout<< msg << " at:" << mesh.points()[pointi] << nl
372  << " minFld:" << minVal << nl
373  << " maxFld:" << maxVal << nl
374  << endl;
375  }
376  }
377 }
378 
379 
381 {
382  Pout<< "meshRefinement::checkData() : Checking refinement structure."
383  << endl;
384  meshCutter_.checkMesh();
385 
386  Pout<< "meshRefinement::checkData() : Checking refinement levels."
387  << endl;
388  meshCutter_.checkRefinementLevels(1, labelList(0));
389 
390 
391  label nBnd = mesh_.nFaces() - mesh_.nInternalFaces();
392 
393  Pout<< "meshRefinement::checkData() : Checking synchronisation."
394  << endl;
395 
396  // Check face centres
397  {
398  // Boundary face centres
399  pointField::subList boundaryFc
400  (
401  mesh_.faceCentres(),
402  nBnd,
403  mesh_.nInternalFaces()
404  );
405 
406  // Get neighbouring face centres
407  pointField neiBoundaryFc(boundaryFc);
409  (
410  mesh_,
411  neiBoundaryFc,
412  eqOp<point>()
413  );
414 
415  // Compare
416  testSyncBoundaryFaceList
417  (
418  mergeDistance_,
419  "testing faceCentres : ",
420  boundaryFc,
421  neiBoundaryFc
422  );
423  }
424  // Check meshRefinement
425  {
426  // Get boundary face centre and level. Coupled aware.
427  labelList neiLevel(nBnd);
428  pointField neiCc(nBnd);
429  calcNeighbourData(neiLevel, neiCc);
430 
431  // Collect segments we want to test for
432  pointField start(mesh_.nFaces());
433  pointField end(mesh_.nFaces());
434 
435  forAll(start, facei)
436  {
437  start[facei] = mesh_.cellCentres()[mesh_.faceOwner()[facei]];
438 
439  if (mesh_.isInternalFace(facei))
440  {
441  end[facei] = mesh_.cellCentres()[mesh_.faceNeighbour()[facei]];
442  }
443  else
444  {
445  end[facei] = neiCc[facei-mesh_.nInternalFaces()];
446  }
447  }
448 
449  // Extend segments a bit
450  {
451  const vectorField smallVec(rootSmall*(end-start));
452  start -= smallVec;
453  end += smallVec;
454  }
455 
456 
457  // Do tests in one go
458  labelList surfaceHit;
459  {
460  labelList surfaceLevel;
461  surfaces_.findHigherIntersection
462  (
463  start,
464  end,
465  labelList(start.size(), -1), // accept any intersection
466  surfaceHit,
467  surfaceLevel
468  );
469  }
470  // Get the coupled hit
471  labelList neiHit
472  (
474  (
475  surfaceHit,
476  nBnd,
477  mesh_.nInternalFaces()
478  )
479  );
480  syncTools::swapBoundaryFaceList(mesh_, neiHit);
481 
482  // Check
483  forAll(surfaceHit, facei)
484  {
485  if (surfaceIndex_[facei] != surfaceHit[facei])
486  {
487  if (mesh_.isInternalFace(facei))
488  {
490  << "Internal face:" << facei
491  << " fc:" << mesh_.faceCentres()[facei]
492  << " cached surfaceIndex_:" << surfaceIndex_[facei]
493  << " current:" << surfaceHit[facei]
494  << " ownCc:"
495  << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
496  << " neiCc:"
497  << mesh_.cellCentres()[mesh_.faceNeighbour()[facei]]
498  << endl;
499  }
500  else if
501  (
502  surfaceIndex_[facei]
503  != neiHit[facei-mesh_.nInternalFaces()]
504  )
505  {
507  << "Boundary face:" << facei
508  << " fc:" << mesh_.faceCentres()[facei]
509  << " cached surfaceIndex_:" << surfaceIndex_[facei]
510  << " current:" << surfaceHit[facei]
511  << " ownCc:"
512  << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
513  << " end:" << end[facei]
514  << endl;
515  }
516  }
517  }
518  }
519  {
520  labelList::subList boundarySurface
521  (
522  surfaceIndex_,
523  mesh_.nFaces() - mesh_.nInternalFaces(),
524  mesh_.nInternalFaces()
525  );
526 
527  labelList neiBoundarySurface(boundarySurface);
529  (
530  mesh_,
531  neiBoundarySurface
532  );
533 
534  // Compare
535  testSyncBoundaryFaceList
536  (
537  0, // tolerance
538  "testing surfaceIndex() : ",
539  boundarySurface,
540  neiBoundarySurface
541  );
542  }
543 
544 
545  // Find duplicate faces
546  Pout<< "meshRefinement::checkData() : Counting duplicate faces."
547  << endl;
548 
549  labelList duplicateFace
550  (
552  (
553  mesh_,
555  (
556  mesh_.nInternalFaces(),
557  mesh_.nFaces() - mesh_.nInternalFaces()
558  )
559  )
560  );
561 
562  // Count
563  {
564  label nDup = 0;
565 
566  forAll(duplicateFace, i)
567  {
568  if (duplicateFace[i] != -1)
569  {
570  nDup++;
571  }
572  }
573  nDup /= 2; // will have counted both faces of duplicate
574  Pout<< "meshRefinement::checkData() : Found " << nDup
575  << " duplicate pairs of faces." << endl;
576  }
577 }
578 
579 
581 {
582  meshCutter_.setInstance(inst);
583  surfaceIndex_.instance() = inst;
584 }
585 
586 
587 Foam::autoPtr<Foam::polyTopoChangeMap> Foam::meshRefinement::doRemoveCells
588 (
589  const labelList& cellsToRemove,
590  const labelList& exposedFaces,
591  const labelList& exposedPatchIDs,
592  removeCells& cellRemover
593 )
594 {
595  polyTopoChange meshMod(mesh_);
596 
597  // Arbitrary: put exposed faces into last patch.
598  cellRemover.setRefinement
599  (
600  cellsToRemove,
601  exposedFaces,
602  exposedPatchIDs,
603  meshMod
604  );
605 
606  // Change the mesh
607  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh_, true);
608 
609  // Update fields
610  mesh_.topoChange(map);
611 
612  // Reset the instance for if in overwrite mode
613  mesh_.setInstance(name());
614  setInstance(mesh_.facesInstance());
615 
616  // Update local mesh data
617  cellRemover.topoChange(map);
618 
619  // Update intersections. Recalculate intersections for exposed faces.
620  labelList newExposedFaces = renumber
621  (
622  map().reverseFaceMap(),
623  exposedFaces
624  );
625 
626  // Pout<< "removeCells : updating intersections for "
627  // << newExposedFaces.size() << " newly exposed faces." << endl;
628 
629  topoChange(map, newExposedFaces);
630 
631  return map;
632 }
633 
634 
636 (
637  const labelList& splitFaces,
638  const labelPairList& splits
639 )
640 {
641  polyTopoChange meshMod(mesh_);
642 
643  forAll(splitFaces, i)
644  {
645  const label facei = splitFaces[i];
646  const face& f = mesh_.faces()[facei];
647 
648  // Split as start and end index in face
649  const labelPair& split = splits[i];
650 
651  label nVerts = split[1] - split[0];
652  if (nVerts < 0)
653  {
654  nVerts += f.size();
655  }
656  nVerts += 1;
657 
658 
659  // Split into f0, f1
660  face f0(nVerts);
661 
662  label fp = split[0];
663  forAll(f0, i)
664  {
665  f0[i] = f[fp];
666  fp = f.fcIndex(fp);
667  }
668 
669  face f1(f.size() - f0.size() + 2);
670  fp = split[1];
671  forAll(f1, i)
672  {
673  f1[i] = f[fp];
674  fp = f.fcIndex(fp);
675  }
676 
677 
678  // Determine face properties
679  const label own = mesh_.faceOwner()[facei];
680  label nei = -1;
681  label patchi = -1;
682  if (facei >= mesh_.nInternalFaces())
683  {
684  patchi = mesh_.poly().boundary().whichPatch(facei);
685  }
686  else
687  {
688  nei = mesh_.faceNeighbour()[facei];
689  }
690 
691  if (debug)
692  {
693  Pout<< "face:" << facei << " verts:" << f
694  << " split into f0:" << f0
695  << " f1:" << f1 << endl;
696  }
697 
698  // Change/add faces
699  meshMod.modifyFace
700  (
701  f0, // modified face
702  facei, // label of face
703  own, // owner
704  nei, // neighbour
705  false, // face flip
706  patchi // patch for face
707  );
708 
709  meshMod.addFace
710  (
711  f1, // modified face
712  own, // owner
713  nei, // neighbour
714  facei, // master face
715  false, // face flip
716  patchi // patch for face
717  );
718  }
719 
720 
721  // Change the mesh (without keeping old points)
722  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh_, true);
723 
724  // Update fields
725  mesh_.topoChange(map);
726 
727  // Reset the instance for if in overwrite mode
728  mesh_.setInstance(name());
729  setInstance(mesh_.facesInstance());
730 
731  // Update local mesh data
732  const labelList& oldToNew = map().reverseFaceMap();
733  labelList newSplitFaces(renumber(oldToNew, splitFaces));
734  // Add added faces (every splitFaces becomes two faces)
735  label sz = newSplitFaces.size();
736  newSplitFaces.setSize(2*sz);
737  forAll(map().faceMap(), facei)
738  {
739  label oldFacei = map().faceMap()[facei];
740  if (oldToNew[oldFacei] != facei)
741  {
742  // Added face
743  newSplitFaces[sz++] = facei;
744  }
745  }
746 
747  topoChange(map, newSplitFaces);
748 
749  return map;
750 }
751 
752 
755 //void Foam::meshRefinement::getCoupledRegionMaster
756 //(
757 // const globalIndex& globalCells,
758 // const boolList& blockedFace,
759 // const regionSplit& globalRegion,
760 // Map<label>& regionToMaster
761 //) const
762 //{
763 // const polyBoundaryMesh& patches = mesh_.poly().boundary();
764 //
765 // forAll(patches, patchi)
766 // {
767 // const polyPatch& pp = patches[patchi];
768 //
769 // if (isA<processorPolyPatch>(pp))
770 // {
771 // forAll(pp, i)
772 // {
773 // label facei = pp.start() + i;
774 //
775 // if (!blockedFace[facei])
776 // {
777 // // Only if there is a connection to the neighbour
778 // // will there be a multi-domain region; if not through
779 // // this face then through another.
780 //
781 // label celli = mesh_.faceOwner()[facei];
782 // label globalCelli = globalCells.toGlobal(celli);
783 //
784 // Map<label>::iterator iter =
785 // regionToMaster.find(globalRegion[celli]);
786 //
787 // if (iter != regionToMaster.end())
788 // {
789 // label master = iter();
790 // iter() = min(master, globalCelli);
791 // }
792 // else
793 // {
794 // regionToMaster.insert
795 // (
796 // globalRegion[celli],
797 // globalCelli
798 // );
799 // }
800 // }
801 // }
802 // }
803 // }
804 //
805 // // Do reduction
806 // Pstream::mapCombineGather(regionToMaster, minEqOp<label>());
807 // Pstream::mapCombineScatter(regionToMaster);
808 //}
809 //
810 //
811 //void Foam::meshRefinement::calcLocalRegions
812 //(
813 // const globalIndex& globalCells,
814 // const labelList& globalRegion,
815 // const Map<label>& coupledRegionToMaster,
816 // const scalarField& cellWeights,
817 //
818 // Map<label>& globalToLocalRegion,
819 // pointField& localPoints,
820 // scalarField& localWeights
821 //) const
822 //{
823 // globalToLocalRegion.resize(globalRegion.size());
824 // DynamicList<point> localCc(globalRegion.size()/2);
825 // DynamicList<scalar> localWts(globalRegion.size()/2);
826 //
827 // forAll(globalRegion, celli)
828 // {
829 // Map<label>::const_iterator fndMaster =
830 // coupledRegionToMaster.find(globalRegion[celli]);
831 //
832 // if (fndMaster != coupledRegionToMaster.end())
833 // {
834 // // Multi-processor region.
835 // if (globalCells.toGlobal(celli) == fndMaster())
836 // {
837 // // I am master. Allocate region for me.
838 // globalToLocalRegion.insert
839 // (
840 // globalRegion[celli],
841 // localCc.size()
842 // );
843 // localCc.append(mesh_.cellCentres()[celli]);
844 // localWts.append(cellWeights[celli]);
845 // }
846 // }
847 // else
848 // {
849 // // Single processor region.
850 // if
851 // (
852 // globalToLocalRegion.insert
853 // (
854 // globalRegion[celli],
855 // localCc.size()
856 // )
857 // )
858 // {
859 // localCc.append(mesh_.cellCentres()[celli]);
860 // localWts.append(cellWeights[celli]);
861 // }
862 // }
863 // }
864 //
865 // localPoints.transfer(localCc);
866 // localWeights.transfer(localWts);
867 //
868 // if (localPoints.size() != globalToLocalRegion.size())
869 // {
870 // FatalErrorInFunction
871 // << "localPoints:" << localPoints.size()
872 // << " globalToLocalRegion:" << globalToLocalRegion.size()
873 // << exit(FatalError);
874 // }
875 //}
876 //
877 //
878 //Foam::label Foam::meshRefinement::getShiftedRegion
879 //(
880 // const globalIndex& indexer,
881 // const Map<label>& globalToLocalRegion,
882 // const Map<label>& coupledRegionToShifted,
883 // const label globalRegion
884 //)
885 //{
886 // Map<label>::const_iterator iter =
887 // globalToLocalRegion.find(globalRegion);
888 //
889 // if (iter != globalToLocalRegion.end())
890 // {
891 // // Region is 'owned' locally. Convert local region index into global.
892 // return indexer.toGlobal(iter());
893 // }
894 // else
895 // {
896 // return coupledRegionToShifted[globalRegion];
897 // }
898 //}
899 //
900 //
902 //void Foam::meshRefinement::addUnique(const label elem, labelList& lst)
903 //{
904 // if (findIndex(lst, elem) == -1)
905 // {
906 // label sz = lst.size();
907 // lst.setSize(sz+1);
908 // lst[sz] = elem;
909 // }
910 //}
911 //
912 //
913 //void Foam::meshRefinement::calcRegionRegions
914 //(
915 // const labelList& globalRegion,
916 // const Map<label>& globalToLocalRegion,
917 // const Map<label>& coupledRegionToMaster,
918 // labelListList& regionRegions
919 //) const
920 //{
921 // // Global region indexing since we now know the shifted regions.
922 // globalIndex shiftIndexer(globalToLocalRegion.size());
923 //
924 // // Redo the coupledRegionToMaster to be in shifted region indexing.
925 // Map<label> coupledRegionToShifted(coupledRegionToMaster.size());
926 // forAllConstIter(Map<label>, coupledRegionToMaster, iter)
927 // {
928 // label region = iter.key();
929 //
930 // Map<label>::const_iterator fndRegion = globalToLocalRegion.find
931 // (region);
932 //
933 // if (fndRegion != globalToLocalRegion.end())
934 // {
935 // // A local cell is master of this region. Get its shifted region.
936 // coupledRegionToShifted.insert
937 // (
938 // region,
939 // shiftIndexer.toGlobal(fndRegion())
940 // );
941 // }
942 // Pstream::mapCombineGather(coupledRegionToShifted, minEqOp<label>());
943 // Pstream::mapCombineScatter(coupledRegionToShifted);
944 // }
945 //
946 //
947 // // Determine region-region connectivity.
948 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
949 // // This is for all my regions (so my local ones or the ones I am master
950 // // of) the neighbouring region indices.
951 //
952 //
953 // // Transfer lists.
954 // PtrList<HashSet<edge, Hash<edge>>> regionConnectivity
955 // (Pstream::nProcs());
956 // forAll(regionConnectivity, proci)
957 // {
958 // if (proci != Pstream::myProcNo())
959 // {
960 // regionConnectivity.set
961 // (
962 // proci,
963 // new HashSet<edge, Hash<edge>>
964 // (
965 // coupledRegionToShifted.size()
966 // / Pstream::nProcs()
967 // )
968 // );
969 // }
970 // }
971 //
972 //
973 // // Connectivity. For all my local regions the connected regions.
974 // regionRegions.setSize(globalToLocalRegion.size());
975 //
976 // // Add all local connectivity to regionRegions; add all non-local
977 // // to the transferlists.
978 // for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
979 // {
980 // label ownRegion = globalRegion[mesh_.faceOwner()[facei]];
981 // label neiRegion = globalRegion[mesh_.faceNeighbour()[facei]];
982 //
983 // if (ownRegion != neiRegion)
984 // {
985 // label shiftOwnRegion = getShiftedRegion
986 // (
987 // shiftIndexer,
988 // globalToLocalRegion,
989 // coupledRegionToShifted,
990 // ownRegion
991 // );
992 // label shiftNeiRegion = getShiftedRegion
993 // (
994 // shiftIndexer,
995 // globalToLocalRegion,
996 // coupledRegionToShifted,
997 // neiRegion
998 // );
999 //
1000 //
1001 // // Connection between two regions. Send to owner of region.
1002 // // - is ownRegion 'owned' by me
1003 // // - is neiRegion 'owned' by me
1004 //
1005 // if (shiftIndexer.isLocal(shiftOwnRegion))
1006 // {
1007 // label localI = shiftIndexer.toLocal(shiftOwnRegion);
1008 // addUnique(shiftNeiRegion, regionRegions[localI]);
1009 // }
1010 // else
1011 // {
1012 // label masterProc = shiftIndexer.whichProcID(shiftOwnRegion);
1013 // regionConnectivity[masterProc].insert
1014 // (
1015 // edge(shiftOwnRegion, shiftNeiRegion)
1016 // );
1017 // }
1018 //
1019 // if (shiftIndexer.isLocal(shiftNeiRegion))
1020 // {
1021 // label localI = shiftIndexer.toLocal(shiftNeiRegion);
1022 // addUnique(shiftOwnRegion, regionRegions[localI]);
1023 // }
1024 // else
1025 // {
1026 // label masterProc = shiftIndexer.whichProcID(shiftNeiRegion);
1027 // regionConnectivity[masterProc].insert
1028 // (
1029 // edge(shiftOwnRegion, shiftNeiRegion)
1030 // );
1031 // }
1032 // }
1033 // }
1034 //
1035 //
1036 // // Send
1037 // forAll(regionConnectivity, proci)
1038 // {
1039 // if (proci != Pstream::myProcNo())
1040 // {
1041 // OPstream str(Pstream::commsTypes::blocking, proci);
1042 // str << regionConnectivity[proci];
1043 // }
1044 // }
1045 // // Receive
1046 // forAll(regionConnectivity, proci)
1047 // {
1048 // if (proci != Pstream::myProcNo())
1049 // {
1050 // IPstream str(Pstream::commsTypes::blocking, proci);
1051 // str >> regionConnectivity[proci];
1052 // }
1053 // }
1054 //
1055 // // Add to addressing.
1056 // forAll(regionConnectivity, proci)
1057 // {
1058 // if (proci != Pstream::myProcNo())
1059 // {
1060 // for
1061 // (
1062 // HashSet<edge, Hash<edge>>::const_iterator iter =
1063 // regionConnectivity[proci].begin();
1064 // iter != regionConnectivity[proci].end();
1065 // ++iter
1066 // )
1067 // {
1068 // const edge& e = iter.key();
1069 //
1070 // bool someLocal = false;
1071 // if (shiftIndexer.isLocal(e[0]))
1072 // {
1073 // label localI = shiftIndexer.toLocal(e[0]);
1074 // addUnique(e[1], regionRegions[localI]);
1075 // someLocal = true;
1076 // }
1077 // if (shiftIndexer.isLocal(e[1]))
1078 // {
1079 // label localI = shiftIndexer.toLocal(e[1]);
1080 // addUnique(e[0], regionRegions[localI]);
1081 // someLocal = true;
1082 // }
1083 //
1084 // if (!someLocal)
1085 // {
1086 // FatalErrorInFunction
1087 // << "Received from processor " << proci
1088 // << " connection " << e
1089 // << " where none of the elements is local to me."
1090 // << abort(FatalError);
1091 // }
1092 // }
1093 // }
1094 // }
1095 //}
1096 
1097 
1098 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1099 
1101 (
1102  fvMesh& mesh,
1103  const dictionary& refineDict,
1104  const scalar mergeDistance,
1105  const bool overwrite,
1106  refinementSurfaces& surfaces,
1107  const refinementFeatures& features,
1108  const refinementRegions& shells
1109 )
1110 :
1111  mesh_(mesh),
1112  mergeDistance_(mergeDistance),
1113  overwrite_(overwrite),
1114  oldInstance_(mesh.pointsInstance()),
1115  surfaces_(surfaces),
1116  features_(features),
1117  shells_(shells),
1118  meshCutter_
1119  (
1120  hexRef8::New
1121  (
1122  mesh,
1123  false // do not try to read history.
1124  )
1125  ),
1126  surfaceIndex_
1127  (
1128  IOobject
1129  (
1130  "surfaceIndex",
1131  mesh_.facesInstance(),
1132  fvMesh::meshSubDir,
1133  mesh_,
1134  IOobject::NO_READ,
1135  IOobject::NO_WRITE,
1136  false
1137  ),
1138  labelList(mesh_.nFaces(), -1)
1139  ),
1140  userFaceData_(0)
1141 {
1143  (
1144  shells_,
1145  meshCutter_.level0EdgeLength(),
1146  refineDict.lookupOrDefault<Switch>("extendedRefinementSpan", true)
1147  );
1148 
1149  // recalculate intersections for all faces
1150  updateIntersections(identityMap(mesh_.nFaces()));
1151 }
1152 
1153 
1154 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1155 
1157 {
1158  // Stats on edges to test. Count proc faces only once.
1159  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
1160 
1161  label nHits = 0;
1162 
1163  forAll(surfaceIndex_, facei)
1164  {
1165  if (surfaceIndex_[facei] >= 0 && isMasterFace.get(facei) == 1)
1166  {
1167  nHits++;
1168  }
1169  }
1170  return nHits;
1171 }
1172 
1173 
1175 //Foam::labelList Foam::meshRefinement::decomposeCombineRegions
1176 //(
1177 // const scalarField& cellWeights,
1178 // const boolList& blockedFace,
1179 // const List<labelPair>& explicitConnections,
1180 // decompositionMethod& decomposer
1181 //) const
1182 //{
1183 // // Determine global regions, separated by blockedFaces
1184 // regionSplit globalRegion(mesh_, blockedFace, explicitConnections);
1185 //
1186 // // Now globalRegion has global region per cell. Problem is that
1187 // // the region might span multiple domains so we want to get
1188 // // a "region master" per domain. Note that multi-processor
1189 // // regions can only occur on cells on coupled patches.
1190 // // Note: since the number of regions does not change by this the
1191 // // process can be seen as just a shift of a region onto a single
1192 // // processor.
1193 //
1194 //
1195 // // Global cell numbering engine
1196 // globalIndex globalCells(mesh_.nCells());
1197 //
1198 //
1199 // // Determine per coupled region the master cell (lowest numbered cell
1200 // // on lowest numbered processor)
1201 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1202 // // (does not determine master for non-coupled=fully-local regions)
1203 //
1204 // Map<label> coupledRegionToMaster(mesh_.nFaces() - mesh_.nInternalFaces());
1205 // getCoupledRegionMaster
1206 // (
1207 // globalCells,
1208 // blockedFace,
1209 // globalRegion,
1210 // coupledRegionToMaster
1211 // );
1212 //
1213 // // Determine my regions
1214 // // ~~~~~~~~~~~~~~~~~~~~
1215 // // These are the fully local ones or the coupled ones of which I am master
1216 //
1217 // Map<label> globalToLocalRegion;
1218 // pointField localPoints;
1219 // scalarField localWeights;
1220 // calcLocalRegions
1221 // (
1222 // globalCells,
1223 // globalRegion,
1224 // coupledRegionToMaster,
1225 // cellWeights,
1226 //
1227 // globalToLocalRegion,
1228 // localPoints,
1229 // localWeights
1230 // );
1231 //
1232 //
1233 //
1234 // // Find distribution for regions
1235 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1236 //
1237 // labelList regionDistribution;
1238 //
1239 // if (isA<decompositionMethods::geometric>(decomposer))
1240 // {
1241 // regionDistribution = decomposer.decompose(localPoints, localWeights);
1242 // }
1243 // else
1244 // {
1245 // labelListList regionRegions;
1246 // calcRegionRegions
1247 // (
1248 // globalRegion,
1249 // globalToLocalRegion,
1250 // coupledRegionToMaster,
1251 //
1252 // regionRegions
1253 // );
1254 //
1255 // regionDistribution = decomposer.decompose
1256 // (
1257 // regionRegions,
1258 // localPoints,
1259 // localWeights
1260 // );
1261 // }
1262 //
1263 //
1264 //
1265 // // Convert region-based decomposition back to cell-based one
1266 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1267 //
1268 // // Transfer destination processor back to all. Use global reduce for now.
1269 // Map<label> regionToDist(coupledRegionToMaster.size());
1270 // forAllConstIter(Map<label>, coupledRegionToMaster, iter)
1271 // {
1272 // label region = iter.key();
1273 //
1274 // Map<label>::const_iterator regionFnd = globalToLocalRegion.find
1275 // (region);
1276 //
1277 // if (regionFnd != globalToLocalRegion.end())
1278 // {
1279 // // Master cell is local. Store my distribution.
1280 // regionToDist.insert(iter.key(), regionDistribution[regionFnd()]);
1281 // }
1282 // else
1283 // {
1284 // // Master cell is not on this processor. Make sure it is
1285 // // overridden.
1286 // regionToDist.insert(iter.key(), labelMax);
1287 // }
1288 // }
1289 // Pstream::mapCombineGather(regionToDist, minEqOp<label>());
1290 // Pstream::mapCombineScatter(regionToDist);
1291 //
1292 //
1293 // // Determine destination for all cells
1294 // labelList distribution(mesh_.nCells());
1295 //
1296 // forAll(globalRegion, celli)
1297 // {
1298 // Map<label>::const_iterator fndRegion =
1299 // regionToDist.find(globalRegion[celli]);
1300 //
1301 // if (fndRegion != regionToDist.end())
1302 // {
1303 // distribution[celli] = fndRegion();
1304 // }
1305 // else
1306 // {
1307 // // region is local to the processor.
1308 // label localRegioni = globalToLocalRegion[globalRegion[celli]];
1309 //
1310 // distribution[celli] = regionDistribution[localRegioni];
1311 // }
1312 // }
1313 //
1314 // return distribution;
1315 //}
1316 
1317 
1319 (
1320  const bool keepZoneFaces,
1321  const bool keepBaffles,
1322  const scalarField& cellWeights,
1323  decompositionMethod& decomposer,
1324  fvMeshDistribute& distributor
1325 )
1326 {
1328 
1329  if (Pstream::parRun())
1330  {
1331  // Wanted distribution
1333 
1334 
1335  // Faces where owner and neighbour are not 'connected' so can
1336  // go to different processors.
1337  boolList blockedFace;
1338  label nUnblocked = 0;
1339 
1340  // Faces that move as block onto single processor
1341  PtrList<labelList> specifiedProcessorFaces;
1342  labelList specifiedProcessor;
1343 
1344  // Pairs of baffles
1345  List<labelPair> couples;
1346 
1347  // Constraints from decomposeParDict
1348  decomposer.setConstraints
1349  (
1350  mesh_,
1351  blockedFace,
1352  specifiedProcessorFaces,
1353  specifiedProcessor,
1354  couples
1355  );
1356 
1357 
1358  if (keepZoneFaces || keepBaffles)
1359  {
1360  if (keepZoneFaces)
1361  {
1362  // Determine decomposition to keep/move surface zones
1363  // on one processor. The reason is that snapping will make these
1364  // into baffles, move and convert them back so if they were
1365  // proc boundaries after baffling&moving the points might be no
1366  // longer synchronised so recoupling will fail. To prevent this
1367  // keep owner&neighbour of such a surface zone on the same
1368  // processor.
1369 
1370  const PtrList<surfaceZonesInfo>& surfZones =
1371  surfaces().surfZones();
1372  const faceZoneList& fZones = mesh_.faceZones();
1373  const polyBoundaryMesh& pbm = mesh_.poly().boundary();
1374 
1375  // Get faces whose owner and neighbour should stay together,
1376  // i.e. they are not 'blocked'.
1377 
1378  forAll(surfZones, surfi)
1379  {
1380  const word& fzName = surfZones[surfi].faceZoneName();
1381 
1382  if (fzName.size())
1383  {
1384  // Get zone
1385  const faceZone& fZone = fZones[fzName];
1386 
1387  forAll(fZone, i)
1388  {
1389  const label facei = fZone[i];
1390  if (blockedFace[facei])
1391  {
1392  if
1393  (
1394  mesh_.isInternalFace(facei)
1395  || pbm[pbm.whichPatch(facei)].coupled()
1396  )
1397  {
1398  blockedFace[facei] = false;
1399  nUnblocked++;
1400  }
1401  }
1402  }
1403  }
1404  }
1405 
1406 
1407  // If the faceZones are not synchronised the blockedFace
1408  // might not be synchronised. If you are sure the faceZones
1409  // are synchronised remove below check.
1411  (
1412  mesh_,
1413  blockedFace,
1414  andEqOp<bool>() // combine operator
1415  );
1416  }
1417  reduce(nUnblocked, sumOp<label>());
1418 
1419  if (keepZoneFaces)
1420  {
1421  Info<< "Found " << nUnblocked
1422  << " zoned faces to keep together." << endl;
1423  }
1424 
1425 
1426  // Extend un-blockedFaces with any cyclics
1427  {
1428  boolList separatedCoupledFace(mesh_.nFaces(), false);
1429  selectSeparatedCoupledFaces(separatedCoupledFace);
1430 
1431  label nSeparated = 0;
1432  forAll(separatedCoupledFace, facei)
1433  {
1434  if (separatedCoupledFace[facei])
1435  {
1436  if (blockedFace[facei])
1437  {
1438  blockedFace[facei] = false;
1439  nSeparated++;
1440  }
1441  }
1442  }
1443  reduce(nSeparated, sumOp<label>());
1444  Info<< "Found " << nSeparated
1445  << " separated coupled faces to keep together." << endl;
1446 
1447  nUnblocked += nSeparated;
1448  }
1449 
1450 
1451  if (keepBaffles)
1452  {
1453  const label nBnd = mesh_.nFaces() - mesh_.nInternalFaces();
1454 
1455  labelList coupledFace(mesh_.nFaces(), -1);
1456  {
1457  // Get boundary baffles that need to stay together
1458  List<labelPair> allCouples
1459  (
1461  );
1462 
1463  // Merge with any couples from
1464  // decompositionMethod::setConstraints
1465  forAll(couples, i)
1466  {
1467  const labelPair& baffle = couples[i];
1468  coupledFace[baffle.first()] = baffle.second();
1469  coupledFace[baffle.second()] = baffle.first();
1470  }
1471  forAll(allCouples, i)
1472  {
1473  const labelPair& baffle = allCouples[i];
1474  coupledFace[baffle.first()] = baffle.second();
1475  coupledFace[baffle.second()] = baffle.first();
1476  }
1477  }
1478 
1479  couples.setSize(nBnd);
1480  label nCpl = 0;
1481  forAll(coupledFace, facei)
1482  {
1483  if (coupledFace[facei] != -1 && facei < coupledFace[facei])
1484  {
1485  couples[nCpl++] = labelPair(facei, coupledFace[facei]);
1486  }
1487  }
1488  couples.setSize(nCpl);
1489  }
1490  label nCouples = returnReduce(couples.size(), sumOp<label>());
1491 
1492  if (keepBaffles)
1493  {
1494  Info<< "Found " << nCouples << " baffles to keep together."
1495  << endl;
1496  }
1497 
1498  // if (nUnblocked > 0 || nCouples > 0)
1499  //{
1500  // Info<< "Applying special decomposition to keep baffles"
1501  // << " and zoned faces together." << endl;
1502  //
1503  // distribution = decomposeCombineRegions
1504  // (
1505  // cellWeights,
1506  // blockedFace,
1507  // couples,
1508  // decomposer
1509  // );
1510  //
1511  // labelList nProcCells(distributor.countCells(distribution));
1512  // Pstream::listCombineGather(nProcCells, plusEqOp<label>());
1513  // Pstream::listCombineScatter(nProcCells);
1514  //
1515  // Info<< "Calculated decomposition:" << endl;
1516  // forAll(nProcCells, proci)
1517  // {
1518  // Info<< " " << proci << '\t' << nProcCells[proci]
1519  // << endl;
1520  // }
1521  // Info<< endl;
1522  //}
1523  // else
1524  //{
1525  // // Normal decomposition
1526  // distribution = decomposer.decompose
1527  // (
1528  // mesh_,
1529  // mesh_.cellCentres(),
1530  // cellWeights
1531  // );
1532  //}
1533  }
1534  // else
1535  //{
1536  // // Normal decomposition
1537  // distribution = decomposer.decompose
1538  // (
1539  // mesh_,
1540  // cellWeights
1541  // );
1542  //}
1543 
1544 
1545  // Make sure blockedFace not set on couples
1546  forAll(couples, i)
1547  {
1548  const labelPair& baffle = couples[i];
1549  blockedFace[baffle.first()] = false;
1550  blockedFace[baffle.second()] = false;
1551  }
1552 
1553  distribution = decomposer.decompose
1554  (
1555  mesh_,
1556  cellWeights,
1557  blockedFace,
1558  specifiedProcessorFaces,
1559  specifiedProcessor,
1560  couples // explicit connections
1561  );
1562 
1563  if (debug)
1564  {
1565  labelList nProcCells(distributor.countCells(distribution));
1566  Pout<< "Wanted distribution:" << nProcCells << endl;
1567 
1569  Pstream::listCombineScatter(nProcCells);
1570 
1571  Pout<< "Wanted resulting decomposition:" << endl;
1572  forAll(nProcCells, proci)
1573  {
1574  Pout<< " " << proci << '\t' << nProcCells[proci] << endl;
1575  }
1576  Pout<< endl;
1577  }
1578 
1579  mesh_.clearOut();
1580 
1581  // Do actual sending/receiving of mesh
1582  map = distributor.distribute(distribution);
1583 
1584  // Update numbering of meshRefiner
1585  distribute(map);
1586 
1587  // Set correct instance (for if overwrite)
1588  mesh_.setInstance(name());
1589  setInstance(mesh_.facesInstance());
1590  }
1591 
1592  return map;
1593 }
1594 
1595 
1597 {
1598  label nBoundaryFaces = 0;
1599 
1600  forAll(surfaceIndex_, facei)
1601  {
1602  if (surfaceIndex_[facei] != -1)
1603  {
1604  nBoundaryFaces++;
1605  }
1606  }
1607 
1608  labelList surfaceFaces(nBoundaryFaces);
1609  nBoundaryFaces = 0;
1610 
1611  forAll(surfaceIndex_, facei)
1612  {
1613  if (surfaceIndex_[facei] != -1)
1614  {
1615  surfaceFaces[nBoundaryFaces++] = facei;
1616  }
1617  }
1618  return surfaceFaces;
1619 }
1620 
1621 
1623 {
1624  const faceList& faces = mesh_.faces();
1625 
1626  // Mark all points on faces that will become baffles
1627  PackedBoolList isBoundaryPoint(mesh_.nPoints());
1628  label nBoundaryPoints = 0;
1629 
1630  forAll(surfaceIndex_, facei)
1631  {
1632  if (surfaceIndex_[facei] != -1)
1633  {
1634  const face& f = faces[facei];
1635 
1636  forAll(f, fp)
1637  {
1638  if (isBoundaryPoint.set(f[fp], 1u))
1639  {
1640  nBoundaryPoints++;
1641  }
1642  }
1643  }
1644  }
1645 
1647  // labelList adaptPatchIDs(meshedPatches());
1648  // forAll(adaptPatchIDs, i)
1649  //{
1650  // label patchi = adaptPatchIDs[i];
1651  //
1652  // if (patchi != -1)
1653  // {
1654  // const polyPatch& pp = mesh_.poly().boundary()[patchi];
1655  //
1656  // label facei = pp.start();
1657  //
1658  // forAll(pp, i)
1659  // {
1660  // const face& f = faces[facei];
1661  //
1662  // forAll(f, fp)
1663  // {
1664  // if (isBoundaryPoint.set(f[fp], 1u))
1665  // nBoundaryPoints++;
1666  // }
1667  // }
1668  // facei++;
1669  // }
1670  // }
1671  //}
1672 
1673 
1674  // Pack
1675  labelList boundaryPoints(nBoundaryPoints);
1676  nBoundaryPoints = 0;
1677  forAll(isBoundaryPoint, pointi)
1678  {
1679  if (isBoundaryPoint.get(pointi) == 1u)
1680  {
1681  boundaryPoints[nBoundaryPoints++] = pointi;
1682  }
1683  }
1684 
1685  return boundaryPoints;
1686 }
1687 
1688 
1690 (
1691  const polyMesh& mesh,
1692  const labelList& patchIDs
1693 )
1694 {
1696 
1697  // Count faces.
1698  label nFaces = 0;
1699 
1700  forAll(patchIDs, i)
1701  {
1702  const polyPatch& pp = patches[patchIDs[i]];
1703 
1704  nFaces += pp.size();
1705  }
1706 
1707  // Collect faces.
1708  labelList addressing(nFaces);
1709  nFaces = 0;
1710 
1711  forAll(patchIDs, i)
1712  {
1713  const polyPatch& pp = patches[patchIDs[i]];
1714 
1715  label meshFacei = pp.start();
1716 
1717  forAll(pp, i)
1718  {
1719  addressing[nFaces++] = meshFacei++;
1720  }
1721  }
1722 
1724  (
1726  (
1727  IndirectList<face>(mesh.faces(), addressing),
1728  mesh.points()
1729  )
1730  );
1731 }
1732 
1733 
1735 (
1736  const pointMesh& pMesh,
1737  const labelList& adaptPatchIDs
1738 )
1739 {
1740  // Construct displacement field.
1741  const pointBoundaryMesh& pointPatches = pMesh.boundary();
1742 
1743  wordList patchFieldTypes
1744  (
1745  pointPatches.size(),
1747  );
1748 
1749  forAll(adaptPatchIDs, i)
1750  {
1751  patchFieldTypes[adaptPatchIDs[i]] =
1753  }
1754 
1755  forAll(pointPatches, patchi)
1756  {
1757  if (isA<processorPointPatch>(pointPatches[patchi]))
1758  {
1760  }
1761  else if (isA<cyclicPointPatch>(pointPatches[patchi]))
1762  {
1764  }
1765  }
1766 
1767  // Note: time().name() instead of meshRefinement::name() since
1768  // postprocessable field.
1770  (
1772  (
1773  "pointDisplacement",
1774  pMesh,
1776  patchFieldTypes
1777  )
1778  );
1779  return tfld;
1780 }
1781 
1782 
1784 {
1785  const faceZoneList& fZones = mesh.faceZones();
1786 
1787  // Check any zones are present anywhere and in same order
1788 
1789  {
1790  List<wordList> zoneNames(Pstream::nProcs());
1791  zoneNames[Pstream::myProcNo()] = fZones.toc();
1792  Pstream::gatherList(zoneNames);
1793  Pstream::scatterList(zoneNames);
1794  // All have same data now. Check.
1795  forAll(zoneNames, proci)
1796  {
1797  if (proci != Pstream::myProcNo())
1798  {
1799  if (zoneNames[proci] != zoneNames[Pstream::myProcNo()])
1800  {
1802  << "faceZones are not synchronised on processors." << nl
1803  << "Processor " << proci << " has faceZones "
1804  << zoneNames[proci] << nl
1805  << "Processor " << Pstream::myProcNo()
1806  << " has faceZones "
1807  << zoneNames[Pstream::myProcNo()] << nl
1808  << exit(FatalError);
1809  }
1810  }
1811  }
1812  }
1813 
1814  // Check that coupled faces are present on both sides.
1815 
1816  labelList faceToZone(mesh.nFaces() - mesh.nInternalFaces(), -1);
1817 
1818  forAll(fZones, zonei)
1819  {
1820  const faceZone& fZone = fZones[zonei];
1821 
1822  forAll(fZone, i)
1823  {
1824  const label bFacei = fZone[i] - mesh.nInternalFaces();
1825 
1826  if (bFacei >= 0)
1827  {
1828  if (faceToZone[bFacei] == -1)
1829  {
1830  faceToZone[bFacei] = zonei;
1831  }
1832  else if (faceToZone[bFacei] == zonei)
1833  {
1835  << "Face " << fZone[i] << " in zone "
1836  << fZone.name()
1837  << " is twice in zone!"
1838  << abort(FatalError);
1839  }
1840  }
1841  }
1842  }
1843 
1844  labelList neiFaceToZone(faceToZone);
1845  syncTools::swapBoundaryFaceList(mesh, neiFaceToZone);
1846 
1847  forAll(faceToZone, i)
1848  {
1849  if (faceToZone[i] != neiFaceToZone[i])
1850  {
1852  << "Face " << mesh.nInternalFaces() + i
1853  << " is in zone " << faceToZone[i]
1854  << ", its coupled face is in zone " << neiFaceToZone[i]
1855  << abort(FatalError);
1856  }
1857  }
1858 }
1859 
1860 
1862 (
1863  const polyMesh& mesh,
1864  const PackedBoolList& isMasterEdge,
1865  const labelList& meshPoints,
1866  const edgeList& edges,
1867  scalarField& edgeWeights,
1868  scalarField& invSumWeight
1869 )
1870 {
1871  const pointField& pts = mesh.points();
1872 
1873  // Calculate edgeWeights and inverse sum of edge weights
1874  edgeWeights.setSize(isMasterEdge.size());
1875  invSumWeight.setSize(meshPoints.size());
1876 
1877  forAll(edges, edgei)
1878  {
1879  const edge& e = edges[edgei];
1880  scalar eMag = max
1881  (
1882  small,
1883  mag
1884  (
1885  pts[meshPoints[e[1]]]
1886  - pts[meshPoints[e[0]]]
1887  )
1888  );
1889  edgeWeights[edgei] = 1.0/eMag;
1890  }
1891 
1892  // Sum per point all edge weights
1893  weightedSum
1894  (
1895  mesh,
1896  isMasterEdge,
1897  meshPoints,
1898  edges,
1899  edgeWeights,
1900  scalarField(meshPoints.size(), 1.0), // data
1901  invSumWeight
1902  );
1903 
1904  // Inplace invert
1905  forAll(invSumWeight, pointi)
1906  {
1907  scalar w = invSumWeight[pointi];
1908 
1909  if (w > 0.0)
1910  {
1911  invSumWeight[pointi] = 1.0/w;
1912  }
1913  }
1914 }
1915 
1916 
1918 (
1919  const word& name,
1920  const dictionary& patchInfo
1921 )
1922 {
1923  const polyBoundaryMesh& pbm = mesh_.poly().boundary();
1924 
1925  const label meshedI = findIndex(meshedPatches_, name);
1926 
1927  if (meshedI != -1)
1928  {
1929  // Already there. Get corresponding polypatch
1930  return pbm.findIndex(name);
1931  }
1932  else
1933  {
1934  // Add patch
1935 
1936  label patchi = pbm.findIndex(name);
1937  if (patchi == -1)
1938  {
1939  patchi = pbm.size();
1940  forAll(pbm, i)
1941  {
1942  const polyPatch& pp = pbm[i];
1943 
1944  if (isA<processorPolyPatch>(pp))
1945  {
1946  patchi = i;
1947  break;
1948  }
1949  }
1950 
1951  dictionary patchDict(patchInfo);
1952  patchDict.set("nFaces", 0);
1953  patchDict.set("startFace", 0);
1954  autoPtr<polyPatch> ppPtr
1955  (
1957  (
1958  name,
1959  patchDict,
1960  0,
1961  pbm
1962  )
1963  );
1964  mesh_.addPatch(patchi, ppPtr());
1965  }
1966 
1967  // Store
1968  meshedPatches_.append(name);
1969 
1970  return patchi;
1971  }
1972 }
1973 
1974 
1976 {
1977  mesh_.addedPatches();
1978 }
1979 
1980 
1982 {
1983  const polyBoundaryMesh& patches = mesh_.poly().boundary();
1984 
1985  DynamicList<label> patchIDs(meshedPatches_.size());
1986  forAll(meshedPatches_, i)
1987  {
1988  const label patchi = patches.findIndex(meshedPatches_[i]);
1989 
1990  if (patchi == -1)
1991  {
1993  << "Problem : did not find patch " << meshedPatches_[i]
1994  << endl << "Valid patches are " << patches.names()
1995  << abort(FatalError);
1996  }
1997 
1998  if (!patches[patchi].constraint())
1999  {
2000  patchIDs.append(patchi);
2001  }
2002  }
2003 
2004  return patchIDs;
2005 }
2006 
2007 
2009 {
2010  const polyBoundaryMesh& patches = mesh_.poly().boundary();
2011 
2013  {
2014  if (isA<coupledPolyPatch>(patches[patchi]))
2015  {
2016  const coupledPolyPatch& cpp =
2017  refCast<const coupledPolyPatch>(patches[patchi]);
2018 
2019  if (cpp.transform().transformsPosition())
2020  {
2021  forAll(cpp, i)
2022  {
2023  selected[cpp.start() + i] = true;
2024  }
2025  }
2026  }
2027  }
2028 }
2029 
2030 
2032 (
2033  const polyMesh& mesh,
2034  const labelList& cellRegion,
2035  const vector& perturbVec,
2036  const point& location
2037 )
2038 {
2039  const meshSearch& searchEngine = meshSearch::New(mesh);
2040 
2041  label regioni = -1;
2042  label celli = searchEngine.findCell(location);
2043  if (celli != -1)
2044  {
2045  regioni = cellRegion[celli];
2046  }
2047  reduce(regioni, maxOp<label>());
2048 
2049  if (regioni == -1)
2050  {
2051  // See if we can perturb a bit
2052  celli = searchEngine.findCell(location + perturbVec);
2053  if (celli != -1)
2054  {
2055  regioni = cellRegion[celli];
2056  }
2057  reduce(regioni, maxOp<label>());
2058  }
2059 
2060  return regioni;
2061 }
2062 
2063 
2065 (
2066  const polyMesh& mesh,
2067  labelList& cellRegion,
2068  const vector& perturbVec,
2069  const refinementParameters::cellSelectionPoints& selectionPoints
2070 )
2071 {
2072  // List of all cells selected cells
2073  PackedBoolList selectedCells(mesh.nCells());
2074 
2075  if (selectionPoints.outside().size())
2076  {
2077  // Select all cells before removing those in regions
2078  // containing locations in selectionPoints.outside()
2079  selectedCells = true;
2080 
2081  // For each of the selectionPoints.outside() find the corresponding
2082  // region and deselect the cells
2083  forAll(selectionPoints.outside(), i)
2084  {
2085  // Find the region corresponding to the selectionPoints.outside()[i]
2086  const label regioni = findRegion
2087  (
2088  mesh,
2089  cellRegion,
2090  perturbVec,
2091  selectionPoints.outside()[i]
2092  );
2093 
2094  // Deselect the cells in the region from selectedCells
2095  forAll(cellRegion, celli)
2096  {
2097  if (cellRegion[celli] == regioni)
2098  {
2099  selectedCells[celli] = false;
2100  }
2101  }
2102  }
2103  }
2104 
2105  // For each of the selectionPoints.inside() find the corresponding region
2106  // and select the cells
2107  forAll(selectionPoints.inside(), i)
2108  {
2109  // Find the region corresponding to the selectionPoints.inside()[i]
2110  const label regioni = findRegion
2111  (
2112  mesh,
2113  cellRegion,
2114  perturbVec,
2115  selectionPoints.inside()[i]
2116  );
2117 
2118  // Add all the cells in the region to selectedCells
2119  forAll(cellRegion, celli)
2120  {
2121  if (cellRegion[celli] == regioni)
2122  {
2123  selectedCells[celli] = true;
2124  }
2125  }
2126  }
2127 
2128  // For all unmarked cells set cellRegion to -1
2129  forAll(selectedCells, celli)
2130  {
2131  if (!selectedCells[celli])
2132  {
2133  cellRegion[celli] = -1;
2134  }
2135  }
2136 }
2137 
2138 
2140 (
2141  const labelList& globalToMasterPatch,
2142  const labelList& globalToSlavePatch,
2143  const refinementParameters::cellSelectionPoints& selectionPoints
2144 )
2145 {
2146  // Force calculation of face decomposition (used in findCell)
2147  (void)mesh_.tetBasePtIs();
2148 
2149  // Determine connected regions. regionSplit is the labelList with the
2150  // region per cell.
2151 
2152  boolList blockedFace(mesh_.nFaces(), false);
2153  selectSeparatedCoupledFaces(blockedFace);
2154 
2155  regionSplit cellRegion(mesh_, blockedFace);
2156 
2157  findRegions
2158  (
2159  mesh_,
2160  cellRegion,
2161  mergeDistance_*vector::one,
2162  selectionPoints
2163  );
2164 
2165  // Subset
2166  // ~~~~~~
2167 
2168  // Get cells to remove
2169  DynamicList<label> cellsToRemove(mesh_.nCells());
2170  forAll(cellRegion, celli)
2171  {
2172  if (cellRegion[celli] == -1)
2173  {
2174  cellsToRemove.append(celli);
2175  }
2176  }
2177  cellsToRemove.shrink();
2178 
2179  const label nCellsToRemove = returnReduce
2180  (
2181  cellsToRemove.size(),
2182  sumOp<label>()
2183  );
2184 
2185  if (nCellsToRemove)
2186  {
2187  label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
2188  reduce(nCellsToKeep, sumOp<label>());
2189 
2190  Info<< "Keeping all cells in regions containing any point in "
2191  << selectionPoints.inside() << endl
2192  << "Selected for keeping : " << nCellsToKeep << " cells." << endl;
2193 
2194  // Remove cells
2195  removeCells cellRemover(mesh_);
2196 
2197  const labelList exposedFaces
2198  (
2199  cellRemover.getExposedFaces(cellsToRemove)
2200  );
2201 
2202  labelList exposedPatch;
2203 
2204  const label nExposedFaces =
2205  returnReduce(exposedFaces.size(), sumOp<label>());
2206 
2207  if (nExposedFaces)
2208  {
2209  // Patch for exposed faces for lack of anything sensible.
2210  label defaultPatch = 0;
2211  if (globalToMasterPatch.size())
2212  {
2213  defaultPatch = globalToMasterPatch[0];
2214  }
2215 
2217  << "Removing non-reachable cells exposes "
2218  << nExposedFaces << " internal or coupled faces." << endl
2219  << " These get put into patch " << defaultPatch << endl;
2220 
2221  exposedPatch.setSize(exposedFaces.size(), defaultPatch);
2222  }
2223 
2224  return doRemoveCells
2225  (
2226  cellsToRemove,
2227  exposedFaces,
2228  exposedPatch,
2229  cellRemover
2230  );
2231  }
2232  else
2233  {
2234  return autoPtr<polyTopoChangeMap>();
2235  }
2236 }
2237 
2238 
2240 {
2241  // mesh_ already distributed; distribute my member data
2242 
2243  // Explicitly redistribute the hexRef8 meshObject
2244  meshCutter_.distribute(map);
2245 
2246  // surfaceIndex is face data.
2247  map.distributeFaceData(surfaceIndex_);
2248 
2249  // maintainedFaces are indices of faces.
2250  forAll(userFaceData_, i)
2251  {
2252  map.distributeFaceData(userFaceData_[i].second());
2253  }
2254 
2255  // Redistribute surface and any fields on it.
2256  {
2257  // Get local mesh bounding box. Single box for now.
2259  treeBoundBox& bb = meshBb[0];
2260  bb = treeBoundBox(mesh_.points()).extend(1e-4);
2261 
2262  // Distribute all geometry (so refinementSurfaces and refinementRegions)
2263  searchableSurfaceList& geometry =
2264  const_cast<searchableSurfaceList&>(surfaces_.geometry());
2265 
2266  forAll(geometry, i)
2267  {
2269  autoPtr<distributionMap> pointMap;
2270  geometry[i].distribute
2271  (
2272  meshBb,
2273  false, // do not keep outside triangles
2274  faceMap,
2275  pointMap
2276  );
2277 
2278  if (faceMap.valid())
2279  {
2280  // (ab)use the instance() to signal current modification time
2281  geometry[i].instance() = geometry[i].time().name();
2282  }
2283 
2284  faceMap.clear();
2285  pointMap.clear();
2286  }
2287  }
2288 }
2289 
2290 
2292 (
2293  const polyTopoChangeMap& map,
2294  const labelList& changedFaces
2295 )
2296 {
2297  // Update surfaceIndex
2298  updateList(map.faceMap(), label(-1), surfaceIndex_);
2299 
2300  // Update cached intersection information
2301  updateIntersections(changedFaces);
2302 
2303  // Update maintained faces
2304  forAll(userFaceData_, i)
2305  {
2306  labelList& data = userFaceData_[i].second();
2307 
2308  if (userFaceData_[i].first() == KEEPALL)
2309  {
2310  // extend list with face-from-face data
2311  updateList(map.faceMap(), label(-1), data);
2312  }
2313  else if (userFaceData_[i].first() == MASTERONLY)
2314  {
2315  // keep master only
2316  labelList newFaceData(map.faceMap().size(), -1);
2317 
2318  forAll(newFaceData, facei)
2319  {
2320  label oldFacei = map.faceMap()[facei];
2321 
2322  if (oldFacei >= 0 && map.reverseFaceMap()[oldFacei] == facei)
2323  {
2324  newFaceData[facei] = data[oldFacei];
2325  }
2326  }
2327  data.transfer(newFaceData);
2328  }
2329  else
2330  {
2331  // remove any face that has been refined i.e. referenced more than
2332  // once.
2333 
2334  // 1. Determine all old faces that get referenced more than once.
2335  // These get marked with -1 in reverseFaceMap
2336  labelList reverseFaceMap(map.reverseFaceMap());
2337 
2338  forAll(map.faceMap(), facei)
2339  {
2340  const label oldFacei = map.faceMap()[facei];
2341 
2342  if (oldFacei >= 0)
2343  {
2344  if (reverseFaceMap[oldFacei] != facei)
2345  {
2346  // facei is slave face. Mark old face.
2347  reverseFaceMap[oldFacei] = -1;
2348  }
2349  }
2350  }
2351 
2352  // 2. Map only faces with intact reverseFaceMap
2353  labelList newFaceData(map.faceMap().size(), -1);
2354  forAll(newFaceData, facei)
2355  {
2356  const label oldFacei = map.faceMap()[facei];
2357 
2358  if (oldFacei >= 0)
2359  {
2360  if (reverseFaceMap[oldFacei] == facei)
2361  {
2362  newFaceData[facei] = data[oldFacei];
2363  }
2364  }
2365  }
2366  data.transfer(newFaceData);
2367  }
2368  }
2369 }
2370 
2371 
2373 {
2374  // Set correct instance (for if overwrite)
2375  mesh_.setInstance(name());
2376  // setInstance(mesh_.facesInstance());
2377 
2378  bool writeOk = mesh_.write();
2379 
2380  // Make sure that any distributed surfaces (so ones which probably have
2381  // been changed) get written as well.
2382  // Note: should ideally have some 'modified' flag to say whether it
2383  // has been changed or not.
2384  searchableSurfaceList& geometry =
2385  const_cast<searchableSurfaceList&>(surfaces_.geometry());
2386 
2387  forAll(geometry, i)
2388  {
2389  searchableSurface& s = geometry[i];
2390 
2391  // Check if instance() of surface is not constant or system.
2392  // Is good hint that surface is distributed.
2393  if
2394  (
2395  s.instance() != s.time().system()
2396  && s.instance() != s.time().caseSystem()
2397  && s.instance() != s.time().constant()
2398  && s.instance() != s.time().caseConstant()
2399  )
2400  {
2401  // Make sure it gets written to current time, not constant.
2402  s.instance() = s.time().name();
2403  writeOk = writeOk && s.write();
2404  }
2405  }
2406 
2407  return writeOk;
2408 }
2409 
2410 
2412 (
2413  const polyMesh& mesh,
2414  const labelList& meshPoints
2415 )
2416 {
2417  const globalIndex globalPoints(meshPoints.size());
2418 
2419  labelList myPoints(meshPoints.size());
2420  forAll(meshPoints, pointi)
2421  {
2422  myPoints[pointi] = globalPoints.toGlobal(pointi);
2423  }
2424 
2426  (
2427  mesh,
2428  meshPoints,
2429  myPoints,
2430  minEqOp<label>(),
2431  labelMax
2432  );
2433 
2434 
2435  PackedBoolList isPatchMasterPoint(meshPoints.size());
2436  forAll(meshPoints, pointi)
2437  {
2438  if (myPoints[pointi] == globalPoints.toGlobal(pointi))
2439  {
2440  isPatchMasterPoint[pointi] = true;
2441  }
2442  }
2443 
2444  return isPatchMasterPoint;
2445 }
2446 
2447 
2449 (
2450  const polyMesh& mesh,
2451  const labelList& meshEdges
2452 )
2453 {
2454  const globalIndex globalEdges(meshEdges.size());
2455 
2456  labelList myEdges(meshEdges.size());
2457  forAll(meshEdges, edgei)
2458  {
2459  myEdges[edgei] = globalEdges.toGlobal(edgei);
2460  }
2461 
2463  (
2464  mesh,
2465  meshEdges,
2466  myEdges,
2467  minEqOp<label>(),
2468  labelMax
2469  );
2470 
2471 
2472  PackedBoolList isMasterEdge(meshEdges.size());
2473  forAll(meshEdges, edgei)
2474  {
2475  if (myEdges[edgei] == globalEdges.toGlobal(edgei))
2476  {
2477  isMasterEdge[edgei] = true;
2478  }
2479  }
2480 
2481  return isMasterEdge;
2482 }
2483 
2484 
2485 void Foam::meshRefinement::printMeshInfo(const bool debug, const string& msg)
2486 const
2487 {
2488  const globalMeshData& pData = mesh_.globalData();
2489 
2490  if (debug)
2491  {
2492  Pout<< msg.c_str()
2493  << " : cells(local):" << mesh_.nCells()
2494  << " faces(local):" << mesh_.nFaces()
2495  << " points(local):" << mesh_.nPoints()
2496  << endl;
2497  }
2498 
2499  {
2500  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
2501  label nMasterFaces = 0;
2502  forAll(isMasterFace, i)
2503  {
2504  if (isMasterFace[i])
2505  {
2506  nMasterFaces++;
2507  }
2508  }
2509 
2510  PackedBoolList isMeshMasterPoint(syncTools::getMasterPoints(mesh_));
2511  label nMasterPoints = 0;
2512  forAll(isMeshMasterPoint, i)
2513  {
2514  if (isMeshMasterPoint[i])
2515  {
2516  nMasterPoints++;
2517  }
2518  }
2519 
2520  Info<< msg.c_str()
2521  << " : cells:" << pData.nTotalCells()
2522  << " faces:" << returnReduce(nMasterFaces, sumOp<label>())
2523  << " points:" << returnReduce(nMasterPoints, sumOp<label>())
2524  << endl;
2525  }
2526 
2527 
2528  // if (debug)
2529  {
2530  const labelList& cellLevel = meshCutter_.cellLevel();
2531 
2532  labelList nCells(gMax(cellLevel) + 1, 0);
2533 
2534  forAll(cellLevel, celli)
2535  {
2536  nCells[cellLevel[celli]]++;
2537  }
2538 
2541 
2542  Info<< "Cells per refinement level:" << endl;
2543  forAll(nCells, leveli)
2544  {
2545  Info<< " " << leveli << '\t' << nCells[leveli]
2546  << endl;
2547  }
2548  }
2549 }
2550 
2551 
2553 {
2554  if (overwrite_ && mesh_.time().timeIndex() == 0)
2555  {
2556  return oldInstance_;
2557  }
2558  else
2559  {
2560  return mesh_.time().name();
2561  }
2562 }
2563 
2564 
2566 {
2567  // Note: use time().name(), not meshRefinement::name()
2568  // so as to dump the fields to 0, not to constant.
2569  {
2570  volScalarField volRefLevel
2571  (
2572  IOobject
2573  (
2574  "cellLevel",
2575  mesh_.time().name(),
2576  mesh_,
2579  false
2580  ),
2581  mesh_,
2583  );
2584 
2585  const labelList& cellLevel = meshCutter_.cellLevel();
2586 
2587  forAll(volRefLevel, celli)
2588  {
2589  volRefLevel[celli] = cellLevel[celli];
2590  }
2591 
2592  volRefLevel.write();
2593  }
2594 
2595  // Dump pointLevel
2596  {
2597  const pointMesh& pMesh = pointMesh::New(mesh_);
2598 
2599  pointScalarField pointRefLevel
2600  (
2601  IOobject
2602  (
2603  "pointLevel",
2604  mesh_.time().name(),
2605  mesh_,
2608  false
2609  ),
2610  pMesh,
2612  );
2613 
2614  const labelList& pointLevel = meshCutter_.pointLevel();
2615 
2616  forAll(pointRefLevel, pointi)
2617  {
2618  pointRefLevel[pointi] = pointLevel[pointi];
2619  }
2620 
2621  pointRefLevel.write();
2622  }
2623 }
2624 
2625 
2627 {
2628  {
2629  const pointField& cellCentres = mesh_.cellCentres();
2630 
2631  OFstream str(prefix + "_edges.obj");
2632  label vertI = 0;
2633  Pout<< "meshRefinement::dumpIntersections :"
2634  << " Writing cellcentre-cellcentre intersections to file "
2635  << str.name() << endl;
2636 
2637 
2638  // Redo all intersections
2639  // ~~~~~~~~~~~~~~~~~~~~~~
2640 
2641  // Get boundary face centre and level. Coupled aware.
2642  labelList neiLevel(mesh_.nFaces() - mesh_.nInternalFaces());
2643  pointField neiCc(mesh_.nFaces() - mesh_.nInternalFaces());
2644  calcNeighbourData(neiLevel, neiCc);
2645 
2646  labelList intersectionFaces(intersectedFaces());
2647 
2648  // Collect segments we want to test for
2649  pointField start(intersectionFaces.size());
2650  pointField end(intersectionFaces.size());
2651 
2652  forAll(intersectionFaces, i)
2653  {
2654  const label facei = intersectionFaces[i];
2655  start[i] = cellCentres[mesh_.faceOwner()[facei]];
2656 
2657  if (mesh_.isInternalFace(facei))
2658  {
2659  end[i] = cellCentres[mesh_.faceNeighbour()[facei]];
2660  }
2661  else
2662  {
2663  end[i] = neiCc[facei-mesh_.nInternalFaces()];
2664  }
2665  }
2666 
2667  // Extend segments a bit
2668  {
2669  const vectorField smallVec(rootSmall*(end-start));
2670  start -= smallVec;
2671  end += smallVec;
2672  }
2673 
2674 
2675  // Do tests in one go
2676  labelList surfaceHit;
2677  List<pointIndexHit> surfaceHitInfo;
2678  surfaces_.findAnyIntersection
2679  (
2680  start,
2681  end,
2682  surfaceHit,
2683  surfaceHitInfo
2684  );
2685 
2686  forAll(intersectionFaces, i)
2687  {
2688  if (surfaceHit[i] != -1)
2689  {
2690  meshTools::writeOBJ(str, start[i]);
2691  vertI++;
2692  meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
2693  vertI++;
2694  meshTools::writeOBJ(str, end[i]);
2695  vertI++;
2696  str << "l " << vertI-2 << ' ' << vertI-1 << nl
2697  << "l " << vertI-1 << ' ' << vertI << nl;
2698  }
2699  }
2700  }
2701 
2702  Pout<< endl;
2703 }
2704 
2705 
2707 (
2708  const debugType debugFlags,
2709  const writeType writeFlags,
2710  const fileName& prefix
2711 ) const
2712 {
2713  if (writeFlags & WRITEMESH)
2714  {
2715  write();
2716  }
2717 
2718  if (writeFlags && !(writeFlags & NOWRITEREFINEMENT))
2719  {
2720  // The hexRef8 meshObject state writing is now handled by polyMesh
2721  // meshCutter_.write();
2722  surfaceIndex_.write();
2723  }
2724 
2725  if (writeFlags & WRITELEVELS)
2726  {
2727  dumpRefinementLevel();
2728  }
2729 
2730  if (debugFlags & OBJINTERSECTIONS && prefix.size())
2731  {
2732  dumpIntersections(prefix);
2733  }
2734 }
2735 
2736 
2738 {
2739  return writeLevel_;
2740 }
2741 
2742 
2744 {
2745  writeLevel_ = flags;
2746 }
2747 
2748 
2750 {
2751  return outputLevel_;
2752 }
2753 
2754 
2756 {
2757  outputLevel_ = flags;
2758 }
2759 
2760 
2761 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
static pointMesh & New(const word &name, const polyMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
wordList toc() const
Return the table of contents.
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:252
SubField< vector > subField
Declare type of subField.
Definition: Field.H:101
Generic GeometricField class.
static tmp< GeometricField< Type, pointMesh, Field > > New(const word &name, const Internal &, const PtrList< Patch > &, const HashPtrTable< Source > &=HashPtrTable< Source >())
Return a temporary field constructed from name,.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
A List with indirect addressing.
Definition: IndirectList.H:105
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:55
Output to file stream.
Definition: OFstream.H:87
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:121
A bit-packed bool list.
void set(const PackedList< 1 > &)
Set specified bits.
label size() const
Number of entries.
Definition: PackedListI.H:695
unsigned int get(const label) const
Get value at index I.
Definition: PackedListI.H:938
const Type & second() const
Return second.
Definition: PairI.H:121
const Type & first() const
Return first.
Definition: PairI.H:107
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
A List obtained as a section of another List.
Definition: SubList.H:56
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static const Form zero
Definition: VectorSpace.H:118
static const Form one
Definition: VectorSpace.H:119
const word & name() const
Return name.
Definition: Zone.H:171
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
void clear()
Delete object (if the pointer is valid) and set pointer to.
Definition: autoPtrI.H:126
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
virtual const transformer & transform() const =0
Return transformation between the coupled patches.
Abstract base class for decomposition.
virtual labelList decompose(const pointField &points, const scalarField &pointWeights)
Return for every coordinate the wanted processor number.
void setConstraints(const polyMesh &mesh, boolList &blockedFace, PtrList< labelList > &specifiedProcessorFaces, labelList &specifiedProcessor, List< labelPair > &explicitConnections)
Helper: extract constraints:
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
Base class for statistical distributions.
Definition: distribution.H:76
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
Definition: ops.H:70
Named list of face indices representing a sub-set of the mesh faces.
Definition: faceZone.H:66
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
A class for handling file names.
Definition: fileName.H:82
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
autoPtr< polyDistributionMap > distribute(const labelList &dist)
Send cells to neighbours according to distribution.
static labelList countCells(const labelList &)
Helper function: count cells per processor in wanted distribution.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:932
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
label nTotalCells() const
Return total number of cells in decomposed mesh.
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:101
Refinement of (split) hexes using polyTopoChange.
Definition: hexRef8.H:73
scalar level0EdgeLength() const
Typical edge length between unrefined points.
Definition: hexRef8.H:415
const labelIOList & cellLevel() const
Definition: hexRef8.H:399
label faceLevel(const label facei) const
Gets level such that the face has four points <= level.
Definition: hexRef8.C:675
static labelList findDuplicateFaces(const primitiveMesh &, const labelList &)
Helper routine to find baffles (two boundary faces using the.
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
autoPtr< polyTopoChangeMap > splitMeshRegions(const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const refinementParameters::cellSelectionPoints &selectionPoints)
Split mesh according to selectionPoints.
labelList intersectedFaces() const
Get faces with intersection.
labelList intersectedPoints() const
Get points on surfaces with intersection and boundary faces.
meshRefinement(fvMesh &mesh, const dictionary &refineDict, const scalar mergeDistance, const bool overwrite, refinementSurfaces &, const refinementFeatures &, const refinementRegions &)
Construct from components.
static void testSyncPointList(const string &msg, const polyMesh &mesh, const List< scalar > &fld)
void checkData()
Debugging: check that all faces still obey start()>end()
const refinementSurfaces & surfaces() const
Reference to surface search engines.
void topoChange(const polyTopoChangeMap &, const labelList &changedFaces)
Update for external change to mesh. changedFaces are in new mesh.
word name() const
Replacement for Time::name() : return oldInstance (if.
static const NamedEnum< IOwriteType, 5 > IOwriteTypeNames
void printMeshInfo(const bool, const string &) const
Print some mesh stats.
void distribute(const polyDistributionMap &)
Update local numbering for mesh redistribution.
void dumpRefinementLevel() const
Write refinement level as volScalarFields for postprocessing.
static void calculateEdgeWeights(const polyMesh &mesh, const PackedBoolList &isMasterEdge, const labelList &meshPoints, const edgeList &edges, scalarField &edgeWeights, scalarField &invSumWeight)
Helper: calculate edge weights (1/length)
label countHits() const
Count number of intersections (local)
static const NamedEnum< IOdebugType, 5 > IOdebugTypeNames
labelList meshedPatches() const
Get patchIDs for patches added in addMeshedPatch.
static void checkCoupledFaceZones(const polyMesh &)
Helper function: check that face zones are synced.
label addMeshedPatch(const word &name, const dictionary &)
Add patch originating from meshing. Update meshedPatches_.
void selectSeparatedCoupledFaces(boolList &) const
Select coupled faces that are not collocated.
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
static const NamedEnum< IOoutputType, 1 > IOoutputTypeNames
static PackedBoolList getMasterEdges(const polyMesh &mesh, const labelList &meshEdges)
Determine master edge for subset of edges. If coupled.
static PackedBoolList getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
autoPtr< polyDistributionMap > balance(const bool keepZoneFaces, const bool keepBaffles, const scalarField &cellWeights, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Redecompose according to cell count.
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
bool write() const
Write mesh and all data.
void setInstance(const fileName &)
Set instance of all local IOobjects.
autoPtr< polyTopoChangeMap > splitFaces(const labelList &splitFaces, const labelPairList &splits)
Split faces into two.
static label findRegion(const polyMesh &, const labelList &cellRegion, const vector &perturbVec, const point &location)
Find region point is in. Uses optional perturbation to re-test.
static writeType writeLevel()
Get/set write level.
static void findRegions(const polyMesh &, labelList &cellRegion, const vector &perturbVec, const refinementParameters::cellSelectionPoints &selectionPoints)
Find regions points are in and update cellRegion.
void dumpIntersections(const fileName &prefix) const
Debug: Write intersection information to OBJ format.
static outputType outputLevel()
Get/set output level.
void addedMeshedPatches()
Complete adding patches originating from meshing.
Mesh object that implements searches within the local cells and faces.
Definition: meshSearch.H:59
label findCell(const point &p, const pointInCellShapes=pointInCellShapes::tets) const
Find the cell containing the given point.
Definition: meshSearch.C:173
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Definition: meshSearch.C:61
Foam::pointBoundaryMesh.
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:52
const pointBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: pointMesh.H:146
Foam::polyBoundaryMesh.
label findIndex(const word &patchName) const
Find patch index given a name.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
void distributeFaceData(List< T > &lst) const
Distribute list of face data.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:432
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return a pointer to a new patch created on freestore from.
Definition: polyPatchNew.C:32
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:277
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseFaceMap() const
Reverse face map.
const labelList & faceMap() const
Old face map.
Direct mesh changes based on v1.3 polyTopoChange syntax.
autoPtr< polyTopoChangeMap > changeMesh(polyMesh &mesh, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
void modifyFace(const face &f, const label facei, const label own, const label nei, const bool flipFaceFlux, const label patchID)
Modify vertices or cell of face.
label addFace(const face &f, const label own, const label nei, const label masterFaceID, const bool flipFaceFlux, const label patchID)
Add face to cells and return new face index.
label nInternalFaces() const
const vectorField & cellCentres() const
label nCells() const
label nPoints() const
label nFaces() const
Encapsulates queries for features.
Class to hold the points to select cells inside and outside.
const List< point > & outside() const
Return the points outside the surface region to deselect cells.
const List< point > & inside() const
Return the points inside the surface regions to selected cells.
Encapsulates queries for volume refinement ('refine all cells within shell').
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
void setMinLevelFields(const refinementRegions &shells, const scalar level0EdgeLength, const bool extendedRefinementSpan)
Calculate the refinement level for every element.
virtual bool write(const bool write=true) const
Write using setting from DB.
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:118
Given list of cells to remove insert all the topology changes.
Definition: removeCells.H:60
void setRefinement(const labelList &cellsToRemove, const labelList &facesToExpose, const labelList &patchIDs, polyTopoChange &) const
Play commands into polyTopoChange to remove cells.
Definition: removeCells.C:175
void topoChange(const polyTopoChangeMap &)
Force recalculation of locally stored data on topological change.
Definition: removeCells.H:115
labelList getExposedFaces(const labelList &cellsToRemove) const
Get labels of exposed faces.
Definition: removeCells.C:69
Container for searchableSurfaces.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
static void syncPointList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh points.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
static PackedBoolList getMasterPoints(const polyMesh &)
Get per point whether it is uncoupled or a master of a.
Definition: syncTools.C:65
static PackedBoolList getMasterFaces(const polyMesh &)
Get per face whether it is uncoupled or a master of a.
Definition: syncTools.C:153
static void syncEdgeList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh edges.
static void syncBoundaryFacePositions(const polyMesh &mesh, UList< point > &l, const CombineOp &cop)
Synchronise locations on boundary faces only.
Definition: syncTools.H:369
static void syncFaceList(const polyMesh &mesh, UList< T > &l, const CombineOp &cop)
Synchronise values on all mesh faces.
Definition: syncTools.H:387
static void swapBoundaryFacePositions(const polyMesh &mesh, UList< point > &l)
Swap coupled positions.
Definition: syncTools.H:452
A class for managing temporary objects.
Definition: tmp.H:55
bool transformsPosition() const
Return true if the transformer transforms a point.
Definition: transformerI.H:146
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:90
treeBoundBox extend(const scalar s) const
Return asymmetrically extended bounding box, with guaranteed.
A class for handling words, derived from string.
Definition: word.H:63
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const fvPatchList & patches
#define WarningInFunction
Report a warning using Foam::Warning.
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
const doubleScalar e
Definition: doubleScalar.H:106
const dimensionSet & dimless
Definition: dimensions.C:138
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
const dimensionSet & dimLength
Definition: dimensions.C:141
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
messageStream Info
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
vector point
Point is a vector.
Definition: point.H:41
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Field< vector > vectorField
Specialisation of Field<T> for vector.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Type gMax(const UList< Type > &f, const label comm)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:213
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
static const label labelMax
Definition: label.H:62
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
defineTypeNameAndDebug(atmosphericBoundaryLayer, 0)
UList< label > labelUList
Definition: UList.H:65
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
static const char nl
Definition: Ostream.H:297
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
labelList f(nPoints)
List< treeBoundBox > meshBb(1, treeBoundBox(boundBox(coarseMesh.points(), false)).extend(1e-3))
const bool overwrite
Definition: setNoOverwrite.H:1