splitMeshRegions.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  splitMeshRegions
26 
27 Description
28  Splits mesh into multiple region meshes.
29 
30 Usage
31  \b splitMeshRegions -disconnected -largest
32  \b splitMeshRegions -cellZones all
33  \b splitMeshRegions -cellZones 'element heatsink' -defaultRegion air
34 
35  Options:
36  - \par -disconnected \n
37  Put disconnected parts of the mesh into separate regions
38 
39  - \par -disconnectedFaceSet <name> \n
40  Specify a set of faces that are considered disconnected
41 
42  - \par -cellZones <names> \n
43  Put cells in the specified zones into separate regions
44 
45  - \par -defaultRegion <name> \n
46  Name given to regions which do not correspond to a named cell zone.
47  Defaults to "region". Multiple such regions will have an index appended
48  (i.e., "region1", "region2", ...).
49 
50  - \par -largest \n
51  Only write the largest region
52 
53  - \par -insidePoint <point> \n
54  Only write the region containing the given point
55 
56  - \par -noMeshes \n
57  Do not write region meshes
58 
59  - \par -noFields \n
60  Do not write fields
61 
62  - \par -minOverlapFraction <fraction> \n
63  The minimum fraction a zone must overlap a cell-zone in
64  order to be named after it and associated with it. Defaults to 0.
65 
66  - \par -faceZonePatches \n
67  Use face zones to define the inter-region patches instead of creating a
68  single inter-region patch per pair of regions
69 
70 \*---------------------------------------------------------------------------*/
71 
72 #include "argList.H"
73 #include "regionSplit.H"
74 #include "fvMeshSubset.H"
75 #include "IOobjectList.H"
76 #include "faceSet.H"
77 #include "polyTopoChange.H"
78 #include "removeCells.H"
79 #include "syncTools.H"
80 #include "ReadFields.H"
81 #include "mappedWallPolyPatch.H"
82 #include "fvMeshTools.H"
83 #include "meshSearch.H"
84 #include "RemoteData.H"
85 #include "IOmanip.H"
86 
87 using namespace Foam;
88 
89 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
90 
91 // Standard default region base name
92 const word standardRegionName("region");
93 
94 
95 // Prepend prefix to selected patches.
96 void renamePatches
97 (
98  fvMesh& mesh,
99  const word& prefix,
100  const labelList& patchesToRename
101 )
102 {
104  const_cast<polyBoundaryMesh&>(mesh.poly().boundary());
105 
106  // Create a list of all the new names
107  wordList newNames = patches.names();
108  forAll(patchesToRename, i)
109  {
110  const label patchi = patchesToRename[i];
111  newNames[patchi] = prefix + '_' + newNames[patchi];
112  }
113 
114  // Apply to the patches
115  patches.renamePatches(newNames, true);
116 }
117 
118 
119 template<class GeoField>
120 void subsetVolFields
121 (
122  const fvMesh& mesh,
123  const fvMesh& subMesh,
124  const labelList& cellMap,
125  const labelList& faceMap,
126  const labelHashSet& addedPatches
127 )
128 {
129  const labelList patchMap(identityMap(mesh.poly().boundary().size()));
130 
132  (
133  mesh.objectRegistry::lookupClass<GeoField>()
134  );
135 
137  {
138  const GeoField& fld = *iter();
139 
140  Info<< indent << "Mapping " << GeoField::typeName
141  << " " << fld.name() << endl;
142 
143  tmp<GeoField> tSubFld
144  (
146  (
147  fld,
148  subMesh,
149  patchMap,
150  cellMap,
151  faceMap
152  )
153  );
154 
155  // Initialise the introduced patch fields with the adjacent cell value
156  forAll(tSubFld().boundaryField(), patchi)
157  {
158  if (addedPatches.found(patchi))
159  {
160  tSubFld.ref().boundaryFieldRef()[patchi] ==
161  tSubFld.ref().boundaryField()[patchi].patchInternalField();
162  }
163  }
164 
165  // Store on subMesh
166  GeoField* subFld = tSubFld.ptr();
167  subFld->rename(fld.name());
168  subFld->writeOpt() = IOobject::AUTO_WRITE;
169  subFld->store();
170  }
171 }
172 
173 
174 template<class GeoField>
175 void subsetSurfaceFields
176 (
177  const fvMesh& mesh,
178  const fvMesh& subMesh,
179  const labelList& cellMap,
180  const labelList& faceMap,
181  const labelHashSet& addedPatches
182 )
183 {
184  const labelList patchMap(identityMap(mesh.poly().boundary().size()));
185 
187  (
188  mesh.objectRegistry::lookupClass<GeoField>()
189  );
190 
192  {
193  const GeoField& fld = *iter();
194 
195  Info<< indent << "Mapping " << GeoField::typeName
196  << " " << fld.name() << endl;
197 
198  tmp<GeoField> tSubFld
199  (
201  (
202  fld,
203  subMesh,
204  patchMap,
205  cellMap,
206  faceMap
207  )
208  );
209 
210  // Store on subMesh
211  GeoField* subFld = tSubFld.ptr();
212  subFld->rename(fld.name());
213  subFld->writeOpt() = IOobject::AUTO_WRITE;
214  subFld->store();
215  }
216 }
217 
218 
219 // Select all cells not in the region
220 labelList getNonRegionCells(const labelList& cellRegion, const label regioni)
221 {
222  DynamicList<label> nonRegionCells(cellRegion.size());
223  forAll(cellRegion, celli)
224  {
225  if (cellRegion[celli] != regioni)
226  {
227  nonRegionCells.append(celli);
228  }
229  }
230  return nonRegionCells.shrink();
231 }
232 
233 
234 void addToInterface
235 (
236  const polyMesh& mesh,
237  const label zoneID,
238  const label ownRegion,
239  const label neiRegion,
240  EdgeMap<Map<label>>& regionsToSize
241 )
242 {
243  edge interface
244  (
245  min(ownRegion, neiRegion),
246  max(ownRegion, neiRegion)
247  );
248 
249  EdgeMap<Map<label>>::iterator iter = regionsToSize.find
250  (
251  interface
252  );
253 
254  if (iter != regionsToSize.end())
255  {
256  // Check if zone present
257  Map<label>::iterator zoneFnd = iter().find(zoneID);
258  if (zoneFnd != iter().end())
259  {
260  // Found zone. Increment count.
261  zoneFnd()++;
262  }
263  else
264  {
265  // New or no zone. Insert with count 1.
266  iter().insert(zoneID, 1);
267  }
268  }
269  else
270  {
271  // Create new interface of size 1.
272  Map<label> zoneToSize;
273  zoneToSize.insert(zoneID, 1);
274  regionsToSize.insert(interface, zoneToSize);
275  }
276 }
277 
278 
279 label whichZone
280 (
281  const polyMesh& mesh,
282  const bool faceZonePatches,
283  const label facei
284 )
285 {
286  if (faceZonePatches)
287  {
288  const labelList zones(mesh.faceZones().whichZones(facei));
289 
290  if (zones.size() == 0)
291  {
292  return -1;
293  }
294  else if (zones.size() == 1)
295  {
296  return zones[0];
297  }
298  else
299  {
301  << "Face " << facei << " is in more than one zone " << zones
302  << exit(FatalError);
303 
304  return -1;
305  }
306  }
307  else
308  {
309  return -1;
310  }
311 }
312 
313 
314 // Get region-region interface name and sizes.
315 // Returns interfaces as straight list for looping in identical order.
316 void getInterfaceSizes
317 (
318  const polyMesh& mesh,
319  const bool faceZonePatches,
320  const labelList& cellRegion,
321  const wordList& regionNames,
322 
323  edgeList& interfaces,
324  List<Pair<word>>& interfaceNames,
325  labelList& interfaceNFaces,
326  labelList& faceInterfaces
327 )
328 {
329  // From region-region to faceZone (or -1) to number of faces.
330 
331  EdgeMap<Map<label>> regionsToSize;
332 
333 
334  // Internal faces
335  // ~~~~~~~~~~~~~~
336 
337  forAll(mesh.faceNeighbour(), facei)
338  {
339  label ownRegion = cellRegion[mesh.faceOwner()[facei]];
340  label neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
341 
342  if (ownRegion != neiRegion)
343  {
344  addToInterface
345  (
346  mesh,
347  whichZone(mesh, faceZonePatches, facei),
348  ownRegion,
349  neiRegion,
350  regionsToSize
351  );
352  }
353  }
354 
355  // Boundary faces
356  // ~~~~~~~~~~~~~~
357 
358  // Neighbour cellRegion.
359  labelList coupledRegion(mesh.nFaces()-mesh.nInternalFaces());
360 
361  forAll(coupledRegion, i)
362  {
363  label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
364  coupledRegion[i] = cellRegion[celli];
365  }
366  syncTools::swapBoundaryFaceList(mesh, coupledRegion);
367 
368  forAll(coupledRegion, i)
369  {
370  label facei = i+mesh.nInternalFaces();
371  label ownRegion = cellRegion[mesh.faceOwner()[facei]];
372  label neiRegion = coupledRegion[i];
373 
374  if (ownRegion != neiRegion)
375  {
376  addToInterface
377  (
378  mesh,
379  whichZone(mesh, faceZonePatches, facei),
380  ownRegion,
381  neiRegion,
382  regionsToSize
383  );
384  }
385  }
386 
387 
388  if (Pstream::parRun())
389  {
390  if (Pstream::master())
391  {
392  // Receive and add to my sizes
393  for
394  (
395  int slave=Pstream::firstSlave();
396  slave<=Pstream::lastSlave();
397  slave++
398  )
399  {
400  IPstream fromSlave(Pstream::commsTypes::blocking, slave);
401 
402  EdgeMap<Map<label>> slaveSizes(fromSlave);
403 
404  forAllConstIter(EdgeMap<Map<label>>, slaveSizes, slaveIter)
405  {
406  EdgeMap<Map<label>>::iterator masterIter =
407  regionsToSize.find(slaveIter.key());
408 
409  if (masterIter != regionsToSize.end())
410  {
411  // Same inter-region
412  const Map<label>& slaveInfo = slaveIter();
413  Map<label>& masterInfo = masterIter();
414 
415  forAllConstIter(Map<label>, slaveInfo, iter)
416  {
417  label zoneID = iter.key();
418  label slaveSize = iter();
419 
420  Map<label>::iterator zoneFnd = masterInfo.find
421  (
422  zoneID
423  );
424  if (zoneFnd != masterInfo.end())
425  {
426  zoneFnd() += slaveSize;
427  }
428  else
429  {
430  masterInfo.insert(zoneID, slaveSize);
431  }
432  }
433  }
434  else
435  {
436  regionsToSize.insert(slaveIter.key(), slaveIter());
437  }
438  }
439  }
440  }
441  else
442  {
443  // Send to master
444  {
445  OPstream toMaster
446  (
449  );
450  toMaster << regionsToSize;
451  }
452  }
453  }
454 
455  // Rework
456 
457  Pstream::scatter(regionsToSize);
458 
459 
460 
461  // Now we have the global sizes of all inter-regions.
462  // Invert this on master and distribute.
463  label nInterfaces = 0;
464  forAllConstIter(EdgeMap<Map<label>>, regionsToSize, iter)
465  {
466  const Map<label>& info = iter();
467  nInterfaces += info.size();
468  }
469 
470  interfaces.setSize(nInterfaces);
471  interfaceNames.setSize(nInterfaces);
472  interfaceNFaces.setSize(nInterfaces);
473  EdgeMap<Map<label>> regionsToInterface(nInterfaces);
474 
475  nInterfaces = 0;
476  forAllConstIter(EdgeMap<Map<label>>, regionsToSize, iter)
477  {
478  const edge& e = iter.key();
479  const word& name0 = regionNames[e[0]];
480  const word& name1 = regionNames[e[1]];
481 
482  const Map<label>& info = iter();
483  forAllConstIter(Map<label>, info, infoIter)
484  {
485  interfaces[nInterfaces] = iter.key();
486  label zoneID = infoIter.key();
487  if (zoneID == -1)
488  {
489  interfaceNames[nInterfaces] = Pair<word>
490  (
491  name0 + "_to_" + name1,
492  name1 + "_to_" + name0
493  );
494  }
495  else
496  {
497  const word& zoneName = mesh.faceZones()[zoneID].name();
498  interfaceNames[nInterfaces] = Pair<word>
499  (
500  zoneName + "_" + name0 + "_to_" + name1,
501  zoneName + "_" + name1 + "_to_" + name0
502  );
503  }
504  interfaceNFaces[nInterfaces] = infoIter();
505 
506  if (regionsToInterface.found(e))
507  {
508  regionsToInterface[e].insert(zoneID, nInterfaces);
509  }
510  else
511  {
512  Map<label> zoneAndInterface;
513  zoneAndInterface.insert(zoneID, nInterfaces);
514  regionsToInterface.insert(e, zoneAndInterface);
515  }
516  nInterfaces++;
517  }
518  }
519 
520 
521  // Now all processor have consistent interface information
522 
523  Pstream::scatter(interfaces);
524  Pstream::scatter(interfaceNames);
525  Pstream::scatter(interfaceNFaces);
526  Pstream::scatter(regionsToInterface);
527 
528  // Mark all inter-region faces.
529  faceInterfaces.setSize(mesh.nFaces(), -1);
530 
531  forAll(mesh.faceNeighbour(), facei)
532  {
533  label ownRegion = cellRegion[mesh.faceOwner()[facei]];
534  label neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
535 
536  if (ownRegion != neiRegion)
537  {
538  const label zoneID = whichZone(mesh, faceZonePatches, facei);
539 
540  edge interface
541  (
542  min(ownRegion, neiRegion),
543  max(ownRegion, neiRegion)
544  );
545 
546  faceInterfaces[facei] = regionsToInterface[interface][zoneID];
547  }
548  }
549  forAll(coupledRegion, i)
550  {
551  label facei = i+mesh.nInternalFaces();
552  label ownRegion = cellRegion[mesh.faceOwner()[facei]];
553  label neiRegion = coupledRegion[i];
554 
555  if (ownRegion != neiRegion)
556  {
557  const label zoneID = whichZone(mesh, faceZonePatches, facei);
558 
559  edge interface
560  (
561  min(ownRegion, neiRegion),
562  max(ownRegion, neiRegion)
563  );
564 
565  faceInterfaces[facei] = regionsToInterface[interface][zoneID];
566  }
567  }
568 }
569 
570 
571 // Create mesh for region.
572 autoPtr<polyTopoChangeMap> createRegionMesh
573 (
574  const fvMesh& mesh,
575  // Region info
576  const labelList& cellRegion,
577  const label regioni,
578  const word& regionName,
579  // Interface info
580  const labelList& interfacePatches,
581  const labelList& faceInterfaces,
582 
583  autoPtr<fvMesh>& newMesh
584 )
585 {
586  // Neighbour cellRegion.
587  labelList coupledRegion(mesh.nFaces()-mesh.nInternalFaces());
588 
589  forAll(coupledRegion, i)
590  {
591  label celli = mesh.faceOwner()[i+mesh.nInternalFaces()];
592  coupledRegion[i] = cellRegion[celli];
593  }
594  syncTools::swapBoundaryFaceList(mesh, coupledRegion);
595 
596 
597  // Topology change container. Start off from existing mesh.
598  polyTopoChange meshMod(mesh);
599 
600  // Cell remover engine
601  removeCells cellRemover(mesh);
602 
603  // Select all but region cells
604  labelList cellsToRemove(getNonRegionCells(cellRegion, regioni));
605 
606  // Find out which faces will get exposed. Note that this
607  // gets faces in mesh face order. So both regions will get same
608  // face in same order (important!)
609  labelList exposedFaces = cellRemover.getExposedFaces(cellsToRemove);
610 
611  labelList exposedPatchIDs(exposedFaces.size());
612  forAll(exposedFaces, i)
613  {
614  label facei = exposedFaces[i];
615  label interfacei = faceInterfaces[facei];
616 
617  label ownRegion = cellRegion[mesh.faceOwner()[facei]];
618  label neiRegion = -1;
619 
620  if (mesh.isInternalFace(facei))
621  {
622  neiRegion = cellRegion[mesh.faceNeighbour()[facei]];
623  }
624  else
625  {
626  neiRegion = coupledRegion[facei-mesh.nInternalFaces()];
627  }
628 
629 
630  // Check which side is being kept - determines which of the two
631  // patches will be used.
632 
633  label otherRegion = -1;
634 
635  if (ownRegion == regioni && neiRegion != regioni)
636  {
637  otherRegion = neiRegion;
638  }
639  else if (ownRegion != regioni && neiRegion == regioni)
640  {
641  otherRegion = ownRegion;
642  }
643  else
644  {
646  << "Exposed face:" << facei
647  << " fc:" << mesh.faceCentres()[facei]
648  << " has owner region " << ownRegion
649  << " and neighbour region " << neiRegion
650  << " when handling region:" << regioni
651  << exit(FatalError);
652  }
653 
654  // Find the patch.
655  if (regioni < otherRegion)
656  {
657  exposedPatchIDs[i] = interfacePatches[interfacei];
658  }
659  else
660  {
661  exposedPatchIDs[i] = interfacePatches[interfacei]+1;
662  }
663  }
664 
665  // Remove faces
666  cellRemover.setRefinement
667  (
668  cellsToRemove,
669  exposedFaces,
670  exposedPatchIDs,
671  meshMod
672  );
673 
674  autoPtr<polyTopoChangeMap> map = meshMod.makeMesh
675  (
676  newMesh,
677  IOobject
678  (
679  regionName,
680  mesh.time().name(),
681  mesh.time(),
684  ),
685  mesh
686  );
687 
688  return map;
689 }
690 
691 
692 void createAndWriteRegion
693 (
694  const fvMesh& mesh,
695  const labelList& cellRegion,
696  const wordList& regionNames,
697  const labelList& faceInterfaces,
698  const labelList& interfacePatches,
699  const label regioni,
700  const word& newMeshInstance
701 )
702 {
703  Info<< "Creating mesh for region \'"
704  << regionNames[regioni] << "\':" << endl << incrIndent;
705 
706  autoPtr<fvMesh> newMesh;
707  autoPtr<polyTopoChangeMap> map = createRegionMesh
708  (
709  mesh,
710  cellRegion,
711  regioni,
712  regionNames[regioni],
713  interfacePatches,
714  faceInterfaces,
715  newMesh
716  );
717 
718  // Make map of all added patches
719  labelHashSet addedPatches(2*interfacePatches.size());
720  forAll(interfacePatches, interfacei)
721  {
722  addedPatches.insert(interfacePatches[interfacei]);
723  addedPatches.insert(interfacePatches[interfacei]+1);
724  }
725 
726  Info<< indent << "Mapping fields" << endl << incrIndent;
727 
728  // Map existing fields
729  newMesh().topoChange(map());
730 
731  // Add subsetted fields
732  #define SUBSET_VOL_FIELDS(Type, nullArg) \
733  subsetVolFields<VolField<Type>> \
734  ( \
735  mesh, \
736  newMesh(), \
737  map().cellMap(), \
738  map().faceMap(), \
739  addedPatches \
740  );
741  FOR_ALL_FIELD_TYPES(SUBSET_VOL_FIELDS);
742  #undef SUBSET_VOL_FIELDS
743 
744  #define SUBSET_SURFACE_FIELDS(Type, nullArg) \
745  subsetSurfaceFields<SurfaceField<Type>> \
746  ( \
747  mesh, \
748  newMesh(), \
749  map().cellMap(), \
750  map().faceMap(), \
751  addedPatches \
752  );
753  FOR_ALL_FIELD_TYPES(SUBSET_SURFACE_FIELDS);
754  #undef SUBSET_SURFACE_FIELDS
755 
756  Info<< decrIndent;
757 
758  const polyBoundaryMesh& newPatches = newMesh().poly().boundary();
759  newPatches.checkParallelSync(true);
760 
761  // Delete empty patches ...
762 
763  // Create reordering list to move patches-to-be-deleted to end
764  labelList oldToNew(newPatches.size(), -1);
765  DynamicList<label> sharedPatches(newPatches.size());
766  label newI = 0;
767 
768  Info<< indent << "Deleting empty patches" << endl;
769 
770  // Assumes all non-proc boundaries are on all processors!
771  forAll(newPatches, patchi)
772  {
773  const polyPatch& pp = newPatches[patchi];
774 
775  if (!isA<processorPolyPatch>(pp))
776  {
777  if (returnReduce(pp.size(), sumOp<label>()) > 0)
778  {
779  oldToNew[patchi] = newI;
780  if (!addedPatches.found(patchi))
781  {
782  sharedPatches.append(newI);
783  }
784  newI++;
785  }
786  }
787  }
788 
789  // Same for processor patches (but need no reduction)
790  forAll(newPatches, patchi)
791  {
792  const polyPatch& pp = newPatches[patchi];
793 
794  if (isA<processorPolyPatch>(pp) && pp.size())
795  {
796  oldToNew[patchi] = newI++;
797  }
798  }
799 
800  const label nNewPatches = newI;
801 
802  // Move all delete-able patches to the end
803  forAll(oldToNew, patchi)
804  {
805  if (oldToNew[patchi] == -1)
806  {
807  oldToNew[patchi] = newI++;
808  }
809  }
810 
811  fvMeshTools::reorderPatches(newMesh(), oldToNew, nNewPatches, true);
812 
813  Info<< indent << "Writing new mesh" << endl;
814 
815  newMesh().setInstance(newMeshInstance);
816  newMesh().write();
817 
818  Info<< endl << decrIndent;
819 }
820 
821 
822 // Create for every region-region interface with non-zero size two patches.
823 // First one is for minimumregion to maximumregion.
824 // Note that patches get created in same order on all processors (if parallel)
825 // since looping over synchronised 'interfaces'.
826 labelList addRegionPatches
827 (
828  fvMesh& mesh,
829  const wordList& regionNames,
830  const edgeList& interfaces,
831  const List<Pair<word>>& interfaceNames
832 )
833 {
834  labelList interfacePatches(interfaces.size());
835 
836  forAll(interfaces, interI)
837  {
838  const edge& e = interfaces[interI];
839  const Pair<word>& names = interfaceNames[interI];
840 
841  mappedWallPolyPatch patch1
842  (
843  names[0],
844  0, // overridden
845  0, // overridden
846  0, // overridden
847  regionNames[e[1]], // neighbourRegion
848  names[1], // neighbourPatch
849  mesh.poly().boundary()
850  );
851 
852  interfacePatches[interI] = fvMeshTools::addPatch(mesh, patch1);
853 
854  mappedWallPolyPatch patch2
855  (
856  names[1],
857  0,
858  0,
859  0,
860  regionNames[e[0]], // neighbourRegion
861  names[0],
862  mesh.poly().boundary()
863  );
864 
865  fvMeshTools::addPatch(mesh, patch2);
866  }
867 
869 
870  return interfacePatches;
871 }
872 
873 
874 void getCellCellZoneis
875 (
876  const polyMesh& mesh,
877  const labelList cellZoneis,
878  labelList& cellCellZones,
879  labelList& bFaceNbrCellZones
880 )
881 {
882  cellCellZones.setSize(mesh.nCells());
883  cellCellZones = -1;
884 
885  label failCelli = -1;
886  DynamicList<label> failCellZones;
887 
888  forAll(cellZoneis, i)
889  {
890  const label cellZonei = cellZoneis[i];
891 
892  const cellZone& cz = mesh.cellZones()[cellZonei];
893 
894  forAll(cz, czCelli)
895  {
896  const label celli = cz[czCelli];
897 
898  if (cellCellZones[celli] == -1)
899  {
900  cellCellZones[celli] = cellZonei;
901  }
902  else
903  {
904  if (failCelli == -1)
905  {
906  failCelli = celli;
907  failCellZones.append(cellCellZones[celli]);
908  }
909  if (failCelli == celli)
910  {
911  failCellZones.append(cellZonei);
912  }
913  }
914  }
915  }
916 
917  if (failCelli != -1)
918  {
920  << "Cell " << failCelli << " with centre "
921  << mesh.cellCentres()[failCelli]
922  << " is multiple selected zones; ";
923  forAll(failCellZones, i)
924  {
925  FatalError<< mesh.cellZones()[failCellZones[i]].name();
926  if (i < failCellZones.size() - 2) FatalError << ", ";
927  if (i == failCellZones.size() - 2) FatalError << " and ";
928  }
929  FatalError
930  << ". This is not allowed."
931  << exit(FatalError);
932  }
933 
934  bFaceNbrCellZones.setSize(mesh.nFaces() - mesh.nInternalFaces());
935  bFaceNbrCellZones = -1;
936 
937  forAll(bFaceNbrCellZones, bFacei)
938  {
939  bFaceNbrCellZones[bFacei] =
940  cellCellZones[mesh.faceOwner()[mesh.nInternalFaces() + bFacei]];
941  }
942 
943  syncTools::swapBoundaryFaceList(mesh, bFaceNbrCellZones);
944 }
945 
946 
947 void matchRegions
948 (
949  const polyMesh& mesh,
950  const label nRegions,
951  const labelList& cellRegion,
952  const word& defaultRegion,
953  labelList& cellZoneRegions,
955  labelList& regionCellZones,
956  const scalar minOverlapFraction
957 )
958 {
959  cellZoneRegions.setSize(mesh.cellZones().size(), -1);
960  regionNames.setSize(nRegions);
961  regionCellZones.setSize(nRegions, -1);
962 
963  // Check the zone names are in sync
964  {
965  List<wordList> cellZoneNames(Pstream::nProcs());
966 
967  cellZoneNames[Pstream::myProcNo()] = mesh.cellZones().toc();
968 
969  Pstream::gatherList(cellZoneNames);
970  Pstream::scatterList(cellZoneNames);
971 
972  forAll(cellZoneNames, proci)
973  {
974  if (cellZoneNames[proci] != cellZoneNames[0])
975  {
977  << "cellZones not synchronised across processors." << endl
978  << "Master has cellZones " << cellZoneNames[0] << endl
979  << "Processor " << proci << " has cellZones "
980  << cellZoneNames[proci] << exit(FatalError);
981  }
982  }
983  }
984 
985  // Get the global numbers of cells in the zones
986  labelList cellZoneNCells(mesh.cellZones().size(), 0);
987  {
988  forAll(mesh.cellZones(), zoneI)
989  {
990  cellZoneNCells[zoneI] = returnReduce
991  (
992  mesh.cellZones()[zoneI].size(),
993  sumOp<label>()
994  );
995  }
996  }
997 
998  boolList cellInZone(mesh.nCells(), false);
999 
1000  Info<< "Trying to match regions to existing cell zones:" << endl;
1001 
1002  forAll(mesh.cellZones(), cellZonei)
1003  {
1004  UIndirectList<bool> cellZoneCellInZone
1005  (
1006  cellInZone,
1007  mesh.cellZones()[cellZonei]
1008  );
1009 
1010  cellZoneCellInZone = true;
1011 
1012  const label minOverlapNCells =
1013  max(1, label(minOverlapFraction*cellZoneNCells[cellZonei]));
1014 
1015  // Per region the number of cells in the zone
1016  labelList nCellsInZone(nRegions, 0);
1017  forAll(cellRegion, celli)
1018  {
1019  if (cellInZone[celli])
1020  {
1021  nCellsInZone[cellRegion[celli]]++;
1022  }
1023  }
1025  Pstream::listCombineScatter(nCellsInZone);
1026 
1027  // Pick the region with largest overlap of the zone
1028  label regioni = findMax(nCellsInZone);
1029 
1030  if (nCellsInZone[regioni] < minOverlapNCells)
1031  {
1032  // This region covers too little of zone. Not good enough.
1033  regioni = -1;
1034  }
1035  else
1036  {
1037  // Check that region contains no cells outside of the zone
1038  forAll(cellRegion, celli)
1039  {
1040  if (cellRegion[celli] == regioni && !cellInZone[celli])
1041  {
1042  regioni = -1;
1043  break;
1044  }
1045  }
1046  reduce(regioni, minOp<label>());
1047  }
1048 
1049  // If successful, name the identified region and map it to the zone
1050  if (regioni != -1)
1051  {
1052  Info<< " Matched region " << regioni
1053  << " to zone " << mesh.cellZones()[cellZonei].name()
1054  << " with " << cellZoneNCells[cellZonei] << " cells "
1055  << endl;
1056 
1057  if (cellZoneRegions[cellZonei] == -1)
1058  {
1059  cellZoneRegions[cellZonei] = regioni;
1060  regionNames[regioni] = mesh.cellZones()[cellZonei].name();
1061  regionCellZones[regioni] = cellZonei;
1062  }
1063  else
1064  {
1065  cellZoneRegions[cellZonei] = -2;
1066  regionNames[regioni] = word::null;
1067  regionCellZones[regioni] = -1;
1068  }
1069  }
1070 
1071  cellZoneCellInZone = false;
1072  }
1073 
1074  // Restore the standard "this cell zone has no region" index
1075  forAll(cellZoneRegions, cellZonei)
1076  {
1077  cellZoneRegions[cellZonei] = max(cellZoneRegions[cellZonei], -1);
1078  }
1079 
1080  // Check if there are any regions which were not matched
1081  label nUnmatchedRegions = 0;
1082  forAll(regionCellZones, regioni)
1083  {
1084  if (regionCellZones[regioni] == -1)
1085  {
1086  nUnmatchedRegions ++;
1087  }
1088  }
1089 
1090  if (nUnmatchedRegions)
1091  {
1092  label nUnmatchedi = 1;
1093 
1094  // Create default names for unmatches regions
1095  forAll(regionCellZones, regioni)
1096  {
1097  if (regionCellZones[regioni] == -1)
1098  {
1099  if
1100  (
1101  nUnmatchedRegions == 1
1102  && defaultRegion != standardRegionName
1103  )
1104  {
1105  regionNames[regioni] = defaultRegion;
1106  }
1107  else
1108  {
1109  regionNames[regioni] =
1110  defaultRegion + Foam::name(nUnmatchedi ++);
1111  }
1112  }
1113  }
1114  }
1115 
1116  Info<< endl;
1117 }
1118 
1119 
1120 void writeCellToRegion(const fvMesh& mesh, const labelList& cellRegion)
1121 {
1122  // Write to manual decomposition option
1123  {
1124  labelIOList cellToRegion
1125  (
1126  IOobject
1127  (
1128  "cellToRegion",
1129  mesh.facesInstance(),
1130  mesh,
1133  false
1134  ),
1135  cellRegion
1136  );
1137  cellToRegion.write();
1138 
1139  Info<< "Writing region index per cell as a "
1140  << labelIOList::typeName << " to "
1141  << cellToRegion.relativeObjectPath() << nl << endl;
1142  }
1143 
1144  // Write for post processing
1145  {
1146  volScalarField::Internal cellToRegion
1147  (
1148  IOobject
1149  (
1150  "cellToRegion",
1151  mesh.time().name(),
1152  mesh,
1155  false
1156  ),
1157  mesh,
1159  );
1160  forAll(cellRegion, celli)
1161  {
1162  cellToRegion[celli] = cellRegion[celli];
1163  }
1164  cellToRegion.write();
1165 
1166  Info<< "Writing region index per cell as a "
1168  << cellToRegion.relativeObjectPath() << nl << endl;
1169  }
1170 }
1171 
1172 
1173 template<unsigned int NColumns>
1175 {
1177  forAll(table, i)
1178  {
1179  forAll(table[i], j)
1180  {
1181  tableWs[j] = max(tableWs[j], table[i][j].size());
1182  }
1183  }
1184 
1185  forAll(table, i)
1186  {
1187  if (i == 1)
1188  {
1189  forAll(table[i], j)
1190  {
1191  if (j) Info << " ";
1192  Info<< string(tableWs[j], '-').c_str();
1193  }
1194  Info<< endl;
1195  }
1196 
1197  forAll(table[i], j)
1198  {
1199  if (j) Info << " ";
1200  Info<< setw(tableWs[j]) << table[i][j].c_str();
1201  }
1202  Info<< nl;
1203  }
1204 }
1205 
1206 
1207 int main(int argc, char *argv[])
1208 {
1210  (
1211  "splits mesh into multiple regions (detected by walking across faces)"
1212  );
1213  #include "addMeshOption.H"
1214  #include "addRegionOption.H"
1215  #include "addNoOverwriteOption.H"
1217  (
1218  "disconnected",
1219  "put disconnected parts of the mesh into separate regions"
1220  );
1222  (
1223  "disconnectedFaceSet",
1224  "name",
1225  "specify a set of faces that are considered disconnected"
1226  );
1228  (
1229  "cellZones",
1230  "names",
1231  "put cells in the specified zones into separate regions"
1232  );
1234  (
1235  "defaultRegion",
1236  "name",
1237  "name given to regions which do not correspond to a named cell zone; "
1238  "default \"region\""
1239  );
1241  (
1242  "largest",
1243  "only write the largest region"
1244  );
1246  (
1247  "insidePoint",
1248  "point",
1249  "only write the region containing the given point"
1250  );
1252  (
1253  "noMeshes",
1254  "do not write region meshes"
1255  );
1257  (
1258  "noFields",
1259  "do not write region fields"
1260  );
1262  (
1263  "minOverlapFraction",
1264  "fraction",
1265  "the minimum fraction a zone must overlap a cell-zone in order to "
1266  "be named after it and associated with it; default 0"
1267  );
1269  (
1270  "faceZonePatches",
1271  "Use face zones to define the inter-region patches instead of creating "
1272  "a single inter-region patch per pair of regions"
1273  );
1274 
1276 
1277  if (!args.optionFound("disconnected") && !args.optionFound("cellZones"))
1278  {
1280  << "Neither -disconnected nor -cellZones specified, so no "
1281  << "criteria is available to identify regions" << exit(FatalError);
1282  }
1283 
1286 
1287  const word oldInstance = mesh.pointsInstance();
1288 
1289  const bool largest = args.optionFound("largest");
1290  const bool insidePoint = args.optionFound("insidePoint");
1291  if (largest && insidePoint)
1292  {
1294  << "-largest (i.e., write the region with most cells)"
1295  << " and -insidePoint (write the region containing the given "
1296  << "point) cannot be used together" << exit(FatalError);
1297  }
1298 
1299  #include "setNoOverwrite.H"
1300 
1301  const bool faceZonePatches = args.optionFound("faceZonePatches");
1302  if (faceZonePatches)
1303  {
1304  Info<< "Using face zones to divide inter-region interfaces"
1305  << " into multiple patches" << nl << endl;
1306  }
1307  else
1308  {
1309  Info<< "Creating single patch per inter-region interface"
1310  << nl << endl;
1311  }
1312 
1313  const word defaultRegion
1314  (
1315  args.optionLookupOrDefault("defaultRegion", standardRegionName)
1316  );
1317 
1318  // Read the set of cell zones (if any) to operate on
1319  labelList cellZoneis;
1320  if (args.optionFound("cellZones"))
1321  {
1322  const wordList cellZoneNames =
1323  args.optionReadList<word>("cellZones");
1324 
1325  DynamicList<label> cellZoneisDyn(cellZoneNames.size());
1326  boolList cellZoneUsed(mesh.cellZones().size(), false);
1327  forAll(cellZoneNames, i)
1328  {
1329  if (cellZoneNames[i] == "all")
1330  {
1331  cellZoneisDyn = identityMap(mesh.cellZones().size());
1332  break;
1333  }
1334 
1335  const label cellZonei =
1336  mesh.cellZones().findIndex(cellZoneNames[i]);
1337 
1338  if (cellZonei == -1)
1339  {
1341  << "Cell zone \'" << cellZoneNames[i] << "\' not found. "
1342  << "Available cell zones are: " << mesh.cellZones().toc()
1343  << exit(FatalError);
1344  }
1345 
1346  if (cellZoneUsed[cellZonei]) continue;
1347 
1348  cellZoneisDyn.append(cellZonei);
1349  cellZoneUsed[cellZonei] = true;
1350  }
1351  cellZoneis.transfer(cellZoneisDyn);
1352  }
1353 
1354  // Identify the regions. For every cell, assign a region index. Also, where
1355  // possible, create correspondence between the existing cellZones and the
1356  // new regions. Create region names.
1357  labelList cellRegions(mesh.nCells(), -1);
1358  labelList cellZoneRegions(mesh.cellZones().size(), -1);
1360  labelList regionCellZones;
1361  if (args.optionFound("disconnected"))
1362  {
1363  boolList faceBlockeds(mesh.nFaces(), false);
1364 
1365  const word disconnectedFaceSetName =
1366  args.optionLookupOrDefault("disconnectedFaceSet", word::null);
1367 
1368  if (disconnectedFaceSetName != word::null)
1369  {
1370  faceSet blockedFaceSet(mesh, disconnectedFaceSetName);
1371 
1372  Info<< "Read "
1373  << returnReduce(blockedFaceSet.size(), sumOp<label>())
1374  << " blocked faces from set \'" << disconnectedFaceSetName
1375  << "\'" << nl << endl;
1376 
1377  forAllConstIter(faceSet, blockedFaceSet, iter)
1378  {
1379  faceBlockeds[iter.key()] = true;
1380  }
1381  }
1382 
1383  if (args.optionFound("cellZones"))
1384  {
1385  labelList cellZoneRegions(mesh.cellZones().size(), -1);
1386  forAll(cellZoneis, i)
1387  {
1388  cellZoneRegions[cellZoneis[i]] = i;
1389  }
1390 
1391  labelList cellCellZones, bFaceNbrCellZones;
1392  getCellCellZoneis
1393  (
1394  mesh,
1395  cellZoneis,
1396  cellCellZones,
1397  bFaceNbrCellZones
1398  );
1399 
1400  forAll(mesh.faces(), facei)
1401  {
1402  const label ownerZone =
1403  cellCellZones[mesh.faceOwner()[facei]];
1404  const label neighbourZone =
1405  facei < mesh.nInternalFaces()
1406  ? cellCellZones[mesh.faceNeighbour()[facei]]
1407  : bFaceNbrCellZones[facei - mesh.nInternalFaces()];
1408 
1409  const label ownerRegion =
1410  ownerZone != -1 ? cellZoneRegions[ownerZone] : -1;
1411  const label neighbourRegion =
1412  neighbourZone != -1 ? cellZoneRegions[neighbourZone] : -1;
1413 
1414  faceBlockeds[facei] =
1415  faceBlockeds[facei] || ownerRegion != neighbourRegion;
1416  }
1417  }
1418 
1419  regionSplit regions(mesh, faceBlockeds);
1420 
1421  cellRegions.transfer(regions);
1422 
1423  matchRegions
1424  (
1425  mesh,
1426  regions.nRegions(),
1427  cellRegions,
1428  defaultRegion,
1429  cellZoneRegions,
1430  regionNames,
1431  regionCellZones,
1432  args.optionLookupOrDefault<scalar>("minOverlapFraction", 0)
1433  );
1434  }
1435  else // args.optionFound("cellZones")
1436  {
1437  regionNames.resize(cellZoneis.size());
1438  regionCellZones.resize(cellZoneis.size());
1439 
1440  forAll(cellZoneis, i)
1441  {
1442  cellZoneRegions[cellZoneis[i]] = i;
1443 
1444  regionNames[i] = mesh.cellZones()[cellZoneis[i]].name();
1445  regionCellZones[i] = cellZoneis[i];
1446  }
1447 
1448  labelList cellCellZones, bFaceNbrCellZones;
1449  getCellCellZoneis
1450  (
1451  mesh,
1452  cellZoneis,
1453  cellCellZones,
1454  bFaceNbrCellZones
1455  );
1456 
1457  renumber(cellZoneRegions, cellCellZones, cellRegions);
1458 
1459  bool haveDefaultRegion = false;
1460  forAll(cellRegions, celli)
1461  {
1462  if (cellRegions[celli] == -1)
1463  {
1464  cellRegions[celli] = cellZoneis.size();
1465  haveDefaultRegion = true;
1466  }
1467  }
1468  reduce(haveDefaultRegion, orOp<bool>());
1469 
1470  if (haveDefaultRegion)
1471  {
1472  regionNames.append(defaultRegion);
1473  regionCellZones.append(-1);
1474  }
1475  }
1476 
1477  // Quit if there is only one region
1478  if (regionNames.size() == 1)
1479  {
1480  Info<< "Only one region identified. Doing nothing." << nl << endl;
1481  Info<< "End" << nl << endl;
1482  return 0;
1483  }
1484 
1485  // Calculate the number of cells in each region
1486  labelList regionNCells(regionNames.size(), 0);
1487  {
1488  forAll(cellRegions, celli)
1489  {
1490  regionNCells[cellRegions[celli]] ++;
1491  }
1492 
1493  forAll(regionNCells, regioni)
1494  {
1495  reduce(regionNCells[regioni], sumOp<label>());
1496  }
1497  }
1498 
1499  // Report identified regions
1500  {
1502  table[0] = {"Region", "nCells", "cellZone"};
1503  forAll(regionNCells, regioni)
1504  {
1505  table[regioni + 1][0] = regionNames[regioni];
1506  table[regioni + 1][1] = Foam::name(regionNCells[regioni]);
1507  table[regioni + 1][2] =
1508  regionCellZones[regioni] == -1
1509  ? "<none>"
1510  : mesh.cellZones()[regionCellZones[regioni]].name();
1511  }
1512  printTable(table);
1513  Info<< endl;
1514  }
1515 
1516  // Write decomposition to file
1517  writeCellToRegion(mesh, cellRegions);
1518 
1519  // Everything from here relates to writing the region meshes, so quit now
1520  // if we are not doing that
1521  if (args.optionFound("noMeshes"))
1522  {
1523  Info<< "End" << nl << endl;
1524  return 0;
1525  }
1526 
1527  // Make sure patches and zones are synchronised
1528  mesh.poly().boundary().checkParallelSync(true);
1530 
1531  // Create information regarding interfaces. Each interface is identified by
1532  // the indices of the two regions on either side. This is stored as an edge
1533  // so that an EdgeMap can then be used later (...). Also constructed are
1534  // the names of the interfaces, the global number of faces they contain,
1535  // and a map from each mesh face to the corresponding interface (or -1).
1536  edgeList interfaces;
1537  List<Pair<word>> interfaceNames;
1538  labelList interfaceNFaces;
1539  labelList faceInterfaces;
1540  getInterfaceSizes
1541  (
1542  mesh,
1543  faceZonePatches,
1544  cellRegions,
1545  regionNames,
1546  interfaces,
1547  interfaceNames,
1548  interfaceNFaces,
1549  faceInterfaces
1550  );
1551 
1552  // Report interfaces
1553  if (interfaces.size())
1554  {
1555  List<FixedList<string, 4>> table(interfaces.size() + 1);
1556  table[0] =
1557  {
1558  "Interface",
1559  "Owner Region",
1560  "Neighbour Region",
1561  "nFaces"
1562  };
1563  forAll(interfaces, interfacei)
1564  {
1565  const edge& e = interfaces[interfacei];
1566 
1567  table[interfacei + 1][0] = interfaceNames[interfacei][0];
1568  table[interfacei + 1][1] = regionNames[e[0]];
1569  table[interfacei + 1][2] = regionNames[e[1]];
1570  table[interfacei + 1][3] = Foam::name(interfaceNFaces[interfacei]);
1571  }
1572  printTable(table);
1573  Info<< endl;
1574  }
1575 
1576  // Read objects in time directory
1577  const bool fields = !args.optionFound("noFields");
1578  IOobjectList objects(mesh, runTime.name());
1579  if (fields) Info<< "Reading geometric fields" << endl << incrIndent;
1580  #include "readVolFields.H"
1581  #include "readSurfaceFields.H"
1582  // #include "readPointFields.H"
1583  if (fields) Info<< endl << decrIndent;
1584 
1585  // Remove any demand-driven fields (e.g., cell-centres)
1586  mesh.clearOut();
1587 
1588  // Add patches for interfaces. These get added to the current mesh, so that
1589  // they are then inherited by the region subsets. All combinations are
1590  // added, and the patches are initially empty. Patches will then be
1591  // populated within the region meshes, and empty patches will be filtered
1592  // out and removed afterwards.
1593  if (interfaces.size())
1594  {
1595  Info<< "Adding interface patches" << nl << endl;
1596  }
1597  else
1598  {
1599  Info<< "No interfaces to add" << nl << endl;
1600  }
1601  const labelList interfacePatches
1602  (
1603  addRegionPatches
1604  (
1605  mesh,
1606  regionNames,
1607  interfaces,
1608  interfaceNames
1609  )
1610  );
1611 
1612  if (!overwrite)
1613  {
1614  runTime++;
1615  }
1616 
1617  // Create regions
1618  if (largest)
1619  {
1620  const label regioni = findMax(regionNCells);
1621 
1622  Info<< "Subsetting largest region " << regioni << " containing "
1623  << regionNCells[regioni] << " cells" << nl << endl;
1624 
1625  if (overwrite)
1626  {
1628  }
1629  else if (regionCellZones[regioni] == -1)
1630  {
1631  regionNames[regioni] = "largest";
1632  }
1633 
1634  createAndWriteRegion
1635  (
1636  mesh,
1637  cellRegions,
1638  regionNames,
1639  faceInterfaces,
1640  interfacePatches,
1641  regioni,
1642  (overwrite ? oldInstance : runTime.name())
1643  );
1644  }
1645  else if (insidePoint)
1646  {
1647  const point insidePoint = args.optionRead<point>("insidePoint");
1648 
1649  const label celli = meshSearch::New(mesh).findCell(insidePoint);
1650 
1651  RemoteData<label> procCellRegion;
1652  if (celli != -1)
1653  {
1654  procCellRegion.proci = Pstream::myProcNo();
1655  procCellRegion.elementi = celli;
1656  procCellRegion.data = cellRegions[celli];
1657  }
1658 
1659  reduce(procCellRegion, RemoteData<label>::firstProcOp());
1660 
1661  if (procCellRegion.proci != -1)
1662  {
1663  Info<< "Found point " << insidePoint
1664  << " in cell " << procCellRegion.elementi;
1665  if (Pstream::parRun())
1666  {
1667  Info<< " of processor " << procCellRegion.proci;
1668  }
1669  Info<< nl << endl;
1670  }
1671  else
1672  {
1674  << "Did not find a cell containing the point " << insidePoint
1675  << ". The bounding box of the mesh is " << mesh.bounds()
1676  << "." << exit(FatalError);
1677  }
1678 
1679  const label regioni = procCellRegion.data;
1680 
1681  Info<< "Subsetting region " << regionNames[regioni]
1682  << " containing point " << insidePoint << nl << endl;
1683 
1684  if (overwrite)
1685  {
1687  }
1688  else if (regionCellZones[regioni] == -1)
1689  {
1690  regionNames[regioni] = "insidePoint";
1691  }
1692 
1693  createAndWriteRegion
1694  (
1695  mesh,
1696  cellRegions,
1697  regionNames,
1698  faceInterfaces,
1699  interfacePatches,
1700  regioni,
1701  (overwrite ? oldInstance : runTime.name())
1702  );
1703  }
1704  else
1705  {
1706  forAll(regionNames, regioni)
1707  {
1708  createAndWriteRegion
1709  (
1710  mesh,
1711  cellRegions,
1712  regionNames,
1713  faceInterfaces,
1714  interfacePatches,
1715  regioni,
1716  (overwrite ? oldInstance : runTime.name())
1717  );
1718  }
1719  }
1720 
1721  Info<< "End" << nl << endl;
1722 
1723  return 0;
1724 }
1725 
1726 
1727 // ************************************************************************* //
Istream and Ostream manipulators taking arguments.
Field reading functions for post-processing utilities.
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
#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
wordList toc() const
Return the table of contents.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
Map from edge (expressed as its endpoints) to value.
Definition: EdgeMap.H:50
A 1D vector of objects of type <T> with a fixed size <Size>.
Definition: FixedList.H:78
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
An STL-conforming hash table.
Definition: HashTable.H:127
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:167
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:138
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
const word & name() const
Return name.
Definition: IOobject.H:307
Input inter-processor communications stream.
Definition: IPstream.H:54
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void resize(const label)
Alias for setSize(const label)
Definition: ListI.H:138
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
Output inter-processor communications stream.
Definition: OPstream.H:54
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
label findIndex(const word &key) const
Return the index of the given the key or -1 if not found.
void append(T *)
Append an element at the end of the list.
Definition: PtrListI.H:39
Struct for keeping processor, element (cell, face, point) and a piece of data. Used for finding minim...
Definition: RemoteData.H:65
Type data
Data.
Definition: RemoteData.H:75
A List with indirect addressing.
Definition: UIndirectList.H:61
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
static int masterNo()
Process index of the master.
Definition: UPstream.H:417
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static int lastSlave(const label communicator=0)
Process index of last slave.
Definition: UPstream.H:452
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static int firstSlave()
Process index of first slave.
Definition: UPstream.H:446
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
labelList whichZones(const label objectIndex) const
Given a global object index, return the list of zones it is in.
Definition: ZoneList.C:159
bool checkParallelSync(const bool report=false) const
Check whether all procs have all zones and in same order. Return.
Definition: ZoneList.C:309
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:121
static void addNote(const string &)
Add extra notes for the usage information.
Definition: argList.C:152
T optionRead(const word &opt) const
Read a value from the named option.
Definition: argListI.H:244
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
List< T > optionReadList(const word &opt) const
Read a List of values from the named option.
T optionLookupOrDefault(const word &opt, const T &deflt) const
Read a value from the named option if present.
Definition: argListI.H:294
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
Named list of cell indices representing a sub-set of the mesh.
Definition: cellZone.H:61
const word & name() const
Return const reference to name.
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
A list of face labels.
Definition: faceSet.H:51
static tmp< VolField< Type > > interpolate(const VolField< Type > &, const fvMesh &sMesh, const labelList &patchMap, const labelList &cellMap, const labelList &faceMap)
Map volume field.
static void reorderPatches(fvMesh &, const labelList &oldToNew, const label nPatches, const bool validBoundary)
Reorder and remove trailing patches. If validBoundary call is.
Definition: fvMeshTools.C:104
static label addPatch(fvMesh &mesh, const polyPatch &patch)
Add patch. Inserts patch before all processor patches. Returns the.
Definition: fvMeshTools.C:33
static void addedPatches(fvMesh &mesh)
Complete adding patches.
Definition: fvMeshTools.C:73
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:98
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:433
const word & name() const
Return reference to name.
Definition: fvMesh.H:447
void clearOut()
Clear all geometry and addressing.
Definition: fvMesh.C:301
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
Wall poly patch which can do interpolative mapping of values from another globally conforming poly pa...
label findCell(const point &p, const pointInCellShapes=pointInCellShapes::tets) const
Find the cell containing the given point.
Definition: meshSearch.C:173
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Definition: meshSearch.C:61
Foam::polyBoundaryMesh.
bool checkParallelSync(const bool report=false) const
Check whether all procs have all patches and in same order. Return.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:1012
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:438
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:260
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1308
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1321
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:1006
const faceZoneList & faceZones() const
Return face zones.
Definition: polyMesh.H:432
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1327
const boundBox & bounds() const
Return mesh bounding box.
Definition: polyMesh.H:399
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
Direct mesh changes based on v1.3 polyTopoChange syntax.
const vectorField & faceCentres() const
label nInternalFaces() const
const vectorField & cellCentres() const
label nCells() const
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
label nFaces() const
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:118
label elementi
Element index.
Definition: remote.H:70
label proci
Processor index.
Definition: remote.H:67
Given list of cells to remove insert all the topology changes.
Definition: removeCells.H:60
A class for handling character strings derived from std::string.
Definition: string.H:79
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
A class for managing temporary objects.
Definition: tmp.H:55
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 FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
int main(int argc, char *argv[])
Definition: financialFoam.C:44
label patchi
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
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 HashTable< dimensionSet > table
Table of dimensions.
Definition: dimensions.C:74
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
const dimensionSet & dimless
Definition: dimensions.C:138
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
label findMax(const ListType &, const label start=0)
Find index of max element (and larger than given element).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
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
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
FOR_ALL_FIELD_TYPES(makeDimensionedPointFieldFunctions)
messageStream Info
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:265
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
void printTable(const List< wordList > &, List< string::size_type > &, Ostream &)
Definition: wordIOList.C:43
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:243
static const char nl
Definition: Ostream.H:297
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
objects
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)
static iteratorEnd end()
iteratorEnd set to beyond the end of any HashTable
Definition: HashTable.H:112
Operator to take the first valid process.
Definition: RemoteData.H:98