All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
createNonConformalCouples.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Application
25  createNonConformalCouples
26 
27 Description
28  Utility to create non-conformal couples between non-coupled patches.
29 
30 Usage
31  \b createNonConformalCouples <patch1> <patch2>
32 
33  Options:
34  - \par -overwrite \n
35  Replace the old mesh with the new one, rather than writing the new one
36  into a separate time directory
37 
38  - \par -fields \n
39  Add non-conformal boundary conditions to the fields.
40 
41 Note
42  If run with two arguments, these arguments specify the patches between
43  which a single couple is to be created. The resulting couple will not have
44  a transformation.
45 
46 Usage
47  \b createNonConformalCouples
48 
49 Note
50  If run without arguments then settings are read from a \b
51  system/createNonConformalCouplesDict dictionary (or from a different
52  dictionary specified by the \b -dict option). This dictionary can specify
53  the creation of multiple couples and/or couples with transformations.
54 
55 \*---------------------------------------------------------------------------*/
56 
57 #include "argList.H"
59 #include "fvMeshTools.H"
60 #include "IOobjectList.H"
64 #include "polyMesh.H"
65 #include "processorPolyPatch.H"
66 #include "systemDict.H"
67 #include "Time.H"
68 
69 #include "ReadFields.H"
70 #include "volFields.H"
71 #include "surfaceFields.H"
72 #include "pointFields.H"
73 
74 using namespace Foam;
75 
76 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
77 
78 int main(int argc, char *argv[])
79 {
80  #include "addOverwriteOption.H"
81  #include "addRegionOption.H"
82  #include "addDictOption.H"
83 
84  const bool haveArgs = argList::hasArgs(argc, argv);
85  if (haveArgs)
86  {
87  argList::validArgs.append("patch1");
88  argList::validArgs.append("patch2");
90  (
91  "fields",
92  "add non-conformal boundary conditions to the fields"
93  );
94  }
95 
96  #include "setRootCase.H"
97  #include "createTime.H"
98  runTime.functionObjects().off();
99 
100  // Flag to determine whether or not patches are added to fields
101  bool fields;
102 
103  // Patch names between which to create couples, field dictionaries, the
104  // associated cyclic name prefix and transformation (if any)
106  List<Pair<dictionary>> patchFieldDicts;
107  wordList cyclicNames;
109 
110  // If there are patch name arguments, then we assume fields are not being
111  // changed, the cyclic name is just the cyclic typename, and that there is
112  // no transformation. If there are no arguments then get all this
113  // information from the system dictionary.
114  if (haveArgs)
115  {
116  fields = args.optionFound("fields");
117 
118  patchNames.append(Pair<word>(args[1], args[2]));
119  patchFieldDicts.append(Pair<dictionary>());
120  cyclicNames.append(nonConformalCyclicPolyPatch::typeName);
121  transforms.append(cyclicTransform(true));
122  }
123  else
124  {
125  static const word dictName("createNonConformalCouplesDict");
126 
128 
129  fields = dict.lookupOrDefault<bool>("fields", false);
130 
131  const dictionary& couplesDict =
132  dict.optionalSubDict("nonConformalCouples");
133 
134  forAllConstIter(dictionary, couplesDict, iter)
135  {
136  if (!iter().isDict()) continue;
137 
138  const dictionary& subDict = iter().dict();
139 
140  const bool havePatches = subDict.found("patches");
141  const bool haveOwnerNeighbour =
142  subDict.found("owner") || subDict.found("neighbour");
143 
144  if (havePatches == haveOwnerNeighbour)
145  {
146  FatalIOErrorInFunction(subDict)
147  << "Patches should be specified with either a single "
148  << "\"patches\" entry with a pair of patch names, or with "
149  << "two sub-dictionaries named \"owner\" and "
150  << "\"neighbour\"." << exit(FatalIOError);
151  }
152 
153  if (havePatches)
154  {
155  patchNames.append(subDict.lookup<Pair<word>>("patches"));
156  patchFieldDicts.append(Pair<dictionary>());
157  }
158 
159  if (haveOwnerNeighbour)
160  {
161  const dictionary& ownerDict = subDict.subDict("owner");
162  const dictionary& neighbourDict = subDict.subDict("neighbour");
163 
164  patchNames.append
165  (
166  Pair<word>
167  (
168  ownerDict["patch"],
169  neighbourDict["patch"]
170  )
171  );
172  patchFieldDicts.append
173  (
175  (
176  ownerDict.subOrEmptyDict("patchFields"),
177  neighbourDict.subOrEmptyDict("patchFields")
178  )
179  );
180  }
181 
182  cyclicNames.append(subDict.dictName());
183  transforms.append(cyclicTransform(subDict, true));
184  }
185  }
186 
187  Foam::word meshRegionName = polyMesh::defaultRegion;
188  args.optionReadIfPresent("region", meshRegionName);
189 
190  #include "createNamedMesh.H"
191 
192  const polyBoundaryMesh& patches = mesh.boundaryMesh();
193 
194  const bool overwrite = args.optionFound("overwrite");
195 
196  const word oldInstance = mesh.pointsInstance();
197 
198  // Read the fields
199  IOobjectList objects(mesh, runTime.timeName());
200  if (fields) Info<< "Reading geometric fields" << nl << endl;
201  #include "readVolFields.H"
202  #include "readSurfaceFields.H"
203  #include "readPointFields.H"
204  if (fields) Info<< endl;
205 
206  // Make sure the mesh is not connected before couples are added
207  mesh.conform();
208 
209  // Start building lists of patches and patch-fields to add
210  List<polyPatch*> newPatches;
211  List<dictionary> newPatchFieldDicts;
212 
213  // Find the first processor patch and face
214  label firstProcPatchi = patches.size(), firstProcFacei = mesh.nFaces();
215  forAll(patches, patchi)
216  {
217  const polyPatch& pp = patches[patchi];
218 
219  if (isA<processorPolyPatch>(pp) && firstProcPatchi == patches.size())
220  {
221  firstProcPatchi = patchi;
222  firstProcFacei = pp.start();
223  }
224 
225  if (!isA<processorPolyPatch>(pp) && firstProcPatchi != patches.size())
226  {
228  << "Processor patches do not follow boundary patches"
229  << exit(FatalError);
230  }
231  }
232 
233  // Clone the non-processor patches
234  for (label patchi = 0; patchi < firstProcPatchi; ++ patchi)
235  {
236  const polyPatch& pp = patches[patchi];
237 
238  newPatches.append
239  (
240  pp.clone(patches, patchi, pp.size(), pp.start()).ptr()
241  );
242  newPatchFieldDicts.append
243  (
244  dictionary()
245  );
246  }
247 
248  // Convenience function to generate patch names for the owner or neighbour
249  auto nccPatchNames = [&](const label i)
250  {
251  return
252  Pair<word>
253  (
254  cyclicNames[i] + "_on_" + patchNames[i][0],
255  cyclicNames[i] + "_on_" + patchNames[i][1]
256  );
257  };
258 
259  // Add the cyclic patches
260  forAll(patchNames, i)
261  {
262  Info<< indent << "Adding "
263  << nonConformalCyclicPolyPatch::typeName
264  << " interfaces between patches: " << incrIndent << nl
265  << indent << patchNames[i] << decrIndent << nl
266  << indent << "Named:" << incrIndent << nl
267  << indent << Pair<word>(nccPatchNames(i)) << decrIndent << nl
268  << indent << "With transform: " << incrIndent << nl;
269  transforms[i].write(Info);
270  Info<< decrIndent << nl;
271 
272  newPatches.append
273  (
275  (
276  nccPatchNames(i)[0],
277  0,
278  firstProcFacei,
279  newPatches.size(),
280  patches,
281  nonConformalCyclicPolyPatch::typeName,
282  nccPatchNames(i)[1],
283  patchNames[i][0],
284  transforms[i]
285  )
286  );
287  newPatchFieldDicts.append
288  (
289  patchFieldDicts[i][0]
290  );
291  newPatches.append
292  (
294  (
295  nccPatchNames(i)[1],
296  0,
297  firstProcFacei,
298  newPatches.size(),
299  patches,
300  nonConformalCyclicPolyPatch::typeName,
301  nccPatchNames(i)[0],
302  patchNames[i][1],
303  inv(transforms[i])
304  )
305  );
306  newPatchFieldDicts.append
307  (
308  patchFieldDicts[i][1]
309  );
310  }
311 
312  // Add the error patches. Note there is only one for each source patch,
313  // regardless of how many interfaces are attached to that patch.
314  auto appendErrorPatches = [&](const bool owner)
315  {
316  wordHashSet patchANames;
317  forAll(patchNames, i)
318  {
319  patchANames.insert(patchNames[i][!owner]);
320  }
321  forAllConstIter(wordHashSet, patchANames, iter)
322  {
323  newPatches.append
324  (
326  (
327  nonConformalErrorPolyPatch::typeName + "_on_" + iter.key(),
328  0,
329  firstProcFacei,
330  newPatches.size(),
331  patches,
332  nonConformalErrorPolyPatch::typeName,
333  iter.key()
334  )
335  );
336  newPatchFieldDicts.append
337  (
338  dictionary()
339  );
340  }
341  };
342  appendErrorPatches(true);
343  appendErrorPatches(false);
344 
345  // Clone the processor patches
346  for (label patchi = firstProcPatchi; patchi < patches.size(); ++ patchi)
347  {
348  const polyPatch& pp = patches[patchi];
349 
350  newPatches.append
351  (
352  pp.clone(patches, newPatches.size(), pp.size(), pp.start()).ptr()
353  );
354  newPatchFieldDicts.append
355  (
356  dictionary()
357  );
358  }
359 
360  // Add the processor cyclic patches
361  if (Pstream::parRun())
362  {
363  forAll(patchNames, i)
364  {
365  const polyPatch& patch1 = patches[patchNames[i][0]];
366  const polyPatch& patch2 = patches[patchNames[i][1]];
367 
368  boolList procHasPatch1(Pstream::nProcs(), false);
369  procHasPatch1[Pstream::myProcNo()] = !patch1.empty();
370  Pstream::gatherList(procHasPatch1);
371  Pstream::scatterList(procHasPatch1);
372 
373  boolList procHasPatch2(Pstream::nProcs(), false);
374  procHasPatch2[Pstream::myProcNo()] = !patch2.empty();
375  Pstream::gatherList(procHasPatch2);
376  Pstream::scatterList(procHasPatch2);
377 
378  // Multiple cyclic interfaces must be ordered in a specific way for
379  // processor communication to function correctly.
380  //
381  // A communication that is sent from the cyclic owner is received
382  // on the cyclic neighbour and vice versa. Therefore, in a coupled
383  // pair of processors if one sends the owner first the other must
384  // receive the neighbour first.
385  //
386  // We ensure the above by ordering the patches so that for the
387  // lower indexed processor the owner interface comes first, and for
388  // the higher indexed processor the neighbour comes first.
389 
390  auto appendProcPatches = [&](const bool owner, const bool first)
391  {
392  const boolList& procHasPatchA =
393  owner ? procHasPatch1 : procHasPatch2;
394  const boolList& procHasPatchB =
395  owner ? procHasPatch2 : procHasPatch1;
396 
397  if (procHasPatchA[Pstream::myProcNo()])
398  {
399  forAll(procHasPatchB, proci)
400  {
401  if
402  (
403  (
404  (first && proci < Pstream::myProcNo())
405  || (!first && proci > Pstream::myProcNo())
406  )
407  && procHasPatchB[proci]
408  )
409  {
410  newPatches.append
411  (
413  (
414  0,
415  mesh.nFaces(),
416  newPatches.size(),
417  patches,
419  proci,
420  nccPatchNames(i)[!owner],
421  patchNames[i][!owner]
422  )
423  );
424  newPatchFieldDicts.append
425  (
426  patchFieldDicts[i][!owner]
427  );
428  }
429  }
430  }
431  };
432 
433  appendProcPatches(true, true);
434  appendProcPatches(false, true);
435  appendProcPatches(false, false);
436  appendProcPatches(true, false);
437  }
438  }
439 
440  // Re-patch the mesh. Note that new patches are all constraints, so the
441  // dictionary and patch type do not get used. Overrides will be handled
442  // later, once all patches have been added and the mesh has been stitched.
443  forAll(newPatches, newPatchi)
444  {
446  (
447  mesh,
448  *newPatches[newPatchi],
449  dictionary(),
451  false
452  );
453  }
454 
455  // Connect the mesh so that the new stitching topology gets written out
456  fvMeshStitchers::stationary(mesh).connect(false, false, false);
457 
458  // Set the fields on the new patches. All new patches are constraints, so
459  // this should only be creating overrides; e.g., jump cyclics.
460  forAll(newPatches, newPatchi)
461  {
462  if (!newPatchFieldDicts[newPatchi].empty())
463  {
464  fvMeshTools::setPatchFields
465  (
466  mesh,
467  newPatchi,
468  newPatchFieldDicts[newPatchi]
469  );
470  }
471  }
472 
473  mesh.setInstance(runTime.timeName());
474 
475  // Set the precision of the points data to 10
477 
478  if (!overwrite)
479  {
480  runTime++;
481  }
482  else
483  {
484  mesh.setInstance(oldInstance);
485  }
486 
487  // Write resulting mesh
488  Info<< "Writing mesh to " << runTime.timeName() << nl << endl;
489  mesh.write();
490 
491  Info<< "End\n" << endl;
492 
493  return 0;
494 }
495 
496 
497 // ************************************************************************* //
const fvPatchList & patches
Foam::surfaceFields.
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:453
transformer transforms
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:38
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
A HashTable with keys but without contents.
Definition: HashSet.H:59
dictionary dict
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:663
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:221
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:50
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
label nFaces() const
static bool hasArgs(int argc, char *argv[])
Return true if there are arguments.
Definition: argList.C:298
Mesh stitcher for stationary meshes.
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:458
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:325
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:153
Field reading functions for post-processing utilities.
virtual bool write(const bool write=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1658
fvMesh & mesh
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:111
IOdictionary systemDict(const word &dictName, const argList &args, const objectRegistry &ob, const word &regionName=polyMesh::defaultRegion)
Definition: systemDict.C:92
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:204
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:53
const word dictName() const
Return the local dictionary name (final part of scoped name)
Definition: dictionary.H:121
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:1002
Non-conformal processor cyclic poly patch. As nonConformalCyclicPolyPatch, but the neighbouring patch...
virtual autoPtr< polyPatch > clone(const polyBoundaryMesh &bm) const
Construct and return a clone, resetting the boundary mesh.
Definition: polyPatch.H:225
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:882
const dictionary & optionalSubDict(const word &) const
Find and return a sub-dictionary if found.
Definition: dictionary.C:1060
A class for handling words, derived from string.
Definition: word.H:59
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:34
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
wordList patchNames(nPatches)
This boundary condition is not designed to be evaluated; it is assumed that the value is assigned via...
virtual bool connect(const bool changing, const bool geometric, const bool load)
Connect the mesh by adding faces into the nonConformalCyclics.
void conform(const surfaceScalarField &phi=NullObjectRef< surfaceScalarField >())
Conform the fvMesh to the polyMesh.
Definition: fvMesh.C:1312
Non-conformal cyclic poly patch. As nonConformalCoupledPolyPatch, but the neighbouring patch is local...
Foam::polyBoundaryMesh.
static const char nl
Definition: Ostream.H:260
Non-conformal error poly patch. As nonConformalPolyPatch. This patch is a non-coupled non-conformal p...
objects
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:235
void setInstance(const fileName &)
Set the instance for mesh files.
Definition: polyMeshIO.C:77
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
Info<< "Reading field p_rgh\"<< endl;volScalarField p_rgh(IOobject("p_rgh", runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE), mesh);pressureReference pressureReference(p, p_rgh, pimple.dict(), thermo.incompressible());mesh.schemes().setFluxRequired(p_rgh.name());hydrostaticInitialisation(p_rgh, p, rho, U, gh, ghf, pRef, thermo, pimple.dict());Info<< "Creating field dpdt\"<< endl;volScalarField dpdt(IOobject("dpdt", runTime.timeName(), mesh), mesh, dimensionedScalar(p.dimensions()/dimTime, 0));Info<< "Creating field kinetic energy K\"<< endl;volScalarField K("K", 0.5 *magSqr(U));dimensionedScalar initialMass=fvc::domainIntegrate(rho);multivariateSurfaceInterpolationScheme< scalar >::fieldTable fields
Definition: createFields.H:131
label patchi
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:318
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:306
messageStream Info
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
Cyclic plane transformation.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Foam::argList args(argc, argv)
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:228
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
dictionary subOrEmptyDict(const word &, const bool mustRead=false) const
Find and return a sub-dictionary as a copy, or.
Definition: dictionary.C:1033
const word dictName("noiseDict")
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:864
IOerror FatalIOError