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 -------------------------------------------------------------------------------
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  surfaceRedistributePar
29 
30 Group
31  grpSurfaceUtilities
32 
33 Description
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 
38 Note
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 
53 using namespace Foam;
54 
55 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
56 
57 // Print on master all the per-processor surface stats.
58 void writeProcStats
59 (
60  const triSurface& s,
62 )
63 {
64  // Determine surface bounding boxes, faces, points
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 
102 int main(int argc, char *argv[])
103 {
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");
114  (
115  "keepNonMapped",
116  "Preserve surface outside of mesh bounds"
117  );
118 
119  #include "setRootCase.H"
120  #include "createTime.H"
122 
123  const auto surfFileName = args.get<fileName>(1);
124  const auto distTypeName = args.get<word>(2);
125  const label distType =
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.
160  {
161  // Ensure demand-driven decompositionMethod finds alternative
162  // decomposeParDict location properly.
163 
164  IOdictionary* dictPtr = new IOdictionary
165  (
167  (
168  IOobject
169  (
171  runTime.system(),
172  runTime,
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 
184  runTime.store(dictPtr);
185  }
186 
187  // Determine mesh bounding boxes:
189  if (distType == distributedTriSurfaceMesh::FOLLOW)
190  {
191  #include "createPolyMesh.H"
192 
194  (
195  1,
196  treeBoundBox(mesh.points()).extend(rndGen, 1e-3)
197  );
199  }
200 
201  IOobject io
202  (
203  surfFileName, // name
204  //runTime.findInstance("triSurface", surfFileName), // instance
205  runTime.constant(), // instance
206  "triSurface", // local
207  runTime, // registry
210  );
211 
212  // Look for file (using searchableSurface rules)
213  const fileName actualPath(typeFilePath<searchableSurface>(io));
214  fileName localPath(actualPath);
215  localPath.replace(runTime.rootPath() + '/', "");
216 
217 
219 
220  if (actualPath == io.objectPath())
221  {
222  Info<< "Loading local (decomposed) surface " << localPath << nl <<endl;
223  surfMeshPtr.reset(new distributedTriSurfaceMesh(io));
224  }
225  else
226  {
227  Info<< "Loading undecomposed surface " << localPath
228  << " on master only" << endl;
229 
230  triSurface s;
231  List<treeBoundBox> bbs;
232  if (Pstream::master())
233  {
234  // Actually load the surface
235  const bool oldParRun = Pstream::parRun(false);
236  triSurfaceMesh surf(io);
237  Pstream::parRun(oldParRun); // Restore parallel state
238  s = surf;
240  }
241  else
242  {
244  }
245 
247  dict.add("distributionType", distTypeName);
248  dict.add("mergeDistance", SMALL);
249  dict.add("bounds", bbs);
250 
251  // Scatter patch information
252  Pstream::broadcast(s.patches());
253 
254  // Construct distributedTrisurfaceMesh from components
255  IOobject notReadIO(io);
256  notReadIO.readOpt(IOobject::NO_READ);
257  surfMeshPtr.reset(new distributedTriSurfaceMesh(notReadIO, s, dict));
258  }
259 
260  distributedTriSurfaceMesh& surfMesh = surfMeshPtr();
261 
262 
263  // Write per-processor stats
264  Info<< "Before redistribution:" << endl;
265  writeProcStats(surfMesh, meshBb);
266 
267 
268  // Do redistribution
269  Info<< "Redistributing surface" << nl << endl;
271  autoPtr<mapDistribute> pointMap;
272  surfMesh.distribute
273  (
275  keepNonMapped,
276  faceMap,
277  pointMap
278  );
279  faceMap.clear();
280  pointMap.clear();
281 
282  Info<< endl;
283 
284 
285  // Write per-processor stats
286  Info<< "After redistribution:" << endl;
287  writeProcStats(surfMesh, meshBb);
288 
289 
290  Info<< "Writing surface." << nl << endl;
291  surfMesh.objectRegistry::write();
292 
293  Info<< "End\n" << endl;
294 
295  return 0;
296 }
297 
298 
299 // ************************************************************************* //
static const Enum< distributionType > distributionTypeNames_
dictionary dict
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:453
Required Variables.
static const treeBoundBox & null() noexcept
The null treeBoundBox is the same as an inverted box.
Definition: treeBoundBox.H:187
A class for handling file names.
Definition: fileName.H:71
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void off()
Switch the function objects off.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
Random rndGen
Definition: createFields.H:23
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
void clear() noexcept
Same as reset(nullptr)
Definition: autoPtr.H:255
static void addBoolOption(const word &optName, const string &usage="", bool advanced=false)
Add a bool option to validOptions with usage information.
Definition: argList.C:365
bool store()
Register object with its registry and transfer ownership to the registry.
Definition: regIOobjectI.H:36
const fileName & rootPath() const noexcept
Return root path.
Definition: TimePathsI.H:43
entry * add(entry *entryPtr, bool mergeEntry=false)
Add a new entry.
Definition: dictionary.C:637
static const boundBox greatBox
A large boundBox: min/max == -/+ ROOTVGREAT.
Definition: boundBox.H:119
Ignore writing from objectRegistry::writeObject()
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:688
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
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:239
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all processes in communicator.
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1066
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
IOoject and searching on triSurface.
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
static void allGatherList(List< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses linear/tree communication. ...
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator) is 1 for serial run.
Definition: UPstream.H:656
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
dynamicFvMesh & mesh
A class for handling words, derived from Foam::string.
Definition: word.H:63
label nPoints
const word & system() const noexcept
Return system name.
Definition: TimePathsI.H:95
Random number generator.
Definition: Random.H:55
A surface mesh consisting of general polygon faces that has IO capabilities and a registry for storin...
Definition: surfMesh.H:59
IOoject and searching on distributed triSurface. All processor hold (possibly overlapping) part of th...
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:89
static const word canonicalName
The canonical name ("decomposeParDict") under which the MeshObject is registered. ...
virtual void rename(const word &newName)
Rename.
Definition: regIOobject.C:413
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:271
const functionObjectList & functionObjects() const
Return the list of function objects.
Definition: Time.H:662
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
Nothing to be read.
Automatically write from objectRegistry::writeObject()
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:342
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
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
Triangulated surface description with patch information.
Definition: triSurface.H:72
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))
Foam::argList args(argc, argv)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
List< treeBoundBox > meshBb(1, treeBoundBox(coarseMesh.points()).extend(rndGen, 1e-3))
bool found(const word &optName) const
Return true if the named option is found.
Definition: argListI.H:171
Namespace for OpenFOAM.
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:231