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