Loading...
Searching...
No Matches
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#include <tuple>
53
54using namespace Foam;
55
56// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
57
58// Print on master all the per-processor surface stats.
59// Determine surface bounding boxes, faces, points
60void writeProcStats
61(
62 const triSurface& s,
63 const UList<List<treeBoundBox>>& meshBb
64)
65{
66 // listGatherValues with treeBoundBox makes gcc-15 unhappy
67 // (complains about non-trivial copy for memmove),
68 // so just collect as a std::tuple in a single MPI call
69
70 typedef std::tuple<label, label, point, point> surfTuple;
71
72 List<surfTuple> surfaceInfo;
73 {
74 treeBoundBox bb(s.points());
75
77 (
78 surfTuple(s.points().size(), s.size(), bb.min(), bb.max())
79 );
80 }
81
82 if (UPstream::master())
83 {
84 forAll(surfaceInfo, proci)
85 {
86 Info<< "processor" << proci << nl;
87
88 const auto& [nPoints, nFaces, smin, smax] = surfaceInfo[proci];
89 const auto& bbs = meshBb[proci];
90
91 forAll(bbs, i)
92 {
93 if (!i)
94 {
95 Info<< "\tMesh bounds : ";
96 }
97 else
98 {
99 Info<< "\t ";
100 }
101 Info<< bbs[i] << nl;
102 }
103 Info<< "\tSurface bounding box : " << smin << ' ' << smax << nl
104 << "\tTriangles : " << nFaces << nl
105 << "\tVertices : " << nPoints << endl;
106 }
107 Info<< endl;
108 }
109}
110
111
112
113int main(int argc, char *argv[])
114{
116 (
117 "Redistribute a triSurface."
118 " The specified surface must be located in the constant/triSurface"
119 " directory"
120 );
121
122 argList::addArgument("triSurfaceMesh");
123 argList::addArgument("distributionType");
125 (
126 "keepNonMapped",
127 "Preserve surface outside of mesh bounds"
128 );
129
130 #include "setRootCase.H"
131 #include "createTime.H"
132 runTime.functionObjects().off();
133
134 const auto surfFileName = args.get<fileName>(1);
135 const auto distTypeName = args.get<word>(2);
136 const label distType =
138
139 Info<< "Reading surface from " << surfFileName << nl << nl
140 << "Using distribution method "
141 << distTypeName << nl << endl;
142
143 const bool keepNonMapped = args.found("keepNonMapped");
144
145 if (keepNonMapped)
146 {
147 Info<< "Preserving surface outside of mesh bounds." << nl << endl;
148 }
149 else
150 {
151 Info<< "Removing surface outside of mesh bounds." << nl << endl;
152 }
153
154
155 if (!Pstream::parRun())
156 {
158 << "Please run this program on the decomposed case."
159 << " It will read surface " << surfFileName
160 << " and decompose it such that it overlaps the mesh bounding box."
161 << exit(FatalError);
162 }
163
164
165 Random rndGen(653213);
166
167 // For independent decomposition, ensure that distributedTriSurfaceMesh
168 // can find the alternative decomposeParDict specified via the
169 // -decomposeParDict option.
171 {
172 // Ensure demand-driven decompositionMethod finds alternative
173 // decomposeParDict location properly.
174
175 IOdictionary* dictPtr = new IOdictionary
176 (
178 (
180 (
182 runTime.system(),
183 runTime,
187 ),
188 args.getOrDefault<fileName>("decomposeParDict", "")
189 )
190 );
191
192 // Store it on the object registry, but to be found it must also
193 // have the expected "decomposeParDict" name.
194
196 runTime.store(dictPtr);
197 }
198
199 // Determine mesh bounding boxes:
200 List<List<treeBoundBox>> meshBb(Pstream::nProcs());
201 if (distType == distributedTriSurfaceMesh::FOLLOW)
202 {
203 #include "createPolyMesh.H"
204
205 meshBb[Pstream::myProcNo()] = List<treeBoundBox>
206 (
207 1,
208 treeBoundBox(mesh.points()).extend(rndGen, 1e-3)
209 );
211 }
212
214 (
215 surfFileName, // name
216 //runTime.findInstance("triSurface", surfFileName), // instance
217 runTime.constant(), // instance
218 "triSurface", // local
219 runTime, // registry
222 );
223
224 // Look for file (using searchableSurface rules)
225 const fileName actualPath(io.typeFilePath<searchableSurface>());
226 fileName localPath(actualPath);
227 localPath.replace(runTime.rootPath() + '/', "");
228
229
231
232 if (actualPath == io.objectPath())
233 {
234 Info<< "Loading local (decomposed) surface " << localPath << nl <<endl;
235 surfMeshPtr.reset(new distributedTriSurfaceMesh(io));
236 }
237 else
238 {
239 Info<< "Loading undecomposed surface " << localPath
240 << " on master only" << endl;
241
243 List<treeBoundBox> bbs;
244 if (Pstream::master())
245 {
246 // Actually load the surface
247 const bool oldParRun = Pstream::parRun(false);
248 triSurfaceMesh surf(io);
249 Pstream::parRun(oldParRun); // Restore parallel state
250 s = surf;
251 bbs = List<treeBoundBox>(1, treeBoundBox(boundBox::greatBox));
252 }
253 else
254 {
255 bbs = List<treeBoundBox>(1, treeBoundBox::null());
256 }
257
259 dict.add("distributionType", distTypeName);
260 dict.add("mergeDistance", SMALL);
261 dict.add("bounds", bbs);
262
263 // Scatter patch information
264 Pstream::broadcast(s.patches());
265
266 // Construct distributedTrisurfaceMesh from components
267 IOobject notReadIO(io);
268 notReadIO.readOpt(IOobject::NO_READ);
269 surfMeshPtr.reset(new distributedTriSurfaceMesh(notReadIO, s, dict));
270 }
271
272 distributedTriSurfaceMesh& surfMesh = surfMeshPtr();
273
274
275 // Write per-processor stats
276 Info<< "Before redistribution:" << endl;
277 writeProcStats(surfMesh, meshBb);
278
279
280 // Do redistribution
281 Info<< "Redistributing surface" << nl << endl;
283 autoPtr<mapDistribute> pointMap;
284 surfMesh.distribute
285 (
287 keepNonMapped,
288 faceMap,
289 pointMap
290 );
291 faceMap.clear();
292 pointMap.clear();
293
294 Info<< endl;
295
296
297 // Write per-processor stats
298 Info<< "After redistribution:" << endl;
299 writeProcStats(surfMesh, meshBb);
300
301
302 Info<< "Writing surface." << nl << endl;
303 surfMesh.objectRegistry::write();
304
305 Info<< "End\n" << endl;
306
307 return 0;
308}
309
310
311// ************************************************************************* //
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
@ REGISTER
Request registration (bool: true).
@ NO_READ
Nothing to be 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
static IOobject selectIO(const IOobject &io, const fileName &altFile, const word &ioName="")
Return the IOobject, but also consider an alternative file name.
Definition IOobject.C:256
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
Random number generator.
Definition Random.H:56
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition UList.H:89
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 parRun(const bool on) noexcept
Set as parallel run on/off.
Definition UPstream.H:1669
static List< T > listGatherValues(const T &localValue, const int communicator=UPstream::worldComm)
Gather individual values into list locations.
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 void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition argList.C:366
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 addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
void clear() noexcept
Same as reset(nullptr).
Definition autoPtr.H:255
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition autoPtrI.H:37
static const boundBox greatBox
A large boundBox: min/max == -/+ ROOTVGREAT.
Definition boundBox.H:126
static const word canonicalName
The canonical name ("decomposeParDict") under which the MeshObject is registered.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
IOoject and searching on distributed triSurface. All processor hold (possibly overlapping) part of th...
static const Enum< distributionType > distributionTypeNames_
A class for handling file names.
Definition fileName.H:75
virtual void rename(const word &newName)
Rename.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines....
A surface mesh consisting of general polygon faces that has IO capabilities and a registry for storin...
Definition surfMesh.H:67
Standard boundBox with extra functionality for use in octree.
treeBoundBox extend(Random &rndGen, const scalar s) const
Return slightly wider bounding box.
static const treeBoundBox & null() noexcept
The null treeBoundBox is the same as an inverted box.
IOoject and searching on triSurface.
Triangulated surface description with patch information.
Definition triSurface.H:74
A class for handling words, derived from Foam::string.
Definition word.H:66
dynamicFvMesh & mesh
engineTime & runTime
Required Variables.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const auto & io
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))
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:519
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
List< treeBoundBox > meshBb(1, treeBoundBox(coarseMesh.points()).extend(rndGen, 1e-3))
Foam::argList args(argc, argv)
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Random rndGen