surfaceRedistributePar.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) 2015-2022 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
27Application
28 surfaceRedistributePar
29
30Group
31 grpSurfaceUtilities
32
33Description
34 (Re)distribution of triSurface. Either takes an undecomposed surface
35 or an already decomposed surface and redistributes it so that each
36 processor has all triangles that overlap its mesh.
37
38Note
39 - best decomposition option is hierarchical since it guarantees
40 square decompositions.
41 - triangles might be present on multiple processors.
42 - merging uses geometric tolerance so take care with writing precision.
43
44\*---------------------------------------------------------------------------*/
45
46#include "argList.H"
47#include "Time.H"
48#include "polyMesh.H"
50#include "mapDistribute.H"
51#include "decompositionModel.H"
52
53using namespace Foam;
54
55// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
56
57// Print on master all the per-processor surface stats.
58void writeProcStats
59(
60 const triSurface& s,
62)
63{
64 // Determine surface bounding boxes, faces, points
65 List<treeBoundBox> surfBb(Pstream::nProcs());
66 surfBb[Pstream::myProcNo()] = treeBoundBox(s.points());
67 Pstream::gatherList(surfBb);
68
69 labelList nPoints(UPstream::listGatherValues<label>(s.points().size()));
70 labelList nFaces(UPstream::listGatherValues<label>(s.size()));
71
72 if (Pstream::master())
73 {
74 forAll(surfBb, proci)
75 {
76 Info<< "processor" << proci << nl;
77
78 const List<treeBoundBox>& bbs = meshBb[proci];
79 forAll(bbs, i)
80 {
81 if (!i)
82 {
83 Info<< "\tMesh bounds : ";
84 }
85 else
86 {
87 Info<< "\t ";
88 }
89 Info<< bbs[i] << nl;
90 }
91 Info<< "\tSurface bounding box : " << surfBb[proci] << nl
92 << "\tTriangles : " << nFaces[proci] << nl
93 << "\tVertices : " << nPoints[proci]
94 << endl;
95 }
96 Info<< endl;
97 }
98}
99
100
101
102int main(int argc, char *argv[])
103{
104 argList::addNote
105 (
106 "Redistribute a triSurface."
107 " The specified surface must be located in the constant/triSurface"
108 " directory"
109 );
110
111 argList::addArgument("triSurfaceMesh");
112 argList::addArgument("distributionType");
113 argList::addBoolOption
114 (
115 "keepNonMapped",
116 "Preserve surface outside of mesh bounds"
117 );
118
119 #include "setRootCase.H"
120 #include "createTime.H"
121 runTime.functionObjects().off();
122
123 const auto surfFileName = args.get<fileName>(1);
124 const auto distTypeName = args.get<word>(2);
125 const label distType =
126 distributedTriSurfaceMesh::distributionTypeNames_[distTypeName];
127
128 Info<< "Reading surface from " << surfFileName << nl << nl
129 << "Using distribution method "
130 << distTypeName << nl << endl;
131
132 const bool keepNonMapped = args.found("keepNonMapped");
133
134 if (keepNonMapped)
135 {
136 Info<< "Preserving surface outside of mesh bounds." << nl << endl;
137 }
138 else
139 {
140 Info<< "Removing surface outside of mesh bounds." << nl << endl;
141 }
142
143
144 if (!Pstream::parRun())
145 {
147 << "Please run this program on the decomposed case."
148 << " It will read surface " << surfFileName
149 << " and decompose it such that it overlaps the mesh bounding box."
150 << exit(FatalError);
151 }
152
153
154 Random rndGen(653213);
155
156 // For independent decomposition, ensure that distributedTriSurfaceMesh
157 // can find the alternative decomposeParDict specified via the
158 // -decomposeParDict option.
159 if (distType == distributedTriSurfaceMesh::INDEPENDENT)
160 {
161 // Ensure demand-driven decompositionMethod finds alternative
162 // decomposeParDict location properly.
163
164 IOdictionary* dictPtr = new IOdictionary
165 (
166 IOobject::selectIO
167 (
169 (
170 decompositionModel::canonicalName,
171 runTime.system(),
172 runTime,
173 IOobject::MUST_READ,
174 IOobject::NO_WRITE
175 ),
176 args.getOrDefault<fileName>("decomposeParDict", "")
177 )
178 );
179
180 // Store it on the object registry, but to be found it must also
181 // have the expected "decomposeParDict" name.
182
183 dictPtr->rename(decompositionModel::canonicalName);
184 runTime.store(dictPtr);
185 }
186
187 // Determine mesh bounding boxes:
188 List<List<treeBoundBox>> meshBb(Pstream::nProcs());
189 if (distType == distributedTriSurfaceMesh::FOLLOW)
190 {
191 #include "createPolyMesh.H"
192
193 meshBb[Pstream::myProcNo()] = List<treeBoundBox>
194 (
195 1,
197 (
198 boundBox(mesh.points(), false)
199 ).extend(rndGen, 1e-3)
200 );
201 Pstream::allGatherList(meshBb);
202 }
203
205 (
206 surfFileName, // name
207 //runTime.findInstance("triSurface", surfFileName), // instance
208 runTime.constant(), // instance
209 "triSurface", // local
210 runTime, // registry
211 IOobject::MUST_READ,
212 IOobject::AUTO_WRITE
213 );
214
215 // Look for file (using searchableSurface rules)
216 const fileName actualPath(typeFilePath<searchableSurface>(io));
217 fileName localPath(actualPath);
218 localPath.replace(runTime.rootPath() + '/', "");
219
220
222
223 if (actualPath == io.objectPath())
224 {
225 Info<< "Loading local (decomposed) surface " << localPath << nl <<endl;
226 surfMeshPtr.reset(new distributedTriSurfaceMesh(io));
227 }
228 else
229 {
230 Info<< "Loading undecomposed surface " << localPath
231 << " on master only" << endl;
232
235 if (Pstream::master())
236 {
237 // Actually load the surface
238 const bool oldParRun = Pstream::parRun(false);
239 triSurfaceMesh surf(io);
240 Pstream::parRun(oldParRun); // Restore parallel state
241 s = surf;
242 bbs = List<treeBoundBox>(1, treeBoundBox(boundBox::greatBox));
243 }
244 else
245 {
246 bbs = List<treeBoundBox>(1, treeBoundBox(boundBox::invertedBox));
247 }
248
250 dict.add("distributionType", distTypeName);
251 dict.add("mergeDistance", SMALL);
252 dict.add("bounds", bbs);
253
254 // Scatter patch information
255 Pstream::scatter(s.patches());
256
257 // Construct distributedTrisurfaceMesh from components
258 IOobject notReadIO(io);
259 notReadIO.readOpt(IOobject::NO_READ);
260 surfMeshPtr.reset(new distributedTriSurfaceMesh(notReadIO, s, dict));
261 }
262
263 distributedTriSurfaceMesh& surfMesh = surfMeshPtr();
264
265
266 // Write per-processor stats
267 Info<< "Before redistribution:" << endl;
268 writeProcStats(surfMesh, meshBb);
269
270
271 // Do redistribution
272 Info<< "Redistributing surface" << nl << endl;
274 autoPtr<mapDistribute> pointMap;
275 surfMesh.distribute
276 (
277 meshBb[Pstream::myProcNo()],
278 keepNonMapped,
279 faceMap,
280 pointMap
281 );
282 faceMap.clear();
283 pointMap.clear();
284
285 Info<< endl;
286
287
288 // Write per-processor stats
289 Info<< "After redistribution:" << endl;
290 writeProcStats(surfMesh, meshBb);
291
292
293 Info<< "Writing surface." << nl << endl;
294 surfMesh.objectRegistry::write();
295
296 Info<< "End\n" << endl;
297
298 return 0;
299}
300
301
302// ************************************************************************* //
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
Random number generator.
Definition: Random.H:60
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:278
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:178
T getOrDefault(const word &optName, const T &deflt) const
Get a value from the named option if present, or return default.
Definition: argListI.H:307
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
void clear() noexcept
Same as reset(nullptr)
Definition: autoPtr.H:176
void reset(autoPtr< T > &&other) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:117
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:64
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
IOoject and searching on distributed triSurface. All processor hold (possibly overlapping) part of th...
A class for handling file names.
Definition: fileName.H:76
virtual void rename(const word &newName)
Rename.
Definition: regIOobject.C:417
A surface mesh consisting of general polygon faces that has IO capabilities and a registry for storin...
Definition: surfMesh.H:68
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:89
treeBoundBox extend(Random &rndGen, const scalar s) const
Return slightly wider bounding box.
IOoject and searching on triSurface.
Triangulated surface description with patch information.
Definition: triSurface.H:79
A class for handling words, derived from Foam::string.
Definition: word.H:68
dynamicFvMesh & mesh
engineTime & runTime
Required Variables.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const labelList nFaces(UPstream::listGatherValues< label >(aMesh.nFaces()))
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
Namespace for OpenFOAM.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
List< treeBoundBox > meshBb(1, treeBoundBox(boundBox(coarseMesh.points(), false)).extend(rndGen, 1e-3))
dictionary dict
Foam::argList args(argc, argv)
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
Random rndGen
Definition: createFields.H:23