meshRefinementRefine.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 "trackedParticle.H"
28 #include "syncTools.H"
29 #include "Time.H"
30 #include "refinementSurfaces.H"
31 #include "refinementFeatures.H"
32 #include "refinementRegions.H"
33 #include "faceSet.H"
34 #include "decompositionMethod.H"
35 #include "fvMeshDistribute.H"
36 #include "polyTopoChange.H"
37 #include "polyDistributionMap.H"
38 #include "Cloud.H"
39 #include "OBJstream.H"
40 #include "cellSet.H"
41 #include "meshSearch.H"
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47  //- To compare normals
48  static bool less(const vector& x, const vector& y)
49  {
50  for (direction i = 0; i < vector::nComponents; i++)
51  {
52  if (x[i] < y[i])
53  {
54  return true;
55  }
56  else if (x[i] > y[i])
57  {
58  return false;
59  }
60  }
61  // All components the same
62  return false;
63  }
64 
65 
66  //- To compare normals
67  class normalLess
68  {
69  const vectorList& values_;
70 
71  public:
72 
73  normalLess(const vectorList& values)
74  :
75  values_(values)
76  {}
77 
78  bool operator()(const label a, const label b) const
79  {
80  return less(values_[a], values_[b]);
81  }
82  };
83 
84 
85  //- Template specialisation for pTraits<labelList> so we can have fields
86  template<>
88  {
89 
90  public:
91 
92  //- Component type
94  };
95 
96  //- Template specialisation for pTraits<labelList> so we can have fields
97  template<>
99  {
100 
101  public:
102 
103  //- Component type
105  };
106 }
107 
108 
109 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
110 
111 // Get faces (on the new mesh) that have in some way been affected by the
112 // mesh change. Picks up all faces but those that are between two
113 // unrefined faces. (Note that of an unchanged face the edge still might be
114 // split but that does not change any face centre or cell centre.
115 Foam::labelList Foam::meshRefinement::getChangedFaces
116 (
117  const polyTopoChangeMap& map,
118  const labelList& oldCellsToRefine
119 )
120 {
121  const polyMesh& mesh = map.mesh();
122 
123  labelList changedFaces;
124 
125  // For reporting: number of masterFaces changed
126  label nMasterChanged = 0;
127  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh));
128 
129  {
130  // Mark any face on a cell which has been added or changed
131  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132  // Note that refining a face changes the face centre (for a warped face)
133  // which changes the cell centre. This again changes the cellcentre-
134  // cellcentre edge across all faces of the cell.
135  // Note: this does not happen for unwarped faces but unfortunately
136  // we don't have this information.
137 
138  const labelList& faceOwner = mesh.faceOwner();
139  const labelList& faceNeighbour = mesh.faceNeighbour();
140  const cellList& cells = mesh.cells();
141  const label nInternalFaces = mesh.nInternalFaces();
142 
143  // Mark refined cells on old mesh
144  PackedBoolList oldRefineCell(map.nOldCells());
145 
146  forAll(oldCellsToRefine, i)
147  {
148  oldRefineCell.set(oldCellsToRefine[i], 1u);
149  }
150 
151  // Mark refined faces
152  PackedBoolList refinedInternalFace(nInternalFaces);
153 
154  // 1. Internal faces
155 
156  for (label facei = 0; facei < nInternalFaces; facei++)
157  {
158  const label oldOwn = map.cellMap()[faceOwner[facei]];
159  const label oldNei = map.cellMap()[faceNeighbour[facei]];
160 
161  if
162  (
163  oldOwn >= 0
164  && oldRefineCell.get(oldOwn) == 0u
165  && oldNei >= 0
166  && oldRefineCell.get(oldNei) == 0u
167  )
168  {
169  // Unaffected face since both neighbours were not refined.
170  }
171  else
172  {
173  refinedInternalFace.set(facei, 1u);
174  }
175  }
176 
177 
178  // 2. Boundary faces
179 
180  boolList refinedBoundaryFace(mesh.nFaces()-nInternalFaces, false);
181 
183  {
184  const polyPatch& pp = mesh.boundary()[patchi];
185 
186  label facei = pp.start();
187 
188  forAll(pp, i)
189  {
190  label oldOwn = map.cellMap()[faceOwner[facei]];
191 
192  if (oldOwn >= 0 && oldRefineCell.get(oldOwn) == 0u)
193  {
194  // owner did exist and wasn't refined.
195  }
196  else
197  {
198  refinedBoundaryFace[facei - nInternalFaces] = true;
199  }
200  facei++;
201  }
202  }
203 
204  // Synchronise refined face status
206  (
207  mesh,
208  refinedBoundaryFace,
209  orEqOp<bool>()
210  );
211 
212 
213  // 3. Mark all faces affected by refinement. Refined faces are in
214  // - refinedInternalFace
215  // - refinedBoundaryFace
216  boolList changedFace(mesh.nFaces(), false);
217 
218  forAll(refinedInternalFace, facei)
219  {
220  if (refinedInternalFace.get(facei) == 1u)
221  {
222  const cell& ownFaces = cells[faceOwner[facei]];
223  forAll(ownFaces, owni)
224  {
225  changedFace[ownFaces[owni]] = true;
226  }
227  const cell& neiFaces = cells[faceNeighbour[facei]];
228  forAll(neiFaces, neii)
229  {
230  changedFace[neiFaces[neii]] = true;
231  }
232  }
233  }
234 
235  forAll(refinedBoundaryFace, i)
236  {
237  if (refinedBoundaryFace[i])
238  {
239  const cell& ownFaces = cells[faceOwner[i+nInternalFaces]];
240  forAll(ownFaces, owni)
241  {
242  changedFace[ownFaces[owni]] = true;
243  }
244  }
245  }
246 
248  (
249  mesh,
250  changedFace,
251  orEqOp<bool>()
252  );
253 
254 
255  // Now we have in changedFace marked all affected faces. Pack.
256  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
257 
258  changedFaces = findIndices(changedFace, true);
259 
260  // Count changed master faces.
261  nMasterChanged = 0;
262 
263  forAll(changedFace, facei)
264  {
265  if (changedFace[facei] && isMasterFace[facei])
266  {
267  nMasterChanged++;
268  }
269  }
270 
271  }
272 
273  if (debug&meshRefinement::MESH)
274  {
275  Pout<< "getChangedFaces : Detected "
276  << " local:" << changedFaces.size()
277  << " global:" << returnReduce(nMasterChanged, sumOp<label>())
278  << " changed faces out of " << mesh.globalData().nTotalFaces()
279  << endl;
280 
281  faceSet changedFacesSet(mesh, "changedFaces", changedFaces);
282  Pout<< "getChangedFaces : Writing " << changedFaces.size()
283  << " changed faces to faceSet " << changedFacesSet.name()
284  << endl;
285  changedFacesSet.write();
286  }
287 
288  return changedFaces;
289 }
290 
291 
292 // Mark cell for refinement (if not already marked). Return false if
293 // refinelimit hit. Keeps running count (in nRefine) of cells marked for
294 // refinement
295 bool Foam::meshRefinement::markForRefine
296 (
297  const label markValue,
298  const label nAllowRefine,
299 
300  label& cellValue,
301  label& nRefine
302 )
303 {
304  if (cellValue == -1)
305  {
306  cellValue = markValue;
307  nRefine++;
308  }
309 
310  return nRefine <= nAllowRefine;
311 }
312 
313 
314 void Foam::meshRefinement::markFeatureCellLevel
315 (
316  const List<point>& insidePoints,
317  labelList& maxFeatureLevel
318 ) const
319 {
320  // We want to refine all cells containing a feature edge.
321  // - don't want to search over whole mesh
322  // - don't want to build octree for whole mesh
323  // - so use tracking to follow the feature edges
324  //
325  // 1. find non-manifold points on feature edges (i.e. start of feature edge
326  // or 'knot')
327  // 2. seed particle starting at insidePoint going to this non-manifold
328  // point
329  // 3. track particles to their non-manifold point
330  //
331  // 4. track particles across their connected feature edges, marking all
332  // visited cells with their level (through trackingData)
333  // 5. do 4 until all edges have been visited.
334 
335  // Find all start cells of features.
336  // Is done by tracking from insidePoint.
337  lagrangian::Cloud<trackedParticle> startPointCloud
338  (
339  mesh_,
340  "startPointCloud",
341  IDLList<trackedParticle>()
342  );
343 
344  // Features are identical on all processors. Number them so we know
345  // what to seed. Do this on only the processor that
346  // holds the insidePoint.
347  label nLocateBoundaryHits = 0;
348 
349  const meshSearch& searchEngine = meshSearch::New(mesh());
350 
351  forAll(insidePoints, i)
352  {
353  const point& insidePoint = insidePoints[i];
354 
355  const label celli = searchEngine.findCell(insidePoint);
356 
357  if (celli != -1)
358  {
359  // I am the processor that holds the insidePoint
360 
361  forAll(features_, feati)
362  {
363  const edgeMesh& featureMesh = features_[feati];
364  const label featureLevel = features_.levels()[feati][0];
365  const labelListList& pointEdges = featureMesh.pointEdges();
366 
367  // Find regions on edgeMesh
368  labelList edgeRegion;
369  const label nRegions = featureMesh.regions(edgeRegion);
370 
371 
372  PackedBoolList regionVisited(nRegions);
373 
374 
375  // 1. Seed all 'knots' in edgeMesh
376 
377 
378  forAll(pointEdges, pointi)
379  {
380  if (pointEdges[pointi].size() != 2)
381  {
383  {
384  Pout<< "Adding particle from point:" << pointi
385  << " coord:" << featureMesh.points()[pointi]
386  << " since number of emanating edges:"
387  << pointEdges[pointi].size()
388  << endl;
389  }
390 
391  // Non-manifold point. Create particle.
392  startPointCloud.addParticle
393  (
394  new trackedParticle
395  (
396  searchEngine,
397  insidePoint,
398  celli,
399  nLocateBoundaryHits,
400  featureMesh.points()[pointi], // endpos
401  featureLevel, // level
402  feati, // featureMesh
403  pointi, // end point
404  -1 // feature edge
405  )
406  );
407 
408  // Mark
409  if (pointEdges[pointi].size() > 0)
410  {
411  label e0 = pointEdges[pointi][0];
412  label regioni = edgeRegion[e0];
413  regionVisited[regioni] = 1u;
414  }
415  }
416  }
417 
418 
419  // 2. Any regions that have not been visited at all? These can
420  // only be circular regions!
421  forAll(featureMesh.edges(), edgei)
422  {
423  if (regionVisited.set(edgeRegion[edgei], 1u))
424  {
425  const edge& e = featureMesh.edges()[edgei];
426  const label pointi = e.start();
428  {
429  Pout<< "Adding particle from point:" << pointi
430  << " coord:" << featureMesh.points()[pointi]
431  << " on circular region:" << edgeRegion[edgei]
432  << endl;
433  }
434 
435  // Non-manifold point. Create particle.
436  startPointCloud.addParticle
437  (
438  new trackedParticle
439  (
440  searchEngine,
441  insidePoint,
442  celli,
443  nLocateBoundaryHits,
444  featureMesh.points()[pointi], // endpos
445  featureLevel, // level
446  feati, // featureMesh
447  pointi, // end point
448  -1 // feature edge
449  )
450  );
451  }
452  }
453  }
454  }
455  }
456 
457 
458  // Largest refinement level of any feature passed through
459  maxFeatureLevel = labelList(mesh_.nCells(), -1);
460 
461  // Whether edge has been visited.
462  List<PackedBoolList> featureEdgeVisited(features_.size());
463 
464  forAll(features_, feati)
465  {
466  featureEdgeVisited[feati].setSize(features_[feati].edges().size());
467  featureEdgeVisited[feati] = 0u;
468  }
469 
470  // Database to pass into trackedParticle::move
471  trackedParticle::trackingData td
472  (
473  startPointCloud,
474  2.0*mesh_.bounds().mag(),
475  maxFeatureLevel,
476  featureEdgeVisited
477  );
478 
479 
480  // Track all particles to their end position (= starting feature point)
481  // Note that the particle might have started on a different processor
482  // so this will transfer across nicely until we can start tracking proper.
484  {
485  Pout<< "Tracking " << startPointCloud.size()
486  << " particles over distance " << td.maxTrackLen_
487  << " to find the starting cell" << endl;
488  }
489  startPointCloud.move(startPointCloud, td);
490 
491 
492  // Reset levels
493  maxFeatureLevel = -1;
494  forAll(features_, feati)
495  {
496  featureEdgeVisited[feati] = 0u;
497  }
498 
499 
500  lagrangian::Cloud<trackedParticle> cloud
501  (
502  mesh_,
503  "featureCloud",
504  IDLList<trackedParticle>()
505  );
506 
508  {
509  Pout<< "Constructing cloud for cell marking" << endl;
510  }
511 
512  forAllIter(lagrangian::Cloud<trackedParticle>, startPointCloud, iter)
513  {
514  const trackedParticle& startTp = iter();
515 
516  const label feati = startTp.i();
517  const label pointi = startTp.j();
518 
519  const edgeMesh& featureMesh = features_[feati];
520  const labelList& pEdges = featureMesh.pointEdges()[pointi];
521 
522  // Now shoot particles down all pEdges.
523  forAll(pEdges, pEdgei)
524  {
525  const label edgei = pEdges[pEdgei];
526 
527  if (featureEdgeVisited[feati].set(edgei, 1u))
528  {
529  // Unvisited edge. Make the particle go to the other point
530  // on the edge.
531 
532  const edge& e = featureMesh.edges()[edgei];
533  label otherPointi = e.otherVertex(pointi);
534 
535  trackedParticle* tp(new trackedParticle(startTp));
536  tp->start() = tp->position(mesh_);
537  tp->end() = featureMesh.points()[otherPointi];
538  tp->fraction() = 1;
539  tp->j() = otherPointi;
540  tp->k() = edgei;
541 
543  {
544  Pout<< "Adding particle for point:" << pointi
545  << " coord:" << tp->position(mesh_)
546  << " feature:" << feati
547  << " to track to:" << tp->end()
548  << endl;
549  }
550 
551  cloud.addParticle(tp);
552  }
553  }
554  }
555 
556  startPointCloud.clear();
557 
558 
559  while (true)
560  {
561  // Track all particles to their end position.
563  {
564  Pout<< "Tracking " << cloud.size()
565  << " particles over distance " << td.maxTrackLen_
566  << " to mark cells" << endl;
567  }
568  cloud.move(cloud, td);
569 
570  // Make particle follow edge.
571  forAllIter(lagrangian::Cloud<trackedParticle>, cloud, iter)
572  {
573  trackedParticle& tp = iter();
574 
575  const label feati = tp.i();
576  const label pointi = tp.j();
577 
578  const edgeMesh& featureMesh = features_[feati];
579  const labelList& pEdges = featureMesh.pointEdges()[pointi];
580 
581  // Particle now at pointi. Check connected edges to see which one
582  // we have to visit now.
583 
584  bool keepParticle = false;
585 
586  forAll(pEdges, i)
587  {
588  const label edgei = pEdges[i];
589 
590  if (featureEdgeVisited[feati].set(edgei, 1u))
591  {
592  // Unvisited edge. Make the particle go to the other point
593  // on the edge.
594 
595  const edge& e = featureMesh.edges()[edgei];
596  const label otherPointi = e.otherVertex(pointi);
597 
598  tp.start() = tp.position(mesh_);
599  tp.end() = featureMesh.points()[otherPointi];
600  tp.fraction() = 1;
601  tp.j() = otherPointi;
602  tp.k() = edgei;
603  keepParticle = true;
604  break;
605  }
606  }
607 
608  if (!keepParticle)
609  {
610  // Particle at 'knot' where another particle already has been
611  // seeded. Delete particle.
612  cloud.deleteParticle(tp);
613  }
614  }
615 
616 
618  {
619  Pout<< "Remaining particles " << cloud.size() << endl;
620  }
621 
622  if (returnReduce(cloud.size(), sumOp<label>()) == 0)
623  {
624  break;
625  }
626  }
627 
628 
629 
630  // if (debug&meshRefinement::FEATURESEEDS)
631  //{
632  // forAll(maxFeatureLevel, celli)
633  // {
634  // if (maxFeatureLevel[celli] != -1)
635  // {
636  // Pout<< "Feature went through cell:" << celli
637  // << " coord:" << mesh_.cellCentres()[celli]
638  // << " level:" << maxFeatureLevel[celli]
639  // << endl;
640  // }
641  // }
642  //}
643 }
644 
645 
646 // Calculates list of cells to refine based on intersection with feature edge.
647 Foam::label Foam::meshRefinement::markFeatureRefinement
648 (
649  const List<point>& insidePoints,
650  const label nAllowRefine,
651 
652  labelList& refineCell,
653  label& nRefine
654 ) const
655 {
656  // Largest refinement level of any feature passed through
657  labelList maxFeatureLevel;
658  markFeatureCellLevel(insidePoints, maxFeatureLevel);
659 
660  // See which cells to refine. maxFeatureLevel will hold highest level
661  // of any feature edge that passed through.
662 
663  const labelList& cellLevel = meshCutter_.cellLevel();
664 
665  const label oldNRefine = nRefine;
666 
667  forAll(maxFeatureLevel, celli)
668  {
669  if (maxFeatureLevel[celli] > cellLevel[celli])
670  {
671  // Mark
672  if
673  (
674  !markForRefine
675  (
676  0, // surface (n/a)
677  nAllowRefine,
678  refineCell[celli],
679  nRefine
680  )
681  )
682  {
683  // Reached limit
684  break;
685  }
686  }
687  }
688 
689  if
690  (
691  returnReduce(nRefine, sumOp<label>())
692  > returnReduce(nAllowRefine, sumOp<label>())
693  )
694  {
695  Info<< "Reached refinement limit." << endl;
696  }
697 
698  return returnReduce(nRefine-oldNRefine, sumOp<label>());
699 }
700 
701 
702 // Mark cells for distance-to-feature based refinement.
703 Foam::label Foam::meshRefinement::markInternalDistanceToFeatureRefinement
704 (
705  const label nAllowRefine,
706 
707  labelList& refineCell,
708  label& nRefine
709 ) const
710 {
711  const labelList& cellLevel = meshCutter_.cellLevel();
712  const pointField& cellCentres = mesh_.cellCentres();
713 
714  // Detect if there are any distance features
715  if (features_.maxDistance() <= 0.0)
716  {
717  return 0;
718  }
719 
720  label oldNRefine = nRefine;
721 
722  // Collect cells to test
723  pointField testCc(cellLevel.size()-nRefine);
724  labelList testLevels(cellLevel.size()-nRefine);
725  label testi = 0;
726 
727  forAll(cellLevel, celli)
728  {
729  if (refineCell[celli] == -1)
730  {
731  testCc[testi] = cellCentres[celli];
732  testLevels[testi] = cellLevel[celli];
733  testi++;
734  }
735  }
736 
737  // Do test to see whether cells are in/near features with higher level
738  labelList maxLevel;
739  features_.findHigherLevel(testCc, testLevels, maxLevel);
740 
741  // Mark for refinement. Note that we didn't store the original cellID so
742  // now just reloop in same order.
743  testi = 0;
744  forAll(cellLevel, celli)
745  {
746  if (refineCell[celli] == -1)
747  {
748  if (maxLevel[testi] > testLevels[testi])
749  {
750  const bool reachedLimit = !markForRefine
751  (
752  maxLevel[testi], // mark with any positive value
753  nAllowRefine,
754  refineCell[celli],
755  nRefine
756  );
757 
758  if (reachedLimit)
759  {
760  if (debug)
761  {
762  Pout<< "Stopped refining internal cells"
763  << " since reaching my cell limit of "
764  << mesh_.nCells()+7*nRefine << endl;
765  }
766  break;
767  }
768  }
769  testi++;
770  }
771  }
772 
773  if
774  (
775  returnReduce(nRefine, sumOp<label>())
776  > returnReduce(nAllowRefine, sumOp<label>())
777  )
778  {
779  Info<< "Reached refinement limit." << endl;
780  }
781 
782  return returnReduce(nRefine-oldNRefine, sumOp<label>());
783 }
784 
785 
786 Foam::label Foam::meshRefinement::markInternalRefinement
787 (
788  const label nAllowRefine,
789 
790  labelList& refineCell,
791  label& nRefine
792 ) const
793 {
794  const labelList& cellLevel = meshCutter_.cellLevel();
795  const pointField& cellCentres = mesh_.cellCentres();
796 
797  const label oldNRefine = nRefine;
798 
799  // Collect cells to test
800  pointField testCc(cellLevel.size()-nRefine);
801  labelList testLevels(cellLevel.size()-nRefine);
802  label testi = 0;
803 
804  forAll(cellLevel, celli)
805  {
806  if (refineCell[celli] == -1)
807  {
808  testCc[testi] = cellCentres[celli];
809  testLevels[testi] = cellLevel[celli];
810  testi++;
811  }
812  }
813 
814  // Do test to see whether cells is inside/outside shell with higher level
815  labelList maxLevel;
816  shells_.findHigherLevel
817  (
818  testCc,
819  testLevels,
820  meshCutter_.level0EdgeLength(),
821  maxLevel
822  );
823 
824  // Mark for refinement. Note that we didn't store the original cellID so
825  // now just reloop in same order.
826  testi = 0;
827  forAll(cellLevel, celli)
828  {
829  if (refineCell[celli] == -1)
830  {
831  if (maxLevel[testi] > testLevels[testi])
832  {
833  bool reachedLimit = !markForRefine
834  (
835  maxLevel[testi], // mark with any positive value
836  nAllowRefine,
837  refineCell[celli],
838  nRefine
839  );
840 
841  if (reachedLimit)
842  {
843  if (debug)
844  {
845  Pout<< "Stopped refining internal cells"
846  << " since reaching my cell limit of "
847  << mesh_.nCells()+7*nRefine << endl;
848  }
849  break;
850  }
851  }
852  testi++;
853  }
854  }
855 
856  if
857  (
858  returnReduce(nRefine, sumOp<label>())
859  > returnReduce(nAllowRefine, sumOp<label>())
860  )
861  {
862  Info<< "Reached refinement limit." << endl;
863  }
864 
865  return returnReduce(nRefine-oldNRefine, sumOp<label>());
866 }
867 
868 
869 Foam::labelList Foam::meshRefinement::getRefineCandidateFaces
870 (
871  const labelList& refineCell
872 ) const
873 {
874  labelList testFaces(mesh_.nFaces());
875 
876  label nTest = 0;
877 
878  forAll(surfaceIndex_, facei)
879  {
880  if (surfaceIndex_[facei] != -1)
881  {
882  label own = mesh_.faceOwner()[facei];
883 
884  if (mesh_.isInternalFace(facei))
885  {
886  const label nei = mesh_.faceNeighbour()[facei];
887 
888  if (refineCell[own] == -1 || refineCell[nei] == -1)
889  {
890  testFaces[nTest++] = facei;
891  }
892  }
893  else
894  {
895  if (refineCell[own] == -1)
896  {
897  testFaces[nTest++] = facei;
898  }
899  }
900  }
901  }
902  testFaces.setSize(nTest);
903 
904  return testFaces;
905 }
906 
907 
908 Foam::label Foam::meshRefinement::markSurfaceRefinement
909 (
910  const label nAllowRefine,
911  const labelList& neiLevel,
912  const pointField& neiCc,
913 
914  labelList& refineCell,
915  label& nRefine
916 ) const
917 {
918  const labelList& cellLevel = meshCutter_.cellLevel();
919  const pointField& cellCentres = mesh_.cellCentres();
920 
921  const label oldNRefine = nRefine;
922 
923  // Use cached surfaceIndex_ to detect if any intersection. If so
924  // re-intersect to determine level wanted.
925 
926  // Collect candidate faces
927  // ~~~~~~~~~~~~~~~~~~~~~~~
928 
929  labelList testFaces(getRefineCandidateFaces(refineCell));
930 
931  // Collect segments
932  // ~~~~~~~~~~~~~~~~
933 
934  pointField start(testFaces.size());
935  pointField end(testFaces.size());
936  labelList minLevel(testFaces.size());
937 
938  forAll(testFaces, i)
939  {
940  const label facei = testFaces[i];
941 
942  const label own = mesh_.faceOwner()[facei];
943 
944  if (mesh_.isInternalFace(facei))
945  {
946  label nei = mesh_.faceNeighbour()[facei];
947 
948  start[i] = cellCentres[own];
949  end[i] = cellCentres[nei];
950  minLevel[i] = min(cellLevel[own], cellLevel[nei]);
951  }
952  else
953  {
954  const label bFacei = facei - mesh_.nInternalFaces();
955 
956  start[i] = cellCentres[own];
957  end[i] = neiCc[bFacei];
958  minLevel[i] = min(cellLevel[own], neiLevel[bFacei]);
959  }
960  }
961 
962  // Extend segments a bit
963  {
964  const vectorField smallVec(rootSmall*(end-start));
965  start -= smallVec;
966  end += smallVec;
967  }
968 
969 
970  // Do test for higher intersections
971  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
972 
973  labelList surfaceHit;
974  labelList surfaceMinLevel;
975  surfaces_.findHigherIntersection
976  (
977  start,
978  end,
979  minLevel,
980 
981  surfaceHit,
982  surfaceMinLevel
983  );
984 
985 
986  // Mark cells for refinement
987  // ~~~~~~~~~~~~~~~~~~~~~~~~~
988 
989  forAll(testFaces, i)
990  {
991  const label facei = testFaces[i];
992 
993  const label surfi = surfaceHit[i];
994 
995  if (surfi != -1)
996  {
997  // Found intersection with surface with higher wanted
998  // refinement. Check if the level field on that surface
999  // specifies an even higher level. Note:this is weird. Should
1000  // do the check with the surfaceMinLevel whilst intersecting the
1001  // surfaces?
1002 
1003  const label own = mesh_.faceOwner()[facei];
1004 
1005  if (surfaceMinLevel[i] > cellLevel[own])
1006  {
1007  // Owner needs refining
1008  if
1009  (
1010  !markForRefine
1011  (
1012  surfi,
1013  nAllowRefine,
1014  refineCell[own],
1015  nRefine
1016  )
1017  )
1018  {
1019  break;
1020  }
1021  }
1022 
1023  if (mesh_.isInternalFace(facei))
1024  {
1025  const label nei = mesh_.faceNeighbour()[facei];
1026 
1027  if (surfaceMinLevel[i] > cellLevel[nei])
1028  {
1029  // Neighbour needs refining
1030  if
1031  (
1032  !markForRefine
1033  (
1034  surfi,
1035  nAllowRefine,
1036  refineCell[nei],
1037  nRefine
1038  )
1039  )
1040  {
1041  break;
1042  }
1043  }
1044  }
1045  }
1046  }
1047 
1048  if
1049  (
1050  returnReduce(nRefine, sumOp<label>())
1051  > returnReduce(nAllowRefine, sumOp<label>())
1052  )
1053  {
1054  Info<< "Reached refinement limit." << endl;
1055  }
1056 
1057  return returnReduce(nRefine-oldNRefine, sumOp<label>());
1058 }
1059 
1060 
1061 // Count number of matches of first argument in second argument
1062 Foam::label Foam::meshRefinement::countMatches
1063 (
1064  const List<point>& normals1,
1065  const List<point>& normals2,
1066  const scalar tol
1067 ) const
1068 {
1069  label nMatches = 0;
1070 
1071  forAll(normals1, i)
1072  {
1073  const vector& n1 = normals1[i];
1074 
1075  forAll(normals2, j)
1076  {
1077  const vector& n2 = normals2[j];
1078 
1079  if (magSqr(n1-n2) < tol)
1080  {
1081  nMatches++;
1082  break;
1083  }
1084  }
1085  }
1086 
1087  return nMatches;
1088 }
1089 
1090 
1091 // Mark cells for surface curvature based refinement.
1092 Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
1093 (
1094  const scalar curvature,
1095  const label nAllowRefine,
1096  const labelList& neiLevel,
1097  const pointField& neiCc,
1098 
1099  labelList& refineCell,
1100  label& nRefine
1101 ) const
1102 {
1103  const labelList& cellLevel = meshCutter_.cellLevel();
1104  const pointField& cellCentres = mesh_.cellCentres();
1105 
1106  const label oldNRefine = nRefine;
1107 
1108  // 1. local test: any cell on more than one surface gets refined
1109  // (if its current level is < max of the surface max level)
1110 
1111  // 2. 'global' test: any cell on only one surface with a neighbour
1112  // on a different surface gets refined (if its current level etc.)
1113 
1114 
1115  const PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
1116 
1117 
1118  // Collect candidate faces (i.e. intersecting any surface and
1119  // owner/neighbour not yet refined.
1120  labelList testFaces(getRefineCandidateFaces(refineCell));
1121 
1122  // Collect segments
1123  pointField start(testFaces.size());
1124  pointField end(testFaces.size());
1125  labelList minLevel(testFaces.size());
1126 
1127  forAll(testFaces, i)
1128  {
1129  const label facei = testFaces[i];
1130  const label own = mesh_.faceOwner()[facei];
1131 
1132  if (mesh_.isInternalFace(facei))
1133  {
1134  const label nei = mesh_.faceNeighbour()[facei];
1135 
1136  start[i] = cellCentres[own];
1137  end[i] = cellCentres[nei];
1138  minLevel[i] = min(cellLevel[own], cellLevel[nei]);
1139  }
1140  else
1141  {
1142  const label bFacei = facei - mesh_.nInternalFaces();
1143 
1144  start[i] = cellCentres[own];
1145  end[i] = neiCc[bFacei];
1146 
1147  if (!isMasterFace[facei])
1148  {
1149  Swap(start[i], end[i]);
1150  }
1151 
1152  minLevel[i] = min(cellLevel[own], neiLevel[bFacei]);
1153  }
1154  }
1155 
1156  // Extend segments a bit
1157  {
1158  const vectorField smallVec(rootSmall*(end-start));
1159  start -= smallVec;
1160  end += smallVec;
1161  }
1162 
1163 
1164  // Test for all intersections (with surfaces of higher max level than
1165  // minLevel) and cache per cell the interesting inter
1166  labelListList cellSurfLevels(mesh_.nCells());
1167  List<vectorList> cellSurfNormals(mesh_.nCells());
1168 
1169  {
1170  // Per segment the normals of the surfaces
1171  List<vectorList> surfaceNormal;
1172 
1173  // Per segment the list of levels of the surfaces
1174  labelListList surfaceLevel;
1175 
1176  surfaces_.findAllHigherIntersections
1177  (
1178  start,
1179  end,
1180  minLevel, // max level of surface has to be bigger
1181  // than min level of neighbouring cells
1182 
1183  surfaces_.maxLevel(),
1184 
1185  surfaceNormal,
1186  surfaceLevel
1187  );
1188 
1189 
1190  // Sort the data according to surface location. This will guarantee
1191  // that on coupled faces both sides visit the intersections in
1192  // the same order so will decide the same
1193  labelList visitOrder;
1194  forAll(surfaceNormal, pointi)
1195  {
1196  vectorList& pNormals = surfaceNormal[pointi];
1197  labelList& pLevel = surfaceLevel[pointi];
1198 
1199  sortedOrder(pNormals, visitOrder, normalLess(pNormals));
1200 
1201  pNormals = List<point>(pNormals, visitOrder);
1202  pLevel = UIndirectList<label>(pLevel, visitOrder);
1203  }
1204 
1205  // Clear out unnecessary data
1206  start.clear();
1207  end.clear();
1208  minLevel.clear();
1209 
1210  // Convert face-wise data to cell.
1211  forAll(testFaces, i)
1212  {
1213  const label facei = testFaces[i];
1214  const label own = mesh_.faceOwner()[facei];
1215 
1216  const vectorList& fNormals = surfaceNormal[i];
1217  const labelList& fLevels = surfaceLevel[i];
1218 
1219  forAll(fNormals, hiti)
1220  {
1221  if (fLevels[hiti] > cellLevel[own])
1222  {
1223  cellSurfLevels[own].append(fLevels[hiti]);
1224  cellSurfNormals[own].append(fNormals[hiti]);
1225  }
1226 
1227  if (mesh_.isInternalFace(facei))
1228  {
1229  label nei = mesh_.faceNeighbour()[facei];
1230  if (fLevels[hiti] > cellLevel[nei])
1231  {
1232  cellSurfLevels[nei].append(fLevels[hiti]);
1233  cellSurfNormals[nei].append(fNormals[hiti]);
1234  }
1235  }
1236  }
1237  }
1238  }
1239 
1240 
1241 
1242  // Bit of statistics
1243  if (debug)
1244  {
1245  label nSet = 0;
1246  label nNormals = 9;
1247  forAll(cellSurfNormals, celli)
1248  {
1249  const vectorList& normals = cellSurfNormals[celli];
1250  if (normals.size())
1251  {
1252  nSet++;
1253  nNormals += normals.size();
1254  }
1255  }
1256  reduce(nSet, sumOp<label>());
1257  reduce(nNormals, sumOp<label>());
1258  Info<< "markSurfaceCurvatureRefinement :"
1259  << " cells:" << mesh_.globalData().nTotalCells()
1260  << " of which with normals:" << nSet
1261  << " ; total normals stored:" << nNormals
1262  << endl;
1263  }
1264 
1265 
1266 
1267  bool reachedLimit = false;
1268 
1269 
1270  // 1. Check normals per cell
1271  // ~~~~~~~~~~~~~~~~~~~~~~~~~
1272 
1273  for
1274  (
1275  label celli = 0;
1276  !reachedLimit && celli < cellSurfNormals.size();
1277  celli++
1278  )
1279  {
1280  const vectorList& normals = cellSurfNormals[celli];
1281  const labelList& levels = cellSurfLevels[celli];
1282 
1283  // n^2 comparison of all normals in a cell
1284  for (label i = 0; !reachedLimit && i < normals.size(); i++)
1285  {
1286  for (label j = i+1; !reachedLimit && j < normals.size(); j++)
1287  {
1288  if ((normals[i] & normals[j]) < curvature)
1289  {
1290  const label maxLevel = max(levels[i], levels[j]);
1291 
1292  if (cellLevel[celli] < maxLevel)
1293  {
1294  if
1295  (
1296  !markForRefine
1297  (
1298  maxLevel,
1299  nAllowRefine,
1300  refineCell[celli],
1301  nRefine
1302  )
1303  )
1304  {
1305  if (debug)
1306  {
1307  Pout<< "Stopped refining since reaching my cell"
1308  << " limit of " << mesh_.nCells()+7*nRefine
1309  << endl;
1310  }
1311  reachedLimit = true;
1312  break;
1313  }
1314  }
1315  }
1316  }
1317  }
1318  }
1319 
1320 
1321 
1322  // 2. Find out a measure of surface curvature
1323  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1324  // Look at normals between neighbouring surfaces
1325  // Loop over all faces. Could only be checkFaces, except if they're coupled
1326 
1327  // Internal faces
1328  for
1329  (
1330  label facei = 0;
1331  !reachedLimit && facei < mesh_.nInternalFaces();
1332  facei++
1333  )
1334  {
1335  const label own = mesh_.faceOwner()[facei];
1336  const label nei = mesh_.faceNeighbour()[facei];
1337 
1338  const vectorList& ownNormals = cellSurfNormals[own];
1339  const labelList& ownLevels = cellSurfLevels[own];
1340  const vectorList& neiNormals = cellSurfNormals[nei];
1341  const labelList& neiLevels = cellSurfLevels[nei];
1342 
1343 
1344  // Special case: owner normals set is a subset of the neighbour
1345  // normals. Do not do curvature refinement since other cell's normals
1346  // do not add any information. Avoids weird corner extensions of
1347  // refinement regions.
1348  bool ownisSubset =
1349  countMatches(ownNormals, neiNormals)
1350  == ownNormals.size();
1351 
1352  bool neiisSubset =
1353  countMatches(neiNormals, ownNormals)
1354  == neiNormals.size();
1355 
1356 
1357  if (!ownisSubset && !neiisSubset)
1358  {
1359  // n^2 comparison of between ownNormals and neiNormals
1360  for (label i = 0; !reachedLimit && i < ownNormals.size(); i++)
1361  {
1362  for (label j = 0; !reachedLimit && j < neiNormals.size(); j++)
1363  {
1364  // Have valid data on both sides. Check curvature.
1365  if ((ownNormals[i] & neiNormals[j]) < curvature)
1366  {
1367  // See which side to refine.
1368  if (cellLevel[own] < ownLevels[i])
1369  {
1370  if
1371  (
1372  !markForRefine
1373  (
1374  ownLevels[i],
1375  nAllowRefine,
1376  refineCell[own],
1377  nRefine
1378  )
1379  )
1380  {
1381  if (debug)
1382  {
1383  Pout<< "Stopped refining since reaching"
1384  << " my cell limit of "
1385  << mesh_.nCells()+7*nRefine << endl;
1386  }
1387  reachedLimit = true;
1388  break;
1389  }
1390  }
1391  if (cellLevel[nei] < neiLevels[j])
1392  {
1393  if
1394  (
1395  !markForRefine
1396  (
1397  neiLevels[j],
1398  nAllowRefine,
1399  refineCell[nei],
1400  nRefine
1401  )
1402  )
1403  {
1404  if (debug)
1405  {
1406  Pout<< "Stopped refining since reaching"
1407  << " my cell limit of "
1408  << mesh_.nCells()+7*nRefine << endl;
1409  }
1410  reachedLimit = true;
1411  break;
1412  }
1413  }
1414  }
1415  }
1416  }
1417  }
1418  }
1419 
1420 
1421  // Send over surface normal to neighbour cell.
1422  List<vectorList> neiSurfaceNormals;
1423  syncTools::swapBoundaryCellList(mesh_, cellSurfNormals, neiSurfaceNormals);
1424 
1425  // Boundary faces
1426  for
1427  (
1428  label facei = mesh_.nInternalFaces();
1429  !reachedLimit && facei < mesh_.nFaces();
1430  facei++
1431  )
1432  {
1433  label own = mesh_.faceOwner()[facei];
1434  label bFacei = facei - mesh_.nInternalFaces();
1435 
1436  const vectorList& ownNormals = cellSurfNormals[own];
1437  const labelList& ownLevels = cellSurfLevels[own];
1438  const vectorList& neiNormals = neiSurfaceNormals[bFacei];
1439 
1440  // Special case: owner normals set is a subset of the neighbour
1441  // normals. Do not do curvature refinement since other cell's normals
1442  // do not add any information. Avoids weird corner extensions of
1443  // refinement regions.
1444  bool ownisSubset =
1445  countMatches(ownNormals, neiNormals)
1446  == ownNormals.size();
1447 
1448  bool neiisSubset =
1449  countMatches(neiNormals, ownNormals)
1450  == neiNormals.size();
1451 
1452 
1453  if (!ownisSubset && !neiisSubset)
1454  {
1455  // n^2 comparison of between ownNormals and neiNormals
1456  for (label i = 0; !reachedLimit && i < ownNormals.size(); i++)
1457  {
1458  for (label j = 0; !reachedLimit && j < neiNormals.size(); j++)
1459  {
1460  // Have valid data on both sides. Check curvature.
1461  if ((ownNormals[i] & neiNormals[j]) < curvature)
1462  {
1463  if (cellLevel[own] < ownLevels[i])
1464  {
1465  if
1466  (
1467  !markForRefine
1468  (
1469  ownLevels[i],
1470  nAllowRefine,
1471  refineCell[own],
1472  nRefine
1473  )
1474  )
1475  {
1476  if (debug)
1477  {
1478  Pout<< "Stopped refining since reaching"
1479  << " my cell limit of "
1480  << mesh_.nCells()+7*nRefine
1481  << endl;
1482  }
1483  reachedLimit = true;
1484  break;
1485  }
1486  }
1487  }
1488  }
1489  }
1490  }
1491  }
1492 
1493 
1494  if
1495  (
1496  returnReduce(nRefine, sumOp<label>())
1497  > returnReduce(nAllowRefine, sumOp<label>())
1498  )
1499  {
1500  Info<< "Reached refinement limit." << endl;
1501  }
1502 
1503  return returnReduce(nRefine-oldNRefine, sumOp<label>());
1504 }
1505 
1506 
1508 (
1509  const scalar planarCos,
1510  const vector& point0,
1511  const vector& normal0,
1512 
1513  const vector& point1,
1514  const vector& normal1
1515 ) const
1516 {
1517  //- Hits differ and angles are oppositeish and
1518  // hits have a normal distance
1519  const vector d = point1 - point0;
1520  const scalar magD = mag(d);
1521 
1522  if (magD > mergeDistance())
1523  {
1524  scalar cosAngle = (normal0 & normal1);
1525 
1526  vector avg = Zero;
1527  if (cosAngle < (-1+planarCos))
1528  {
1529  // Opposite normals
1530  avg = 0.5*(normal0-normal1);
1531  }
1532  else if (cosAngle > (1-planarCos))
1533  {
1534  avg = 0.5*(normal0+normal1);
1535  }
1536 
1537  if (avg != vector::zero)
1538  {
1539  avg /= mag(avg);
1540 
1541  // Check normal distance of intersection locations
1542  if (mag(avg&d) > mergeDistance())
1543  {
1544  return true;
1545  }
1546  else
1547  {
1548  return false;
1549  }
1550  }
1551  else
1552  {
1553  return false;
1554  }
1555  }
1556  else
1557  {
1558  return false;
1559  }
1560 }
1561 
1562 
1563 // Mark small gaps
1565 (
1566  const scalar planarCos,
1567  const vector& point0,
1568  const vector& normal0,
1569 
1570  const vector& point1,
1571  const vector& normal1
1572 ) const
1573 {
1574  //- Hits differ and angles are oppositeish and
1575  // hits have a normal distance
1576  vector d = point1 - point0;
1577  const scalar magD = mag(d);
1578 
1579  if (magD > mergeDistance())
1580  {
1581  scalar cosAngle = (normal0 & normal1);
1582 
1583  vector avg = Zero;
1584  if (cosAngle < (-1+planarCos))
1585  {
1586  // Opposite normals
1587  avg = 0.5*(normal0-normal1);
1588  }
1589  else if (cosAngle > (1-planarCos))
1590  {
1591  avg = 0.5*(normal0+normal1);
1592  }
1593 
1594  if (avg != vector::zero)
1595  {
1596  avg /= mag(avg);
1597  d /= magD;
1598 
1599  // Check average normal with respect to intersection locations
1600  if (mag(avg&d) > Foam::cos(degToRad(45.0)))
1601  {
1602  return true;
1603  }
1604  else
1605  {
1606  return false;
1607  }
1608  }
1609  else
1610  {
1611  return false;
1612  }
1613  }
1614  else
1615  {
1616  return false;
1617  }
1618 }
1619 
1620 
1621 bool Foam::meshRefinement::checkProximity
1622 (
1623  const scalar planarCos,
1624  const label nAllowRefine,
1625 
1626  const label surfaceLevel, // current intersection max level
1627  const vector& surfaceLocation, // current intersection location
1628  const vector& surfaceNormal, // current intersection normal
1629 
1630  const label celli,
1631 
1632  label& cellMaxLevel, // cached max surface level for this cell
1633  vector& cellMaxLocation, // cached surface normal for this cell
1634  vector& cellMaxNormal, // cached surface normal for this cell
1635 
1637  label& nRefine
1638 ) const
1639 {
1640  const labelList& cellLevel = meshCutter_.cellLevel();
1641 
1642  // Test if surface applicable
1643  if (surfaceLevel > cellLevel[celli])
1644  {
1645  if (cellMaxLevel == -1)
1646  {
1647  // First visit of cell. Store
1648  cellMaxLevel = surfaceLevel;
1649  cellMaxLocation = surfaceLocation;
1650  cellMaxNormal = surfaceNormal;
1651  }
1652  else
1653  {
1654  // Second or more visit.
1655  // Check if
1656  // - different location
1657  // - opposite surface
1658 
1659  bool closeSurfaces = isNormalGap
1660  (
1661  planarCos,
1662  cellMaxLocation,
1663  cellMaxNormal,
1664  surfaceLocation,
1665  surfaceNormal
1666  );
1667 
1668  // Set normal to that of highest surface. Not really necessary
1669  // over here but we reuse cellMax info when doing coupled faces.
1670  if (surfaceLevel > cellMaxLevel)
1671  {
1672  cellMaxLevel = surfaceLevel;
1673  cellMaxLocation = surfaceLocation;
1674  cellMaxNormal = surfaceNormal;
1675  }
1676 
1677 
1678  if (closeSurfaces)
1679  {
1680  // Pout<< "Found gap:" << nl
1681  // << " location:" << surfaceLocation
1682  // << "\tnormal :" << surfaceNormal << nl
1684  // << "\tnormal :" << cellMaxNormal << nl
1685  // << "\tcos :" << (surfaceNormal&cellMaxNormal) << nl
1686  // << endl;
1687 
1688  return markForRefine
1689  (
1690  surfaceLevel, // mark with any non-neg number.
1691  nAllowRefine,
1692  refineCell[celli],
1693  nRefine
1694  );
1695  }
1696  }
1697  }
1698 
1699  // Did not reach refinement limit.
1700  return true;
1701 }
1702 
1703 
1704 Foam::label Foam::meshRefinement::markProximityRefinement
1705 (
1706  const scalar planarCos,
1707  const label nAllowRefine,
1708  const labelList& neiLevel,
1709  const pointField& neiCc,
1710 
1711  labelList& refineCell,
1712  label& nRefine
1713 ) const
1714 {
1715  const labelList& cellLevel = meshCutter_.cellLevel();
1716  const pointField& cellCentres = mesh_.cellCentres();
1717 
1718  const label oldNRefine = nRefine;
1719 
1720  // 1. local test: any cell on more than one surface gets refined
1721  // (if its current level is < max of the surface max level)
1722 
1723  // 2. 'global' test: any cell on only one surface with a neighbour
1724  // on a different surface gets refined (if its current level etc.)
1725 
1726 
1727  // Collect candidate faces (i.e. intersecting any surface and
1728  // owner/neighbour not yet refined.
1729  labelList testFaces(getRefineCandidateFaces(refineCell));
1730 
1731  // Collect segments
1732  pointField start(testFaces.size());
1733  pointField end(testFaces.size());
1734  labelList minLevel(testFaces.size());
1735 
1736  forAll(testFaces, i)
1737  {
1738  const label facei = testFaces[i];
1739  const label own = mesh_.faceOwner()[facei];
1740 
1741  if (mesh_.isInternalFace(facei))
1742  {
1743  const label nei = mesh_.faceNeighbour()[facei];
1744 
1745  start[i] = cellCentres[own];
1746  end[i] = cellCentres[nei];
1747  minLevel[i] = min(cellLevel[own], cellLevel[nei]);
1748  }
1749  else
1750  {
1751  const label bFacei = facei - mesh_.nInternalFaces();
1752 
1753  start[i] = cellCentres[own];
1754  end[i] = neiCc[bFacei];
1755  minLevel[i] = min(cellLevel[own], neiLevel[bFacei]);
1756  }
1757  }
1758 
1759  // Extend segments a bit
1760  {
1761  const vectorField smallVec(rootSmall*(end-start));
1762  start -= smallVec;
1763  end += smallVec;
1764  }
1765 
1766 
1767  // Test for all intersections (with surfaces of higher gap level than
1768  // minLevel) and cache per cell the max surface level and the local normal
1769  // on that surface.
1770  labelList cellMaxLevel(mesh_.nCells(), -1);
1771  vectorField cellMaxNormal(mesh_.nCells(), Zero);
1772  pointField cellMaxLocation(mesh_.nCells(), Zero);
1773 
1774  {
1775  // Per segment the normals of the surfaces
1776  List<vectorList> surfaceLocation;
1777  List<vectorList> surfaceNormal;
1778  // Per segment the list of levels of the surfaces
1779  labelListList surfaceLevel;
1780 
1781  surfaces_.findAllHigherIntersections
1782  (
1783  start,
1784  end,
1785  minLevel, // gap level of surface has to be bigger
1786  // than min level of neighbouring cells
1787 
1788  surfaces_.gapLevel(),
1789 
1790  surfaceLocation,
1791  surfaceNormal,
1792  surfaceLevel
1793  );
1794  // Clear out unnecessary data
1795  start.clear();
1796  end.clear();
1797  minLevel.clear();
1798 
1800  // OBJstream str
1801  //(
1802  // mesh_.time().path()
1803  // / "findAllHigherIntersections_"
1804  // + mesh_.time().name()
1805  // + ".obj"
1806  //);
1808  // OBJstream str2
1809  //(
1810  // mesh_.time().path()
1811  // / "findAllHigherIntersections2_"
1812  // + mesh_.time().name()
1813  // + ".obj"
1814  //);
1815 
1816  forAll(testFaces, i)
1817  {
1818  label facei = testFaces[i];
1819  label own = mesh_.faceOwner()[facei];
1820 
1821  const labelList& fLevels = surfaceLevel[i];
1822  const vectorList& fPoints = surfaceLocation[i];
1823  const vectorList& fNormals = surfaceNormal[i];
1824 
1825  forAll(fLevels, hiti)
1826  {
1827  checkProximity
1828  (
1829  planarCos,
1830  nAllowRefine,
1831 
1832  fLevels[hiti],
1833  fPoints[hiti],
1834  fNormals[hiti],
1835 
1836  own,
1837  cellMaxLevel[own],
1838  cellMaxLocation[own],
1839  cellMaxNormal[own],
1840 
1841  refineCell,
1842  nRefine
1843  );
1844  }
1845 
1846  if (mesh_.isInternalFace(facei))
1847  {
1848  label nei = mesh_.faceNeighbour()[facei];
1849 
1850  forAll(fLevels, hiti)
1851  {
1852  checkProximity
1853  (
1854  planarCos,
1855  nAllowRefine,
1856 
1857  fLevels[hiti],
1858  fPoints[hiti],
1859  fNormals[hiti],
1860 
1861  nei,
1862  cellMaxLevel[nei],
1863  cellMaxLocation[nei],
1864  cellMaxNormal[nei],
1865 
1866  refineCell,
1867  nRefine
1868  );
1869  }
1870  }
1871  }
1872  }
1873 
1874  // 2. Find out a measure of surface curvature and region edges.
1875  // Send over surface region and surface normal to neighbour cell.
1876 
1877  labelList neiBndMaxLevel(mesh_.nFaces()-mesh_.nInternalFaces());
1878  pointField neiBndMaxLocation(mesh_.nFaces()-mesh_.nInternalFaces());
1879  vectorField neiBndMaxNormal(mesh_.nFaces()-mesh_.nInternalFaces());
1880 
1881  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
1882  {
1883  const label bFacei = facei-mesh_.nInternalFaces();
1884  const label own = mesh_.faceOwner()[facei];
1885 
1886  neiBndMaxLevel[bFacei] = cellMaxLevel[own];
1887  neiBndMaxLocation[bFacei] = cellMaxLocation[own];
1888  neiBndMaxNormal[bFacei] = cellMaxNormal[own];
1889  }
1890  syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel);
1891  syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLocation);
1892  syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal);
1893 
1894  // Loop over all faces. Could only be checkFaces.. except if they're coupled
1895 
1896  // Internal faces
1897  for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1898  {
1899  const label own = mesh_.faceOwner()[facei];
1900  const label nei = mesh_.faceNeighbour()[facei];
1901 
1902  if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1)
1903  {
1904  // Have valid data on both sides. Check planarCos.
1905  if
1906  (
1907  isNormalGap
1908  (
1909  planarCos,
1910  cellMaxLocation[own],
1911  cellMaxNormal[own],
1912  cellMaxLocation[nei],
1913  cellMaxNormal[nei]
1914  )
1915  )
1916  {
1917  // See which side to refine
1918  if (cellLevel[own] < cellMaxLevel[own])
1919  {
1920  if
1921  (
1922  !markForRefine
1923  (
1924  cellMaxLevel[own],
1925  nAllowRefine,
1926  refineCell[own],
1927  nRefine
1928  )
1929  )
1930  {
1931  if (debug)
1932  {
1933  Pout<< "Stopped refining since reaching my cell"
1934  << " limit of " << mesh_.nCells()+7*nRefine
1935  << endl;
1936  }
1937  break;
1938  }
1939  }
1940 
1941  if (cellLevel[nei] < cellMaxLevel[nei])
1942  {
1943  if
1944  (
1945  !markForRefine
1946  (
1947  cellMaxLevel[nei],
1948  nAllowRefine,
1949  refineCell[nei],
1950  nRefine
1951  )
1952  )
1953  {
1954  if (debug)
1955  {
1956  Pout<< "Stopped refining since reaching my cell"
1957  << " limit of " << mesh_.nCells()+7*nRefine
1958  << endl;
1959  }
1960  break;
1961  }
1962  }
1963  }
1964  }
1965  }
1966  // Boundary faces
1967  for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
1968  {
1969  const label own = mesh_.faceOwner()[facei];
1970  const label bFacei = facei - mesh_.nInternalFaces();
1971 
1972  if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFacei] != -1)
1973  {
1974  // Have valid data on both sides. Check planarCos.
1975  if
1976  (
1977  isNormalGap
1978  (
1979  planarCos,
1980  cellMaxLocation[own],
1981  cellMaxNormal[own],
1982  neiBndMaxLocation[bFacei],
1983  neiBndMaxNormal[bFacei]
1984  )
1985  )
1986  {
1987  if
1988  (
1989  !markForRefine
1990  (
1991  cellMaxLevel[own],
1992  nAllowRefine,
1993  refineCell[own],
1994  nRefine
1995  )
1996  )
1997  {
1998  if (debug)
1999  {
2000  Pout<< "Stopped refining since reaching my cell"
2001  << " limit of " << mesh_.nCells()+7*nRefine
2002  << endl;
2003  }
2004  break;
2005  }
2006  }
2007  }
2008  }
2009 
2010  if
2011  (
2012  returnReduce(nRefine, sumOp<label>())
2013  > returnReduce(nAllowRefine, sumOp<label>())
2014  )
2015  {
2016  Info<< "Reached refinement limit." << endl;
2017  }
2018 
2019  return returnReduce(nRefine-oldNRefine, sumOp<label>());
2020 }
2021 
2022 
2023 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
2024 
2025 // Calculate list of cells to refine. Gets for any edge (start - end)
2026 // whether it intersects the surface. Does more accurate test and checks
2027 // the wanted level on the surface intersected.
2028 // Does approximate precalculation of how many cells can be refined before
2029 // hitting overall limit maxGlobalCells.
2031 (
2032  const List<point>& insidePoints,
2033  const scalar curvature,
2034  const scalar planarAngle,
2035 
2036  const bool featureRefinement,
2037  const bool featureDistanceRefinement,
2038  const bool internalRefinement,
2039  const bool surfaceRefinement,
2040  const bool curvatureRefinement,
2041  const bool gapRefinement,
2042  const label maxGlobalCells,
2043  const label maxLocalCells
2044 ) const
2045 {
2046  const label totNCells = mesh_.globalData().nTotalCells();
2047 
2048  labelList cellsToRefine;
2049 
2050  if (totNCells >= maxGlobalCells)
2051  {
2052  Info<< "No cells marked for refinement since reached limit "
2053  << maxGlobalCells << '.' << endl;
2054  }
2055  else
2056  {
2057  // Every cell I refine adds 7 cells. Estimate the number of cells
2058  // I am allowed to refine.
2059  // Assume perfect distribution so can only refine as much the fraction
2060  // of the mesh I hold. This prediction step prevents us having to do
2061  // lots of reduces to keep count of the total number of cells selected
2062  // for refinement.
2063 
2064  // scalar fraction = scalar(mesh_.nCells())/totNCells;
2065  // label myMaxCells = label(maxGlobalCells*fraction);
2066  // label nAllowRefine = (myMaxCells - mesh_.nCells())/7;
2068  //
2069  // Pout<< "refineCandidates:" << nl
2070  // << " total cells:" << totNCells << nl
2071  // << " local cells:" << mesh_.nCells() << nl
2072  // << " local fraction:" << fraction << nl
2073  // << " local allowable cells:" << myMaxCells << nl
2074  // << " local allowable refinement:" << nAllowRefine << nl
2075  // << endl;
2076 
2077  //- Disable refinement shortcut. nAllowRefine is per processor limit.
2078  const label nAllowRefine = labelMax / Pstream::nProcs();
2079 
2080  // Marked for refinement (>= 0) or not (-1). Actual value is the
2081  // index of the surface it intersects.
2082  labelList refineCell(mesh_.nCells(), -1);
2083  label nRefine = 0;
2084 
2085 
2086  // Swap neighbouring cell centres and cell level
2087  labelList neiLevel(mesh_.nFaces()-mesh_.nInternalFaces());
2088  pointField neiCc(mesh_.nFaces()-mesh_.nInternalFaces());
2089  calcNeighbourData(neiLevel, neiCc);
2090 
2091 
2092 
2093  // Cells pierced by feature edges
2094  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2095 
2096  if (featureRefinement)
2097  {
2098  const label nFeatures = markFeatureRefinement
2099  (
2100  insidePoints,
2101  nAllowRefine,
2102 
2103  refineCell,
2104  nRefine
2105  );
2106 
2107  Info<< "Marked for refinement due to explicit features "
2108  << ": " << nFeatures << " cells." << endl;
2109  }
2110 
2111  // Inside distance-to-feature
2112  // ~~~~~~~~~~~~~~~~~~~~~~~~~~
2113 
2114  if (featureDistanceRefinement)
2115  {
2116  const label nCellsFeat = markInternalDistanceToFeatureRefinement
2117  (
2118  nAllowRefine,
2119 
2120  refineCell,
2121  nRefine
2122  );
2123  Info<< "Marked for refinement due to distance to explicit features "
2124  ": " << nCellsFeat << " cells." << endl;
2125  }
2126 
2127  // Inside refinement shells
2128  // ~~~~~~~~~~~~~~~~~~~~~~~~
2129 
2130  if (internalRefinement)
2131  {
2132  const label nShell = markInternalRefinement
2133  (
2134  nAllowRefine,
2135 
2136  refineCell,
2137  nRefine
2138  );
2139  Info<< "Marked for refinement due to refinement shells "
2140  << ": " << nShell << " cells." << endl;
2141  }
2142 
2143  // Refinement based on intersection of surface
2144  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2145 
2146  if (surfaceRefinement)
2147  {
2148  const label nSurf = markSurfaceRefinement
2149  (
2150  nAllowRefine,
2151  neiLevel,
2152  neiCc,
2153 
2154  refineCell,
2155  nRefine
2156  );
2157  Info<< "Marked for refinement due to surface intersection "
2158  << ": " << nSurf << " cells." << endl;
2159  }
2160 
2161  // Refinement based on curvature of surface
2162  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2163 
2164  if
2165  (
2166  curvatureRefinement
2167  && (curvature >= -1 && curvature <= 1)
2168  && (surfaces_.minLevel() != surfaces_.maxLevel())
2169  )
2170  {
2171  const label nCurv = markSurfaceCurvatureRefinement
2172  (
2173  curvature,
2174  nAllowRefine,
2175  neiLevel,
2176  neiCc,
2177 
2178  refineCell,
2179  nRefine
2180  );
2181  Info<< "Marked for refinement due to curvature/regions "
2182  << ": " << nCurv << " cells." << endl;
2183  }
2184 
2185 
2186  const scalar planarCos = Foam::cos(planarAngle);
2187 
2188  if
2189  (
2190  gapRefinement
2191  && (planarCos >= -1 && planarCos <= 1)
2192  && (max(surfaces_.gapLevel()) > -1)
2193  )
2194  {
2195  Info<< "Specified gap level : " << max(surfaces_.gapLevel())
2196  << ", planar angle " << radToDeg(planarAngle) << endl;
2197 
2198  const label nGap = markProximityRefinement
2199  (
2200  planarCos,
2201  nAllowRefine,
2202  neiLevel,
2203  neiCc,
2204 
2205  refineCell,
2206  nRefine
2207  );
2208  Info<< "Marked for refinement due to close opposite surfaces "
2209  << ": " << nGap << " cells." << endl;
2210  }
2211 
2212 
2213 
2214  // Pack cells-to-refine
2215  // ~~~~~~~~~~~~~~~~~~~~
2216 
2217  cellsToRefine.setSize(nRefine);
2218  nRefine = 0;
2219 
2220  forAll(refineCell, celli)
2221  {
2222  if (refineCell[celli] != -1)
2223  {
2224  cellsToRefine[nRefine++] = celli;
2225  }
2226  }
2227  }
2228 
2229  return cellsToRefine;
2230 }
2231 
2232 
2234 (
2235  const labelList& cellsToRefine
2236 )
2237 {
2238  // Mesh changing engine.
2239  polyTopoChange meshMod(mesh_);
2240 
2241  // Play refinement commands into mesh changer.
2242  meshCutter_.setRefinement(cellsToRefine, meshMod);
2243 
2244  // Create mesh
2245  // return map from old to new mesh.
2246  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh_);
2247 
2248  // Update fields
2249  mesh_.topoChange(map);
2250 
2251  // Reset the instance for if in overwrite mode
2252  mesh_.setInstance(name());
2253 
2254  // Update intersection info
2255  topoChange(map, getChangedFaces(map, cellsToRefine));
2256 
2257  return map;
2258 }
2259 
2260 
2263 (
2264  const string& msg,
2265  decompositionMethod& decomposer,
2266  fvMeshDistribute& distributor,
2267  const labelList& cellsToRefine,
2268  const scalar maxLoadUnbalance
2269 )
2270 {
2271  // Do all refinement
2272  refine(cellsToRefine);
2273 
2274  if (debug&meshRefinement::MESH)
2275  {
2276  Pout<< "Writing refined but unbalanced " << msg
2277  << " mesh to time " << name() << endl;
2278  write
2279  (
2280  debugType(debug),
2281  writeType(writeLevel() | WRITEMESH),
2282  mesh_.time().path()/name()
2283  );
2284  Pout<< "Dumped debug data in = "
2285  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2286 
2287  // test all is still synced across proc patches
2288  checkData();
2289  }
2290 
2291  Info<< "Refined mesh in = "
2292  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2293  printMeshInfo(debug, "After refinement " + msg);
2294 
2295 
2296  // Load balancing
2297  // ~~~~~~~~~~~~~~
2298 
2300 
2301  if (Pstream::nProcs() > 1)
2302  {
2303  const scalar nIdealCells =
2304  mesh_.globalData().nTotalCells()
2305  / Pstream::nProcs();
2306 
2307  const scalar unbalance = returnReduce
2308  (
2309  mag(1.0-mesh_.nCells()/nIdealCells),
2310  maxOp<scalar>()
2311  );
2312 
2313  if (unbalance <= maxLoadUnbalance)
2314  {
2315  Info<< "Skipping balancing since max unbalance " << unbalance
2316  << " is less than allowable " << maxLoadUnbalance
2317  << endl;
2318  }
2319  else
2320  {
2321  scalarField cellWeights(mesh_.nCells(), 1);
2322 
2323  distMap = balance
2324  (
2325  false, // keepZoneFaces
2326  false, // keepBaffles
2327  cellWeights,
2328  decomposer,
2329  distributor
2330  );
2331 
2332  Info<< "Balanced mesh in = "
2333  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2334 
2335  printMeshInfo(debug, "After balancing " + msg);
2336 
2337 
2338  if (debug&meshRefinement::MESH)
2339  {
2340  Pout<< "Writing balanced " << msg
2341  << " mesh to time " << name() << endl;
2342  write
2343  (
2344  debugType(debug),
2345  writeType(writeLevel() | WRITEMESH),
2346  mesh_.time().path()/name()
2347  );
2348  Pout<< "Dumped debug data in = "
2349  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2350 
2351  // test all is still synced across proc patches
2352  checkData();
2353  }
2354  }
2355  }
2356 
2357  return distMap;
2358 }
2359 
2360 
2361 // Do load balancing followed by refinement of consistent set of cells.
2364 (
2365  const string& msg,
2366  decompositionMethod& decomposer,
2367  fvMeshDistribute& distributor,
2368  const labelList& initCellsToRefine,
2369  const scalar maxLoadUnbalance
2370 )
2371 {
2372  labelList cellsToRefine(initCellsToRefine);
2373 
2374  //{
2375  // globalIndex globalCells(mesh_.nCells());
2376  //
2377  // Info<< "** Distribution before balancing/refining:" << endl;
2378  // for (label proci = 0; proci < Pstream::nProcs(); proci++)
2379  // {
2380  // Info<< " " << proci << '\t'
2381  // << globalCells.localSize(proci) << endl;
2382  // }
2383  // Info<< endl;
2384  //}
2385  //{
2386  // globalIndex globalCells(cellsToRefine.size());
2387  //
2388  // Info<< "** Cells to be refined:" << endl;
2389  // for (label proci = 0; proci < Pstream::nProcs(); proci++)
2390  // {
2391  // Info<< " " << proci << '\t'
2392  // << globalCells.localSize(proci) << endl;
2393  // }
2394  // Info<< endl;
2395  //}
2396 
2397 
2398  // Load balancing
2399  // ~~~~~~~~~~~~~~
2400 
2402 
2403  if (Pstream::nProcs() > 1)
2404  {
2405  // First check if we need to balance at all. Precalculate number of
2406  // cells after refinement and see what maximum difference is.
2407  const scalar nNewCells =
2408  scalar(mesh_.nCells() + 7*cellsToRefine.size());
2409  const scalar nIdealNewCells =
2410  returnReduce(nNewCells, sumOp<scalar>())/Pstream::nProcs();
2411  const scalar unbalance = returnReduce
2412  (
2413  mag(1.0-nNewCells/nIdealNewCells),
2414  maxOp<scalar>()
2415  );
2416 
2417  if (unbalance <= maxLoadUnbalance)
2418  {
2419  Info<< "Skipping balancing since max unbalance " << unbalance
2420  << " is less than allowable " << maxLoadUnbalance
2421  << endl;
2422  }
2423  else
2424  {
2425  scalarField cellWeights(mesh_.nCells(), 1);
2426  forAll(cellsToRefine, i)
2427  {
2428  cellWeights[cellsToRefine[i]] += 7;
2429  }
2430 
2431  distMap = balance
2432  (
2433  false, // keepZoneFaces
2434  false, // keepBaffles
2435  cellWeights,
2436  decomposer,
2437  distributor
2438  );
2439 
2440  // Update cells to refine
2441  distMap().distributeCellIndices(cellsToRefine);
2442 
2443  Info<< "Balanced mesh in = "
2444  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2445  }
2446 
2447  //{
2448  // globalIndex globalCells(mesh_.nCells());
2449  //
2450  // Info<< "** Distribution after balancing:" << endl;
2451  // for (label proci = 0; proci < Pstream::nProcs(); proci++)
2452  // {
2453  // Info<< " " << proci << '\t'
2454  // << globalCells.localSize(proci) << endl;
2455  // }
2456  // Info<< endl;
2457  //}
2458 
2459  printMeshInfo(debug, "After balancing " + msg);
2460 
2461  if (debug&meshRefinement::MESH)
2462  {
2463  Pout<< "Writing balanced " << msg
2464  << " mesh to time " << name() << endl;
2465  write
2466  (
2467  debugType(debug),
2468  writeType(writeLevel() | WRITEMESH),
2469  mesh_.time().path()/name()
2470  );
2471  Pout<< "Dumped debug data in = "
2472  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2473 
2474  // test all is still synced across proc patches
2475  checkData();
2476  }
2477  }
2478 
2479 
2480  // Refinement
2481  // ~~~~~~~~~~
2482 
2483  refine(cellsToRefine);
2484 
2485  if (debug&meshRefinement::MESH)
2486  {
2487  Pout<< "Writing refined " << msg
2488  << " mesh to time " << name() << endl;
2489  write
2490  (
2491  debugType(debug),
2492  writeType(writeLevel() | WRITEMESH),
2493  mesh_.time().path()/name()
2494  );
2495  Pout<< "Dumped debug data in = "
2496  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2497 
2498  // test all is still synced across proc patches
2499  checkData();
2500  }
2501 
2502  Info<< "Refined mesh in = "
2503  << mesh_.time().cpuTimeIncrement() << " s" << endl;
2504 
2505  //{
2506  // globalIndex globalCells(mesh_.nCells());
2507  //
2508  // Info<< "** After refinement distribution:" << endl;
2509  // for (label proci = 0; proci < Pstream::nProcs(); proci++)
2510  // {
2511  // Info<< " " << proci << '\t'
2512  // << globalCells.localSize(proci) << endl;
2513  // }
2514  // Info<< endl;
2515  //}
2516 
2517  printMeshInfo(debug, "After refinement " + msg);
2518 
2519  return distMap;
2520 }
2521 
2522 
2523 // ************************************************************************* //
scalar y
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:474
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
void setSize(const label)
Reset size of List.
Definition: List.C:281
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:85
virtual Ostream & write(const token &)
Write token.
Definition: Ostream.C:51
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static const Form zero
Definition: VectorSpace.H:118
static const direction nComponents
Number of components in this vector space.
Definition: VectorSpace.H:105
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
Abstract base class for decomposition.
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:932
label nTotalFaces() const
Return total number of faces in decomposed mesh. Not.
autoPtr< polyDistributionMap > refineAndBalance(const string &msg, decompositionMethod &decomposer, fvMeshDistribute &distributor, const labelList &cellsToRefine, const scalar maxLoadUnbalance)
Refine some cells and rebalance.
labelList refineCandidates(const List< point > &insidePoints, const scalar curvature, const scalar planarAngle, const bool featureRefinement, const bool featureDistanceRefinement, const bool internalRefinement, const bool surfaceRefinement, const bool curvatureRefinement, const bool gapRefinement, const label maxGlobalCells, const label maxLocalCells) const
Calculate list of cells to refine.
const fvMesh & mesh() const
Reference to mesh.
autoPtr< polyTopoChangeMap > refine(const labelList &cellsToRefine)
Refine some cells.
bool isGap(const scalar, const vector &, const vector &, const vector &, const vector &) const
Is local topology a small gap?
autoPtr< polyDistributionMap > balanceAndRefine(const string &msg, decompositionMethod &decomposer, fvMeshDistribute &distributor, const labelList &cellsToRefine, const scalar maxLoadUnbalance)
Balance before refining some cells.
bool isNormalGap(const scalar, const vector &, const vector &, const vector &, const vector &) const
Is local topology a small gap normal to the test vector.
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Definition: meshSearch.C:61
To compare normals.
normalLess(const vectorList &values)
bool operator()(const label a, const label b) const
labelList cmptType
Component type.
vectorList cmptType
Component type.
Traits class for primitives.
Definition: pTraits.H:53
Motion of the mesh specified as a list of pointMeshMovers.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1321
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1471
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1327
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.
label nInternalFaces() const
const cellList & cells() const
label nFaces() const
Container with cells to refine. Refinement given as single direction.
Definition: refineCell.H:57
Contains information about location on a triSurface.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
static PackedBoolList getMasterFaces(const polyMesh &)
Get per face whether it is uncoupled or a master of a.
Definition: syncTools.C:153
static void syncFaceList(const polyMesh &mesh, UList< T > &l, const CombineOp &cop)
Synchronise values on all mesh faces.
Definition: syncTools.H:387
static void syncBoundaryFaceList(const polyMesh &, UList< T > &, const CombineOp &cop, const TransformOp &top, const bool parRun=Pstream::parRun())
Synchronise values on boundary faces only.
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
label patchi
const cellShapeList & cells
volScalarField & b
Definition: createFields.H:27
labelList getChangedFaces(const polyMesh &mesh, const labelHashSet &patchIDs)
Get initial set of changed faces.
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Namespace for OpenFOAM.
static const zero Zero
Definition: zero.H:97
const doubleScalar e
Definition: doubleScalar.H:106
scalar radToDeg(const scalar rad)
Convert radians to degrees.
Definition: units.C:370
scalar degToRad(const scalar deg)
Convert degrees to radians.
Definition: units.C:364
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
List< cell > cellList
list of cells
Definition: cellList.H:42
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
labelList findIndices(const ListType &, typename ListType::const_reference, const label start=0)
Find all occurrences of given element. Linear search.
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vector point
Point is a vector.
Definition: point.H:41
List< vector > vectorList
A List of vectors.
Definition: vectorList.H:50
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)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Field< vector > vectorField
Specialisation of Field<T> for vector.
static bool less(const vector &x, const vector &y)
To compare normals.
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
void Swap(T &a, T &b)
Definition: Swap.H:43
static const label labelMax
Definition: label.H:62
void sortedOrder(const UList< T > &, labelList &order)
Generate the (stable) sort order for the list.
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
dimensionedScalar cos(const dimensionedScalar &ds)
uint8_t direction
Definition: direction.H:45
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
insidePoints((1 2 3))