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