1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "FaceCellWave.H"
28 #include "processorPolyPatch.H"
29 #include "cyclicPolyPatch.H"
32 #include "PstreamReduceOps.H"
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 Foam::debug::tolerancesSwitch Foam::FaceCellWave<Type>::geomTol_
41 "FaceCellWaveGeomTol",
46 Foam::debug::tolerancesSwitch Foam::FaceCellWave<Type>::propagationTol_
48 "FaceCellWavePropagationTol",
54 Foam::Ostream& Foam::FaceCellWave<Type>::writeFaces
57 const labelList& faceLabels,
58 const List<Type>& faceInfo,
62 // Write list contents depending on data format
63 if (os.format() == IOstream::ASCII)
67 for(label i = 0; i < nFaces; i++)
69 os << ' ' << faceLabels[i];
71 for(label i = 0; i < nFaces; i++)
73 os << ' ' << faceInfo[i];
80 for(label i = 0; i < nFaces; i++)
84 for(label i = 0; i < nFaces; i++)
95 Foam::Istream& Foam::FaceCellWave<Type>::readFaces
98 labelList& faceLabels,
105 for(label i = 0; i < nFaces; i++)
109 for(label i = 0; i < nFaces; i++)
117 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
119 // Update info for cellI, at position pt, with information from
120 // neighbouring face/cell.
122 // - changedCell_, changedCells_, nChangedCells_,
123 // - statistics: nEvals_, nUnvisitedCells_
124 template <class Type>
125 bool Foam::FaceCellWave<Type>::updateCell
128 const label neighbourFaceI,
129 const Type& neighbourInfo,
136 bool wasValid = cellInfo.valid();
150 if (!changedCell_[cellI])
152 changedCell_[cellI] = true;
153 changedCells_[nChangedCells_++] = cellI;
157 if (!wasValid && cellInfo.valid())
166 // Update info for faceI, at position pt, with information from
167 // neighbouring face/cell.
169 // - changedFace_, changedFaces_, nChangedFaces_,
170 // - statistics: nEvals_, nUnvisitedFaces_
171 template <class Type>
172 bool Foam::FaceCellWave<Type>::updateFace
175 const label neighbourCellI,
176 const Type& neighbourInfo,
183 bool wasValid = faceInfo.valid();
197 if (!changedFace_[faceI])
199 changedFace_[faceI] = true;
200 changedFaces_[nChangedFaces_++] = faceI;
204 if (!wasValid && faceInfo.valid())
213 // Update info for faceI, at position pt, with information from
216 // - changedFace_, changedFaces_, nChangedFaces_,
217 // - statistics: nEvals_, nUnvisitedFaces_
218 template <class Type>
219 bool Foam::FaceCellWave<Type>::updateFace
222 const Type& neighbourInfo,
229 bool wasValid = faceInfo.valid();
242 if (!changedFace_[faceI])
244 changedFace_[faceI] = true;
245 changedFaces_[nChangedFaces_++] = faceI;
249 if (!wasValid && faceInfo.valid())
258 // For debugging: check status on both sides of cyclic
259 template <class Type>
260 void Foam::FaceCellWave<Type>::checkCyclic(const polyPatch& patch) const
262 label cycOffset = patch.size()/2;
264 for(label patchFaceI = 0; patchFaceI < cycOffset; patchFaceI++)
266 label i1 = patch.start() + patchFaceI;
267 label i2 = i1 + cycOffset;
269 if (!allFaceInfo_[i1].sameGeometry(mesh_, allFaceInfo_[i2], geomTol_()))
271 FatalErrorIn("FaceCellWave<Type>::checkCyclic(const polyPatch&)")
272 << "problem: i:" << i1 << " otheri:" << i2
273 << " faceInfo:" << allFaceInfo_[i1]
274 << " otherfaceInfo:" << allFaceInfo_[i2]
275 << abort(FatalError);
278 if (changedFace_[i1] != changedFace_[i2])
280 FatalErrorIn("FaceCellWave<Type>::checkCyclic(const polyPatch&)")
281 << " problem: i:" << i1 << " otheri:" << i2
282 << " faceInfo:" << allFaceInfo_[i1]
283 << " otherfaceInfo:" << allFaceInfo_[i2]
284 << " changedFace:" << changedFace_[i1]
285 << " otherchangedFace:" << changedFace_[i2]
286 << abort(FatalError);
292 // Check if patches of given type name are present
293 template <class Type>
294 bool Foam::FaceCellWave<Type>::hasPatchType(const word& nameOfType)
296 forAll(mesh_.boundaryMesh(), patchI)
298 if (mesh_.boundaryMesh()[patchI].type() == nameOfType)
307 // Copy face information into member data
308 template <class Type>
309 void Foam::FaceCellWave<Type>::setFaceInfo
311 const labelList& changedFaces,
312 const List<Type>& changedFacesInfo
315 forAll(changedFaces, changedFaceI)
317 label faceI = changedFaces[changedFaceI];
319 bool wasValid = allFaceInfo_[faceI].valid();
321 // Copy info for faceI
322 allFaceInfo_[faceI] = changedFacesInfo[changedFaceI];
324 // Maintain count of unset faces
325 if (!wasValid && allFaceInfo_[faceI].valid())
330 // Mark faceI as changed, both on list and on face itself.
332 changedFace_[faceI] = true;
333 changedFaces_[nChangedFaces_++] = faceI;
338 // Merge face information into member data
339 template <class Type>
340 void Foam::FaceCellWave<Type>::mergeFaceInfo
342 const polyPatch& patch,
344 const labelList& changedFaces,
345 const List<Type>& changedFacesInfo,
349 for(label changedFaceI = 0; changedFaceI < nFaces; changedFaceI++)
351 const Type& neighbourWallInfo = changedFacesInfo[changedFaceI];
352 label patchFaceI = changedFaces[changedFaceI];
354 label meshFaceI = patch.start() + patchFaceI;
356 Type& currentWallInfo = allFaceInfo_[meshFaceI];
358 if (currentWallInfo != neighbourWallInfo)
372 // Construct compact patchFace change arrays for a (slice of a) single patch.
373 // changedPatchFaces in local patch numbering.
374 // Return length of arrays.
375 template <class Type>
376 Foam::label Foam::FaceCellWave<Type>::getChangedPatchFaces
378 const polyPatch& patch,
379 const label startFaceI,
381 labelList& changedPatchFaces,
382 List<Type>& changedPatchFacesInfo
385 label nChangedPatchFaces = 0;
387 for(label i = 0; i < nFaces; i++)
389 label patchFaceI = i + startFaceI;
391 label meshFaceI = patch.start() + patchFaceI;
393 if (changedFace_[meshFaceI])
395 changedPatchFaces[nChangedPatchFaces] = patchFaceI;
396 changedPatchFacesInfo[nChangedPatchFaces] =
397 allFaceInfo_[meshFaceI];
398 nChangedPatchFaces++;
401 return nChangedPatchFaces;
405 // Handle leaving domain. Implementation referred to Type
406 template <class Type>
407 void Foam::FaceCellWave<Type>::leaveDomain
409 const polyPatch& patch,
411 const labelList& faceLabels,
415 const vectorField& fc = mesh_.faceCentres();
417 for(label i = 0; i < nFaces; i++)
419 label patchFaceI = faceLabels[i];
421 label meshFaceI = patch.start() + patchFaceI;
422 faceInfo[i].leaveDomain(mesh_, patch, patchFaceI, fc[meshFaceI]);
427 // Handle entering domain. Implementation referred to Type
428 template <class Type>
429 void Foam::FaceCellWave<Type>::enterDomain
431 const polyPatch& patch,
433 const labelList& faceLabels,
437 const vectorField& fc = mesh_.faceCentres();
439 for(label i = 0; i < nFaces; i++)
441 label patchFaceI = faceLabels[i];
443 label meshFaceI = patch.start() + patchFaceI;
444 faceInfo[i].enterDomain(mesh_, patch, patchFaceI, fc[meshFaceI]);
449 // Transform. Implementation referred to Type
450 template <class Type>
451 void Foam::FaceCellWave<Type>::transform
453 const tensorField& rotTensor,
458 if (rotTensor.size() == 1)
460 const tensor& T = rotTensor[0];
462 for(label faceI = 0; faceI < nFaces; faceI++)
464 faceInfo[faceI].transform(mesh_, T);
469 for(label faceI = 0; faceI < nFaces; faceI++)
471 faceInfo[faceI].transform(mesh_, rotTensor[faceI]);
477 // Send face info to neighbour.
478 template <class Type>
479 void Foam::FaceCellWave<Type>::sendPatchInfo
481 const label neighbour,
483 const labelList& faceLabels,
484 const List<Type>& faceInfo
487 OPstream toNeighbour(Pstream::blocking, neighbour);
489 writeFaces(nFaces, faceLabels, faceInfo, toNeighbour);
493 // Receive face info from neighbour
494 template <class Type>
495 Foam::label Foam::FaceCellWave<Type>::receivePatchInfo
497 const label neighbour,
498 labelList& faceLabels,
502 IPstream fromNeighbour(Pstream::blocking, neighbour);
505 readFaces(nFaces, faceLabels, faceInfo, fromNeighbour);
511 // Offset mesh face. Used for transferring from one cyclic half to the other.
512 template <class Type>
513 void Foam::FaceCellWave<Type>::offset
516 const label cycOffset,
521 for(label faceI = 0; faceI < nFaces; faceI++)
523 faces[faceI] += cycOffset;
528 // Tranfer all the information to/from neighbouring processors
529 template <class Type>
530 void Foam::FaceCellWave<Type>::handleProcPatches()
534 forAll(mesh_.boundaryMesh(), patchI)
536 const polyPatch& patch = mesh_.boundaryMesh()[patchI];
538 if (isA<processorPolyPatch>(patch))
542 labelList sendFaces(patch.size());
543 List<Type> sendFacesInfo(patch.size());
545 // Determine which faces changed on current patch
546 nSendFaces = getChangedPatchFaces
555 // Adapt wallInfo for leaving domain
564 const processorPolyPatch& procPatch =
565 refCast<const processorPolyPatch>(patch);
569 Pout<< " Processor patch " << patchI << ' ' << patch.name()
570 << " communicating with " << procPatch.neighbProcNo()
571 << " Sending:" << nSendFaces
577 procPatch.neighbProcNo(),
587 forAll(mesh_.boundaryMesh(), patchI)
589 const polyPatch& patch = mesh_.boundaryMesh()[patchI];
591 if (isA<processorPolyPatch>(patch))
593 const processorPolyPatch& procPatch =
594 refCast<const processorPolyPatch>(patch);
598 labelList receiveFaces(patch.size());
599 List<Type> receiveFacesInfo(patch.size());
601 nReceiveFaces = receivePatchInfo
603 procPatch.neighbProcNo(),
610 Pout<< " Processor patch " << patchI << ' ' << patch.name()
611 << " communicating with " << procPatch.neighbProcNo()
612 << " Receiving:" << nReceiveFaces
616 // Apply transform to received data for non-parallel planes
617 if (!procPatch.parallel())
621 procPatch.forwardT(),
627 // Adapt wallInfo for entering domain
636 // Merge received info
650 // Transfer information across cyclic halves.
651 // Note: Cyclic is two patches in one: one side from 0..size/2 and other
652 // side from size/2 .. size.
653 template <class Type>
654 void Foam::FaceCellWave<Type>::handleCyclicPatches()
656 forAll(mesh_.boundaryMesh(), patchI)
658 const polyPatch& patch = mesh_.boundaryMesh()[patchI];
660 if (isA<cyclicPolyPatch>(patch))
662 label halfSize = patch.size()/2;
666 labelList sendFaces(halfSize);
667 List<Type> sendFacesInfo(halfSize);
670 labelList receiveFaces(halfSize);
671 List<Type> receiveFacesInfo(halfSize);
673 // Half1: Determine which faces changed. Use sendFaces for storage
674 nSendFaces = getChangedPatchFaces
683 // Half2: Determine which faces changed. Use receiveFaces_ ,,
684 nReceiveFaces = getChangedPatchFaces
693 //Info<< "Half1:" << endl;
694 //writeFaces(nSendFaces, sendFaces, sendFacesInfo, Info);
697 //Info<< "Half2:" << endl;
698 //writeFaces(nReceiveFaces, receiveFaces, receiveFacesInfo, Info);
702 // Half1: Adapt wallInfo for leaving domain
710 // Half2: Adapt wallInfo for leaving domain
719 // Half1: 'transfer' to other side by offsetting patchFaceI
720 offset(patch, halfSize, nSendFaces, sendFaces);
722 // Half2: 'transfer' to other side
723 offset(patch, -halfSize, nReceiveFaces, receiveFaces);
725 // Apply rotation for non-parallel planes
726 const cyclicPolyPatch& cycPatch =
727 refCast<const cyclicPolyPatch>(patch);
729 if (!cycPatch.parallel())
731 // sendFaces = received data from half1
739 // receiveFaces = received data from half2
750 Pout<< " Cyclic patch " << patchI << ' ' << patch.name()
751 << " Changed on first half : " << nSendFaces
752 << " Changed on second half : " << nReceiveFaces
756 // Half1: Adapt wallInfo for entering domain
765 // Half2: Adapt wallInfo for entering domain
774 // Merge into global storage
783 // Merge into global storage
802 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
804 // Set up only. Use setFaceInfo and iterate() to do actual calculation.
805 template <class Type>
806 Foam::FaceCellWave<Type>::FaceCellWave
808 const polyMesh& mesh,
809 UList<Type>& allFaceInfo,
810 UList<Type>& allCellInfo
814 allFaceInfo_(allFaceInfo),
815 allCellInfo_(allCellInfo),
816 changedFace_(mesh_.nFaces(), false),
817 changedFaces_(mesh_.nFaces()),
819 changedCell_(mesh_.nCells(), false),
820 changedCells_(mesh_.nCells()),
822 hasCyclicPatches_(hasPatchType(cyclicPolyPatch::typeName)),
824 nUnvisitedCells_(mesh_.nCells()),
825 nUnvisitedFaces_(mesh_.nFaces()),
830 // Iterate, propagating changedFacesInfo across mesh, until no change (or
831 // maxIter reached). Initial cell values specified.
832 template <class Type>
833 Foam::FaceCellWave<Type>::FaceCellWave
835 const polyMesh& mesh,
836 const labelList& changedFaces,
837 const List<Type>& changedFacesInfo,
838 UList<Type>& allFaceInfo,
839 UList<Type>& allCellInfo,
844 allFaceInfo_(allFaceInfo),
845 allCellInfo_(allCellInfo),
846 changedFace_(mesh_.nFaces(), false),
847 changedFaces_(mesh_.nFaces()),
849 changedCell_(mesh_.nCells(), false),
850 changedCells_(mesh_.nCells()),
852 hasCyclicPatches_(hasPatchType(cyclicPolyPatch::typeName)),
854 nUnvisitedCells_(mesh_.nCells()),
855 nUnvisitedFaces_(mesh_.nFaces()),
858 // Copy initial changed faces data
859 setFaceInfo(changedFaces, changedFacesInfo);
861 // Iterate until nothing changes
864 if ((maxIter > 0) && (iter_ >= maxIter))
868 "FaceCellWave<Type>::FaceCellWave"
869 "(const polyMesh&, const labelList&, const List<Type>,"
870 " UList<Type>&, UList<Type>&, const label maxIter)"
872 << "Maximum number of iterations reached. Increase maxIter." << nl
873 << " maxIter:" << maxIter << endl
874 << " nChangedCells:" << nChangedCells_ << endl
875 << " nChangedFaces:" << nChangedFaces_ << endl
881 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
884 template <class Type>
885 Foam::label Foam::FaceCellWave<Type>::getUnsetCells() const
887 return nUnvisitedCells_;
891 template <class Type>
892 Foam::label Foam::FaceCellWave<Type>::getUnsetFaces() const
894 return nUnvisitedFaces_;
899 // Propagate cell to face
900 template <class Type>
901 Foam::label Foam::FaceCellWave<Type>::faceToCell()
903 const labelList& owner = mesh_.faceOwner();
904 const labelList& neighbour = mesh_.faceNeighbour();
905 label nInternalFaces = mesh_.nInternalFaces();
909 label changedFaceI = 0;
910 changedFaceI < nChangedFaces_;
914 label faceI = changedFaces_[changedFaceI];
915 if (!changedFace_[faceI])
917 FatalErrorIn("FaceCellWave<Type>::faceToCell()")
919 << " not marked as having been changed"
920 << abort(FatalError);
924 const Type& neighbourWallInfo = allFaceInfo_[faceI];
926 // Evaluate all connected cells
929 label cellI = owner[faceI];
930 Type& currentWallInfo = allCellInfo_[cellI];
932 if (currentWallInfo != neighbourWallInfo)
944 // Neighbour. Hack for check if face has neighbour.
945 if (faceI < nInternalFaces)
947 cellI = neighbour[faceI];
948 Type& currentWallInfo2 = allCellInfo_[cellI];
950 if (currentWallInfo2 != neighbourWallInfo)
963 // Reset status of face
964 changedFace_[faceI] = false;
967 // Handled all changed faces by now
972 Pout<< " Changed cells : " << nChangedCells_ << endl;
975 // Sum nChangedCells over all procs
976 label totNChanged = nChangedCells_;
978 reduce(totNChanged, sumOp<label>());
984 // Propagate cell to face
985 template <class Type>
986 Foam::label Foam::FaceCellWave<Type>::cellToFace()
988 const cellList& cells = mesh_.cells();
992 label changedCellI = 0;
993 changedCellI < nChangedCells_;
997 label cellI = changedCells_[changedCellI];
998 if (!changedCell_[cellI])
1000 FatalErrorIn("FaceCellWave<Type>::cellToFace()")
1002 << " not marked as having been changed"
1003 << abort(FatalError);
1006 const Type& neighbourWallInfo = allCellInfo_[cellI];
1008 // Evaluate all connected faces
1010 const labelList& faceLabels = cells[cellI];
1011 forAll(faceLabels, faceLabelI)
1013 label faceI = faceLabels[faceLabelI];
1014 Type& currentWallInfo = allFaceInfo_[faceI];
1016 if (currentWallInfo != neighbourWallInfo)
1029 // Reset status of cell
1030 changedCell_[cellI] = false;
1033 // Handled all changed cells by now
1036 if (hasCyclicPatches_)
1038 // Transfer changed faces across cyclic halves
1039 handleCyclicPatches();
1041 if (Pstream::parRun())
1043 // Transfer changed faces from neighbouring processors.
1044 handleProcPatches();
1049 Pout<< " Changed faces : " << nChangedFaces_ << endl;
1052 // Sum nChangedFaces over all procs
1053 label totNChanged = nChangedFaces_;
1055 reduce(totNChanged, sumOp<label>());
1062 template <class Type>
1063 Foam::label Foam::FaceCellWave<Type>::iterate(const label maxIter)
1065 if (hasCyclicPatches_)
1067 // Transfer changed faces across cyclic halves
1068 handleCyclicPatches();
1070 if (Pstream::parRun())
1072 // Transfer changed faces from neighbouring processors.
1073 handleProcPatches();
1076 while(iter_ < maxIter)
1080 Pout<< " Iteration " << iter_ << endl;
1085 label nCells = faceToCell();
1089 Pout<< " Total changed cells : " << nCells << endl;
1097 label nFaces = cellToFace();
1101 Pout<< " Total changed faces : " << nFaces << nl
1102 << " Total evaluations : " << nEvals_ << nl
1103 << " Remaining unvisited cells: " << nUnvisitedCells_ << nl
1104 << " Remaining unvisited faces: " << nUnvisitedFaces_ << endl;
1115 return nUnvisitedCells_;
1118 // ************************************************************************* //