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-2026 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 -region \n
35  Specify an alternative mesh region
36 
37  - \par -fields \n
38  Add non-conformal boundary conditions to the fields
39 
40  - \par -noOverwrite \n
41  Do not replace the old mesh with the new one, writing the new one
42  into a separate time directory
43 
44 Note
45  If run with two arguments, these arguments specify the patches between
46  which a single couple is to be created. The resulting couple will not have
47  a transformation.
48 
49 Usage
50  \b createNonConformalCouples
51 
52  Options:
53  - \par -dict <filename>
54  Specify alternative dictionary for the non-conformal couples,
55  defaults to system/createNonConformalCouplesDict
56 
57  - \par -noOverwrite \n
58  Do not replace the old mesh with the new one, writing the new one
59  into a separate time directory
60 
61 Note
62  If run without arguments then settings are read from a \b
63  system/createNonConformalCouplesDict dictionary (or from a different
64  dictionary specified by the \b -dict option). This dictionary can specify
65  the creation of multiple couples, inter-region couples, and/or couples with
66  transformations. Annotated examples can be found in
67  $FOAM_ETC/caseDicts/annotated/createNonConformalCouplesDict.
68 
69 \*---------------------------------------------------------------------------*/
70 
71 #include "argList.H"
72 #include "fvMeshTools.H"
73 #include "hashedWordList.H"
74 #include "IOobjectList.H"
75 #include "MultiRegionList.H"
80 #include "polyMesh.H"
81 #include "processorPolyPatch.H"
83 #include "systemDict.H"
84 #include "Time.H"
85 
86 #include "ReadFields.H"
87 #include "volFields.H"
88 #include "surfaceFields.H"
89 #include "pointFields.H"
90 
91 using namespace Foam;
92 
93 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
94 
95 struct nonConformalCouple
96 {
97  // Public Data
98 
100 
101  Pair<word> origPatchNames;
102 
103  word ncPatchType;
104 
105  Pair<word> ncPatchNames;
106 
107  Pair<dictionary> ncPatchDicts;
108 
109  Pair<dictionary> ncPatchFieldDicts;
110 
112 
113 
114  // Constructors
115 
116  // Construct null (for List)
117  nonConformalCouple()
118  {}
119 
120  // Construct from arguments
121  nonConformalCouple
122  (
123  const word& primaryRegionName,
124  const argList& args
125  )
126  :
127  regionNames(primaryRegionName, primaryRegionName),
128  origPatchNames(args[1], args[2]),
130  ncPatchNames
131  (
132  ncPatchType + "_on_" + args[1],
133  ncPatchType + "_on_" + args[2]
134  ),
135  ncPatchDicts(),
136  ncPatchFieldDicts(),
137  transform(true)
138  {}
139 
140  //- Construct from dictionary
141  nonConformalCouple
142  (
143  const word& primaryRegionName,
144  const dictionary& dict
145  )
146  {
147  const bool haveRegion = dict.found("region");
148  const bool haveRegions = dict.found("regions");
149 
150  if (haveRegion && haveRegions)
151  {
153  << "Regions should be specified either by a \"region\" "
154  << "entry with a single region name (for in-region "
155  << "cyclics), or by a \"regions\" entry with a pair of "
156  << "names (for inter-region mapped walls)"
157  << exit(FatalIOError);
158  }
159 
160  const bool havePatches = dict.found("patches");
161  const bool haveOwnerNeighbour =
162  dict.found("owner") || dict.found("neighbour");
163 
164  if (havePatches == haveOwnerNeighbour)
165  {
167  << "Patches should be specified with either a single "
168  << "\"patches\" entry with a pair of patch names, "
169  << "or with two sub-dictionaries named \"owner\" and "
170  << "\"neighbour\"" << exit(FatalIOError);
171  }
172 
173  if (havePatches)
174  {
175  const word thisRegionName =
176  haveRegion ? dict.lookup<word>("region") : word::null;
177 
178  regionNames =
179  haveRegion ? Pair<word>(thisRegionName, thisRegionName)
180  : haveRegions ? dict.lookup<Pair<word>>("regions")
181  : Pair<word>(primaryRegionName, primaryRegionName);
182  origPatchNames =
183  dict.lookup<Pair<word>>("patches");
184  ncPatchType =
186  (
187  "type",
188  regionNames.first() == regionNames.second()
191  );
192  ncPatchNames =
194  (
195  "names",
196  Pair<word>
197  (
198  dict.dictName() + "_on_" + origPatchNames[0],
199  dict.dictName() + "_on_" + origPatchNames[1]
200  )
201  );
202  forAll(ncPatchDicts, i)
203  {
204  ncPatchDicts[i] = dict;
205  ncPatchDicts[i].remove("region");
206  ncPatchDicts[i].remove("regions");
207  ncPatchDicts[i].remove("patches");
208  ncPatchDicts[i].remove("type");
209  ncPatchDicts[i].remove("names");
210  ncPatchDicts[i].remove(cyclicTransform::keywords);
211  }
212  ncPatchFieldDicts = Pair<dictionary>();
213  transform = cyclicTransform(dict, true);
214  }
215  else
216  {
217  const dictionary& ownerDict = dict.subDict("owner");
218  const dictionary& neighbourDict = dict.subDict("neighbour");
219 
220  regionNames =
221  Pair<word>
222  (
223  ownerDict.lookupOrDefault<word>
224  (
225  "region",
226  primaryRegionName
227  ),
228  neighbourDict.lookupOrDefault<word>
229  (
230  "region",
231  primaryRegionName
232  )
233  );
234  origPatchNames =
235  Pair<word>
236  (
237  ownerDict.lookup<word>("patch"),
238  neighbourDict.lookup<word>("patch")
239  );
240  ncPatchType =
242  (
243  "type",
244  regionNames.first() == regionNames.second()
247  );
248  ncPatchNames =
249  Pair<word>
250  (
251  ownerDict.lookupOrDefault<word>
252  (
253  "name",
254  dict.dictName() + "_on_" + origPatchNames[0]
255  ),
256  neighbourDict.lookupOrDefault<word>
257  (
258  "name",
259  dict.dictName() + "_on_" + origPatchNames[1]
260  )
261  );
262  ncPatchDicts[0] = ownerDict;
263  ncPatchDicts[1] = neighbourDict;
264  forAll(ncPatchDicts, i)
265  {
266  ncPatchDicts[i].remove("region");
267  ncPatchDicts[i].remove("patch");
268  ncPatchDicts[i].remove("name");
269  ncPatchDicts[i].remove("patchFields");
270  }
271  ncPatchFieldDicts =
273  (
274  ownerDict.subOrEmptyDict("patchFields"),
275  neighbourDict.subOrEmptyDict("patchFields")
276  );
277  transform = cyclicTransform(dict, true);
278  }
279  }
280 };
281 
282 
283 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
284 
285 template<class Type>
286 void evaluateNonConformalProcessorCyclics(const fvMesh& mesh)
287 {
289 
290  forAll(fields, i)
291  {
292  const label nReq = Pstream::nRequests();
293 
295  {
296  typename VolField<Type>::Patch& pf =
297  fields[i].boundaryFieldRef()[patchi];
298 
299  if (isA<nonConformalProcessorCyclicPolyPatch>(pf.patch().poly()))
300  {
301  pf.initEvaluate(Pstream::defaultCommsType);
302  }
303  }
304 
305  if
306  (
309  )
310  {
311  Pstream::waitRequests(nReq);
312  }
313 
315  {
316  typename VolField<Type>::Patch& pf =
317  fields[i].boundaryFieldRef()[patchi];
318 
319  if (isA<nonConformalProcessorCyclicPolyPatch>(pf.patch().poly()))
320  {
321  pf.evaluate(Pstream::defaultCommsType);
322  }
323  }
324  }
325 }
326 
327 
328 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
329 
330 int main(int argc, char *argv[])
331 {
332  #include "addNoOverwriteOption.H"
333  #include "addMeshOption.H"
334  #include "addRegionOption.H"
335  #include "addDictOption.H"
336 
337  const bool haveArgs = argList::nArgs(argc, argv);
338  if (haveArgs)
339  {
340  argList::validArgs.append("patch1");
341  argList::validArgs.append("patch2");
343  (
344  "fields",
345  "add non-conformal boundary conditions to the fields"
346  );
347  }
348 
350  #include "setMeshPath.H"
352 
353  const Foam::word primaryRegionName =
355 
356  // Flag to determine whether or not patches are added to fields
357  bool fields;
358 
359  // Read the couples to be created from arguments or a system dictionary
360  List<nonConformalCouple> couples;
361  if (haveArgs)
362  {
363  fields = args.optionFound("fields");
364 
365  couples.append(nonConformalCouple(primaryRegionName, args));
366  }
367  else
368  {
369  const dictionary dict
370  (
371  systemDict
372  (
373  "createNonConformalCouplesDict",
374  args,
375  runTime,
376  primaryRegionName
377  )
378  );
379 
380  fields = dict.lookupOrDefault<bool>("fields", false);
381 
382  const dictionary& couplesDict =
383  dict.optionalSubDict("nonConformalCouples");
384 
385  forAllConstIter(dictionary, couplesDict, iter)
386  {
387  if (!iter().isDict()) continue;
388 
389  const dictionary& subDict = iter().dict();
390 
391  const bool havePatches = subDict.found("patches");
392  const bool haveOwnerNeighbour =
393  subDict.found("owner") || subDict.found("neighbour");
394 
395  if (havePatches == haveOwnerNeighbour)
396  {
397  FatalIOErrorInFunction(subDict)
398  << "Patches should be specified with either a single "
399  << "\"patches\" entry with a pair of patch names, "
400  << "or with two sub-dictionaries named \"owner\" and "
401  << "\"neighbour\"." << exit(FatalIOError);
402  }
403 
404  couples.append(nonConformalCouple(primaryRegionName, subDict));
405  }
406  }
407 
408  // Determine if operating on meshes within a sub-path
409  const bool haveMeshPath = meshPath != word::null;
410 
411  // Create all the meshes needed
413  PtrList<fvMesh> regionMeshes;
414  forAll(couples, i)
415  {
416  forAll(couples[i].regionNames, sidei)
417  {
418  const word& regionName = couples[i].regionNames[sidei];
419 
420  if (regionNames.found(regionName)) continue;
421 
422  const IOobject regionMeshIo
423  (
424  regionName,
425  runTime.name(),
426  meshPath,
427  runTime,
429  );
430 
431  // If we are creating couples on a mesh within a mesh path
432  // sub-directory then these couples will not be stitched so loading
433  // the neighbouring regions is optional
434  if
435  (
436  haveMeshPath
437  && polyMesh::meshDirInstance(regionMeshIo) == fileName::null
438  ) continue;
439 
441  regionMeshes.append(new fvMesh(regionMeshIo, false));
442  }
443  }
444 
445  // Early exit if there is nothing to do
446  if (regionMeshes.empty())
447  {
448  Info<< "Nothing to be done" << nl << endl
449  << "End" << nl << endl;
450 
451  return 0;
452  }
453 
454  #include "setNoOverwrite.H"
455 
456  const word oldInstance = regionMeshes[0].pointsInstance();
457 
458  // Read the fields
459  if (fields) Info<< "Reading geometric fields" << nl << endl;
460 
461  #define DeclareRegionGeoTypeFields(Type, Geo) \
462  PtrList<PtrList<Geo##Field<Type>>> \
463  CAT4(region, Geo, CAPITALIZE(Type), Fields)(regionMeshes.size()); \
464  forAll(regionMeshes, regioni) \
465  { \
466  CAT4(region, Geo, CAPITALIZE(Type), Fields).set \
467  ( \
468  regioni, \
469  new PtrList<Geo##Field<Type>> \
470  ); \
471  }
472  FOR_ALL_FIELD_TYPES(DeclareRegionGeoTypeFields, Vol);
473  FOR_ALL_FIELD_TYPES(DeclareRegionGeoTypeFields, Surface);
474  FOR_ALL_FIELD_TYPES(DeclareRegionGeoTypeFields, Point);
475  #undef DeclareRegionGeoTypeFields
476 
477  if (fields)
478  {
479  MultiRegionUList<fvMesh> multiRegionMeshes(regionMeshes, false);
480 
481  forAll(regionMeshes, regioni)
482  {
483  RegionRef<fvMesh> mesh = multiRegionMeshes[regioni];
484 
485  IOobjectList objects(mesh, runTime.name());
486 
487  #define ReadRegionGeoTypeFields(Type, Geo, mesh) \
488  ReadFields \
489  ( \
490  mesh, \
491  objects, \
492  CAT4(region, Geo, CAPITALIZE(Type), Fields)[regioni] \
493  );
494  FOR_ALL_FIELD_TYPES(ReadRegionGeoTypeFields, Vol, mesh);
495  FOR_ALL_FIELD_TYPES(ReadRegionGeoTypeFields, Surface, mesh);
496  const pointMesh& pMesh = pointMesh::New(mesh);
497  FOR_ALL_FIELD_TYPES(ReadRegionGeoTypeFields, Point, pMesh);
498  #undef ReadRegionGeoTypeFields
499  }
500 
501  Info<< endl;
502  }
503 
504  if (!overwrite)
505  {
506  runTime++;
507  }
508 
509  // Make sure the meshes are not connected before couples are added
510  forAll(regionMeshes, regioni)
511  {
512  regionMeshes[regioni].conform();
513  }
514 
515  // Find the first processor patch and face
516  labelList regionFirstProcPatchis(regionMeshes.size());
517  labelList regionFirstProcFaceis(regionMeshes.size());;
518  forAll(regionMeshes, regioni)
519  {
520  const fvMesh& mesh = regionMeshes[regioni];
522  label& firstProcPatchi = regionFirstProcPatchis[regioni];
523  label& firstProcFacei = regionFirstProcFaceis[regioni];
524 
525  firstProcPatchi = patches.size();
526  firstProcFacei = mesh.nFaces();
527 
529  {
530  const polyPatch& pp = patches[patchi];
531 
532  const bool isProcPp = isA<processorPolyPatch>(pp);
533 
534  if (isProcPp && firstProcPatchi == patches.size())
535  {
536  firstProcPatchi = patchi;
537  firstProcFacei = pp.start();
538  }
539 
540  if (!isProcPp && firstProcPatchi != patches.size())
541  {
543  << "Processor patches of region " << regionNames[regioni]
544  << " do not follow boundary patches"
545  << exit(FatalError);
546  }
547  }
548  }
549 
550  // Start building lists of patches and patch-fields to add
551  List<List<polyPatch*>> newPatches(regionMeshes.size());
552  List<boolList> newPatchIsCouple(regionMeshes.size());
553  List<List<dictionary>> newPatchFieldDicts(regionMeshes.size());
554 
555  // Clone the non-processor patches
556  forAll(regionMeshes, regioni)
557  {
558  const fvMesh& mesh = regionMeshes[regioni];
560  const label firstProcPatchi = regionFirstProcPatchis[regioni];
561 
562  for (label patchi = 0; patchi < firstProcPatchi; ++ patchi)
563  {
564  const polyPatch& pp = patches[patchi];
565 
566  newPatches[regioni].append
567  (
568  pp.clone
569  (
570  patches,
571  patchi,
572  pp.size(),
573  pp.start()
574  ).ptr()
575  );
576  newPatchIsCouple[regioni].append(false);
577  newPatchFieldDicts[regioni].append(dictionary());
578  }
579  }
580 
581  // Add the non-processor coupled patches
582  forAll(couples, couplei)
583  {
584  const nonConformalCouple& couple = couples[couplei];
585 
586  Info<< indent << "Adding " << couple.ncPatchType
587  << " interfaces between patches: " << incrIndent << nl
588  << indent << couple.origPatchNames << decrIndent << nl
589  << "In regions: " << incrIndent << nl
590  << indent << couple.regionNames << decrIndent << nl
591  << indent << "Named:" << incrIndent << nl
592  << indent << couple.ncPatchNames << decrIndent << nl
593  << indent << "With transform: " << incrIndent << nl;
594  couple.transform.write(Info);
595  Info<< decrIndent << nl;
596 
597  auto appendPatch = [&](const bool owner)
598  {
599  if (!regionNames.found(couple.regionNames[!owner])) return;
600 
601  const label regioni =
602  regionNames[couple.regionNames[!owner]];
603 
604  dictionary patchDict = dictionary::entries
605  (
606  "type", couple.ncPatchType,
607  "nFaces", 0,
608  "startFace", regionFirstProcFaceis[regioni],
609  "originalPatch", couple.origPatchNames[!owner],
610  "neighbourRegion", couple.regionNames[owner],
611  "neighbourPatch", couple.ncPatchNames[owner],
612  "owner", owner
613  );
614 
615  {
616  OStringStream oss;
617  (owner ? couple.transform : inv(couple.transform)).write(oss);
618  patchDict.merge(IStringStream(oss.str())());
619  }
620 
621  patchDict.merge(couple.ncPatchDicts[!owner]);
622 
623  newPatches[regioni].append
624  (
626  (
627  couple.ncPatchNames[!owner],
628  patchDict,
629  newPatches[regioni].size(),
630  regionMeshes[regioni].poly().boundary()
631  ).ptr()
632  );
633  newPatchIsCouple[regioni].append(true);
634  newPatchFieldDicts[regioni].append
635  (
636  couple.ncPatchFieldDicts[!owner]
637  );
638  };
639  appendPatch(true);
640  appendPatch(false);
641  }
642 
643  // Add the error patches. Note there is only one for each original patch,
644  // regardless of how many couplings are attached to that patch.
645  {
646  // Create a table of unique original patches
647  HashTable<label, Pair<word>, Hash<Pair<word>>> regionOrigPatchToIndex;
648  DynamicList<Pair<word>> regionOrigPatches;
649  forAll(couples, couplei)
650  {
651  const nonConformalCouple& couple = couples[couplei];
652  forAll(couple.regionNames, i)
653  {
654  const Pair<word> regionOrigPatch
655  (
656  couple.regionNames[i],
657  couple.origPatchNames[i]
658  );
659 
660  if (!regionOrigPatchToIndex.found(regionOrigPatch))
661  {
662  regionOrigPatchToIndex.insert
663  (
664  regionOrigPatch,
665  regionOrigPatches.size()
666  );
667  regionOrigPatches.append(regionOrigPatch);
668  }
669  }
670  }
671 
672  // Add an error patch for each unique original patch
673  forAll(regionOrigPatches, i)
674  {
675  const word& regionName = regionOrigPatches[i].first();
676 
677  if (!regionNames.found(regionName)) continue;
678 
679  const label regioni = regionNames[regionName];
680  const word& origPatchName = regionOrigPatches[i].second();
681 
682  newPatches[regioni].append
683  (
685  (
687  + "_on_"
688  + origPatchName,
689  0,
690  regionFirstProcFaceis[regioni],
691  newPatches[regioni].size(),
692  regionMeshes[regioni].poly().boundary(),
693  origPatchName
694  )
695  );
696  newPatchIsCouple[regioni].append(false);
697  newPatchFieldDicts[regioni].append(dictionary());
698  }
699  }
700 
701  // Clone the processor patches
702  forAll(regionMeshes, regioni)
703  {
704  const fvMesh& mesh = regionMeshes[regioni];
706  const label firstProcPatchi = regionFirstProcPatchis[regioni];
707 
708  for (label patchi = firstProcPatchi; patchi < patches.size(); ++ patchi)
709  {
710  const polyPatch& pp = patches[patchi];
711 
712  newPatches[regioni].append
713  (
714  pp.clone
715  (
716  patches,
717  newPatches[regioni].size(),
718  pp.size(),
719  pp.start()
720  ).ptr()
721  );
722  newPatchIsCouple[regioni].append(false);
723  newPatchFieldDicts[regioni].append(dictionary());
724  }
725  }
726 
727  // Add the processor cyclic patches
728  if (Pstream::parRun())
729  {
730  forAll(couples, couplei)
731  {
732  const nonConformalCouple& couple = couples[couplei];
733 
734  if (couple.ncPatchType != nonConformalCyclicPolyPatch::typeName)
735  continue;
736 
737  if (!regionNames.found(couples[couplei].regionNames[0]))
738  continue;
739 
740  const label regioni = regionNames[couples[couplei].regionNames[0]];
741  const fvMesh& mesh = regionMeshes[regioni];
743 
744  const polyPatch& patch1 = patches[couple.origPatchNames[0]];
745  const polyPatch& patch2 = patches[couple.origPatchNames[1]];
746 
747  boolList procHasPatch1(Pstream::nProcs(), false);
748  procHasPatch1[Pstream::myProcNo()] = !patch1.empty();
749  Pstream::gatherList(procHasPatch1);
750  Pstream::scatterList(procHasPatch1);
751 
752  boolList procHasPatch2(Pstream::nProcs(), false);
753  procHasPatch2[Pstream::myProcNo()] = !patch2.empty();
754  Pstream::gatherList(procHasPatch2);
755  Pstream::scatterList(procHasPatch2);
756 
757  // Multiple cyclic interfaces must be ordered in a specific way for
758  // processor communication to function correctly.
759  //
760  // A communication that is sent from the cyclic owner is received
761  // on the cyclic neighbour and vice versa. Therefore, in a coupled
762  // pair of processors if one sends the owner first the other must
763  // receive the neighbour first.
764  //
765  // We ensure the above by ordering the patches so that for the
766  // lower indexed processor the owner interface comes first, and for
767  // the higher indexed processor the neighbour comes first.
768 
769  auto appendProcPatches = [&](const bool owner, const bool first)
770  {
771  const boolList& procHasPatchA =
772  owner ? procHasPatch1 : procHasPatch2;
773  const boolList& procHasPatchB =
774  owner ? procHasPatch2 : procHasPatch1;
775 
776  if (procHasPatchA[Pstream::myProcNo()])
777  {
778  forAll(procHasPatchB, proci)
779  {
780  if
781  (
782  (
783  (first && proci > Pstream::myProcNo())
784  || (!first && proci < Pstream::myProcNo())
785  )
786  && procHasPatchB[proci]
787  )
788  {
789  newPatches[regioni].append
790  (
792  (
793  0,
794  mesh.nFaces(),
795  newPatches.size(),
796  patches,
798  proci,
799  couple.ncPatchNames[!owner],
800  couple.origPatchNames[!owner]
801  )
802  );
803  newPatchIsCouple[regioni].append(true);
804  newPatchFieldDicts[regioni].append
805  (
806  couple.ncPatchFieldDicts[!owner]
807  );
808  }
809  }
810  }
811  };
812 
813  appendProcPatches(true, true);
814  appendProcPatches(false, true);
815  appendProcPatches(false, false);
816  appendProcPatches(true, false);
817  }
818  }
819 
820  // Re-patch the meshes. Create constraint or calculated patch fields at
821  // this stage; don't apply the patch field dictionaries. The patch fields
822  // will be specified properly later after all patches have been added and
823  // the meshes have been stitched. That way the geometry is fully available
824  // for construction of the patch fields.
825  forAll(regionMeshes, regioni)
826  {
827  forAll(newPatches[regioni], newPatchi)
828  {
830  (
831  regionMeshes[regioni],
832  *newPatches[regioni][newPatchi]
833  );
834  }
835  }
836 
837  // Connect the meshes
838  {
839  MultiRegionUList<fvMesh> multiRegionMeshes(regionMeshes, false);
840  forAll(regionMeshes, regioni)
841  {
842  RegionRef<fvMesh> mesh = multiRegionMeshes[regioni];
843  fvMeshStitchers::stationary(mesh).connect(false, false, false);
844  }
845 
846  if (!haveMeshPath) Info<< endl;
847  }
848 
849  // Set the fields on the new patches. This allows constraint types (e.g.,
850  // nonConformalCyclic) to be set by default, but requires a dictionary
851  // setting for non-constrained types (e.g., nonConformalMappedWall). It
852  // also allows constraint types to be overridden (e.g., with jumpCyclic) if
853  // there is a dictionary present.
854  forAll(regionMeshes, regioni)
855  {
856  forAll(newPatches[regioni], newPatchi)
857  {
858  if (newPatchIsCouple[regioni][newPatchi])
859  {
860  fvMeshTools::setPatchFields
861  (
862  regionMeshes[regioni],
863  newPatchi,
864  newPatchFieldDicts[regioni][newPatchi]
865  );
866  }
867  }
868  }
869 
870  // Communicate values across non-conformal processor cyclics so that they
871  // contain valid values that can be written to disk
872  if (Pstream::parRun())
873  {
874  forAll(regionMeshes, regioni)
875  {
876  const fvMesh& mesh = regionMeshes[regioni];
877 
878  #define EVALUATE_NON_CONFORMAL_PROCESSOR_CYCLICS(Type, nullArg) \
879  evaluateNonConformalProcessorCyclics<Type>(mesh);
880  FOR_ALL_FIELD_TYPES(EVALUATE_NON_CONFORMAL_PROCESSOR_CYCLICS)
881  #undef EVALUATE_NON_CONFORMAL_PROCESSOR_CYCLICS
882  }
883  }
884 
885  // Ensure the points are written to a sufficient precision
887 
888  // Set the instance so that the mesh writes
889  const word newInstance = overwrite ? oldInstance : runTime.name();
890  forAll(regionMeshes, regioni)
891  {
892  regionMeshes[regioni].setInstance(newInstance);
893  regionMeshes[regioni].setPolyFacesBfInstance(newInstance);
894  }
895 
896  // Write resulting mesh
897  Info<< "Writing mesh to " << runTime.name() << nl << endl;
898  forAll(regionMeshes, regioni)
899  {
900  regionMeshes[regioni].write();
901  }
902 
903  Info<< "End" << nl << endl;
904 
905  return 0;
906 }
907 
908 
909 // ************************************************************************* //
Field reading functions for post-processing utilities.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:492
static pointMesh & New(const word &name, const polyMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
Generic GeometricField class.
GeoMesh::template PatchField< Type > Patch
Type of the patch field of which the Boundary is composed.
An STL-conforming hash table.
Definition: HashTable.H:127
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:138
Hash function class for primitives. All non-primitives used to hash entries on hash tables likely nee...
Definition: Hash.H:53
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:53
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:473
static unsigned int highPrecision()
Return a high precision for writing data that is.
Definition: IOstream.C:90
Input from memory buffer stream.
Definition: IStringStream.H:52
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:91
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Output to memory buffer stream.
Definition: OStringStream.H:52
string str() const
Return the string.
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
void append(T *)
Append an element at the end of the list.
Definition: PtrListI.H:39
T & first()
Return the first element of the list.
Definition: UListI.H:114
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
static label nRequests()
Get number of outstanding requests.
Definition: UPstream.C:137
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static void waitRequests(const label start=0)
Wait until all requests (from start onwards) have finished.
Definition: UPstream.C:147
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:272
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: UPtrList.H:66
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
bool empty() const
Return true if the UPtrList is empty (ie, size() is zero)
Definition: UPtrListI.H:36
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:103
static label nArgs(int argc, char *argv[])
Return the number of arguments (not options)
Definition: argList.C:291
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:111
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
T optionLookupOrDefault(const word &opt, const T &deflt) const
Read a value from the named option if present.
Definition: argListI.H:294
Cyclic plane transformation.
static const wordList keywords
const word dictName() const
Return the local dictionary name (final part of scoped name)
Definition: dictionary.H:123
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
T lookupOrDefault(const word &, const T &) const
Find and return a T, if not found return the given default.
const dictionary & subOrEmptyDict(const word &, const bool mustRead=false) const
Find and return a sub-dictionary.
Definition: dictionary.C:829
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:669
const dictionary & optionalSubDict(const word &) const
Find and return a sub-dictionary if found.
Definition: dictionary.C:856
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:778
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:468
bool merge(const dictionary &)
Merge entries from the given dictionary.
Definition: dictionary.C:1313
static std::tuple< const Entries &... > entries(const Entries &...)
Construct an entries tuple from which to make a dictionary.
static const fileName null
An empty fileName.
Definition: fileName.H:97
bool connect(const bool changing, const bool geometric, const bool load)
Connect the mesh by adding faces into the nonConformalCyclics.
Mesh stitcher for stationary meshes.
static label addPatch(fvMesh &mesh, const polyPatch &patch)
Add patch. Inserts patch before all processor patches. Returns the.
Definition: fvMeshTools.C:33
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:932
UPtrList< GeoField > fields(bool strict=false, const HashSet< word > &geometryFields=fvMesh::geometryFields) const
Return the list of fields of type GeoField.
const word & name() const
Return reference to name.
Definition: fvMesh.H:447
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
A wordList with hashed indices for faster lookup by name.
Non-conformal cyclic poly patch. As nonConformalCoupledPolyPatch, but the neighbouring patch is local...
Non-conformal error poly patch. As nonConformalPolyPatch. This patch is a non-coupled non-conformal p...
Non-conformal processor cyclic poly patch. As nonConformalCyclicPolyPatch, but the neighbouring patch...
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:52
Foam::polyBoundaryMesh.
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:260
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
static fileName meshDirInstance(const IOobject &io)
Return the instance of the polyMesh directory. Returns.
Definition: polyMesh.C:974
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return a pointer to a new patch created on freestore from.
Definition: polyPatchNew.C:32
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:277
virtual autoPtr< polyPatch > clone(const polyBoundaryMesh &bm) const
Construct and return a clone, resetting the boundary mesh.
Definition: polyPatch.H:212
label nFaces() const
Read and return the specified dictionary from system or from path provided with the -dict option.
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
int main(int argc, char *argv[])
Definition: financialFoam.C:44
label patchi
const fvPatchList & patches
Info<< "Calculating turbulent flame speed field St\n"<< endl;volScalarField St(IOobject("St", runTime.name(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE), flameWrinkling->Xi() *Su);multivariateSurfaceInterpolationScheme< scalar >::fieldTable fields
Definition: createFields.H:234
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:272
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
void transform(GeometricField< Type, GeoMesh > &rtf, const GeometricField< tensor, GeoMesh > &trf, const GeometricField< Type, GeoMesh > &tf)
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
const word & regionName(const solver &region)
Definition: solver.H:218
FOR_ALL_FIELD_TYPES(makeDimensionedPointFieldFunctions)
messageStream Info
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:265
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
void inv(pointPatchField< tensor > &, const pointPatchField< tensor > &)
IOerror FatalIOError
error FatalError
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:243
static const char nl
Definition: Ostream.H:297
faceListList boundary(nPatches)
objects
dictionary dict
word meshPath
Definition: setMeshPath.H:1
const bool overwrite
Definition: setNoOverwrite.H:1
const Foam::wordList regionNames(args.optionFound("allRegions") ? runTime.regionNames() :wordList(1, args.optionFound("region") ? args.optionRead< word >("region") :polyMesh::defaultRegion))
Foam::argList args(argc, argv)
Foam::surfaceFields.