reconstructParMesh.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) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2026 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Application
28  reconstructParMesh
29 
30 Group
31  grpParallelUtilities
32 
33 Description
34  Reconstructs a mesh using geometric information only.
35 
36  Writes point/face/cell procAddressing so afterwards reconstructPar can be
37  used to reconstruct fields.
38 
39 Usage
40  \b reconstructParMesh [OPTION]
41 
42  Options:
43  - \par -fullMatch
44  Does geometric matching on all boundary faces. Assumes no point
45  ordering
46 
47  - \par -procMatch
48  Assumes processor patches already in face order but not point order.
49  This is the pre v2106 default behaviour but might be removed if the new
50  topological method works well
51 
52  - \par -mergeTol <tol>
53  Specifies non-default merge tolerance (fraction of mesh bounding box)
54  for above options
55 
56  The default is to assume all processor boundaries are correctly ordered
57  (both faces and points) in which case no merge tolerance is needed.
58 
59 \*---------------------------------------------------------------------------*/
60 
61 #include "argList.H"
62 #include "timeSelector.H"
63 
64 #include "IOobjectList.H"
65 #include "labelIOList.H"
66 #include "processorPolyPatch.H"
67 #include "mapAddedPolyMesh.H"
68 #include "polyMeshAdder.H"
69 #include "faceCoupleInfo.H"
70 #include "fvMeshAdder.H"
71 #include "polyTopoChange.H"
72 #include "topoSet.H"
73 #include "regionProperties.H"
74 #include "fvMeshTools.H"
75 
76 #include "faMeshReconstructor.H"
77 #include "ignoreFaPatch.H"
78 
79 using namespace Foam;
80 
81 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
82 
83 // Tolerance (as fraction of the bounding box). Needs to be fairly lax since
84 // usually meshes get written with limited precision (6 digits)
85 static const scalar defaultMergeTol = 1e-7;
86 
87 
88 // Determine which faces are coupled. Uses geometric merge distance.
89 // Looks either at all boundaryFaces (fullMatch) or only at the
90 // procBoundaries for proci. Assumes that masterMesh contains already merged
91 // all the processors < proci.
92 autoPtr<faceCoupleInfo> determineCoupledFaces
93 (
94  const bool fullMatch,
95  const label masterMeshProcStart,
96  const label masterMeshProcEnd,
97  const polyMesh& masterMesh,
98  const label meshToAddProcStart,
99  const label meshToAddProcEnd,
100  const polyMesh& meshToAdd,
101  const scalar mergeDist
102 )
103 {
104  if (fullMatch || masterMesh.nCells() == 0)
105  {
107  (
108  masterMesh,
109  meshToAdd,
110  mergeDist, // Absolute merging distance
111  true // Matching faces identical
112  );
113  }
114  else
115  {
116  // Pick up all patches on masterMesh ending in "toDDD" where DDD is
117  // the processor number proci.
118 
119  const polyBoundaryMesh& masterPatches = masterMesh.boundaryMesh();
120 
121 
122  DynamicList<label> masterFaces(masterMesh.nBoundaryFaces());
123 
124  for (const polyPatch& pp : masterPatches)
125  {
126  if (isA<processorPolyPatch>(pp))
127  {
128  for
129  (
130  label proci=meshToAddProcStart;
131  proci<meshToAddProcEnd;
132  proci++
133  )
134  {
135  const string toProcString("to" + Foam::name(proci));
136  if (pp.name().ends_with(toProcString))
137  {
138  label meshFacei = pp.start();
139  forAll(pp, i)
140  {
141  masterFaces.append(meshFacei++);
142  }
143  break;
144  }
145  }
146 
147  }
148  }
149 
150 
151  // Pick up all patches on meshToAdd ending in "procBoundaryDDDtoYYY"
152  // where DDD is the processor number proci and YYY is < proci.
153 
154  const polyBoundaryMesh& addPatches = meshToAdd.boundaryMesh();
155 
156  DynamicList<label> addFaces(meshToAdd.nBoundaryFaces());
157 
158  for (const polyPatch& pp : addPatches)
159  {
160  if (isA<processorPolyPatch>(pp))
161  {
162  bool isConnected = false;
163 
164  for
165  (
166  label mergedProci=masterMeshProcStart;
167  !isConnected && (mergedProci < masterMeshProcEnd);
168  mergedProci++
169  )
170  {
171  for
172  (
173  label proci = meshToAddProcStart;
174  proci < meshToAddProcEnd;
175  proci++
176  )
177  {
178  const word fromProcString
179  (
180  processorPolyPatch::newName(proci, mergedProci)
181  );
182 
183  if (pp.name() == fromProcString)
184  {
185  isConnected = true;
186  break;
187  }
188  }
189  }
190 
191  if (isConnected)
192  {
193  label meshFacei = pp.start();
194  forAll(pp, i)
195  {
196  addFaces.append(meshFacei++);
197  }
198  }
199  }
200  }
201 
203  (
204  masterMesh,
205  masterFaces,
206  meshToAdd,
207  addFaces,
208  mergeDist, // Absolute merging distance
209  true, // Matching faces identical?
210  false, // If perfect match are faces already ordered
211  // (e.g. processor patches)
212  false // are faces each on separate patch?
213  );
214  }
215 }
216 
217 
218 autoPtr<mapPolyMesh> mergeSharedPoints
219 (
220  const scalar mergeDist,
221  polyMesh& mesh,
222  labelListList& pointProcAddressing
223 )
224 {
225  // Find out which sets of points get merged and create a map from
226  // mesh point to unique point.
227  Map<label> pointToMaster
228  (
230  (
231  mesh,
232  mergeDist
233  )
234  );
235 
236  Info<< "mergeSharedPoints : detected " << pointToMaster.size()
237  << " points that are to be merged." << endl;
238 
239  if (returnReduceAnd(pointToMaster.empty()))
240  {
241  return nullptr;
242  }
243 
244  polyTopoChange meshMod(mesh);
245 
246  fvMeshAdder::mergePoints(mesh, pointToMaster, meshMod);
247 
248  // Change the mesh (no inflation). Note: parallel comms allowed.
249  autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false, true);
250 
251  // Update fields. No inflation, parallel sync.
252  mesh.updateMesh(map());
253 
254  // pointProcAddressing give indices into the master mesh so adapt them
255  // for changed point numbering.
256 
257  // Adapt constructMaps for merged points.
258  forAll(pointProcAddressing, proci)
259  {
260  labelList& constructMap = pointProcAddressing[proci];
261 
262  forAll(constructMap, i)
263  {
264  label oldPointi = constructMap[i];
265 
266  // New label of point after changeMesh.
267  label newPointi = map().reversePointMap()[oldPointi];
268 
269  if (newPointi < -1)
270  {
271  constructMap[i] = -newPointi-2;
272  }
273  else if (newPointi >= 0)
274  {
275  constructMap[i] = newPointi;
276  }
277  else
278  {
280  << "Problem. oldPointi:" << oldPointi
281  << " newPointi:" << newPointi << abort(FatalError);
282  }
283  }
284  }
285 
286  return map;
287 }
288 
289 
290 boundBox procBounds
291 (
292  const UPtrList<Time>& databases,
293  const word& regionName
294 )
295 {
296  boundBox bb;
297 
298  for (const Time& procDb : databases)
299  {
300  fileName pointsInstance
301  (
302  procDb.findInstance(polyMesh::meshDir(regionName), "points")
303  );
304 
305  if (pointsInstance != procDb.timeName())
306  {
308  << "Your time was specified as " << procDb.timeName()
309  << " but there is no polyMesh/points in that time." << nl
310  << "(points file at " << pointsInstance << ')' << nl
311  << "Please rerun with the correct time specified"
312  << " (through the -constant, -time or -latestTime "
313  << "(at your option)."
314  << endl << exit(FatalError);
315  }
316 
317  Info<< "Reading points from "
318  << procDb.caseName()
319  << " for time = " << procDb.timeName()
320  << nl << endl;
321 
323  (
324  IOobject
325  (
326  "points",
327  pointsInstance,
329  procDb,
333  )
334  );
335 
336  bb.add(points);
337  }
338 
339  return bb;
340 }
341 
342 
343 void writeDistribution
344 (
345  Time& runTime,
346  const fvMesh& masterMesh,
347  const labelListList& cellProcAddressing
348 )
349 {
350  // Write the decomposition as labelList for use with 'manual'
351  // decomposition method.
352  labelIOList cellDecomposition
353  (
354  IOobject
355  (
356  "cellDecomposition",
357  masterMesh.facesInstance(),
358  masterMesh,
362  ),
363  masterMesh.nCells()
364  );
365 
366  forAll(cellProcAddressing, proci)
367  {
368  const labelList& pCells = cellProcAddressing[proci];
369  labelUIndList(cellDecomposition, pCells) = proci;
370  }
371 
372  cellDecomposition.write();
373 
374  Info<< nl << "Wrote decomposition to "
375  << cellDecomposition.objectRelPath()
376  << " for use in manual decomposition." << endl;
377 
378  // Write as volScalarField for postprocessing.
379  // Change time to 0 if was 'constant'
380  {
381  const scalar oldTime = runTime.value();
382  const label oldIndex = runTime.timeIndex();
383  if (runTime.timeName() == runTime.constant() && oldIndex == 0)
384  {
385  runTime.setTime(0, oldIndex+1);
386  }
387 
388  volScalarField cellDist
389  (
390  IOobject
391  (
392  "cellDist",
393  runTime.timeName(),
394  masterMesh,
398  ),
399  masterMesh,
402  );
403 
404  forAll(cellDecomposition, celli)
405  {
406  cellDist[celli] = cellDecomposition[celli];
407  }
408 
409  cellDist.correctBoundaryConditions();
410  cellDist.write();
411 
412  Info<< nl << "Wrote decomposition to "
413  << cellDist.objectRelPath()
414  << " (volScalarField) for visualization."
415  << endl;
416 
417  // Restore time
418  runTime.setTime(oldTime, oldIndex);
419  }
420 }
421 
422 
423 void writeMesh
424 (
425  const fvMesh& mesh,
426  const labelListList& cellProcAddressing
427 )
428 {
429  const fileName outputDir
430  (
431  mesh.time().path()
432  / mesh.time().timeName()
433  / mesh.regionName()
435  );
436 
437  Info<< nl << "Writing merged mesh to "
438  << mesh.time().relativePath(outputDir) << nl << endl;
439 
440  if (!mesh.write())
441  {
443  << "Failed writing polyMesh."
444  << exit(FatalError);
445  }
447 }
448 
449 
450 void writeMaps
451 (
452  const label masterInternalFaces,
453  const labelUList& masterOwner,
454  const polyMesh& procMesh,
455  const labelUList& cellProcAddressing,
456  const labelUList& faceProcAddressing,
457  const labelUList& pointProcAddressing,
458  const labelUList& boundProcAddressing
459 )
460 {
461  const fileName outputDir
462  (
463  procMesh.time().caseName()
464  / procMesh.facesInstance()
465  / procMesh.regionName()
467  );
468 
469  IOobject ioAddr
470  (
471  "procAddressing",
472  procMesh.facesInstance(),
474  procMesh,
478  );
479 
480 
481  Info<< "Writing addressing : " << outputDir << nl;
482 
483  // From processor point to reconstructed mesh point
484 
485  Info<< " pointProcAddressing" << endl;
486  ioAddr.rename("pointProcAddressing");
487  labelIOList::writeContents(ioAddr, pointProcAddressing);
488 
489  // From processor face to reconstructed mesh face
490  // - add turning index to faceProcAddressing.
491  // See reconstructPar for meaning of turning index.
492 
493  labelList faceProcAddr(faceProcAddressing);
494 
495  forAll(faceProcAddr, procFacei)
496  {
497  const label masterFacei = faceProcAddr[procFacei];
498 
499  if
500  (
501  !procMesh.isInternalFace(procFacei)
502  && masterFacei < masterInternalFaces
503  )
504  {
505  // proc face is now external but used to be internal face.
506  // Check if we have owner or neighbour.
507 
508  label procOwn = procMesh.faceOwner()[procFacei];
509  label masterOwn = masterOwner[masterFacei];
510 
511  if (cellProcAddressing[procOwn] == masterOwn)
512  {
513  // No turning. Offset by 1.
514  faceProcAddr[procFacei]++;
515  }
516  else
517  {
518  // Turned face.
519  faceProcAddr[procFacei] = -1 - faceProcAddr[procFacei];
520  }
521  }
522  else
523  {
524  // No turning. Offset by 1.
525  faceProcAddr[procFacei]++;
526  }
527  }
528 
529  Info<< " faceProcAddressing" << endl;
530  ioAddr.rename("faceProcAddressing");
531  labelIOList::writeContents(ioAddr, faceProcAddr);
532  faceProcAddr.clear();
533 
534  // From processor cell to reconstructed mesh cell
535  Info<< " cellProcAddressing" << endl;
536  ioAddr.rename("cellProcAddressing");
537  labelIOList::writeContents(ioAddr, cellProcAddressing);
538 
539 
540  // From processor patch to reconstructed mesh patch
541  Info<< " boundaryProcAddressing" << endl;
542  ioAddr.rename("boundaryProcAddressing");
543  labelIOList::writeContents(ioAddr, boundProcAddressing);
544 
545  Info<< endl;
546 }
547 
548 
549 void printWarning()
550 {
551  Info<<
552 "Merge individual processor meshes back into one master mesh.\n"
553 "Use if the original master mesh has been deleted or the processor meshes\n"
554 "have been modified (topology change).\n"
555 "This tool will write the resulting mesh to a new time step and construct\n"
556 "{cell,face,point}ProcAddressing files in the processor directories so that\n"
557 "reconstructPar can be used to reconstruct fields onto the master mesh.\n\n"
558 "Reasonably tested, but use at your own risk!\n\n";
559 }
560 
561 
562 // Used to determine the correspondence between the edges.
563 // See faMeshReconstructor::calcAddressing
564 void determineFaEdgeMapping
565 (
566  // The reconstructed faMesh patch
567  const uindirectPrimitivePatch& onePatch,
568  // The individual processor faMeshes
569  const UPtrList<faMesh>& procFaMeshes,
570  // Mapping of procPolyMesh to reconstructed points
571  const labelListList& pointProcAddressing,
572 
573  // [out] the edgeProcAddressing but in primitive-patch order
574  labelListList& faEdgeProcAddressing
575 )
576 {
577  // Determines ordering from faMesh to onePatch (= reconstructed faMesh)
578 
579  // Hash the edges using the reconstructed polyMesh mesh points
580  // so we can use pointProcAddressing to reach a common basis.
581 
582  EdgeMap<label> edgesHash;
583  edgesHash.reserve(onePatch.nEdges());
584  {
585  const auto& mp = onePatch.meshPoints();
586 
587  for (const auto& patchEdge : onePatch.edges())
588  {
589  const edge serialMeshEdge(mp, patchEdge);
590  edgesHash.insert(serialMeshEdge, edgesHash.size());
591  }
592  }
593 
594  // Now we can create the mapping from patch-edge on processor
595  // to patch-edge on onePatch
596 
597  faEdgeProcAddressing.resize_nocopy(procFaMeshes.size());
598  forAll(procFaMeshes, proci)
599  {
600  const auto& procMesh = procFaMeshes[proci];
601  const auto& procPatch = procMesh.patch();
602  const auto& mp = procPatch.meshPoints();
603  const auto& ppAddressing = pointProcAddressing[proci];
604 
605  auto& edgeProcAddr = faEdgeProcAddressing[proci];
606  edgeProcAddr.resize_nocopy(procPatch.nEdges());
607 
608  label edgei = 0;
609  for (const auto& e : procPatch.edges())
610  {
611  const edge procMeshEdge(mp, e);
612  const edge serialMeshEdge(ppAddressing, procMeshEdge);
613 
614  edgeProcAddr[edgei] = edgesHash[serialMeshEdge];
615  ++edgei;
616  }
617  }
618 }
619 
620 
621 void sortFaEdgeMapping
622 (
623  // The reconstructed faMesh patch
624  const uindirectPrimitivePatch& onePatch,
625  // The individual processor faMeshes
626  const UPtrList<faMesh>& procFaMeshes,
627  // Mapping of procPolyMesh to reconstructed points
628  const labelListList& pointProcAddressing,
629  const labelListList& faFaceProcAddressing,
630 
631  // [in,out] per proc map of edge to the master.
632  // - on input: primitive patch order.
633  // - on output: sorted by boundary patch
634  labelListList& faEdgeProcAddressing,
635  // [out] per patch the map to the master
636  labelListList& singlePatchEdgeLabels
637 )
638 {
639  // From faMeshReconstructor.C - edge shuffling on patches
640 
641  Map<label> remapGlobal;
642  remapGlobal.reserve(onePatch.nEdges());
643  for (label edgei = 0; edgei < onePatch.nInternalEdges(); ++edgei)
644  {
645  remapGlobal.insert(edgei, remapGlobal.size());
646  }
647 
648 
649  const faMesh& procMesh0 = procFaMeshes[0];
650  const label nNonProcessor = procMesh0.boundary().nNonProcessor();
651 
652  singlePatchEdgeLabels.resize_nocopy(nNonProcessor);
653 
654  forAll(singlePatchEdgeLabels, patchi)
655  {
656  if (isA<ignoreFaPatch>(procMesh0.boundary()[patchi]))
657  {
658  // These are not real edges
659  continue;
660  }
661 
662  forAll(procFaMeshes, proci)
663  {
664  const auto& procMesh = procFaMeshes[proci];
665  const auto& fap = procMesh.boundary()[patchi];
666 
667  labelList patchEdgeLabels(fap.edgeLabels());
668 
669  // Renumber from local edges to global edges (natural order)
670  for (label& edgeId : patchEdgeLabels)
671  {
672  edgeId = faEdgeProcAddressing[proci][edgeId];
673  }
674 
675  // Combine from all processors
676  singlePatchEdgeLabels[patchi].append(patchEdgeLabels);
677  }
678 
679  // Sorted order will be the original non-decomposed order
680  Foam::sort(singlePatchEdgeLabels[patchi]);
681 
682  for (const label sortedEdgei : singlePatchEdgeLabels[patchi])
683  {
684  remapGlobal.insert(sortedEdgei, remapGlobal.size());
685  }
686  }
687 
688  {
689  // Use the map to rewrite the local faEdgeProcAddressing
690 
691  labelListList newEdgeProcAddressing(faEdgeProcAddressing);
692 
693  forAll(procFaMeshes, proci)
694  {
695  const auto& procMesh = procFaMeshes[proci];
696  const auto& procPatch = procMesh.patch();
697 
698  const auto& procEdgeAddr = faEdgeProcAddressing[proci];
699  const auto& procFaceAddr = faFaceProcAddressing[proci];
700  auto& newEdgeProcAddr = newEdgeProcAddressing[proci];
701 
702  // Internal edges are encoded without flipping
703  {
704  auto internalSlice
705  (
706  newEdgeProcAddr.slice(0, procMesh.nInternalEdges())
707  );
708  for (auto& val : internalSlice)
709  {
710  ++val;
711  }
712  }
713 
714  label edgei = procMesh.nInternalEdges();
715 
716  for (const faPatch& fap : procMesh.boundary())
717  {
718  for (const label patchEdgei : fap.edgeLabels())
719  {
720  const label globalEdgei = procEdgeAddr[patchEdgei];
721 
722  const bool isOwner
723  (
724  onePatch.edgeOwner(globalEdgei)
725  == procFaceAddr[procPatch.edgeOwner(patchEdgei)]
726  );
727 
728  if (auto fnd = remapGlobal.cfind(globalEdgei); fnd.good())
729  {
730  if (isOwner)
731  {
732  newEdgeProcAddr[edgei] = (fnd.val()+1);
733  }
734  else
735  {
736  newEdgeProcAddr[edgei] = -(fnd.val()+1);
737  }
738  }
739  else
740  {
742  << "Failed to find edge " << globalEdgei
743  << " this indicates a programming error" << nl
744  << exit(FatalError);
745  }
746  ++edgei;
747  }
748  }
749  }
750  faEdgeProcAddressing = std::move(newEdgeProcAddressing);
751  }
752 }
753 
754 
755 int main(int argc, char *argv[])
756 {
758  (
759  "Reconstruct a mesh using geometric/topological information only"
760  );
761 
762  // Enable -constant ... if someone really wants it
763  // Enable -withZero to prevent accidentally trashing the initial fields
764  timeSelector::addOptions(true, true); // constant(true), zero(true)
765 
767 
770  (
771  "addressing-only",
772  "Create procAddressing only without overwriting the mesh"
773  );
775  (
776  "mergeTol",
777  "scalar",
778  "The merge distance relative to the bounding box size (default 1e-7)"
779  );
781  (
782  "fullMatch",
783  "Do (slower) geometric matching on all boundary faces"
784  );
786  (
787  "procMatch",
788  "Do matching on processor faces only"
789  );
791  (
792  "cellDist",
793  "Write cell distribution as a labelList - for use with 'manual' "
794  "decomposition method or as a volScalarField for post-processing."
795  );
797  (
798  "no-finite-area",
799  "Suppress finiteArea mesh reconstruction",
800  true // Advanced option
801  );
802 
804  (
805  "disable-edge-encoding",
806  "Emit edgeProcAddressing without encoding edge flips, "
807  "as per 2512 and earlier [special use]",
808  true // Advanced option
809  );
810 
811  #include "addAllRegionOptions.H"
812  #include "addAllFaRegionOptions.H"
813 
814  // Prevent volume BCs from triggering finite-area
816 
817  #include "setRootCase.H"
818  #include "createTime.H"
819 
820  printWarning();
821 
822  // ------------------------------------------------------------------------
823  // Configuration
824 
825  const bool fullMatch = args.found("fullMatch");
826  const bool procMatch = args.found("procMatch");
827  const bool writeCellDist = args.found("cellDist");
828  bool doFiniteArea = !args.found("no-finite-area");
829  const bool writeAddrOnly = args.found("addressing-only");
830 
831  const scalar mergeTol =
832  args.getOrDefault<scalar>("mergeTol", defaultMergeTol);
833 
834  // Special use - emit old (2512 and earlier) edgeProcAddressing format
835  // without encoded edge flips.
836  const bool disallowEdgeEncoding = args.found("disable-edge-encoding");
837 
838 
839  if (fullMatch)
840  {
841  Info<< "Use geometric matching on all boundary faces." << nl << endl;
842  }
843  else if (procMatch)
844  {
845  Info<< "Use geometric matching on correct procBoundaries only." << nl
846  << "This assumes a correct decomposition." << endl;
847  }
848  else
849  {
850  Info<< "Merge assuming correct, fully matched procBoundaries." << nl
851  << endl;
852  }
853 
854  if (fullMatch || procMatch)
855  {
856  const scalar writeTol =
857  std::pow(scalar(10), -scalar(IOstream::defaultPrecision()));
858 
859  Info<< "Merge tolerance : " << mergeTol << nl
860  << "Write tolerance : " << writeTol << endl;
861 
862  if
863  (
865  && mergeTol < writeTol
866  )
867  {
869  << "Your current settings specify ASCII writing with "
870  << IOstream::defaultPrecision() << " digits precision." << endl
871  << "Your merging tolerance (" << mergeTol << ")"
872  << " is finer than this." << endl
873  << "Please change your writeFormat to binary"
874  << " or increase the writePrecision" << endl
875  << "or adjust the merge tolerance (-mergeTol)."
876  << exit(FatalError);
877  }
878  }
879 
880  // Handle volume region selections
881  #include "getAllRegionOptions.H"
882 
883  // Handle area region selections
884  #include "getAllFaRegionOptions.H"
885 
886  if (!doFiniteArea)
887  {
888  areaRegionNames.clear(); // For consistency
889  }
890 
891  // Determine the processor count
892  label nProcs{0};
893 
894  if (regionNames.empty())
895  {
897  << "No regions specified or detected."
898  << exit(FatalError);
899  }
900  else if (regionNames[0] == polyMesh::defaultRegion)
901  {
902  nProcs = fileHandler().nProcs(args.path());
903  }
904  else
905  {
906  nProcs = fileHandler().nProcs(args.path(), regionNames[0]);
907 
908  if (regionNames.size() == 1)
909  {
910  Info<< "Using region: " << regionNames[0] << nl << endl;
911  }
912  }
913 
914  if (!nProcs)
915  {
917  << "No processor* directories found"
918  << exit(FatalError);
919  }
920 
921  // Read all time databases
922  PtrList<Time> databases(nProcs);
923 
924  Info<< "Found " << nProcs << " processor directories" << endl;
925  forAll(databases, proci)
926  {
927  Info<< " Reading database "
928  << args.caseName()/("processor" + Foam::name(proci))
929  << endl;
930 
931  databases.set
932  (
933  proci,
934  new Time
935  (
937  args.rootPath(),
938  args.caseName()/("processor" + Foam::name(proci)),
940  args.allowLibs()
941  )
942  );
943  }
944  Info<< endl;
945 
946  // Use the times list from the master processor
947  // and select a subset based on the command-line options
949  (
950  databases[0].times(),
951  args
952  );
953 
954  // Loop over all times
955  forAll(timeDirs, timei)
956  {
957  // Set time for global database
958  runTime.setTime(timeDirs[timei], timei);
959 
960  // Set time for all databases
961  forAll(databases, proci)
962  {
963  databases[proci].setTime(timeDirs[timei], timei);
964  }
965 
966  Info<< "Time = " << runTime.timeName() << endl;
967 
968  // Check for any mesh changes
969  label nMeshChanged = 0;
970  boolList hasRegionMesh(regionNames.size(), false);
971  forAll(regionNames, regioni)
972  {
973  const word& regionName = regionNames[regioni];
974 
975  IOobject facesIO
976  (
977  "faces",
978  databases[0].timeName(),
980  databases[0],
984  );
985 
986  // Problem: faceCompactIOList recognises both 'faceList' and
987  // 'faceCompactList' so we should be lenient when doing
988  // typeHeaderOk
989 
990  const bool ok = facesIO.typeHeaderOk<faceCompactIOList>(false);
991 
992  if (ok)
993  {
994  hasRegionMesh[regioni] = true;
995  ++nMeshChanged;
996  }
997  }
998 
999  // Check for any mesh changes
1000  if (!nMeshChanged)
1001  {
1002  Info<< "No meshes" << nl << endl;
1003  continue;
1004  }
1005 
1006  Info<< endl;
1007 
1008  forAll(regionNames, regioni)
1009  {
1010  const word& regionName = regionNames[regioni];
1012 
1013  if (!hasRegionMesh[regioni])
1014  {
1015  Info<< "region=" << regionName << " (no mesh)" << nl << endl;
1016  continue;
1017  }
1018 
1019  if (regionNames.size() > 1)
1020  {
1021  Info<< "region=" << regionName << nl;
1022  }
1023 
1024 
1025  // Addressing from processor to reconstructed case
1026  labelListList cellProcAddressing(nProcs);
1027  labelListList faceProcAddressing(nProcs);
1028  labelListList pointProcAddressing(nProcs);
1029  labelListList boundProcAddressing(nProcs);
1030 
1031 
1032  // Internal faces on the final reconstructed mesh
1033  label masterInternalFaces;
1034 
1035  // Owner addressing on the final reconstructed mesh
1036  labelList masterOwner;
1037 
1038  if (procMatch)
1039  {
1040  // Read point on individual processors to determine
1041  // merge tolerance
1042  // (otherwise single cell domains might give problems)
1043 
1044  const boundBox bb = procBounds(databases, regionDir);
1045  const scalar mergeDist = mergeTol*bb.mag();
1046 
1047  Info<< "Overall mesh bounding box : " << bb << nl
1048  << "Relative tolerance : " << mergeTol << nl
1049  << "Absolute matching distance : " << mergeDist << nl
1050  << endl;
1051 
1052 
1053  // Construct empty mesh.
1054  PtrList<fvMesh> masterMesh(nProcs);
1055 
1056  for (label proci=0; proci<nProcs; proci++)
1057  {
1058  masterMesh.set
1059  (
1060  proci,
1061  new fvMesh
1062  (
1063  IOobject
1064  (
1065  regionName,
1066  runTime.timeName(),
1067  runTime,
1069  ),
1070  Zero
1071  )
1072  );
1073 
1074  fvMesh meshToAdd
1075  (
1076  IOobject
1077  (
1078  regionName,
1079  databases[proci].timeName(),
1080  databases[proci]
1081  )
1082  );
1083 
1084  // Initialize its addressing
1085  cellProcAddressing[proci] = identity(meshToAdd.nCells());
1086  faceProcAddressing[proci] = identity(meshToAdd.nFaces());
1087  pointProcAddressing[proci] = identity(meshToAdd.nPoints());
1088  boundProcAddressing[proci] =
1089  identity(meshToAdd.boundaryMesh().size());
1090 
1091  // Find geometrically shared points/faces.
1092  autoPtr<faceCoupleInfo> couples = determineCoupledFaces
1093  (
1094  fullMatch,
1095  proci,
1096  proci,
1097  masterMesh[proci],
1098  proci,
1099  proci,
1100  meshToAdd,
1101  mergeDist
1102  );
1103 
1104  // Add elements to mesh
1106  (
1107  masterMesh[proci],
1108  meshToAdd,
1109  couples()
1110  );
1111 
1112  // Added processor
1113  renumber(map().addedCellMap(), cellProcAddressing[proci]);
1114  renumber(map().addedFaceMap(), faceProcAddressing[proci]);
1115  renumber(map().addedPointMap(), pointProcAddressing[proci]);
1116  renumber(map().addedPatchMap(), boundProcAddressing[proci]);
1117  }
1118  for (label step=2; step<nProcs*2; step*=2)
1119  {
1120  for (label proci=0; proci<nProcs; proci+=step)
1121  {
1122  label next = proci + step/2;
1123  if(next >= nProcs)
1124  {
1125  continue;
1126  }
1127 
1128  Info<< "Merging mesh " << proci << " with "
1129  << next << endl;
1130 
1131  // Find geometrically shared points/faces.
1132  autoPtr<faceCoupleInfo> couples = determineCoupledFaces
1133  (
1134  fullMatch,
1135  proci,
1136  next,
1137  masterMesh[proci],
1138  next,
1139  proci+step,
1140  masterMesh[next],
1141  mergeDist
1142  );
1143 
1144  // Add elements to mesh
1146  (
1147  masterMesh[proci],
1148  masterMesh[next],
1149  couples()
1150  );
1151 
1152  // Processors that were already in masterMesh
1153  for (label mergedI=proci; mergedI<next; mergedI++)
1154  {
1155  renumber
1156  (
1157  map().oldCellMap(),
1158  cellProcAddressing[mergedI]
1159  );
1160 
1161  renumber
1162  (
1163  map().oldFaceMap(),
1164  faceProcAddressing[mergedI]
1165  );
1166 
1167  renumber
1168  (
1169  map().oldPointMap(),
1170  pointProcAddressing[mergedI]
1171  );
1172 
1173  // Note: boundary is special since can contain -1.
1174  renumber
1175  (
1176  map().oldPatchMap(),
1177  boundProcAddressing[mergedI]
1178  );
1179  }
1180 
1181  // Added processor
1182  for
1183  (
1184  label addedI=next;
1185  addedI < Foam::min(proci+step, nProcs);
1186  addedI++
1187  )
1188  {
1189  renumber
1190  (
1191  map().addedCellMap(),
1192  cellProcAddressing[addedI]
1193  );
1194 
1195  renumber
1196  (
1197  map().addedFaceMap(),
1198  faceProcAddressing[addedI]
1199  );
1200 
1201  renumber
1202  (
1203  map().addedPointMap(),
1204  pointProcAddressing[addedI]
1205  );
1206 
1207  renumber
1208  (
1209  map().addedPatchMap(),
1210  boundProcAddressing[addedI]
1211  );
1212  }
1213 
1214  masterMesh.set(next, nullptr);
1215  }
1216  }
1217 
1218  for (label proci=0; proci<nProcs; proci++)
1219  {
1220  Info<< "Reading mesh to add from "
1221  << databases[proci].caseName()
1222  << " for time = " << databases[proci].timeName()
1223  << nl << nl << endl;
1224  }
1225 
1226  // See if any points on the mastermesh have become connected
1227  // because of connections through processor meshes.
1228  mergeSharedPoints(mergeDist,masterMesh[0],pointProcAddressing);
1229 
1230  // Save some properties on the reconstructed mesh
1231  masterInternalFaces = masterMesh[0].nInternalFaces();
1232  masterOwner = masterMesh[0].faceOwner();
1233 
1234 
1235  if (writeAddrOnly)
1236  {
1237  Info<< nl
1238  << "Disabled writing of merged mesh (-addressing-only)"
1239  << nl << nl;
1240  }
1241  else
1242  {
1243  // Write reconstructed mesh
1244  writeMesh(masterMesh[0], cellProcAddressing);
1245  if (writeCellDist)
1246  {
1247  writeDistribution
1248  (
1249  runTime,
1250  masterMesh[0],
1251  cellProcAddressing
1252  );
1253  }
1254  }
1255  }
1256  else
1257  {
1258  // Load all meshes
1259  PtrList<fvMesh> fvMeshes(nProcs);
1260  for (label proci=0; proci<nProcs; proci++)
1261  {
1262  fvMeshes.set
1263  (
1264  proci,
1265  new fvMesh
1266  (
1267  IOobject
1268  (
1269  regionName,
1270  databases[proci].timeName(),
1271  databases[proci]
1272  )
1273  )
1274  );
1275  }
1276 
1277  // Construct pointers to meshes
1278  UPtrList<polyMesh> meshes(fvMeshes.size());
1279  forAll(fvMeshes, proci)
1280  {
1281  meshes.set(proci, &fvMeshes[proci]);
1282  }
1283 
1284  // Get pairs of patches to stitch. These pairs have to
1285  // - have ordered, opposite faces (so one to one correspondence)
1286  List<DynamicList<label>> localPatch;
1287  List<DynamicList<label>> remoteProc;
1288  List<DynamicList<label>> remotePatch;
1289  const label nGlobalPatches = polyMeshAdder::procPatchPairs
1290  (
1291  meshes,
1292  localPatch,
1293  remoteProc,
1294  remotePatch
1295  );
1296 
1297  // Collect matching boundary faces on patches-to-stitch
1298  labelListList localBoundaryFace;
1299  labelListList remoteFaceProc;
1300  labelListList remoteBoundaryFace;
1302  (
1303  meshes,
1304  localPatch,
1305  remoteProc,
1306  remotePatch,
1307  localBoundaryFace,
1308  remoteFaceProc,
1309  remoteBoundaryFace
1310  );
1311 
1312  // All matched faces assumed to have vertex0 matched
1313  labelListList remoteFaceStart(meshes.size());
1314  forAll(meshes, proci)
1315  {
1316  const labelList& procFaces = localBoundaryFace[proci];
1317  remoteFaceStart[proci].setSize(procFaces.size(), 0);
1318  }
1319 
1320 
1321 
1322  labelListList patchMap(meshes.size());
1323  labelListList pointZoneMap(meshes.size());
1324  labelListList faceZoneMap(meshes.size());
1325  labelListList cellZoneMap(meshes.size());
1326  forAll(meshes, proci)
1327  {
1328  const polyMesh& mesh = meshes[proci];
1329  patchMap[proci] = identity(mesh.boundaryMesh().size());
1330 
1331  // Remove excess patches
1332  patchMap[proci].setSize(nGlobalPatches);
1333 
1334  pointZoneMap[proci] = identity(mesh.pointZones().size());
1335  faceZoneMap[proci] = identity(mesh.faceZones().size());
1336  cellZoneMap[proci] = identity(mesh.cellZones().size());
1337  }
1338 
1339 
1340  refPtr<fvMesh> masterMeshPtr;
1341  {
1342  // Do in-place addition on proc0.
1343 
1344  const labelList oldFaceOwner(fvMeshes[0].faceOwner());
1345 
1347  (
1348  0, // index of mesh to modify (== mesh_)
1349  fvMeshes,
1350  oldFaceOwner,
1351 
1352  // Coupling info
1353  localBoundaryFace,
1354  remoteFaceProc,
1355  remoteBoundaryFace,
1356 
1357  boundProcAddressing,
1358  cellProcAddressing,
1359  faceProcAddressing,
1360  pointProcAddressing
1361  );
1362 
1363  // Remove zero-faces processor patches
1364  const polyBoundaryMesh& pbm = fvMeshes[0].boundaryMesh();
1365  labelList oldToNew(pbm.size(), -1);
1366  label newi = 0;
1367  // Non processor patches first
1368  forAll(pbm, patchi)
1369  {
1370  const auto& pp = pbm[patchi];
1371  if (!isA<processorPolyPatch>(pp) || pp.size())
1372  {
1373  oldToNew[patchi] = newi++;
1374  }
1375  }
1376  const label nNonProcPatches = newi;
1377 
1378  // Move all deletable patches to the end
1379  forAll(oldToNew, patchi)
1380  {
1381  if (oldToNew[patchi] == -1)
1382  {
1383  oldToNew[patchi] = newi++;
1384  }
1385  }
1387  (
1388  fvMeshes[0],
1389  oldToNew,
1390  nNonProcPatches,
1391  false
1392  );
1393 
1394  masterMeshPtr.cref(fvMeshes[0]);
1395  }
1396 
1397 
1398  const fvMesh& masterMesh = masterMeshPtr();
1399 
1400  // Number of internal faces on the final reconstructed mesh
1401  masterInternalFaces = masterMesh.nInternalFaces();
1402 
1403  // Owner addressing on the final reconstructed mesh
1404  masterOwner = masterMesh.faceOwner();
1405 
1406 
1407  // Write reconstructed mesh
1408  // Override:
1409  // - caseName
1410  // - processorCase flag
1411  // so the resulting mesh goes to the correct location (even with
1412  // collated). The better way of solving this is to construct
1413  // (zero) mesh on the undecomposed runTime.
1414 
1415  if (writeAddrOnly)
1416  {
1417  Info<< nl
1418  << "Disabled writing of merged mesh (-addressing-only)"
1419  << nl << nl;
1420  }
1421  else
1422  {
1423  Time& masterTime = const_cast<Time&>(masterMesh.time());
1424 
1425  const word oldCaseName = masterTime.caseName();
1426  masterTime.caseName() = runTime.caseName();
1427  const bool oldProcCase(masterTime.processorCase(false));
1428 
1429  // Write reconstructed mesh
1430  writeMesh(masterMesh, cellProcAddressing);
1431  if (writeCellDist)
1432  {
1433  writeDistribution
1434  (
1435  runTime,
1436  masterMesh,
1437  cellProcAddressing
1438  );
1439  }
1440  masterTime.caseName() = oldCaseName;
1441  masterTime.processorCase(oldProcCase);
1442  }
1443  }
1444 
1445 
1446  // Write the addressing
1447 
1448  Info<< "Reconstructing addressing from processor meshes"
1449  << " to the newly reconstructed mesh" << nl << endl;
1450 
1451 
1452  // Read finite-area
1453  // For each named area region that exists create a HashTable
1454  // entry that will contain the PtrList for all processors
1455 
1456  PtrList<polyMesh> procMeshes(databases.size());
1457  HashTable<PtrList<faMesh>> procAreaRegionMeshes;
1458  procAreaRegionMeshes.reserve(areaRegionNames.size());
1459 
1460  forAll(databases, proci)
1461  {
1462  Info<< "Processor " << proci << nl
1463  << "Read processor mesh: "
1464  << (databases[proci].caseName()/regionDir) << endl;
1465 
1466  const polyMesh& procMesh = procMeshes.emplace
1467  (
1468  proci,
1469  IOobject
1470  (
1471  regionName,
1472  databases[proci].timeName(),
1473  databases[proci]
1474  )
1475  );
1476 
1477  writeMaps
1478  (
1479  masterInternalFaces,
1480  masterOwner,
1481  procMesh,
1482  cellProcAddressing[proci],
1483  faceProcAddressing[proci],
1484  pointProcAddressing[proci],
1485  boundProcAddressing[proci]
1486  );
1487 
1488 
1489  if (doFiniteArea)
1490  {
1491  const word boundaryInst =
1492  procMesh.time().findInstance
1493  (
1494  procMesh.meshDir(),
1495  "boundary"
1496  );
1497 
1498  for (const word& areaName : areaRegionNames)
1499  {
1500  IOobject io
1501  (
1502  "faBoundary",
1503  boundaryInst,
1504  faMesh::meshDir(procMesh, areaName),
1505  procMesh.time(),
1509  );
1510 
1511  if (io.typeHeaderOk<faBoundaryMesh>(true))
1512  {
1513  // Always based on the volume decomposition!
1514  auto& procFaMeshes = procAreaRegionMeshes(areaName);
1515  procFaMeshes.resize(databases.size());
1516 
1517  procFaMeshes.set
1518  (
1519  proci,
1520  new faMesh(areaName, procMesh)
1521  );
1522  }
1523  }
1524  }
1525  }
1526 
1527 
1528  // A finite-area mapping exists if procFaMeshes was filled
1529 
1530  // Re-read reconstructed polyMesh. Note: could probably be avoided
1531  // by merging into loops above.
1532  refPtr<polyMesh> masterPolyMeshPtr;
1533 
1534  if (!procAreaRegionMeshes.empty())
1535  {
1536  masterPolyMeshPtr.reset
1537  (
1538  new polyMesh
1539  (
1540  IOobject
1541  (
1542  regionName,
1543  runTime.timeName(),
1544  runTime
1545  ),
1546  true
1547  )
1548  );
1549  }
1550 
1551  // Process any finite-area meshes
1552  for (const auto& iter : procAreaRegionMeshes.csorted())
1553  {
1554  const auto& areaName = iter.key();
1555  const auto& procFaMeshes = iter.val();
1556 
1557  const polyMesh& masterMesh = masterPolyMeshPtr();
1558 
1559  // Addressing from processor to reconstructed case
1560  labelListList faFaceProcAddressing(nProcs);
1561  labelListList faEdgeProcAddressing(nProcs);
1562  labelListList faPointProcAddressing(nProcs);
1563  labelListList faBoundProcAddressing(nProcs);
1564 
1565 
1566  // boundProcAddressing and some basic sizing
1567  // ~~~~~~~~~~~~~~~~~~~
1568 
1569  label nPatchFaces = 0;
1570 
1571  forAll(procFaMeshes, proci)
1572  {
1573  const auto& procMesh = procFaMeshes[proci];
1574  const auto& bm = procMesh.boundary();
1575 
1576  nPatchFaces += procMesh.nFaces();
1577 
1578  faBoundProcAddressing[proci] = Foam::identity(bm.size());
1579  // Mark processor patches
1580  faBoundProcAddressing[proci].slice(bm.nNonProcessor()) = -1;
1581  }
1582 
1583 
1584  // faceProcAddressing
1585  // ~~~~~~~~~~~~~~~~~~
1586 
1587  labelList masterFaceLabels(nPatchFaces);
1588  nPatchFaces = 0;
1589  forAll(procFaMeshes, proci)
1590  {
1591  const auto& procMesh = procFaMeshes[proci];
1592  const auto& procPolyFaces = procMesh.faceLabels();
1593  const auto nProcFaces = procMesh.nFaces();
1594  const auto& fpa = faceProcAddressing[proci];
1595 
1596  // Note: faceProcAddressing (polyMesh) is without
1597  // face flips here. Can use directly to map to
1598  // masterPolyMesh faces
1599  masterFaceLabels.slice(nPatchFaces, nProcFaces) =
1600  UIndirectList<label>(fpa, procPolyFaces);
1601 
1602  // Face addressing is just a concatenation
1603  faFaceProcAddressing[proci] =
1604  Foam::identity(nProcFaces, nPatchFaces);
1605 
1606  nPatchFaces += nProcFaces;
1607  }
1608 
1609  // faMesh itself
1610  // ~~~~~~~~~~~~~
1611 
1612  // Set up to read-if-present
1613  IOobject io(masterMesh);
1614  io.readOpt(IOobject::READ_IF_PRESENT);
1615 
1616  // Construct without patches
1617  faMesh masterFaMesh
1618  (
1619  areaName,
1620  masterMesh,
1621  std::move(masterFaceLabels),
1622  io
1623  );
1624 
1625  const auto& masterPatch = masterFaMesh.patch();
1626 
1627 
1628  // pointProcAddressing
1629  // ~~~~~~~~~~~~~~~~~~~
1630 
1631  const auto& mpm = masterPatch.meshPointMap();
1632  forAll(procFaMeshes, proci)
1633  {
1634  const auto& procPatch = procFaMeshes[proci].patch();
1635  const auto& mp = procPatch.meshPoints();
1636 
1637  auto& pointAddr = faPointProcAddressing[proci];
1638  pointAddr.resize_nocopy(mp.size());
1639 
1640  forAll(mp, i)
1641  {
1642  pointAddr[i] = mpm[pointProcAddressing[proci][mp[i]]];
1643  }
1644  }
1645 
1646 
1647  // edgeProcAddressing
1648  // ~~~~~~~~~~~~~~~~~~
1649  // 1. straight mapping from proc faMesh back to reconstructed
1650  // faMesh
1651  determineFaEdgeMapping
1652  (
1653  masterPatch, // reconstructed faMesh patch
1654  procFaMeshes, // individual faMeshes
1655  pointProcAddressing, // procPolyMesh to reconstructed
1656 
1657  faEdgeProcAddressing
1658  );
1659 
1660 
1661  // Per patch all edges on the masterPatch
1662  labelListList singlePatchEdgeLabels;
1663 
1664  // 2. edgeProcAddressing : fix ordering on patches
1665  sortFaEdgeMapping
1666  (
1667  // [inputs]
1668  masterPatch, // reconstructed faMesh patch
1669  procFaMeshes, // individual faMeshes
1670  pointProcAddressing, // procPolyMesh to reconstructed
1671  faFaceProcAddressing, // per proc the map to the master
1672 
1673  // [outputs]
1674  faEdgeProcAddressing, // per proc the map to the master
1675  singlePatchEdgeLabels // per patch the map to the master
1676  );
1677 
1678 
1679  const faMesh& procMesh0 = procFaMeshes[0];
1680 
1681 
1682  // Add faPatches
1683  // ~~~~~~~~~~~~~
1684 
1685  faPatchList completePatches(singlePatchEdgeLabels.size());
1686  label nPatches = 0;
1687  forAll(completePatches, patchi)
1688  {
1689  const auto& patchEdgeLabels = singlePatchEdgeLabels[patchi];
1690 
1691  const faPatch& fap = procMesh0.boundary()[patchi];
1692 
1693  if (isA<ignoreFaPatch>(fap))
1694  {
1695  // These are not real edges
1696  continue;
1697  }
1698 
1699  const label neiPolyPatchId = fap.ngbPolyPatchIndex();
1700 
1701  completePatches.set
1702  (
1703  nPatches,
1704  fap.clone
1705  (
1706  masterFaMesh.boundary(),
1707  patchEdgeLabels,
1708  nPatches, // index
1709  neiPolyPatchId
1710  )
1711  );
1712 
1713  ++nPatches;
1714  }
1715 
1716  completePatches.resize(nPatches);
1717 
1718  // Serial mesh - no parallel communication
1719 
1720  const bool oldParRun = UPstream::parRun(false);
1721 
1722  masterFaMesh.addFaPatches(completePatches);
1723 
1724  UPstream::parRun(oldParRun); // Restore parallel state
1725 
1726 
1727  // Write mesh & individual addressing
1728  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1729 
1731  (
1732  masterMesh.time().timeName(),
1733  masterFaMesh,
1734  masterFaMesh.faceLabels()
1735  );
1736 
1737  forAll(procFaMeshes, proci)
1738  {
1739  const faMesh& procMesh = procFaMeshes[proci];
1740 
1742  (
1743  IOobject
1744  (
1745  "procAddressing",
1746  masterMesh.time().timeName(),
1748  procMesh.thisDb(),
1752  ),
1753  faBoundProcAddressing[proci],
1754  faFaceProcAddressing[proci],
1755  faPointProcAddressing[proci],
1756  faEdgeProcAddressing[proci],
1757  // Turning index (on/off) for edgeProcAddressing
1758  disallowEdgeEncoding
1759  );
1760  }
1761  }
1762  }
1763  }
1764 
1765  Info<< "End\n" << endl;
1766 
1767  return 0;
1768 }
1769 
1770 
1771 // ************************************************************************* //
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
Definition: fvPatchField.H:206
label nPatches
Definition: readKivaGrid.H:394
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
const polyBoundaryMesh & pbm
const Type & value() const noexcept
Return const reference to value.
static void reorderPatches(fvMesh &, const labelList &oldToNew, const label nPatches, const bool validBoundary)
Reorder and remove trailing patches.
Definition: fvMeshTools.C:317
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:477
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:119
void writeMesh() const
Write equivalent mesh information at the polyMesh faceInstances time.
Info<< "Creating field kinetic energy K\"<< endl;volScalarField K("K", 0.5 *magSqr(U));if(U.nOldTimes()){ volVectorField *Uold=&U.oldTime();volScalarField *Kold=&K.oldTime();*Kold==0.5 *magSqr(*Uold);while(Uold->nOldTimes()) { Uold=&Uold-> oldTime()
Definition: createK.H:12
A class for handling file names.
Definition: fileName.H:72
bool emplace(const Key &key, Args &&... args)
Emplace insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:129
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:844
label edgeOwner(label edgei) const
The edge owner face.
label nPoints() const noexcept
Number of mesh points.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:652
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:496
fileName path() const
The path for the case = rootPath/caseName.
Definition: TimePathsI.H:102
const word & regionName() const
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:832
bool allowFaModels() noexcept
The enable/disable state for regionFaModel (default: true)
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values within a list.
const fileName & caseName() const noexcept
The case name.
Definition: TimePathsI.H:78
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
"ascii" (normal default)
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:702
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:65
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:412
engineTime & runTime
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch ("procBoundary..") constructed from the pair of processor IDs...
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:518
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1774
virtual autoPtr< faPatch > clone(const faBoundaryMesh &bm) const
Construct and return a clone, resetting the boundary mesh.
Definition: faPatch.H:261
fileName relativePath(const fileName &input, const bool caseTag=false) const
Return the input relative to the globalPath by stripping off a leading value of the globalPath...
Definition: TimePathsI.H:122
label nInternalEdges() const
Number of internal edges.
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:437
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:389
static void noParallel()
Remove the parallel options.
Definition: argList.C:599
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:171
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:70
wordList regionNames
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:300
static void writeContents(const IOobject &io, const UList< label > &content)
Write contents. The IOobject is never registered.
Definition: IOList.C:194
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
const T & cref() const
Return const reference to the object or to the contents of a (non-null) managed pointer.
Definition: refPtrI.H:216
label nFaces() const noexcept
Number of mesh faces.
const labelList & edgeLabels() const noexcept
Return the list of edges.
Definition: faPatch.H:339
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
instantList select(const instantList &times) const
Select a list of Time values that are within the ranges.
Definition: timeSelector.C:88
bool processorCase() const noexcept
True if this is a processor case.
Definition: TimePathsI.H:52
wordList areaRegionNames
bool allowFunctionObjects() const
The controlDict &#39;functions&#39; entry is allowed to be used.
Definition: argList.C:2279
const labelList & meshPoints() const
Return labelList of mesh points in patch.
virtual const objectRegistry & thisDb() const
Reference to the mesh database.
Definition: faMesh.H:1209
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:400
bool insert(const Key &key, const T &obj)
Copy insert a new entry, not overwriting existing entries.
Definition: HashTableI.H:152
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:358
word timeName
Definition: getTimeIndex.H:3
A list of faces which address into the list of points.
bool allowLibs() const
The controlDict &#39;libs&#39; entry is allowed to be used. (eg, has not been disabled by the -no-libs option...
Definition: argList.C:2297
void add(const boundBox &bb)
Extend to include the second box.
Definition: boundBoxI.H:323
static void removeFiles(const polyMesh &)
Helper: remove all sets files from mesh instance.
Definition: topoSet.C:693
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
virtual void updateMesh(const mapPolyMesh &mpm)
Update mesh corresponding to the given map.
Definition: fvMesh.C:960
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
SubList< T > slice(const label pos, label len=-1)
Return SubList slice (non-const access) - no range checking.
Definition: SubList.H:257
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:113
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition: edge.H:59
static void mergePoints(const polyMesh &, const Map< label > &pointToMaster, polyTopoChange &meshMod)
Helper: Merge points.
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:133
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:611
A class for handling words, derived from Foam::string.
Definition: word.H:63
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir)
Definition: faMesh.C:1022
const Time & time() const noexcept
Return time registry.
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:283
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:407
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
scalar mag() const
The magnitude/length of the bounding box diagonal.
Definition: boundBoxI.H:198
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const auto & io
Foam::PtrList< Foam::fvMesh > meshes(regionNames.size())
static autoPtr< mapAddedPolyMesh > add(fvMesh &mesh0, const fvMesh &mesh1, const faceCoupleInfo &coupleInfo, const bool validBoundary=true, const bool fullyMapped=false)
Inplace add mesh to fvMesh. Maps all stored fields. Returns map.
Definition: fvMeshAdder.C:67
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1101
Reading is optional [identical to LAZY_READ].
static const word null
An empty word.
Definition: word.H:84
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition: argList.C:400
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
virtual void setTime(const Time &t)
Reset the time and time-index to those of the given time.
Definition: Time.C:904
label nInternalFaces() const noexcept
Number of internal faces.
label timeIndex() const noexcept
Return the current time index.
Definition: TimeStateI.H:43
A HashTable similar to std::unordered_map.
Definition: HashTable.H:108
void resize(const label newLen)
Change the size of the list. Any new entries are nullptr.
Definition: UPtrListI.H:251
static word controlDictName
The default control dictionary name (normally "controlDict")
Definition: Time.H:267
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition: HashTable.H:106
errorManip< error > abort(error &err)
Definition: errorManip.H:139
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: PtrList.H:174
const fileName & caseName() const noexcept
Return case name (parallel run) or global case (serial run)
Definition: argListI.H:62
static label procPatchPairs(const UPtrList< polyMesh > &meshes, List< DynamicList< label >> &localPatch, List< DynamicList< label >> &remoteMesh, List< DynamicList< label >> &remotePatch)
Helper: find pairs of processor patches. Return number of non-processor patches.
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1068
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh...
static void addVerboseOption(const string &usage="", bool advanced=false)
Enable a &#39;verbose&#39; bool option, with usage information.
Definition: argList.C:535
label nEdges() const
Number of edges in patch.
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:713
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:131
const fileName & rootPath() const noexcept
Return root path.
Definition: argListI.H:56
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:673
Finite area patch class. Used for 2-D non-Euclidian finite area method.
Definition: faPatch.H:73
const faBoundaryMesh & boundary() const noexcept
Return constant reference to boundary mesh.
Definition: faMeshI.H:24
Required Classes.
fileName path() const
Return the full path to the (processor local) case.
Definition: argListI.H:74
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
bool empty() const noexcept
True if the list is empty (ie, size() is zero)
Definition: UPtrListI.H:99
void writeAddressing() const
Write proc addressing at the polyMesh faceInstances time.
const pointZoneMesh & pointZones() const noexcept
Return point zone mesh.
Definition: polyMesh.H:665
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:750
static void patchFacePairs(const UPtrList< polyMesh > &meshes, const List< DynamicList< label >> &localPatch, const List< DynamicList< label >> &remoteMesh, const List< DynamicList< label >> &remotePatch, labelListList &localBoundaryFace, labelListList &remoteFaceMesh, labelListList &remoteBoundaryFace)
Helper: expand list of coupled patches into pairs of coupled faces.
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
label newPointi
Definition: readKivaGrid.H:497
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
label nCells() const noexcept
Number of mesh cells.
const word & regionDir
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: PtrList.H:56
label nNonProcessor() const
The number of patches before the first processor patch.
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.
void reserve(label numEntries)
Reserve space for at least the specified number of elements (not the number of buckets) and regenerat...
Definition: HashTable.C:729
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir)
Definition: polyMesh.C:826
Required Classes.
Nothing to be read.
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition: polyMesh.H:681
Finite area boundary mesh, which is a faPatch list with registered IO, a reference to the associated ...
messageStream Info
Information stream (stdout output on master, null elsewhere)
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
IOstreamOption::streamFormat writeFormat() const noexcept
Get write stream format.
Definition: TimeI.H:123
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
bool good() const noexcept
True if iterator points to an entry.
Definition: HashTable.H:990
Foam::argList args(argc, argv)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:188
A primitive field of type <T> with automated input and output.
void setSize(label n)
Alias for resize()
Definition: List.H:535
static const word & regionName(const word &region)
The mesh region name or word::null if polyMesh::defaultRegion.
Definition: polyMesh.C:796
Do not request registration (bool: false)
const dimensionedScalar mp
Proton mass.
static Map< label > findSharedPoints(const polyMesh &, const scalar mergeTol)
Find topologically and geometrically shared points.
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
static void addOptions(const bool constant=true, const bool withZero=false)
Add timeSelector options to argList::validOptions.
Definition: timeSelector.C:101
bool set(const Key &key, const T &obj)
Copy assign a new entry, overwriting existing entries.
Definition: HashTableI.H:174
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
label ngbPolyPatchIndex() const noexcept
The neighbour polyPatch index.
Definition: faPatch.H:363
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...
void reset(T *p=nullptr) noexcept
Delete managed pointer and set to new given pointer.
Definition: refPtrI.H:314
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: UPtrList.H:366
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127