snappyLayerDriverSinglePass.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2021 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 Description
27  Single pass layer addition. Can be removed once multi-pass works ok.
28 
29 \*----------------------------------------------------------------------------*/
30 
31 #include "snappyLayerDriver.H"
32 //#include "motionSmoother.H"
33 //#include "pointSet.H"
34 //#include "faceSet.H"
35 //#include "cellSet.H"
36 #include "polyTopoChange.H"
37 #include "mapPolyMesh.H"
38 #include "addPatchCellLayer.H"
39 #include "mapDistributePolyMesh.H"
40 //#include "OBJstream.H"
41 #include "layerParameters.H"
43 //#include "profiling.H"
44 
45 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
46 
48 (
49  const layerParameters& layerParams,
50  const dictionary& motionDict,
51  const labelList& patchIDs,
52  const label nAllowableErrors,
53  decompositionMethod& decomposer,
54  fvMeshDistribute& distributor
55 )
56 {
57  fvMesh& mesh = meshRefiner_.mesh();
58 
59  // Undistorted edge length
60  const scalar edge0Len = meshRefiner_.meshCutter().level0EdgeLength();
61 
62  // faceZones of type internal or baffle (for merging points across)
63  labelList internalOrBaffleFaceZones;
64  {
66  fzTypes[0] = surfaceZonesInfo::INTERNAL;
67  fzTypes[1] = surfaceZonesInfo::BAFFLE;
68  internalOrBaffleFaceZones = meshRefiner_.getZones(fzTypes);
69  }
70 
71  // faceZones of type internal (for checking mesh quality across and
72  // merging baffles)
73  const labelList internalFaceZones
74  (
75  meshRefiner_.getZones
76  (
78  (
79  1,
81  )
82  )
83  );
84 
85  // Create baffles (pairs of faces that share the same points)
86  // Baffles stored as owner and neighbour face that have been created.
87  List<labelPair> baffles;
88  {
89  labelList originatingFaceZone;
90  meshRefiner_.createZoneBaffles
91  (
92  identity(mesh.faceZones().size()),
93  baffles,
94  originatingFaceZone
95  );
96 
98  {
99  const_cast<Time&>(mesh.time())++;
100  Info<< "Writing baffled mesh to time "
101  << meshRefiner_.timeName() << endl;
102  meshRefiner_.write
103  (
106  (
109  ),
110  mesh.time().path()/meshRefiner_.timeName()
111  );
112  }
113  }
114 
115 
116  // Duplicate points on faceZones of type boundary. Should normally already
117  // be done by snapping phase
118  {
120  if (map)
121  {
122  const labelList& reverseFaceMap = map->reverseFaceMap();
123  forAll(baffles, i)
124  {
125  label f0 = reverseFaceMap[baffles[i].first()];
126  label f1 = reverseFaceMap[baffles[i].second()];
127  baffles[i] = labelPair(f0, f1);
128  }
129  }
130  }
131 
132 
133 
134  // Now we have all patches determine the number of layer per patch
135  // This will be layerParams.numLayers() except for faceZones where one
136  // side does get layers and the other not in which case we want to
137  // suppress movement by explicitly setting numLayers 0
138  labelList numLayers(layerParams.numLayers());
139  {
140  labelHashSet layerIDs(patchIDs);
141  forAll(mesh.faceZones(), zonei)
142  {
143  label mpi, spi;
145  bool hasInfo = meshRefiner_.getFaceZoneInfo
146  (
147  mesh.faceZones()[zonei].name(),
148  mpi,
149  spi,
150  fzType
151  );
152  if (hasInfo)
153  {
154  const polyBoundaryMesh& pbm = mesh.boundaryMesh();
155  if (layerIDs.found(mpi) && !layerIDs.found(spi))
156  {
157  // Only layers on master side. Fix points on slave side
158  Info<< "On faceZone " << mesh.faceZones()[zonei].name()
159  << " adding layers to master patch " << pbm[mpi].name()
160  << " only. Freezing points on slave patch "
161  << pbm[spi].name() << endl;
162  numLayers[spi] = 0;
163  }
164  else if (!layerIDs.found(mpi) && layerIDs.found(spi))
165  {
166  // Only layers on slave side. Fix points on master side
167  Info<< "On faceZone " << mesh.faceZones()[zonei].name()
168  << " adding layers to slave patch " << pbm[spi].name()
169  << " only. Freezing points on master patch "
170  << pbm[mpi].name() << endl;
171  numLayers[mpi] = 0;
172  }
173  }
174  }
175  }
176 
177 
178  // Duplicate points on faceZones that layers are added to
179  labelList pointToMaster;
181  (
182  meshRefiner_,
183  patchIDs, // patch indices
184  numLayers, // number of layers per patch
185  baffles,
186  pointToMaster
187  );
188 
189 
190  // Add layers to patches
191  // ~~~~~~~~~~~~~~~~~~~~~
192 
193  // Now we have
194  // - mesh with optional baffles and duplicated points for faceZones
195  // where layers are to be added
196  // - pointToMaster : correspondence for duplicated points
197  // - baffles : list of pairs of faces
198 
199 
201  (
203  (
204  mesh,
205  patchIDs
206  )
207  );
208 
209 
210  // Global face indices engine
211  const globalIndex globalFaces(mesh.nFaces());
212 
213  // Determine extrudePatch.edgeFaces in global numbering (so across
214  // coupled patches). This is used only to string up edges between coupled
215  // faces (all edges between same (global)face indices get extruded).
216  const labelListList edgeGlobalFaces
217  (
219  (
220  mesh,
221  globalFaces,
222  *pp
223  )
224  );
225 
226  // Determine patches for extruded boundary edges. Calculates if any
227  // additional processor patches need to be constructed.
228 
229  labelList edgePatchID;
230  labelList edgeZoneID;
231  boolList edgeFlip;
232  labelList inflateFaceID;
234  (
235  meshRefiner_,
236  globalFaces,
237  edgeGlobalFaces,
238  *pp,
239 
240  edgePatchID,
241  edgeZoneID,
242  edgeFlip,
243  inflateFaceID
244  );
245 
246 
247  // Point-wise extrusion data
248  // ~~~~~~~~~~~~~~~~~~~~~~~~~
249 
250  // Displacement for all pp.localPoints. Set to large value so does
251  // not trigger the minThickness truncation (see syncPatchDisplacement below)
252  vectorField patchDisp(pp().nPoints(), vector(GREAT, GREAT, GREAT));
253 
254  // Number of layers for all pp.localPoints. Note: only valid if
255  // extrudeStatus = EXTRUDE.
256  labelList patchNLayers(pp().nPoints(), Zero);
257 
258  // Whether to add edge for all pp.localPoints.
259  List<extrudeMode> extrudeStatus(pp().nPoints(), EXTRUDE);
260 
261  // Ideal number of cells added
262  const label nIdealTotAddedCells = setPointNumLayers
263  (
264  layerParams,
265 
266  numLayers,
267  patchIDs,
268  pp(),
269  edgeGlobalFaces,
270 
271  patchDisp,
272  patchNLayers,
273  extrudeStatus
274  );
275 
276  // Determine (wanted) point-wise overall layer thickness and expansion
277  // ratio
278  scalarField thickness(pp().nPoints());
279  scalarIOField minThickness
280  (
281  IOobject
282  (
283  "minThickness",
284  meshRefiner_.timeName(),
285  mesh,
287  ),
288  pp().nPoints()
289  );
290  scalarField expansionRatio(pp().nPoints());
291  calculateLayerThickness
292  (
293  *pp,
294  patchIDs,
295  layerParams,
296  meshRefiner_.meshCutter().cellLevel(),
297  patchNLayers,
298  edge0Len,
299 
300  thickness,
301  minThickness,
302  expansionRatio
303  );
304 
305 
306 
307  // Per cell 0 or number of layers in the cell column it is part of
308  labelList cellNLayers;
309  // Per face actual overall layer thickness
310  scalarField faceRealThickness;
311  // Per face wanted overall layer thickness
312  scalarField faceWantedThickness(mesh.nFaces(), Zero);
313  {
314  UIndirectList<scalar>(faceWantedThickness, pp->addressing()) =
315  avgPointData(*pp, thickness);
316  }
317 
318 
319  // Current set of topology changes. (changing mesh clears out
320  // polyTopoChange)
321  polyTopoChange meshMod(mesh.boundaryMesh().size());
322 
323  // Play changes into meshMod
324  addLayers
325  (
326  layerParams,
327  layerParams.nLayerIter(),
328 
329  // Mesh quality
330  motionDict,
331  layerParams.nRelaxedIter(),
332  nAllowableErrors,
333 
334  patchIDs,
335  internalFaceZones,
336  baffles,
337  numLayers,
338  nIdealTotAddedCells,
339 
340  // Patch information
341  globalFaces,
342  pp(),
343  edgeGlobalFaces,
344  edgePatchID,
345  edgeZoneID,
346  edgeFlip,
347  inflateFaceID,
348 
349  // Per patch point the wanted thickness
350  thickness,
351  minThickness,
352  expansionRatio,
353 
354  // Per patch point the obtained thickness
355  patchDisp,
356  patchNLayers,
357  extrudeStatus,
358 
359  // Complete mesh changes
360  meshMod,
361 
362  // Stats
363  cellNLayers,
364  faceRealThickness
365  );
366 
367 
368  // At this point we have a (shrunk) mesh and a set of topology changes
369  // which will make a valid mesh with layer. Apply these changes to the
370  // current mesh.
371 
372  {
373  // Apply the stored topo changes to the current mesh.
374  autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh, false);
375 
376  mapPolyMesh& map = *mapPtr;
377 
378  // Hack to remove meshPhi - mapped incorrectly. TBD.
379  mesh.moving(false);
380  mesh.clearOut();
381 
382  // Update fields
383  mesh.updateMesh(map);
384 
385  // Move mesh (since morphing does not do this)
386  if (map.hasMotionPoints())
387  {
388  mesh.movePoints(map.preMotionPoints());
389  }
390  else
391  {
392  // Delete mesh volumes.
393  mesh.clearOut();
394  }
395 
396  // Reset the instance for if in overwrite mode
397  mesh.setInstance(meshRefiner_.timeName());
398 
399  meshRefiner_.updateMesh(map, labelList(0));
400 
401  // Update numbering of faceWantedThickness
403  (
404  map.faceMap(),
405  scalar(0),
406  faceWantedThickness
407  );
408 
409  // Print data now that we still have patches for the zones
410  //if (meshRefinement::outputLevel() & meshRefinement::OUTPUTLAYERINFO)
411  printLayerData
412  (
413  mesh,
414  patchIDs,
415  cellNLayers,
416  faceWantedThickness,
417  faceRealThickness,
418  layerParams
419  );
420 
421 
422  // Dump for debugging
424  {
425  const_cast<Time&>(mesh.time())++;
426  Info<< "Writing mesh with layers but disconnected to time "
427  << meshRefiner_.timeName() << endl;
428  meshRefiner_.write
429  (
432  (
435  ),
436  mesh.time().path()/meshRefiner_.timeName()
437  );
438  }
439 
440 
441  // Map baffles, pointToMaster
442  mapFaceZonePoints(meshRefiner_, map, baffles, pointToMaster);
443  }
444 
445 
446  // Merge baffles
447  mergeFaceZonePoints
448  (
449  pointToMaster, // -1 or index of duplicated point
450  cellNLayers,
451  faceRealThickness,
452  faceWantedThickness
453  );
454 
455 
456  // Do final balancing
457  // ~~~~~~~~~~~~~~~~~~
458 
459  if (Pstream::parRun())
460  {
461  Info<< nl
462  << "Doing final balancing" << nl
463  << "---------------------" << nl
464  << endl;
465 
466  if (debug)
467  {
468  const_cast<Time&>(mesh.time())++;
469  }
470 
471  // Balance. No restriction on face zones and baffles.
472  autoPtr<mapDistributePolyMesh> map = meshRefiner_.balance
473  (
474  false,
475  false,
476  labelList::null(),
477  scalarField(mesh.nCells(), 1.0),
478  decomposer,
479  distributor
480  );
481 
482  // Re-distribute flag of layer faces and cells
483  map().distributeCellData(cellNLayers);
484  map().distributeFaceData(faceWantedThickness);
485  map().distributeFaceData(faceRealThickness);
486  }
487 
488 
489  // Write mesh data
490  // ~~~~~~~~~~~~~~~
491 
492  if (!dryRun_)
493  {
494  writeLayerData
495  (
496  mesh,
497  patchIDs,
498  cellNLayers,
499  faceWantedThickness,
500  faceRealThickness
501  );
502  }
503 }
504 
505 
506 // ************************************************************************* //
const labelList patchIDs(pbm.indices(polyPatchNames, true))
const polyBoundaryMesh & pbm
Simple container to keep together layer specific information.
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
bool found(const Key &key) const
Same as contains()
Definition: HashTable.H:1370
bool getFaceZoneInfo(const word &fzName, label &masterPatchID, label &slavePatchID, surfaceZonesInfo::faceZoneType &fzType) const
Lookup faceZone information. Return false if no information.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
static writeType writeLevel()
Get/set write level.
labelList getZones(const List< surfaceZonesInfo::faceZoneType > &fzTypes) const
Get zones of given type.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
const labelList & numLayers() const
How many layers to add.
scalar level0EdgeLength() const
Typical edge length between unrefined points.
Definition: hexRef8.H:499
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
const fvMesh & mesh() const
Reference to mesh.
label nRelaxedIter() const
Number of iterations after which relaxed motion rules.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static void updateList(const labelList &newToOld, const T &nullValue, List< T > &elems)
Helper: reorder list according to map.
void addLayersSinglePass(const layerParameters &layerParams, const dictionary &motionDict, const labelList &patchIDs, const label nAllowableErrors, decompositionMethod &decomposer, fvMeshDistribute &distributor)
For debugging. Can be removed.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
static labelListList globalEdgeFaces(const polyMesh &, const globalIndex &globalFaces, const indirectPrimitivePatch &pp, const bitSet &orientation)
Per patch edge the pp faces (in global indices) using it.
dynamicFvMesh & mesh
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Abstract base class for domain decomposition.
Vector< scalar > vector
Definition: vector.H:57
label nLayerIter() const
Number of overall layer addition iterations.
word timeName() const
Replacement for Time::timeName() that returns oldInstance (if overwrite_)
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
const hexRef8 & meshCutter() const
Reference to meshcutting engine.
autoPtr< mapDistributePolyMesh > balance(const bool keepZoneFaces, const bool keepBaffles, const labelList &singleProcPoints, const scalarField &cellWeights, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Redecompose according to cell count.
int debug
Static debugging option.
static void mapFaceZonePoints(meshRefinement &meshRefiner, const mapPolyMesh &map, labelPairList &baffles, labelList &pointToMaster)
Map numbering after adding cell layers.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
void updateMesh(const mapPolyMesh &, const labelList &changedFaces)
Update for external change to mesh. changedFaces are in new mesh.
static void determineSidePatches(meshRefinement &meshRefiner, const globalIndex &globalFaces, const labelListList &edgeGlobalFaces, const indirectPrimitivePatch &pp, labelList &edgePatchID, labelList &edgeZoneID, boolList &edgeFlip, labelList &inflateFaceID)
Helper: see what zones and patches edges should be extruded into.
bool hasMotionPoints() const noexcept
Has valid preMotionPoints?
Definition: mapPolyMesh.H:767
autoPtr< mapPolyMesh > createZoneBaffles(const labelList &zoneIDs, List< labelPair > &baffles, labelList &originatingFaceZone)
Create baffles for faces on faceZones. Return created baffles.
autoPtr< mapPolyMesh > dupNonManifoldBoundaryPoints()
Find boundary points that are on faceZones of type boundary.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:52
Direct mesh changes based on v1.3 polyTopoChange syntax.
Nothing to be read.
messageStream Info
Information stream (stdout output on master, null elsewhere)
writeType
Enumeration for what to write. Used as a bit-pattern.
faceZoneType
What to do with faceZone faces.
debugType
Enumeration for what to debug. Used as a bit-pattern.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
void addLayers(const layerParameters &layerParams, const label nLayerIter, const dictionary &motionDict, const label nRelaxedIter, const label nAllowableErrors, const labelList &patchIDs, const labelList &internalFaceZones, const List< labelPair > &baffles, const labelList &numLayers, const label nIdealTotAddedCells, const globalIndex &globalFaces, indirectPrimitivePatch &pp, const labelListList &edgeGlobalFaces, const labelList &edgePatchID, const labelList &edgeZoneID, const boolList &edgeFlip, const labelList &inflateFaceID, const scalarField &thickness, const scalarIOField &minThickness, const scalarField &expansionRatio, vectorField &patchDisp, labelList &patchNLayers, List< extrudeMode > &extrudeStatus, polyTopoChange &savedMeshMod, labelList &cellNLayers, scalarField &faceRealThickness)
const labelList & faceMap() const noexcept
Old face map.
Definition: mapPolyMesh.H:503
bool write() const
Write mesh and all data.
List< label > labelList
A List of labels.
Definition: List.H:62
static autoPtr< mapPolyMesh > dupFaceZonePoints(meshRefinement &meshRefiner, const labelList &patchIDs, const labelList &numLayers, List< labelPair > baffles, labelList &pointToMaster)
Duplicate points on faceZones with layers. Re-used when adding buffer layers. Can be made private aga...
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
A primitive field of type <T> with automated input and output.
const pointField & preMotionPoints() const noexcept
Pre-motion point positions.
Definition: mapPolyMesh.H:759
static const List< label > & null() noexcept
Return a null List (reference to a nullObject). Behaves like an empty List.
Definition: List.H:153
const labelIOList & cellLevel() const
Definition: hexRef8.H:481
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127