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/>.
28 Implementation of lengthScaleEstimator members
32 University of Massachusetts Amherst
35 \*----------------------------------------------------------------------------*/
38 #include "volFields.H"
39 #include "lengthScaleEstimator.H"
40 #include "processorPolyPatch.H"
45 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
47 defineTypeNameAndDebug(lengthScaleEstimator, 0);
49 lengthScaleEstimator::ScaleFnPair lengthScaleEstimator::methods_[] =
51 ScaleFnPair("constant", &lengthScaleEstimator::constantScale),
52 ScaleFnPair("direct", &lengthScaleEstimator::directScale),
53 ScaleFnPair("inverse", &lengthScaleEstimator::inverseScale)
56 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
58 // Construct from polyMesh and dictionary
59 lengthScaleEstimator::lengthScaleEstimator
68 minLengthScale_(VSMALL),
69 maxLengthScale_(GREAT),
70 curvatureDeviation_(0.0),
73 sliceThreshold_(VSMALL),
80 lowerRefineLevel_(0.001),
81 upperRefineLevel_(0.999),
83 maxRefineLevel_(labelMax)
86 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
88 lengthScaleEstimator::~lengthScaleEstimator()
91 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
93 // Check for legitimacy of patches
94 void lengthScaleEstimator::checkPatches(const wordList& patchList) const
96 const polyBoundaryMesh& boundary = mesh_.boundaryMesh();
98 forAll(patchList, wordI)
100 if (boundary.findPatchID(patchList[wordI]) < 0)
104 "void lengthScaleEstimator::checkPatches"
105 "(const wordList& patchList) const"
107 << " Could not find patch: "
108 << patchList[wordI] << nl
109 << abort(FatalError);
115 // Prepare for proximity-based refinement, if necessary
116 void lengthScaleEstimator::prepareProximityPatches()
118 if (!proximityPatches_.size())
125 Info << "Preparing patches for proximity-based refinement...";
128 // Clear out existing lists.
129 proximityBins_.clear();
130 proximityBins_.setSize(997, labelList(0));
132 const polyBoundaryMesh& boundary = mesh_.boundaryMesh();
134 bool setSpatialRes = false;
136 // Loop through all proximity patches and spatially hash patch faces.
137 forAll(boundary, patchI)
141 (proximityPatches_.found(boundary[patchI].name())) ||
142 (boundary[patchI].type() == "symmetryPlane")
145 const polyPatch& proxPatch = boundary[patchI];
147 // Construct a bounding-box of face centres.
148 // Do not synchronize in parallel, since the patch
149 // may not be present on all sub-domains.
150 boundBox box(proxPatch.faceCentres(), false);
152 const point& bMin = box.min();
153 const point& bMax = box.max();
155 // Further hashing requires this information.
156 proxBoundBox_.min() = bMin;
157 proxBoundBox_.max() = bMax;
159 // Build a list of face indices
160 labelList faceIndices
162 identity(proxPatch.size()) + proxPatch.start()
165 // For spatial resolution, pick a face on this patch.
170 Foam::sqrt(mag(proxPatch.faceAreas()[0]))
175 label(::floor(mag(bMax - bMin) / (3.0 * eLength)))
178 setSpatialRes = true;
183 proxPatch.faceCentres(),
194 Info << "Done." << endl;
199 // Perform spatial hashing on a set of points
200 void lengthScaleEstimator::spatialHash
202 const pointField& pointLocations,
203 const labelList& pointIndices,
205 const label resolution,
209 label binSize = bins.size(), nD = resolution;
211 const point& bMin = box.min();
212 const point& bMax = box.max();
214 // Extend bounding-box dimensions a bit to avoid edge-effects.
215 scalar ext = 0.02*(mag(bMax - bMin));
217 // Define an inverse grid-cell size.
218 scalar xL = nD/(bMax.x() - bMin.x() + ext);
219 scalar yL = nD/(bMax.y() - bMin.y() + ext);
220 scalar zL = nD/(bMax.z() - bMin.z() + ext);
222 // Loop through all points and bin them.
223 forAll(pointLocations, pointI)
225 // Translate to boundBox minimum.
226 point p = pointLocations[pointI] - bMin;
228 // Hash the position.
229 label i = label(mag(::floor(p.x()*xL)));
230 label j = label(mag(::floor(p.y()*yL)));
231 label k = label(mag(::floor(p.z()*zL)));
233 label pos = mag(((k*nD*nD)+(j*nD)+i) % binSize);
236 label newSize = bins[pos].size() + 1;
237 bins[pos].setSize(newSize, pointIndices[pointI]);
242 // Send length-scale info across processors
243 void lengthScaleEstimator::writeLengthScaleInfo
245 const labelList& cellLevels,
246 const scalarList& lengthScale
249 const polyBoundaryMesh& boundary = mesh_.boundaryMesh();
251 // Clear existing buffers
252 sendLblBuffer_.clear();
253 recvLblBuffer_.clear();
254 sendLvlBuffer_.clear();
255 recvLvlBuffer_.clear();
256 sendSclBuffer_.clear();
257 recvSclBuffer_.clear();
259 // Number of sent faces across processors
260 labelList nSendFaces(boundary.size(), 0);
261 labelList nRecvFaces(boundary.size(), 0);
263 // Corresponding face labels
264 sendLblBuffer_.setSize(boundary.size());
265 sendLvlBuffer_.setSize(boundary.size());
266 recvLblBuffer_.setSize(boundary.size());
267 recvLvlBuffer_.setSize(boundary.size());
269 // Length-scales corresponding to face-labels
270 sendSclBuffer_.setSize(boundary.size());
271 recvSclBuffer_.setSize(boundary.size());
273 // Fill send buffers with cell-level and length-scale info.
276 if (isA<processorPolyPatch>(boundary[pI]))
278 const labelList& fCells = boundary[pI].faceCells();
280 // Set the initial buffer size
281 sendLblBuffer_[pI].setSize(boundary[pI].size(), 0);
282 sendLvlBuffer_[pI].setSize(boundary[pI].size(), 0);
283 sendSclBuffer_[pI].setSize(boundary[pI].size(), 0.0);
285 forAll(fCells, faceI)
287 label cI = fCells[faceI];
289 // Does the adjacent cell have a non-zero level?
290 if (cellLevels[cI] > 0)
292 // Fill the send buffer.
293 sendLblBuffer_[pI][nSendFaces[pI]] = faceI;
294 sendLvlBuffer_[pI][nSendFaces[pI]] = cellLevels[cI];
295 sendSclBuffer_[pI][nSendFaces[pI]] = lengthScale[cI];
301 // Resize to actual value
302 sendLblBuffer_[pI].setSize(nSendFaces[pI]);
303 sendLvlBuffer_[pI].setSize(nSendFaces[pI]);
304 sendSclBuffer_[pI].setSize(nSendFaces[pI]);
306 const processorPolyPatch& pp =
308 refCast<const processorPolyPatch>(boundary[pI])
311 label neiProcNo = pp.neighbProcNo();
313 // First perform a blocking send/receive of the number of faces.
316 Pstream::nonBlocking,
318 reinterpret_cast<const char*>(&(nSendFaces[pI])),
324 Pstream::nonBlocking,
326 reinterpret_cast<char*>(&(nRecvFaces[pI])),
332 // Wait for all transfers to complete.
333 OPstream::waitRequests();
334 IPstream::waitRequests();
336 // Send info to neighbouring processors.
337 forAll(boundary, patchI)
339 if (isA<processorPolyPatch>(boundary[patchI]))
341 const processorPolyPatch& pp =
343 refCast<const processorPolyPatch>(boundary[patchI])
346 label neiProcNo = pp.neighbProcNo();
350 Pout << " Processor patch " << patchI << ' ' << pp.name()
351 << " communicating with " << neiProcNo
352 << " Sending: " << nSendFaces[patchI]
353 << " Recving: " << nRecvFaces[patchI]
357 // Next, perform a non-blocking send/receive of buffers.
358 // But only if the buffer size is non-zero.
359 if (nSendFaces[patchI] != 0)
363 Pstream::nonBlocking,
365 reinterpret_cast<const char*>(&(sendLblBuffer_[patchI][0])),
366 sendLblBuffer_[patchI].size()*sizeof(label)
371 Pstream::nonBlocking,
373 reinterpret_cast<const char*>(&(sendLvlBuffer_[patchI][0])),
374 sendLblBuffer_[patchI].size()*sizeof(label)
379 Pstream::nonBlocking,
381 reinterpret_cast<const char*>(&(sendSclBuffer_[patchI][0])),
382 sendSclBuffer_[patchI].size()*sizeof(scalar)
386 if (nRecvFaces[patchI] != 0)
388 // Size the receive buffers
389 recvLblBuffer_[patchI].setSize(nRecvFaces[patchI], 0);
390 recvLvlBuffer_[patchI].setSize(nRecvFaces[patchI], 0);
391 recvSclBuffer_[patchI].setSize(nRecvFaces[patchI], 0.0);
395 Pstream::nonBlocking,
397 reinterpret_cast<char*>(&(recvLblBuffer_[patchI][0])),
398 nRecvFaces[patchI]*sizeof(label)
403 Pstream::nonBlocking,
405 reinterpret_cast<char*>(&(recvLvlBuffer_[patchI][0])),
406 nRecvFaces[patchI]*sizeof(label)
411 Pstream::nonBlocking,
413 reinterpret_cast<char*>(&(recvSclBuffer_[patchI][0])),
414 nRecvFaces[patchI]*sizeof(scalar)
422 // Receive length-scale info across processors
423 void lengthScaleEstimator::readLengthScaleInfo
427 labelList& cellLevels,
428 UList<scalar>& lengthScale,
429 labelHashSet& levelCells
432 const polyBoundaryMesh& boundary = mesh_.boundaryMesh();
434 const labelList& own = mesh_.faceOwner();
435 const labelList& nei = mesh_.faceNeighbour();
437 // Wait for all transfers to complete.
438 OPstream::waitRequests();
439 IPstream::waitRequests();
441 // Now re-visit cells and update length-scales.
442 forAll(boundary, patchI)
444 if (recvLblBuffer_[patchI].size())
446 const labelList& fCells = boundary[patchI].faceCells();
448 forAll(recvLblBuffer_[patchI], i)
450 label nLabel = recvLblBuffer_[patchI][i];
451 label pLevel = recvLvlBuffer_[patchI][i];
453 label cI = fCells[nLabel];
455 label& ngbLevel = cellLevels[cI];
457 // For an unvisited cell, update the level
458 bool unvisited = false;
462 ngbLevel = pLevel + 1;
466 // Visit all neighbours and re-calculate length-scale
467 const cell& cellCheck = mesh_.cells()[cI];
469 scalar sumLength = 0.0;
470 label nTouchedNgb = 0;
472 forAll(cellCheck, faceI)
474 label sLevel = -1, sLCell = -1;
475 label pF = boundary.whichPatch(cellCheck[faceI]);
479 // Internal face. Determine neighbour.
480 if (own[cellCheck[faceI]] == cI)
482 sLCell = nei[cellCheck[faceI]];
486 sLCell = own[cellCheck[faceI]];
489 sLevel = cellLevels[sLCell];
491 if ((sLevel < ngbLevel) && (sLevel > 0))
493 sumLength += lengthScale[sLCell];
499 if (isA<processorPolyPatch>(boundary[pF]))
501 // Determine the local index.
504 boundary[pF].whichFace(cellCheck[faceI])
507 // Is this label present in the list?
510 if ((j = findIndex(recvLblBuffer_[pF], local)) > -1)
514 (recvLvlBuffer_[pF][j] < ngbLevel) &&
515 (recvLvlBuffer_[pF][j] > 0)
518 sumLength += recvSclBuffer_[pF][j];
525 if (!isFreePatch(pF))
529 fixedLengthScale(cellCheck[faceI], pF, true)
536 sumLength /= nTouchedNgb;
538 // Scale the length and assign to this cell
539 if (level < maxRefineLevel_)
541 sumLength *= growthFactor_;
544 if (meanScale_ > 0.0)
546 // If a mean scale has been specified,
547 // override the value
548 sumLength = meanScale_;
551 lengthScale[cI] = sumLength;
555 levelCells.insert(cI);
565 // Use a constant length scale for field-based refinement
566 scalar lengthScaleEstimator::constantScale(const scalar fieldValue) const
572 // Use a direct-proportion length scale for field-based refinement
573 scalar lengthScaleEstimator::directScale(const scalar fieldValue) const
575 if (fieldValue > upperRefineLevel_)
580 scalar value = fieldValue;
582 // Bracket the value within limits
583 value = min(value, upperRefineLevel_);
584 value = max(value, lowerRefineLevel_);
588 (value - lowerRefineLevel_) / (upperRefineLevel_ - lowerRefineLevel_)
593 minLengthScale_ + ((maxLengthScale_ - minLengthScale_) * ratio)
600 // Use an inverse-proportion length scale for field-based refinement
601 scalar lengthScaleEstimator::inverseScale(const scalar fieldValue) const
603 if (fieldValue < lowerRefineLevel_)
608 scalar value = fieldValue;
610 // Bracket the value within limits
611 value = min(value, upperRefineLevel_);
612 value = max(value, lowerRefineLevel_);
616 (value - lowerRefineLevel_) / (upperRefineLevel_ - lowerRefineLevel_)
621 minLengthScale_ + ((maxLengthScale_ - minLengthScale_) * (1.0 - ratio))
628 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
630 // Read edge refinement options from the dictionary
631 void lengthScaleEstimator::readRefinementOptions
633 const dictionary& refineDict,
639 scalar oldRatioMax = ratioMax_;
640 scalar oldRatioMin = ratioMin_;
641 scalar oldGrowthFactor = growthFactor_;
642 scalar oldMinScale = minLengthScale_;
643 scalar oldMaxScale = maxLengthScale_;
645 ratioMax_ = readScalar(refineDict.lookup("bisectionRatio"));
646 ratioMin_ = readScalar(refineDict.lookup("collapseRatio"));
647 growthFactor_ = readScalar(refineDict.lookup("growthFactor"));
649 // Sanity check: Are ratios and growth-factor correctly specified?
652 ratioMin_ > ratioMax_ ||
653 ratioMin_ < VSMALL ||
654 ratioMax_ < VSMALL ||
660 "void lengthScaleEstimator::readRefinementOptions"
661 "(const dictionary&, bool, bool)"
663 << " Options are incorrectly specified." << nl
664 << " ratioMin: " << ratioMin_ << nl
665 << " ratioMax: " << ratioMax_ << nl
666 << " growthFactor: " << growthFactor_ << nl
667 << abort(FatalError);
670 if (refineDict.found("minLengthScale") || mandatory)
672 minLengthScale_ = readScalar(refineDict.lookup("minLengthScale"));
675 if (refineDict.found("maxLengthScale") || mandatory)
677 maxLengthScale_ = readScalar(refineDict.lookup("maxLengthScale"));
680 // Sanity check: Are min/max length scales correctly specified?
681 if (minLengthScale_ > maxLengthScale_)
685 "void lengthScaleEstimator::readRefinementOptions"
686 "(const dictionary&, bool, bool)"
688 << " Length-scales are incorrectly specified." << nl
689 << " minLengthScale: " << minLengthScale_ << nl
690 << " maxLengthScale: " << maxLengthScale_ << nl
691 << abort(FatalError);
696 // Check if values have changed, and report it.
697 if (mag(oldRatioMax - ratioMax_) > SMALL)
699 Info << "\tOld ratioMax: " << oldRatioMax << nl
700 << "\tNew ratioMax: " << ratioMax_ << endl;
703 if (mag(oldRatioMin - ratioMin_) > SMALL)
705 Info << "\tOld ratioMin: " << oldRatioMin << nl
706 << "\tNew ratioMin: " << ratioMin_ << endl;
709 if (mag(oldGrowthFactor - growthFactor_) > SMALL)
711 Info << "\tOld growthFactor: " << oldGrowthFactor << nl
712 << "\tNew growthFactor: " << growthFactor_ << endl;
715 if (mag(oldMinScale - minLengthScale_) > SMALL)
717 Info << "\tOld minLengthScale: " << oldMinScale << nl
718 << "\tNew minLengthScale: " << minLengthScale_ << endl;
721 if (mag(oldMaxScale - maxLengthScale_) > SMALL)
723 Info << "\tOld maxLengthScale: " << oldMaxScale << nl
724 << "\tNew maxLengthScale: " << maxLengthScale_ << endl;
728 if (refineDict.found("fixedLengthScalePatches") || mandatory)
730 fixedPatches_ = refineDict.subDict("fixedLengthScalePatches");
732 // Ensure that patches are legitimate.
733 checkPatches(fixedPatches_.toc());
736 if (refineDict.found("freeLengthScalePatches") || mandatory)
738 freePatches_ = refineDict.subDict("freeLengthScalePatches");
740 // Ensure that patches are legitimate.
741 checkPatches(freePatches_.toc());
743 // Check if fixed and free patches are conflicting
744 if (fixedPatches_.size() && freePatches_.size())
746 wordList fixedPatchList = fixedPatches_.toc();
747 wordList freePatchList = freePatches_.toc();
749 forAll(fixedPatchList, wordI)
751 if (findIndex(freePatchList, fixedPatchList[wordI]) > -1)
755 "void lengthScaleEstimator::readRefinementOptions"
756 "(const dictionary&, bool, bool)"
758 << " Conflicting fixed/free patches." << nl
759 << " Patch: " << fixedPatchList[wordI] << nl
760 << abort(FatalError);
766 if (refineDict.found("curvaturePatches") || mandatory)
768 curvaturePatches_ = refineDict.subDict("curvaturePatches");
770 // Ensure that patches are legitimate.
771 checkPatches(curvaturePatches_.toc());
773 curvatureDeviation_ =
775 readScalar(refineDict.lookup("curvatureDeviation"))
778 if (curvatureDeviation_ > 1.0 || curvatureDeviation_ < 0.0)
782 "void lengthScaleEstimator::readRefinementOptions"
783 "(const dictionary&, bool, bool)"
785 << " Curvature deviation out of range [0..1]"
786 << abort(FatalError);
790 if (refineDict.found("proximityPatches") || mandatory)
794 refineDict.subDict("proximityPatches")
797 // Ensure that patches are legitimate.
798 checkPatches(proximityPatches_.toc());
800 // Check if a threshold for slicing has been specified.
801 if (refineDict.found("sliceThreshold") || mandatory)
805 readScalar(refineDict.lookup("sliceThreshold"))
808 // Cap the threshold value
809 // sliceThreshold_ = Foam::max(sliceThreshold_, minLengthScale_);
813 // Check if edge-refinement is to be avoided on any patches
814 if (refineDict.found("noModificationPatches") || mandatory)
816 wordList noModPatches =
818 refineDict.subDict("noModificationPatches").toc()
821 // Ensure that patches are legitimate.
822 checkPatches(noModPatches);
824 noModPatchIDs_.setSize(noModPatches.size());
828 forAll(noModPatches, wordI)
830 const word& patchName = noModPatches[wordI];
832 noModPatchIDs_[indexI++] =
834 mesh_.boundaryMesh().findPatchID(patchName)
839 // Check if refinement is to be performed based on a field-value
840 if (refineDict.found("fieldRefinement") || mandatory)
842 field_ = word(refineDict.lookup("fieldRefinement"));
844 word scaleMethod(refineDict.lookup("fieldScaleMethod"));
846 const label nMethods(sizeof(methods_) / sizeof(methods_[0]));
848 bool invalidMethod = true;
850 for (label i = 0; i < nMethods; i++)
852 if (scaleMethod == methods_[i].first())
854 scale_ = methods_[i].second();
855 invalidMethod = false;
862 Info << nl << " Available methods: " << endl;
864 for (label i = 0; i < nMethods; i++)
866 Info << " " << methods_[i].first() << nl;
871 "void lengthScaleEstimator::readRefinementOptions"
872 "(const dictionary&, bool, bool)"
874 << " Invalid method: " << scaleMethod << " specified." << nl
875 << abort(FatalError);
878 // Define whether the gradient must be evaluated
879 gradient_ = readBool(refineDict.lookup("fieldGradient"));
881 // Lookup a specified length-scale
882 fieldLength_ = readScalar(refineDict.lookup("fieldLengthScale"));
884 lowerRefineLevel_ = readScalar(refineDict.lookup("lowerRefineLevel"));
885 upperRefineLevel_ = readScalar(refineDict.lookup("upperRefineLevel"));
887 // Sanity check: Are refinement levels correctly specified?
888 if (lowerRefineLevel_ > upperRefineLevel_)
892 "void lengthScaleEstimator::readRefinementOptions"
893 "(const dictionary&, bool, bool)"
895 << " Refinement levels are incorrectly specified." << nl
896 << " lowerRefineLevel: " << lowerRefineLevel_ << nl
897 << " upperRefineLevel: " << upperRefineLevel_ << nl
898 << abort(FatalError);
902 // Check if a max refinement level has been specified
903 if (refineDict.found("maxRefineLevel") || mandatory)
905 maxRefineLevel_ = readLabel(refineDict.lookup("maxRefineLevel"));
908 // Update switch for mean-scale
909 if (refineDict.found("meanScale") || mandatory)
911 meanScale_ = readScalar(refineDict.lookup("meanScale"));
916 // Set explicitly coupled patch information
917 void lengthScaleEstimator::setCoupledPatches
919 const dictionary& coupledPatches
924 // Determine master and slave patches
925 wordList masterPatches(coupledPatches.size());
926 wordList slavePatches(coupledPatches.size());
928 forAllConstIter(dictionary, coupledPatches, dIter)
930 const dictionary& dictI = dIter().dict();
932 masterPatches[indexI] = word(dictI.lookup("master"));
933 slavePatches[indexI] = word(dictI.lookup("slave"));
938 // Ensure that patches are legitimate.
939 checkPatches(masterPatches);
941 // Check whether coupled patches are fixedPatches as well.
942 forAll(masterPatches, wordI)
944 word pName(masterPatches[wordI]);
946 if (fixedPatches_.found(pName))
948 // Add the slave patch to the list as well.
949 // If it already exists, over-ride the value.
953 fixedPatches_[pName][0].scalarToken(),
961 // Calculate the length scale field
962 void lengthScaleEstimator::calculateLengthScale
964 UList<scalar>& lengthScale
967 label level = 1, visitedCells = 0;
968 labelList cellLevels(mesh_.nCells(), 0);
970 // Check for allocation
971 if (lengthScale.size() != mesh_.nCells())
975 "void lengthScaleEstimator::calculateLengthScale"
976 "(UList<scalar>& lengthScale)"
978 << " Field is incorrectly sized." << nl
979 << " Field size: " << lengthScale.size()
980 << " nCells: " << mesh_.nCells()
981 << abort(FatalError);
984 // HashSet to keep track of cells in each level
985 labelHashSet levelCells;
987 // Prepare for proximity-based refinement, if necessary
988 prepareProximityPatches();
990 // Obtain the cellCells addressing list
991 const labelList& own = mesh_.faceOwner();
992 const labelListList& cc = mesh_.cellCells();
993 const polyBoundaryMesh& boundary = mesh_.boundaryMesh();
995 forAll(boundary,patchI)
997 // Skip floating length-scale patches
998 if (isFreePatch(patchI))
1003 const polyPatch& bdyPatch = boundary[patchI];
1005 label pStart = bdyPatch.start();
1007 forAll(bdyPatch,faceI)
1009 label ownCell = own[pStart+faceI];
1011 if (cellLevels[ownCell] != 0)
1016 cellLevels[ownCell] = level;
1018 lengthScale[ownCell] =
1020 fixedLengthScale(pStart+faceI, patchI, true) * growthFactor_
1023 levelCells.insert(ownCell);
1029 // If a field has been specified, use that.
1030 if (field_ != "none")
1032 const volScalarField* vFldPtr = NULL;
1034 // Temporary pointer for gradient
1035 volScalarField* magGradPtr = NULL;
1039 // Lookup various field types, and evaluate the gradient
1040 bool invalidObject = true;
1042 // Evaluate using gradient scheme
1043 word gradName("grad(" + field_ + ')');
1045 // Register field under a name that's unique
1046 word registerName("lengthScaleGradient(" + field_ + ')');
1048 if (mesh_.objectRegistry::foundObject<volScalarField>(field_))
1050 const volScalarField& field =
1052 mesh_.objectRegistry::lookupObject<volScalarField>(field_)
1062 mesh_.time().timeName(),
1068 mag(fvc::grad(field, gradName))
1072 invalidObject = false;
1075 if (mesh_.objectRegistry::foundObject<volVectorField>(field_))
1077 const volVectorField& field =
1079 mesh_.objectRegistry::lookupObject<volVectorField>(field_)
1089 mesh_.time().timeName(),
1095 mag(fvc::grad(field, gradName))
1099 invalidObject = false;
1106 "void lengthScaleEstimator::calculateLengthScale"
1107 "(UList<scalar>& lengthScale)"
1109 << " Invalid field: " << field_
1110 << " specified for gradient." << nl
1111 << abort(FatalError);
1114 vFldPtr = magGradPtr;
1118 // Lookup a scalar field by default
1119 const volScalarField& field =
1121 mesh_.objectRegistry::lookupObject<volScalarField>(field_)
1127 const volScalarField& vFld = *vFldPtr;
1129 const labelList& own = mesh_.faceOwner();
1130 const labelList& nei = mesh_.faceNeighbour();
1134 label ownCell = own[faceI], neiCell = nei[faceI];
1136 scalar fAvg = 0.5 * (vFld[ownCell] + vFld[neiCell]);
1138 if ((fAvg > lowerRefineLevel_) && (fAvg < upperRefineLevel_))
1140 // Set the scale for cells on either side
1141 if (!cellLevels[ownCell])
1143 cellLevels[ownCell] = level;
1144 lengthScale[ownCell] = (this->*scale_)(fAvg);
1146 levelCells.insert(ownCell);
1151 if (!cellLevels[neiCell])
1153 cellLevels[neiCell] = level;
1154 lengthScale[neiCell] = (this->*scale_)(fAvg);
1156 levelCells.insert(neiCell);
1163 // Clean up gradient, if necessary
1166 deleteDemandDrivenData(magGradPtr);
1170 bool doneWithSweeps = false;
1172 // Perform multiple sweeps through the mesh...
1173 while (!doneWithSweeps)
1175 if (Pstream::parRun())
1177 writeLengthScaleInfo(cellLevels, lengthScale);
1180 // Loop through cells of the current level
1181 labelList currLvlCells = levelCells.toc();
1184 // Loop through cells, and increment neighbour
1185 // cells of the current level
1186 forAll(currLvlCells,cellI)
1188 // Obtain the cells neighbouring this one
1189 const labelList& cList = cc[currLvlCells[cellI]];
1191 forAll(cList, indexI)
1193 label& ngbLevel = cellLevels[cList[indexI]];
1197 ngbLevel = level + 1;
1199 // Compute the mean of the existing
1200 // neighbour length-scales
1201 const labelList& ncList = cc[cList[indexI]];
1202 scalar sumLength = 0.0;
1203 label nTouchedNgb = 0;
1205 forAll(ncList, indexJ)
1207 label sLevel = cellLevels[ncList[indexJ]];
1209 if ((sLevel < ngbLevel) && (sLevel > 0))
1211 sumLength += lengthScale[ncList[indexJ]];
1217 sumLength /= nTouchedNgb;
1219 // Scale the length and assign to this cell
1220 if (level < maxRefineLevel_)
1222 sumLength *= growthFactor_;
1225 if (meanScale_ > 0.0)
1227 // If a mean scale has been specified,
1228 // override the value
1229 sumLength = meanScale_;
1232 lengthScale[cList[indexI]] = sumLength;
1234 levelCells.insert(cList[indexI]);
1241 if (Pstream::parRun())
1255 Pout << "Processed level: " << level << nl
1256 << " Visited: " << visitedCells
1257 << " out of " << mesh_.nCells() << endl;
1260 // Move on to the next level
1263 if (visitedCells >= mesh_.nCells())
1265 doneWithSweeps = true;
1268 // Wait for everyone to complete.
1269 reduce(doneWithSweeps, andOp<bool>());
1274 Info << "Max Length Scale: " << maxLengthScale_ << endl;
1275 Info << "Length Scale sweeps: " << level << endl;
1278 // Check if everything went okay
1279 if (visitedCells != mesh_.nCells())
1283 "void lengthScaleEstimator::calculateLengthScale"
1284 "(UList<scalar>& lengthScale)"
1286 << " Algorithm did not visit every cell in the mesh."
1287 << " Something's messed up." << nl
1288 << " Visited cells: " << visitedCells
1289 << " nCells: " << mesh_.nCells()
1290 << abort(FatalError);
1293 // Wait for transfers before continuing.
1294 if (Pstream::parRun())
1296 OPstream::waitRequests();
1297 IPstream::waitRequests();
1302 } // End namespace Foam
1304 // ************************************************************************* //