1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "FaceCellWave.H"
28 #include <OpenFOAM/polyMesh.H>
29 #include <OpenFOAM/processorPolyPatch.H>
30 #include <OpenFOAM/cyclicPolyPatch.H>
31 #include <OpenFOAM/OPstream.H>
32 #include <OpenFOAM/IPstream.H>
33 #include <OpenFOAM/PstreamReduceOps.H>
34 #include <OpenFOAM/debug.H>
35 #include <OpenFOAM/typeInfo.H>
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 const Foam::scalar Foam::FaceCellWave<Type>::geomTol_ = 1e-6;
43 const Foam::scalar Foam::FaceCellWave<Type>::propagationTol_ = 0.01;
47 Foam::Ostream& Foam::FaceCellWave<Type>::writeFaces
50 const labelList& faceLabels,
51 const List<Type>& faceInfo,
55 // Write list contents depending on data format
56 if (os.format() == IOstream::ASCII)
60 for(label i = 0; i < nFaces; i++)
62 os << ' ' << faceLabels[i];
64 for(label i = 0; i < nFaces; i++)
66 os << ' ' << faceInfo[i];
73 for(label i = 0; i < nFaces; i++)
77 for(label i = 0; i < nFaces; i++)
88 Foam::Istream& Foam::FaceCellWave<Type>::readFaces
91 labelList& faceLabels,
98 for(label i = 0; i < nFaces; i++)
102 for(label i = 0; i < nFaces; i++)
110 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
112 // Update info for cellI, at position pt, with information from
113 // neighbouring face/cell.
115 // - changedCell_, changedCells_, nChangedCells_,
116 // - statistics: nEvals_, nUnvisitedCells_
117 template <class Type>
118 bool Foam::FaceCellWave<Type>::updateCell
121 const label neighbourFaceI,
122 const Type& neighbourInfo,
129 bool wasValid = cellInfo.valid();
143 if (!changedCell_[cellI])
145 changedCell_[cellI] = true;
146 changedCells_[nChangedCells_++] = cellI;
150 if (!wasValid && cellInfo.valid())
159 // Update info for faceI, at position pt, with information from
160 // neighbouring face/cell.
162 // - changedFace_, changedFaces_, nChangedFaces_,
163 // - statistics: nEvals_, nUnvisitedFaces_
164 template <class Type>
165 bool Foam::FaceCellWave<Type>::updateFace
168 const label neighbourCellI,
169 const Type& neighbourInfo,
176 bool wasValid = faceInfo.valid();
190 if (!changedFace_[faceI])
192 changedFace_[faceI] = true;
193 changedFaces_[nChangedFaces_++] = faceI;
197 if (!wasValid && faceInfo.valid())
206 // Update info for faceI, at position pt, with information from
209 // - changedFace_, changedFaces_, nChangedFaces_,
210 // - statistics: nEvals_, nUnvisitedFaces_
211 template <class Type>
212 bool Foam::FaceCellWave<Type>::updateFace
215 const Type& neighbourInfo,
222 bool wasValid = faceInfo.valid();
235 if (!changedFace_[faceI])
237 changedFace_[faceI] = true;
238 changedFaces_[nChangedFaces_++] = faceI;
242 if (!wasValid && faceInfo.valid())
251 // For debugging: check status on both sides of cyclic
252 template <class Type>
253 void Foam::FaceCellWave<Type>::checkCyclic(const polyPatch& patch) const
255 label cycOffset = patch.size()/2;
257 for(label patchFaceI = 0; patchFaceI < cycOffset; patchFaceI++)
259 label i1 = patch.start() + patchFaceI;
260 label i2 = i1 + cycOffset;
262 if (!allFaceInfo_[i1].sameGeometry(mesh_, allFaceInfo_[i2], geomTol_))
264 FatalErrorIn("FaceCellWave<Type>::checkCyclic(const polyPatch&)")
265 << "problem: i:" << i1 << " otheri:" << i2
266 << " faceInfo:" << allFaceInfo_[i1]
267 << " otherfaceInfo:" << allFaceInfo_[i2]
268 << abort(FatalError);
271 if (changedFace_[i1] != changedFace_[i2])
273 FatalErrorIn("FaceCellWave<Type>::checkCyclic(const polyPatch&)")
274 << " problem: i:" << i1 << " otheri:" << i2
275 << " faceInfo:" << allFaceInfo_[i1]
276 << " otherfaceInfo:" << allFaceInfo_[i2]
277 << " changedFace:" << changedFace_[i1]
278 << " otherchangedFace:" << changedFace_[i2]
279 << abort(FatalError);
285 // Check if patches of given type name are present
286 template <class Type>
287 bool Foam::FaceCellWave<Type>::hasPatchType(const word& nameOfType)
289 forAll(mesh_.boundaryMesh(), patchI)
291 if (mesh_.boundaryMesh()[patchI].type() == nameOfType)
300 // Copy face information into member data
301 template <class Type>
302 void Foam::FaceCellWave<Type>::setFaceInfo
304 const labelList& changedFaces,
305 const List<Type>& changedFacesInfo
308 forAll(changedFaces, changedFaceI)
310 label faceI = changedFaces[changedFaceI];
312 bool wasValid = allFaceInfo_[faceI].valid();
314 // Copy info for faceI
315 allFaceInfo_[faceI] = changedFacesInfo[changedFaceI];
317 // Maintain count of unset faces
318 if (!wasValid && allFaceInfo_[faceI].valid())
323 // Mark faceI as changed, both on list and on face itself.
325 changedFace_[faceI] = true;
326 changedFaces_[nChangedFaces_++] = faceI;
331 // Merge face information into member data
332 template <class Type>
333 void Foam::FaceCellWave<Type>::mergeFaceInfo
335 const polyPatch& patch,
337 const labelList& changedFaces,
338 const List<Type>& changedFacesInfo,
342 for(label changedFaceI = 0; changedFaceI < nFaces; changedFaceI++)
344 const Type& neighbourWallInfo = changedFacesInfo[changedFaceI];
345 label patchFaceI = changedFaces[changedFaceI];
347 label meshFaceI = patch.start() + patchFaceI;
349 Type& currentWallInfo = allFaceInfo_[meshFaceI];
351 if (currentWallInfo != neighbourWallInfo)
365 // Construct compact patchFace change arrays for a (slice of a) single patch.
366 // changedPatchFaces in local patch numbering.
367 // Return length of arrays.
368 template <class Type>
369 Foam::label Foam::FaceCellWave<Type>::getChangedPatchFaces
371 const polyPatch& patch,
372 const label startFaceI,
374 labelList& changedPatchFaces,
375 List<Type>& changedPatchFacesInfo
378 label nChangedPatchFaces = 0;
380 for(label i = 0; i < nFaces; i++)
382 label patchFaceI = i + startFaceI;
384 label meshFaceI = patch.start() + patchFaceI;
386 if (changedFace_[meshFaceI])
388 changedPatchFaces[nChangedPatchFaces] = patchFaceI;
389 changedPatchFacesInfo[nChangedPatchFaces] = allFaceInfo_[meshFaceI];
390 nChangedPatchFaces++;
393 return nChangedPatchFaces;
397 // Handle leaving domain. Implementation referred to Type
398 template <class Type>
399 void Foam::FaceCellWave<Type>::leaveDomain
401 const polyPatch& patch,
403 const labelList& faceLabels,
407 const vectorField& fc = mesh_.faceCentres();
409 for(label i = 0; i < nFaces; i++)
411 label patchFaceI = faceLabels[i];
413 label meshFaceI = patch.start() + patchFaceI;
414 faceInfo[i].leaveDomain(mesh_, patch, patchFaceI, fc[meshFaceI]);
419 // Handle entering domain. Implementation referred to Type
420 template <class Type>
421 void Foam::FaceCellWave<Type>::enterDomain
423 const polyPatch& patch,
425 const labelList& faceLabels,
429 const vectorField& fc = mesh_.faceCentres();
431 for(label i = 0; i < nFaces; i++)
433 label patchFaceI = faceLabels[i];
435 label meshFaceI = patch.start() + patchFaceI;
436 faceInfo[i].enterDomain(mesh_, patch, patchFaceI, fc[meshFaceI]);
441 // Transform. Implementation referred to Type
442 template <class Type>
443 void Foam::FaceCellWave<Type>::transform
445 const tensorField& rotTensor,
450 if (rotTensor.size() == 1)
452 const tensor& T = rotTensor[0];
454 for(label faceI = 0; faceI < nFaces; faceI++)
456 faceInfo[faceI].transform(mesh_, T);
461 for(label faceI = 0; faceI < nFaces; faceI++)
463 faceInfo[faceI].transform(mesh_, rotTensor[faceI]);
469 // Send face info to neighbour.
470 template <class Type>
471 void Foam::FaceCellWave<Type>::sendPatchInfo
473 const label neighbour,
475 const labelList& faceLabels,
476 const List<Type>& faceInfo
479 OPstream toNeighbour(Pstream::blocking, neighbour);
481 writeFaces(nFaces, faceLabels, faceInfo, toNeighbour);
485 // Receive face info from neighbour
486 template <class Type>
487 Foam::label Foam::FaceCellWave<Type>::receivePatchInfo
489 const label neighbour,
490 labelList& faceLabels,
494 IPstream fromNeighbour(Pstream::blocking, neighbour);
497 readFaces(nFaces, faceLabels, faceInfo, fromNeighbour);
503 // Offset mesh face. Used for transferring from one cyclic half to the other.
504 template <class Type>
505 void Foam::FaceCellWave<Type>::offset
508 const label cycOffset,
513 for(label faceI = 0; faceI < nFaces; faceI++)
515 faces[faceI] += cycOffset;
520 // Tranfer all the information to/from neighbouring processors
521 template <class Type>
522 void Foam::FaceCellWave<Type>::handleProcPatches()
526 forAll(mesh_.boundaryMesh(), patchI)
528 const polyPatch& patch = mesh_.boundaryMesh()[patchI];
530 if (isA<processorPolyPatch>(patch))
534 labelList sendFaces(patch.size());
535 List<Type> sendFacesInfo(patch.size());
537 // Determine which faces changed on current patch
538 nSendFaces = getChangedPatchFaces
547 // Adapt wallInfo for leaving domain
556 const processorPolyPatch& procPatch =
557 refCast<const processorPolyPatch>(patch);
561 Pout<< " Processor patch " << patchI << ' ' << patch.name()
562 << " communicating with " << procPatch.neighbProcNo()
563 << " Sending:" << nSendFaces
569 procPatch.neighbProcNo(),
579 forAll(mesh_.boundaryMesh(), patchI)
581 const polyPatch& patch = mesh_.boundaryMesh()[patchI];
583 if (isA<processorPolyPatch>(patch))
585 const processorPolyPatch& procPatch =
586 refCast<const processorPolyPatch>(patch);
590 labelList receiveFaces(patch.size());
591 List<Type> receiveFacesInfo(patch.size());
593 nReceiveFaces = receivePatchInfo
595 procPatch.neighbProcNo(),
602 Pout<< " Processor patch " << patchI << ' ' << patch.name()
603 << " communicating with " << procPatch.neighbProcNo()
604 << " Receiving:" << nReceiveFaces
608 // Apply transform to received data for non-parallel planes
609 if (!procPatch.parallel())
613 procPatch.reverseT(),
619 // Adapt wallInfo for entering domain
628 // Merge received info
642 // Transfer information across cyclic halves.
643 // Note: Cyclic is two patches in one: one side from 0..size/2 and other
644 // side from size/2 .. size.
645 template <class Type>
646 void Foam::FaceCellWave<Type>::handleCyclicPatches()
648 forAll(mesh_.boundaryMesh(), patchI)
650 const polyPatch& patch = mesh_.boundaryMesh()[patchI];
652 if (isA<cyclicPolyPatch>(patch))
654 label halfSize = patch.size()/2;
658 labelList sendFaces(halfSize);
659 List<Type> sendFacesInfo(halfSize);
662 labelList receiveFaces(halfSize);
663 List<Type> receiveFacesInfo(halfSize);
665 // Half1: Determine which faces changed. Use sendFaces for storage
666 nSendFaces = getChangedPatchFaces
675 // Half2: Determine which faces changed. Use receiveFaces_ ,,
676 nReceiveFaces = getChangedPatchFaces
685 //Info<< "Half1:" << endl;
686 //writeFaces(nSendFaces, sendFaces, sendFacesInfo, Info);
689 //Info<< "Half2:" << endl;
690 //writeFaces(nReceiveFaces, receiveFaces, receiveFacesInfo, Info);
694 // Half1: Adapt wallInfo for leaving domain
702 // Half2: Adapt wallInfo for leaving domain
711 // Half1: 'transfer' to other side by offsetting patchFaceI
712 offset(patch, halfSize, nSendFaces, sendFaces);
714 // Half2: 'transfer' to other side
715 offset(patch, -halfSize, nReceiveFaces, receiveFaces);
717 // Apply rotation for non-parallel planes
718 const cyclicPolyPatch& cycPatch =
719 refCast<const cyclicPolyPatch>(patch);
721 if (!cycPatch.parallel())
723 // sendFaces = received data from half1
731 // receiveFaces = received data from half2
742 Pout<< " Cyclic patch " << patchI << ' ' << patch.name()
743 << " Changed on first half : " << nSendFaces
744 << " Changed on second half : " << nReceiveFaces
748 // Half1: Adapt wallInfo for entering domain
757 // Half2: Adapt wallInfo for entering domain
766 // Merge into global storage
775 // Merge into global storage
794 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
796 // Set up only. Use setFaceInfo and iterate() to do actual calculation.
797 template <class Type>
798 Foam::FaceCellWave<Type>::FaceCellWave
800 const polyMesh& mesh,
801 UList<Type>& allFaceInfo,
802 UList<Type>& allCellInfo
806 allFaceInfo_(allFaceInfo),
807 allCellInfo_(allCellInfo),
808 changedFace_(mesh_.nFaces(), false),
809 changedFaces_(mesh_.nFaces()),
811 changedCell_(mesh_.nCells(), false),
812 changedCells_(mesh_.nCells()),
814 hasCyclicPatches_(hasPatchType(cyclicPolyPatch::typeName)),
816 nUnvisitedCells_(mesh_.nCells()),
817 nUnvisitedFaces_(mesh_.nFaces()),
822 // Iterate, propagating changedFacesInfo across mesh, until no change (or
823 // maxIter reached). Initial cell values specified.
824 template <class Type>
825 Foam::FaceCellWave<Type>::FaceCellWave
827 const polyMesh& mesh,
828 const labelList& changedFaces,
829 const List<Type>& changedFacesInfo,
830 UList<Type>& allFaceInfo,
831 UList<Type>& allCellInfo,
836 allFaceInfo_(allFaceInfo),
837 allCellInfo_(allCellInfo),
838 changedFace_(mesh_.nFaces(), false),
839 changedFaces_(mesh_.nFaces()),
841 changedCell_(mesh_.nCells(), false),
842 changedCells_(mesh_.nCells()),
844 hasCyclicPatches_(hasPatchType(cyclicPolyPatch::typeName)),
846 nUnvisitedCells_(mesh_.nCells()),
847 nUnvisitedFaces_(mesh_.nFaces()),
850 // Copy initial changed faces data
851 setFaceInfo(changedFaces, changedFacesInfo);
853 // Iterate until nothing changes
856 if ((maxIter > 0) && (iter_ >= maxIter))
860 "FaceCellWave<Type>::FaceCellWave"
861 "(const polyMesh&, const labelList&, const List<Type>,"
862 " UList<Type>&, UList<Type>&, const label maxIter)"
864 << "Maximum number of iterations reached. Increase maxIter." << endl
865 << " maxIter:" << maxIter << endl
866 << " nChangedCells:" << nChangedCells_ << endl
867 << " nChangedFaces:" << nChangedFaces_ << endl
873 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
876 template <class Type>
877 Foam::label Foam::FaceCellWave<Type>::getUnsetCells() const
879 return nUnvisitedCells_;
883 template <class Type>
884 Foam::label Foam::FaceCellWave<Type>::getUnsetFaces() const
886 return nUnvisitedFaces_;
891 // Propagate cell to face
892 template <class Type>
893 Foam::label Foam::FaceCellWave<Type>::faceToCell()
895 const labelList& owner = mesh_.faceOwner();
896 const labelList& neighbour = mesh_.faceNeighbour();
897 label nInternalFaces = mesh_.nInternalFaces();
901 label changedFaceI = 0;
902 changedFaceI < nChangedFaces_;
906 label faceI = changedFaces_[changedFaceI];
907 if (!changedFace_[faceI])
909 FatalErrorIn("FaceCellWave<Type>::faceToCell()")
911 << " not marked as having been changed"
912 << abort(FatalError);
916 const Type& neighbourWallInfo = allFaceInfo_[faceI];
918 // Evaluate all connected cells
921 label cellI = owner[faceI];
922 Type& currentWallInfo = allCellInfo_[cellI];
924 if (currentWallInfo != neighbourWallInfo)
936 // Neighbour. Hack for check if face has neighbour.
937 if (faceI < nInternalFaces)
939 cellI = neighbour[faceI];
940 Type& currentWallInfo2 = allCellInfo_[cellI];
942 if (currentWallInfo2 != neighbourWallInfo)
955 // Reset status of face
956 changedFace_[faceI] = false;
959 // Handled all changed faces by now
964 Pout<< " Changed cells : " << nChangedCells_ << endl;
967 // Sum nChangedCells over all procs
968 label totNChanged = nChangedCells_;
970 reduce(totNChanged, sumOp<label>());
976 // Propagate cell to face
977 template <class Type>
978 Foam::label Foam::FaceCellWave<Type>::cellToFace()
980 const cellList& cells = mesh_.cells();
984 label changedCellI = 0;
985 changedCellI < nChangedCells_;
989 label cellI = changedCells_[changedCellI];
990 if (!changedCell_[cellI])
992 FatalErrorIn("FaceCellWave<Type>::cellToFace()") << "Cell " << cellI
993 << " not marked as having been changed"
994 << abort(FatalError);
997 const Type& neighbourWallInfo = allCellInfo_[cellI];
999 // Evaluate all connected faces
1001 const labelList& faceLabels = cells[cellI];
1002 forAll(faceLabels, faceLabelI)
1004 label faceI = faceLabels[faceLabelI];
1005 Type& currentWallInfo = allFaceInfo_[faceI];
1007 if (currentWallInfo != neighbourWallInfo)
1020 // Reset status of cell
1021 changedCell_[cellI] = false;
1024 // Handled all changed cells by now
1027 if (hasCyclicPatches_)
1029 // Transfer changed faces across cyclic halves
1030 handleCyclicPatches();
1032 if (Pstream::parRun())
1034 // Transfer changed faces from neighbouring processors.
1035 handleProcPatches();
1040 Pout<< " Changed faces : " << nChangedFaces_ << endl;
1043 // Sum nChangedFaces over all procs
1044 label totNChanged = nChangedFaces_;
1046 reduce(totNChanged, sumOp<label>());
1053 template <class Type>
1054 Foam::label Foam::FaceCellWave<Type>::iterate(const label maxIter)
1056 if (hasCyclicPatches_)
1058 // Transfer changed faces across cyclic halves
1059 handleCyclicPatches();
1061 if (Pstream::parRun())
1063 // Transfer changed faces from neighbouring processors.
1064 handleProcPatches();
1067 while(iter_ < maxIter)
1071 Pout<< " Iteration " << iter_ << endl;
1076 label nCells = faceToCell();
1080 Pout<< " Total changed cells : " << nCells << endl;
1088 label nFaces = cellToFace();
1092 Pout<< " Total changed faces : " << nFaces << nl
1093 << " Total evaluations : " << nEvals_ << nl
1094 << " Remaining unvisited cells: " << nUnvisitedCells_ << nl
1095 << " Remaining unvisited faces: " << nUnvisitedFaces_ << endl;
1106 return nUnvisitedCells_;
1109 // ************************ vim: set sw=4 sts=4 et: ************************ //