Loading...
Searching...
No Matches
fvMeshTools.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) 2012-2016 OpenFOAM Foundation
9 Copyright (C) 2015-2025 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
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\*---------------------------------------------------------------------------*/
28
29#include "fvMeshTools.H"
30#include "pointSet.H"
31#include "faceSet.H"
32#include "cellSet.H"
33#include "fileOperation.H"
34#include "BitOps.H"
35#include "IOobjectList.H"
40
41// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42
43// Adds patch if not yet there. Returns patchID.
45(
46 fvMesh& mesh,
47 const polyPatch& patch,
48 const dictionary& patchFieldDict,
49 const word& defaultPatchFieldType,
50 const bool validBoundary
51)
52{
53 auto& polyPatches = const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
54
55 label patchi = polyPatches.findPatchID(patch.name());
56 if (patchi != -1)
57 {
58 // Already there
59 return patchi;
60 }
61
62
63 // Append at end unless there are processor patches
64 label insertPatchi = polyPatches.size();
65 label startFacei = mesh.nFaces();
66
67 if (!isA<processorPolyPatch>(patch))
68 {
69 forAll(polyPatches, patchi)
70 {
71 const polyPatch& pp = polyPatches[patchi];
72
74 {
75 insertPatchi = patchi;
76 startFacei = pp.start();
77 break;
78 }
79 }
80 }
81
82
83 // Below is all quite a hack. Feel free to change once there is a better
84 // mechanism to insert and reorder patches.
85
86 // Clear local fields and e.g. polyMesh parallelInfo.
87 mesh.clearOut();
88
89 label sz = polyPatches.size();
90
91 auto& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
92
93 // Add polyPatch at the end
94 polyPatches.resize(sz+1);
95 polyPatches.set
96 (
97 sz,
98 patch.clone
99 (
100 polyPatches,
101 insertPatchi, //index
102 0, //size
103 startFacei //start
104 )
105 );
106 fvPatches.resize(sz+1);
107 fvPatches.set
108 (
109 sz,
111 (
112 polyPatches[sz], // point to newly added polyPatch
113 mesh.boundary()
114 )
115 );
116
117
118 do
119 {
120 #undef doLocalCode
121 #define doLocalCode(FieldType) \
122 { \
123 addPatchFields<FieldType> \
124 ( \
125 mesh, patchFieldDict, defaultPatchFieldType, Zero \
126 ); \
127 }
128
129 // Volume fields
135
136 // Surface fields
142
143 #undef doLocalCode
144 }
145 while (false);
146
147
148 // Create reordering list
149 // - patches before insert position stay as is
150 // - patches after insert position move one up
151 // - appended patch gets moved to insert position
152
153 labelList oldToNew(identity(sz+1));
154 for (label i = insertPatchi; i < sz; ++i)
155 {
156 oldToNew[i] = i+1;
157 }
158 oldToNew[sz] = insertPatchi;
159
160
161 // Shuffle into place
162 polyPatches.reorder(oldToNew, validBoundary);
163 fvPatches.reorder(oldToNew);
164
165 do
166 {
167 #undef doLocalCode
168 #define doLocalCode(FieldType) \
169 { \
170 reorderPatchFields<FieldType>(mesh, oldToNew); \
171 }
172
173 // Volume fields
179
180 // Surface fields
186
187 #undef doLocalCode
189 while (false);
190
191 return insertPatchi;
192}
193
194
195void Foam::fvMeshTools::setPatchFields
196(
197 fvMesh& mesh,
198 const label patchi,
199 const dictionary& patchFieldDict
200)
201{
202 do
203 {
204 #undef doLocalCode
205 #define doLocalCode(FieldType) \
206 { \
207 setPatchFields<FieldType>(mesh, patchi, patchFieldDict); \
208 }
209
210 // Volume fields
216
217 // Surface fields
224 #undef doLocalCode
225 }
226 while (false);
227}
228
229
230void Foam::fvMeshTools::zeroPatchFields(fvMesh& mesh, const label patchi)
231{
232 do
233 {
234 #undef doLocalCode
235 #define doLocalCode(FieldType) \
236 { \
237 setPatchFields<FieldType>(mesh, patchi, Zero); \
238 }
239
240 // Volume fields
246
247 // Surface fields
253
254 #undef doLocalCode
255 }
256 while (false);
257}
258
259
260// Deletes last patch
261void Foam::fvMeshTools::trimPatches(fvMesh& mesh, const label nPatches)
262{
263 // Clear local fields and e.g. polyMesh globalMeshData.
264 mesh.clearOut();
265
266 auto& polyPatches = const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
267 auto& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
268
269 if (polyPatches.empty())
270 {
272 << "No patches in mesh"
273 << abort(FatalError);
274 }
275
276 label nFaces = 0;
277 for (label patchi = nPatches; patchi < polyPatches.size(); patchi++)
278 {
279 nFaces += polyPatches[patchi].size();
280 }
281 reduce(nFaces, sumOp<label>());
282
283 if (nFaces)
284 {
286 << "There are still " << nFaces
287 << " faces in " << polyPatches.size()-nPatches
288 << " patches to be deleted" << abort(FatalError);
289 }
290
291 // Remove actual patches
292 polyPatches.resize(nPatches);
293 fvPatches.resize(nPatches);
294
295 do
296 {
297 #undef doLocalCode
298 #define doLocalCode(FieldType) \
299 { \
300 trimPatchFields<FieldType>(mesh, nPatches); \
301 }
302
303 // Volume fields
309
310 // Surface fields
317 #undef doLocalCode
318 }
319 while (false);
320}
321
322
324(
325 fvMesh& mesh,
326 const labelList& oldToNew,
327 const label nNewPatches,
328 const bool validBoundary
329)
330{
331 auto& polyPatches = const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
332 auto& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
333
334 // Shuffle into place
335 polyPatches.reorder(oldToNew, validBoundary);
336 fvPatches.reorder(oldToNew);
337
338 do
339 {
340 #undef doLocalCode
341 #define doLocalCode(FieldType) \
342 { \
343 reorderPatchFields<FieldType>(mesh, oldToNew); \
344 }
345
346 // Volume fields
352
353 // Surface fields
359
360 #undef doLocalCode
361 }
362 while (false);
363
364 // Remove last.
365 trimPatches(mesh, nNewPatches);
366}
367
368
370(
371 fvMesh& mesh,
372 const wordList& keepPatches,
373 const bool validBoundary
374)
375{
376 const polyBoundaryMesh& pbm = mesh.boundaryMesh();
377
378 labelList newToOld(pbm.size());
379 labelList oldToNew(pbm.size(), -1);
380 label newI = 0;
381
382
383 // Assumes all non-coupled boundaries are on all processors!
384 forAll(pbm, patchI)
385 {
386 const polyPatch& pp = pbm[patchI];
387
389 {
390 if (keepPatches.found(pp.name()))
391 {
392 newToOld[newI] = patchI;
393 oldToNew[patchI] = newI++;
394 }
395 else
396 {
397 label nFaces = pp.size();
398 if (validBoundary)
399 {
400 reduce(nFaces, sumOp<label>());
401 }
402
403 if (nFaces > 0)
404 {
405 newToOld[newI] = patchI;
406 oldToNew[patchI] = newI++;
407 }
408 }
409 }
410 }
411
412 // Same for processor patches (but need no reduction)
413 forAll(pbm, patchI)
414 {
415 const polyPatch& pp = pbm[patchI];
416
417 if
418 (
420 && (
421 pp.size()
422 || keepPatches.found(pp.name())
423 )
424 )
425 {
426 newToOld[newI] = patchI;
427 oldToNew[patchI] = newI++;
428 }
429 }
430
431 newToOld.resize(newI);
432
433 // Move all deletable patches to the end
434 forAll(oldToNew, patchI)
435 {
436 if (oldToNew[patchI] == -1)
437 {
438 oldToNew[patchI] = newI++;
439 }
440 }
442 reorderPatches(mesh, oldToNew, newToOld.size(), validBoundary);
443
444 return newToOld;
445}
446
447
449(
450 fvMesh& mesh,
451 const bool validBoundary
452)
453{
454 return removeEmptyPatches(mesh, wordList::null(), validBoundary);
455}
456
457
459{
460 // Set the fvGeometryScheme to basic since it does not require
461 // any parallel communication to construct the geometry. During
462 // redistributePar one might temporarily end up with processors
463 // with zero procBoundaries. Normally procBoundaries trigger geometry
464 // calculation (e.g. send over cellCentres) so on the processors without
465 // procBoundaries this will not happen. The call to the geometry calculation
466 // is not synchronised and this might lead to a hang for geometry schemes
467 // that do require synchronisation
468
469 tmp<fvGeometryScheme> basicGeometry
470 (
472 );
473 mesh.geometry(basicGeometry);
474}
475
476
479(
480 const IOobject& io,
481 const bool masterOnlyReading,
482 const bool verbose
483)
484{
485 // Region name
486 // ~~~~~~~~~~~
487
488 const fileName meshSubDir
489 (
490 polyMesh::meshDir(io.name())
491 );
492
493
494 fileName facesInstance;
495 fileName pointsInstance;
496
497 // Patch types
498 // ~~~~~~~~~~~
499 // Read and scatter master patches (without reading master mesh!)
500
501 PtrList<entry> patchEntries;
502 if (UPstream::master())
503 {
504 const bool oldParRun = Pstream::parRun(false);
505
506 facesInstance = io.time().findInstance
507 (
508 meshSubDir,
509 "faces",
511 );
512 pointsInstance = io.time().findInstance
513 (
514 meshSubDir,
515 "points",
517 );
518
519 patchEntries = polyBoundaryMeshEntries
520 (
522 (
523 "boundary",
524 facesInstance,
525 meshSubDir,
526 io.db(),
530 )
531 );
532
533 UPstream::parRun(oldParRun);
534 }
535
536 // Broadcast information to all
538 (
540 patchEntries,
541 facesInstance,
542 pointsInstance
543 );
544
545
546 // Dummy meshes
547 // ~~~~~~~~~~~~
548
549 // Set up to read-if-present.
550 // Note: does not search for mesh so set instance explicitly
551
552 IOobject meshIO(io);
553 meshIO.instance() = facesInstance;
554 meshIO.readOpt(IOobject::READ_IF_PRESENT);
555
556 // For mesh components (points, faces, ...)
557 IOobject cmptIO(meshIO, "points", meshSubDir);
558 cmptIO.readOpt(IOobject::MUST_READ);
559 cmptIO.writeOpt(IOobject::NO_WRITE);
560 cmptIO.registerObject(false);
561
562
563 // Check who has a mesh
564 const fileName meshDir = io.time().path()/facesInstance/meshSubDir;
565 bool haveMesh = isDir(meshDir);
566 if (masterOnlyReading && !Pstream::master())
567 {
568 haveMesh = false;
569 meshIO.readOpt(IOobject::NO_READ);
570 }
571
572 if (!haveMesh)
573 {
574 cmptIO.readOpt(IOobject::NO_READ);
575 }
576
577
578 // Read mesh
579 // ~~~~~~~~~
580 // Now all processors use supplied points,faces etc
581 // Note: solution, schemes are also using the supplied IOobject so
582 // on slave will be NO_READ, on master READ_IF_PRESENT. This will
583 // conflict with e.g. timeStampMaster reading so switch off.
584 // Note: v2006 used the READ_IF_PRESENT flag in the meshIO.readOpt(). v2012
585 // (correctly) does no longer so below code explicitly addFvPatches
586 // using the separately read boundary file.
587
588 const auto oldCheckType = IOobject::fileModificationChecking;
590
591
592 // Points
593 cmptIO.instance() = pointsInstance;
594 cmptIO.rename("points");
595 pointIOField points(cmptIO);
596
597 // All other mesh components use facesInstance ...
598 cmptIO.instance() = facesInstance;
599
600 // Faces
601 cmptIO.rename("faces");
602 faceCompactIOList faces(cmptIO);
603
604 // Face owner
605 cmptIO.rename("owner");
606 labelIOList owner(cmptIO);
607
608 // Face neighbour
609 cmptIO.rename("neighbour");
610 labelIOList neighbour(cmptIO);
611
612
614 (
615 meshIO,
616 std::move(points),
617 std::move(faces),
618 std::move(owner),
619 std::move(neighbour)
620 );
621 fvMesh& mesh = *meshPtr;
622
624
625
626 // Some processors without patches? - add patches
627
629 {
630 DynamicList<polyPatch*> newPatches(patchEntries.size());
631
632 if (mesh.boundary().size() == patchEntries.size())
633 {
634 // Assumably we have correctly read the boundary and can clone.
635 // Note: for
636 // v2012 onwards this is probably never the case and this whole
637 // section can be removed.
638 forAll(mesh.boundary(), patchi)
639 {
640 newPatches.append
641 (
642 mesh.boundaryMesh()[patchi].clone(mesh.boundaryMesh()).ptr()
643 );
644 }
645 }
646 else
647 {
648 // Use patchEntries, which were read on master and broadcast
649 label nPatches = 0;
650
651 const bool isEmptyMesh = (mesh.nInternalFaces() == 0);
652
653 forAll(patchEntries, patchi)
654 {
655 const entry& e = patchEntries[patchi];
656 const word type(e.dict().get<word>("type"));
657 const word& name = e.keyword();
658
659 if
660 (
661 type == processorPolyPatch::typeName
662 || type == processorCyclicPolyPatch::typeName
663 )
664 {
665 // Unlikely to work with inter-mixed proc-patches anyhow
666 // - could break out of loop here
667 }
668 else
669 {
670 dictionary patchDict(e.dict());
671
672 if (isEmptyMesh)
673 {
674 patchDict.set("nFaces", 0);
675 patchDict.set("startFace", 0);
676 }
677
678 newPatches.append
679 (
681 (
682 name,
683 patchDict,
684 nPatches++,
686 ).ptr()
687 );
688 }
689 }
690 }
691
693 mesh.addFvPatches(newPatches);
694 }
695
696
697 // Determine zones
698 // ~~~~~~~~~~~~~~~
699
700 wordList pointZoneNames(mesh.pointZones().names());
701 wordList faceZoneNames(mesh.faceZones().names());
702 wordList cellZoneNames(mesh.cellZones().names());
703
705 (
707 pointZoneNames,
708 faceZoneNames,
709 cellZoneNames
710 );
711
712 if (!haveMesh)
713 {
714 // Add the zones. Make sure to remove the old dummy ones first
716 mesh.faceZones().clear();
717 mesh.cellZones().clear();
718
719 List<pointZone*> pz(pointZoneNames.size());
720 forAll(pointZoneNames, i)
721 {
722 pz[i] = new pointZone
723 (
724 pointZoneNames[i],
725 i,
727 );
728 }
729 List<faceZone*> fz(faceZoneNames.size());
730 forAll(faceZoneNames, i)
731 {
732 fz[i] = new faceZone
733 (
734 faceZoneNames[i],
735 i,
737 );
738 }
739 List<cellZone*> cz(cellZoneNames.size());
740 forAll(cellZoneNames, i)
741 {
742 cz[i] = new cellZone
743 (
744 cellZoneNames[i],
745 i,
747 );
748 }
749
750 if (pz.size() || fz.size() || cz.size())
751 {
752 mesh.addZones(pz, fz, cz);
753 }
754 }
755
756 return meshPtr;
757}
758
759
760Foam::autoPtr<Foam::fvMesh>
761Foam::fvMeshTools::loadOrCreateMeshImpl
762(
763 const IOobject& io,
764 refPtr<fileOperation>* readHandlerPtr, // Can be nullptr
765 const bool decompose,
766 const bool verbose
767)
768{
769 // Region name
770 // ~~~~~~~~~~~
771
772 const fileName meshSubDir
773 (
774 polyMesh::meshDir(io.name())
775 );
776
777
778 // Patch types
779 // ~~~~~~~~~~~
780 // Read and broadcast master patches (without reading master mesh!)
781
782 PtrList<entry> patchEntries;
783 if (UPstream::master())
784 {
785 const bool oldParRun = UPstream::parRun(false);
786 const label oldNumProcs = fileHandler().nProcs();
787 const int oldCache = fileOperation::cacheLevel(0);
788
789 const fileName facesInstance = io.time().findInstance
790 (
791 meshSubDir,
792 "faces",
794 );
795
796 patchEntries = polyBoundaryMeshEntries
797 (
799 (
800 "boundary",
801 facesInstance,
802 meshSubDir,
803 io.db(),
807 )
808 );
809
811 if (oldParRun)
812 {
813 const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
814 }
815 UPstream::parRun(oldParRun);
816 }
817
818 // Broadcast: send patches to all
820
821
822 // Check who has or needs a mesh.
823 bool haveLocalMesh = false;
824
825 if (readHandlerPtr)
826 {
827 // Non-null reference when a mesh exists on given processor
828 haveLocalMesh = (*readHandlerPtr).good();
829 }
830
831 // Globally consistent information about who has a mesh
832 boolList haveMesh
833 (
835 );
836
837 // Make sure all have the same number of processors
838 label masterNProcs = fileHandler().nProcs();
839 Pstream::broadcast(masterNProcs);
840 const_cast<fileOperation&>(fileHandler()).nProcs(masterNProcs);
841
842
844
845 if (!haveLocalMesh)
846 {
847 // No local mesh - need to synthesize one
848
849 const bool oldParRun = UPstream::parRun(false);
850 const label oldNumProcs = fileHandler().nProcs();
851 const int oldCache = fileOperation::cacheLevel(0);
852
853 // Create dummy mesh - on procs that don't already have a mesh
854 meshPtr.reset
855 (
856 new fvMesh
857 (
859 Foam::zero{},
860 false
861 )
862 );
863 fvMesh& mesh = *meshPtr;
864
865 // Add patches
866 polyPatchList patches(patchEntries.size());
867 label nPatches = 0;
868
869 forAll(patchEntries, patchi)
870 {
871 const entry& e = patchEntries[patchi];
872 const word type(e.dict().get<word>("type"));
873 const word& name = e.keyword();
874
875 if
876 (
877 type == processorPolyPatch::typeName
878 || type == processorCyclicPolyPatch::typeName
879 )
880 {
881 // Stop at the first processor patch.
882 // - logic fails with inter-mixed proc-patches anyhow
883 break;
884 }
885 else
886 {
887 dictionary patchDict(e.dict());
888 patchDict.set("nFaces", 0);
889 patchDict.set("startFace", 0);
890
892 (
893 patchi,
895 (
896 name,
897 patchDict,
898 nPatches++,
900 )
901 );
902 }
903 }
905 mesh.addFvPatches(patches, false); // No parallel comms
906
907 if (!readHandlerPtr)
908 {
909 // The 'old' way of doing things.
910 // Write the dummy mesh to disk for subsequent re-reading.
911 //
912 // This is not particularly elegant.
913 //
914 // Note: add some dummy zones so upon reading it does not read them
915 // from the undecomposed case. Should be done as extra argument to
916 // regIOobject::readStream?
917
919 (
920 1,
921 new pointZone("dummyZone", 0, mesh.pointZones())
922 );
924 (
925 1,
926 new faceZone("dummyZone", 0, mesh.faceZones())
927 );
929 (
930 1,
931 new cellZone("dummyZone", 0, mesh.cellZones())
932 );
933 mesh.addZones(pz, fz, cz);
935 mesh.faceZones().clear();
936 mesh.cellZones().clear();
937 //Pout<< "Writing dummy mesh: " << mesh.polyMesh::objectPath()
938 // << endl;
939 mesh.write();
940
941 // Discard - it will be re-read later
942 meshPtr.reset(nullptr);
943 }
944
946 if (oldParRun)
947 {
948 const_cast<fileOperation&>(fileHandler()).nProcs(oldNumProcs);
949 }
950 UPstream::parRun(oldParRun); // Restore parallel state
951 }
952 else if (readHandlerPtr && haveLocalMesh)
953 {
954 const label numWorldProcs = UPstream::nProcs(UPstream::worldComm);
955 const label realWorldComm = UPstream::worldComm;
956
957 const labelList meshProcIds(BitOps::sortedToc(haveMesh));
958
959 UPstream::communicator newCommunicator;
960
961 auto& readHandler = *readHandlerPtr;
962 auto oldHandler = fileOperation::fileHandler(readHandler);
963
964 // With IO ranks the communicator of the fileOperation will
965 // only include the ranks for the current IO rank.
966 // Instead allocate a new communicator for everyone with a mesh
967
968 // Comparing global ranks in the communicator.
969 if (UPstream::sameProcs(fileHandler().comm(), meshProcIds))
970 {
971 const_cast<fileOperation&>(fileHandler()).nProcs(numWorldProcs);
972 // Can use the handler communicator as is.
974 }
975 else if (UPstream::nProcs(fileHandler().comm()) != numWorldProcs)
976 {
977 // Need a new communicator for the fileHandler.
978
979 // Warning: MS-MPI currently uses MPI_Comm_create() instead of
980 // MPI_Comm_create_group() so it will block here!
981
982 newCommunicator.reset(UPstream::worldComm, meshProcIds);
983 UPstream::commWorld(newCommunicator.comm());
984 }
985
986 // Load but do not initialise
988
989 readHandler = fileOperation::fileHandler(oldHandler);
990 UPstream::commWorld(realWorldComm);
991
992 // Reset mesh communicator to the real world comm
993 meshPtr().polyMesh::comm() = realWorldComm;
994 }
995
996
997 if (!meshPtr)
998 {
999 // Using the 'old' way of doing things (writing to disk and re-reading).
1000
1001 // Read mesh from disk
1002 //
1003 // Now all processors have a (possibly zero size) mesh so can
1004 // read in parallel
1005
1006 //Pout<< "Reading mesh from " << io.objectRelPath() << endl;
1007 // Load but do not initialise
1009 }
1010
1011 fvMesh& mesh = meshPtr();
1012
1013
1014 // Check patches
1015 // ~~~~~~~~~~~~~
1016
1017 #if 0
1018 if (!UPstream::master() && haveLocalMesh)
1019 {
1020 // Check master patch entries names against local ones
1021
1023
1024 forAll(patchEntries, patchi)
1025 {
1026 const entry& e = patchEntries[patchi];
1027 const word type(e.dict().get<word>("type"));
1028 const word& name = e.keyword();
1029
1030 if
1031 (
1032 type == processorPolyPatch::typeName
1033 || type == processorCyclicPolyPatch::typeName
1034 )
1035 {
1036 break;
1037 }
1038
1039 if (patchi >= patches.size())
1040 {
1042 << "Non-processor patches not synchronised." << endl
1043 << "Processor " << UPstream::myProcNo()
1044 << " has only " << patches.size()
1045 << " patches, master has "
1046 << patchi << endl
1047 << exit(FatalError);
1048 }
1049
1050 if
1051 (
1052 type != patches[patchi].type()
1053 || name != patches[patchi].name()
1054 )
1055 {
1057 << "Non-processor patches not synchronised." << endl
1058 << "Master patch " << patchi
1059 << " name:" << type
1060 << " type:" << type << endl
1061 << "Processor " << UPstream::myProcNo()
1062 << " patch " << patchi
1063 << " has name:" << patches[patchi].name()
1064 << " type:" << patches[patchi].type()
1065 << exit(FatalError);
1066 }
1067 }
1068 }
1069 #endif
1070
1071
1072 // Synchronize zones
1073 // ~~~~~~~~~~~~~~~~~
1074
1075 {
1076 wordList pointZoneNames(mesh.pointZones().names());
1077 wordList faceZoneNames(mesh.faceZones().names());
1078 wordList cellZoneNames(mesh.cellZones().names());
1080 (
1082 pointZoneNames,
1083 faceZoneNames,
1084 cellZoneNames
1085 );
1086
1087
1088 if (!haveLocalMesh)
1089 {
1090 // Add the zones. Make sure to remove the old dummy ones first
1091 mesh.pointZones().clear();
1092 mesh.faceZones().clear();
1093 mesh.cellZones().clear();
1094
1095 PtrList<pointZone> pz(pointZoneNames.size());
1096 forAll(pointZoneNames, i)
1097 {
1098 pz.emplace_set(i, pointZoneNames[i], i, mesh.pointZones());
1099 }
1100
1101 PtrList<faceZone> fz(faceZoneNames.size());
1102 forAll(faceZoneNames, i)
1103 {
1104 fz.emplace_set(i, faceZoneNames[i], i, mesh.faceZones());
1105 }
1106
1107 PtrList<cellZone> cz(cellZoneNames.size());
1108 forAll(cellZoneNames, i)
1109 {
1110 cz.emplace_set(i, cellZoneNames[i], i, mesh.cellZones());
1111 }
1112 mesh.addZones(std::move(pz), std::move(fz), std::move(cz));
1113 }
1114 }
1115
1116
1117 // Synchronize sets (on disk)
1118 // ~~~~~~~~~~~~~~~~~~~~~~~~~~
1119
1120 if (!readHandlerPtr)
1121 {
1122 wordList pointSetNames;
1123 wordList faceSetNames;
1124 wordList cellSetNames;
1125 if (UPstream::master())
1126 {
1127 // Read sets
1128 const bool oldParRun = UPstream::parRun(false);
1129
1130 IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
1131 UPstream::parRun(oldParRun);
1132
1133 pointSetNames = objects.sortedNames<pointSet>();
1134 faceSetNames = objects.sortedNames<faceSet>();
1135 cellSetNames = objects.sortedNames<cellSet>();
1136 }
1138 (
1140 pointSetNames,
1141 faceSetNames,
1142 cellSetNames
1143 );
1144
1145 if (!haveLocalMesh)
1146 {
1147 for (const word& setName : pointSetNames)
1148 {
1149 pointSet(mesh, setName, 0).write();
1150 }
1151 for (const word& setName : faceSetNames)
1152 {
1153 faceSet(mesh, setName, 0).write();
1154 }
1155 for (const word& setName : cellSetNames)
1156 {
1157 cellSet(mesh, setName, 0).write();
1158 }
1159 }
1160 }
1161
1162
1163 // Meshes have been done without init so now can do full initialisation
1164
1166 mesh.init(true);
1167
1168 // Force early recreation of globalMeshData etc
1169 mesh.globalData();
1170 mesh.tetBasePtIs();
1171 mesh.geometricD();
1172
1173
1174 // Do some checks.
1175
1176 // Check if the boundary definition is unique
1177 // and processor patches are correct
1180
1181 // Check names of zones are equal
1182 mesh.cellZones().checkDefinition(verbose);
1183 mesh.cellZones().checkParallelSync(verbose);
1184 mesh.faceZones().checkDefinition(verbose);
1185 mesh.faceZones().checkParallelSync(verbose);
1186 mesh.pointZones().checkDefinition(verbose);
1187 mesh.pointZones().checkParallelSync(verbose);
1188
1189 return meshPtr;
1190}
1191
1192
1195(
1196 const IOobject& io,
1197 const bool decompose,
1198 const bool verbose
1199)
1200{
1201 return fvMeshTools::loadOrCreateMeshImpl
1202 (
1203 io,
1204 nullptr, // fileOperation (ignore)
1205 decompose,
1206 verbose
1207 );
1208}
1209
1210
1213(
1214 const IOobject& io,
1215 refPtr<fileOperation>& readHandler,
1216 const bool verbose
1217)
1218{
1219 return fvMeshTools::loadOrCreateMeshImpl
1220 (
1221 io,
1222 &readHandler,
1223 false, // decompose (ignored)
1224 verbose
1225 );
1226}
1227
1228
1230(
1231 const objectRegistry& mesh,
1232 const word& regionName,
1233 const bool verbose
1234)
1235{
1236 // Create dummy system/fv*
1237 {
1238 IOobject io
1239 (
1240 "fvSchemes",
1241 mesh.time().system(),
1242 regionName,
1243 mesh.thisDb(),
1247 );
1248
1249 if (!io.typeHeaderOk<IOdictionary>(false))
1250 {
1251 if (verbose)
1252 {
1253 Info<< "Writing dummy " << regionName/io.name() << endl;
1254 }
1256 dict.add("divSchemes", dictionary());
1257 dict.add("gradSchemes", dictionary());
1258 dict.add("laplacianSchemes", dictionary());
1259
1260 IOdictionary(io, dict).regIOobject::write();
1261 }
1262 }
1263 {
1264 IOobject io
1265 (
1266 "fvSolution",
1267 mesh.time().system(),
1268 regionName,
1269 mesh.thisDb(),
1273 );
1274
1275 if (!io.typeHeaderOk<IOdictionary>(false))
1276 {
1277 if (verbose)
1278 {
1279 Info<< "Writing dummy " << regionName/io.name() << endl;
1280 }
1282 IOdictionary(io, dict).regIOobject::write();
1283 }
1284 }
1285}
1286
1287
1288// ************************************************************************* //
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const polyBoundaryMesh & pbm
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
List of IOobjects with searching and retrieving facilities. Implemented as a HashTable,...
@ NO_REGISTER
Do not request registration (bool: false).
readOption readOpt() const noexcept
Get the read option.
writeOption writeOpt() const noexcept
Get the write option.
bool registerObject() const noexcept
Should objects created with this IOobject be registered?
@ NO_READ
Nothing to be read.
@ READ_IF_PRESENT
Reading is optional [identical to LAZY_READ].
@ MUST_READ
Reading required.
@ NO_WRITE
Ignore writing from objectRegistry::writeObject().
@ AUTO_WRITE
Automatically write from objectRegistry::writeObject().
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition IOobject.H:191
const word & name() const noexcept
Return the object name.
Definition IOobjectI.H:205
const fileName & instance() const noexcept
Read access to instance path component.
Definition IOobjectI.H:289
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition IOobject.H:358
virtual void rename(const word &newName)
Rename the object.
Definition IOobject.H:697
label size() const noexcept
The number of elements in the list.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void resize(const label len)
Adjust allocated size of list.
Definition ListI.H:153
static const List< word > & null() noexcept
Definition List.H:138
static void broadcasts(const int communicator, Type &value, Args &&... values)
Broadcast multiple items to all communicator ranks. Does nothing in non-parallel.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition PtrList.H:67
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:171
PtrList< T > clone(Args &&... args) const
Make a copy by cloning each of the list elements.
void resize(const label newLen)
Adjust size of PtrList.
Definition PtrList.C:124
const word & system() const noexcept
Return system name.
Definition TimePathsI.H:137
bool found(const T &val, label pos=0) const
Same as contains().
Definition UList.H:983
bool get(const label i) const
Return bool value at specified position, always false for out-of-range access.
Definition UList.H:868
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
Wrapper for internally indexed communicator label. Always invokes UPstream::allocateCommunicatorCompo...
Definition UPstream.H:2546
static label commWorld() noexcept
Communicator for all ranks (respecting any local worlds).
Definition UPstream.H:1101
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run.
Definition UPstream.H:1697
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition UPstream.H:1069
static bool sameProcs(int communicator1, int communicator2)
Test for communicator equality.
Definition UPstream.H:1778
static List< T > allGatherValues(const T &localValue, const int communicator=UPstream::worldComm)
Allgather individual values into list locations.
@ broadcast
broadcast [MPI]
Definition UPstream.H:189
static bool & parRun() noexcept
Test if this a parallel run.
Definition UPstream.H:1681
void reorder(const labelUList &oldToNew, const bool check=false)
Reorder elements. Reordering must be unique (ie, shuffle).
Definition UPtrList.C:62
bool empty() const noexcept
True if the list is empty (ie, size() is zero).
Definition UPtrListI.H:99
label size() const noexcept
The number of entries in the list.
Definition UPtrListI.H:106
bool checkDefinition(const bool report=false) const
Check zone definition. Return true if in error.
Definition ZoneMesh.C:979
void clear()
Clear the zones.
Definition ZoneMesh.C:970
wordList names() const
A list of the zone names.
Definition ZoneMesh.C:463
bool checkParallelSync(const bool report=false) const
Check whether all procs have all zones and in same order.
Definition ZoneMesh.C:998
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition autoPtr.H:178
Default geometry calculation scheme. Slight stabilisation for bad meshes.
A collection of cell labels.
Definition cellSet.H:50
A subset of mesh cells.
Definition cellZone.H:61
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition dictionary.C:765
virtual bool init(const bool doInit)
Initialise all non-demand-driven data.
A keyword and a list of tokens is an 'entry'.
Definition entry.H:66
A list of face labels.
Definition faceSet.H:50
A subset of mesh faces organised as a primitive patch.
Definition faceZone.H:63
A class for handling file names.
Definition fileName.H:75
An encapsulation of filesystem-related operations.
static const fileOperation & fileHandler()
Return the current file handler. Will create the default file handler if necessary.
static int cacheLevel() noexcept
Return cache level.
A fvBoundaryMesh is a fvPatch list with a reference to the associated fvMesh, with additional search ...
static void reorderPatches(fvMesh &, const labelList &oldToNew, const label nPatches, const bool validBoundary)
Reorder and remove trailing patches.
static labelList removeEmptyPatches(fvMesh &, const bool validBoundary)
Remove zero sized patches. All but processor patches are.
static void createDummyFvMeshFiles(const objectRegistry &parent, const word &regionName, const bool verbose=false)
Create additional fvSchemes/fvSolution files.
static label addPatch(fvMesh &mesh, const polyPatch &patch, const dictionary &patchFieldDict, const word &defaultPatchFieldType, const bool validBoundary)
Add patch. Inserts patch before all processor patches.
Definition fvMeshTools.C:38
static autoPtr< fvMesh > newMesh(const IOobject &io, const bool masterOnlyReading, const bool verbose=false)
Read mesh or create dummy mesh (0 cells, >0 patches).
static void setBasicGeometry(fvMesh &mesh)
Set the fvGeometryScheme to basic (to avoid parallel communication).
static autoPtr< fvMesh > loadOrCreateMesh(const IOobject &io, const bool decompose, const bool verbose=false)
Read mesh if available, or create empty mesh with non-proc as per proc0 mesh.
static void zeroPatchFields(fvMesh &mesh, const label patchi)
Change patchField to zero on registered fields.
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition fvMesh.H:376
void addFvPatches(polyPatchList &plist, const bool validBoundary=true)
Add boundary patches. Constructor helper.
Definition fvMesh.C:628
const Time & time() const
Return the top-level database.
Definition fvMesh.H:360
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition fvMesh.H:395
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition fvMesh.C:1068
void removeFvBoundary()
Remove boundary patches. Warning: fvPatchFields hold ref to these fvPatches.
Definition fvMesh.C:658
void clearOut(const bool isMeshUpdate=false)
Clear all geometry and addressing.
Definition fvMesh.C:227
static autoPtr< fvPatch > New(const polyPatch &, const fvBoundaryMesh &)
Return a pointer to a new patch created on freestore from polyPatch.
Definition fvPatchNew.C:28
Registry of regIOobjects.
A set of point labels.
Definition pointSet.H:50
A subset of mesh points.
Definition pointZone.H:64
Read and store dictionary entries for boundary patches The object is *never* registered to avoid regi...
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
bool checkDefinition(const bool report=false) const
Check boundary definition.
label findPatchID(const word &patchName, const bool allowNotFound=true) const
Find patch index given a name, return -1 if not found.
bool checkParallelSync(const bool report=false) const
Check whether all procs have all patches and in same order.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition polyMesh.H:671
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition polyMesh.C:844
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir).
Definition polyMesh.C:826
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition polyMesh.C:884
const globalMeshData & globalData() const
Return parallel info (demand-driven).
Definition polyMesh.C:1296
const cellZoneMesh & cellZones() const noexcept
Return cell zone mesh.
Definition polyMesh.H:679
void addZones(PtrList< pointZone > &&pz, PtrList< faceZone > &&fz, PtrList< cellZone > &&cz)
Add mesh zones.
Definition polyMesh.C:994
const pointZoneMesh & pointZones() const noexcept
Return point zone mesh.
Definition polyMesh.H:663
const Vector< label > & geometricD() const
Return the vector of geometric directions in mesh.
Definition polyMesh.C:850
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return pointer to a new patch created on freestore from components.
label nInternalFaces() const noexcept
Number of internal faces.
A class for managing references or pointers (no reference counting).
Definition refPtr.H:54
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
A class for managing temporary objects.
Definition tmp.H:75
A class for handling words, derived from Foam::string.
Definition word.H:66
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
Foam::autoPtr< Foam::dynamicFvMesh > meshPtr
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const auto & io
#define doLocalCode(FieldType, Variable)
auto & name
const pointField & points
List< label > sortedToc(const UList< bool > &bools)
Return the (sorted) values corresponding to 'true' entries.
Definition BitOps.C:200
GeometricField< vector, fvsPatchField, surfaceMesh > surfaceVectorField
PtrList< polyPatch > polyPatchList
Store lists of polyPatch as a PtrList.
Definition polyPatch.H:61
List< word > wordList
List of word.
Definition fileName.H:60
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
GeometricField< vector, fvPatchField, volMesh > volVectorField
List< label > labelList
A List of labels.
Definition List.H:62
GeometricField< scalar, fvPatchField, volMesh > volScalarField
IOList< label > labelIOList
IO for a List of label.
Definition labelIOList.H:32
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler().
CompactIOList< face > faceCompactIOList
Compact IO for a List of face.
Definition faceIOList.H:35
messageStream Info
Information stream (stdout output on master, null elsewhere).
vectorIOField pointIOField
pointIOField is a vectorIOField.
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
GeometricField< tensor, fvPatchField, volMesh > volTensorField
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
GeometricField< tensor, fvsPatchField, surfaceMesh > surfaceTensorField
GeometricField< sphericalTensor, fvPatchField, volMesh > volSphericalTensorField
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
GeometricField< sphericalTensor, fvsPatchField, surfaceMesh > surfaceSphericalTensorField
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...
errorManip< error > abort(error &err)
Definition errorManip.H:139
GeometricField< symmTensor, fvPatchField, volMesh > volSymmTensorField
List< bool > boolList
A List of bools.
Definition List.H:60
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
GeometricField< symmTensor, fvsPatchField, surfaceMesh > surfaceSymmTensorField
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition POSIX.C:862
label nPatches
dictionary dict
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299