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/>.
25 MixingPlane interpolation functions
28 Martin Beaudoin, Hydro-Quebec, 2009. All rights reserved
31 Hrvoje Jasak, Wikki Ltd.
33 \*---------------------------------------------------------------------------*/
38 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 template<class MasterPatch, class SlavePatch>
42 MixingPlaneInterpolation<MasterPatch, SlavePatch>::computeProfileFromHistograms
44 const profileHistogram& masterHisto,
45 const profileHistogram& slaveHisto,
46 const scalar halfSizeBin
49 // Find min, max bounds
50 scalar histoMinValue =
53 masterHisto.begin()->first,
54 slaveHisto.begin()->first
57 scalar histoMaxValue =
60 (--masterHisto.end())->first,
61 (--slaveHisto.end())->first
64 // Next, we compare both histograms, leap-frogging from one histogram
65 // to the other, everytime jumping to the next largest value from
67 std::list<point> leapFrogProfile(0);
69 scalar curRvalue = histoMinValue;
71 if (masterHisto.find(curRvalue) != masterHisto.end())
73 leapFrogProfile.push_back
75 *(masterHisto.find(curRvalue)->second.begin())
80 leapFrogProfile.push_back
82 *(slaveHisto.find(curRvalue)->second.begin())
88 profileHistogram::const_iterator nextMaster =
89 masterHisto.lower_bound(curRvalue + halfSizeBin - SMALL);
91 profileHistogram::const_iterator nextSlave =
92 slaveHisto.lower_bound(curRvalue + halfSizeBin - SMALL);
96 nextMaster == masterHisto.end()
97 || nextSlave == slaveHisto.end()
101 if (curRvalue != histoMaxValue)
103 if (masterHisto.find(histoMaxValue) != masterHisto.end())
105 leapFrogProfile.push_back
107 *(masterHisto.find(histoMaxValue)->second.begin())
112 leapFrogProfile.push_back
114 *(slaveHisto.find(histoMaxValue)->second.begin())
121 // Leap frog to the next largest delta
122 // Please note that we are not taking into account the number of
123 // values at the specific map index (the attribute called 'second'
124 // of the map container)
125 // So by leap-frogging this way, we might ran into the situation
126 // where the next jump will bring us to a radius value shared by only
127 // one patch face point, and we might oversee a slightly smaller
128 // radius shared by 100s of points.
129 // There is a definite advantage of sticking to existing radius values
130 // for the profile because this will tend to keep the number of
131 // GGI face neighbours low.
132 // I am not sure if there is a nice solution to this problem.... MB
134 curRvalue = max(nextMaster->first, nextSlave->first);
136 if (masterHisto.find(curRvalue) != masterHisto.end())
138 leapFrogProfile.push_back
140 *(masterHisto.find(curRvalue)->second.begin())
145 leapFrogProfile.push_back
147 *(slaveHisto.find(curRvalue)->second.begin())
150 } while (curRvalue != histoMaxValue);
152 // Re-package the data into pointField
153 tmp<pointField> tprofile(new pointField(leapFrogProfile.size()));
155 pointField& profile = tprofile();
159 forAllIter (std::list<point>, leapFrogProfile, lI)
168 template<class MasterPatch, class SlavePatch>
170 MixingPlaneInterpolation<MasterPatch, SlavePatch>::updateProfileHistogram
172 profileHistogram& histo,
173 const point& profileCoord, // 3D point reference
174 const direction dir, // Sorting dimension 0: x, 1: y, 2: z
175 const scalar halfSizeBin // half size of min width for histogram bins
178 bool foundNewBin = true;
180 scalar keyValue = profileCoord.component(dir);
182 forAllIter (profileHistogram, histo, histoI)
186 keyValue >= histoI->first - halfSizeBin
187 && keyValue < histoI->first + halfSizeBin
191 histoI->second.push_back(profileCoord);
198 std::list<point> initValue;
200 initValue.push_back(profileCoord);
203 std::pair<scalar, std::list<point> >(keyValue, initValue)
209 template<class MasterPatch, class SlavePatch>
211 MixingPlaneInterpolation<MasterPatch, SlavePatch>::calcProfile() const
213 // First, transform patch points over one single global profile
214 // into local coordinates
216 pointField masterGlobalProfile =
217 cs_.localPosition(masterPatch_.localPoints());
219 pointField slaveGlobalProfile =
220 cs_.localPosition(slavePatch_.localPoints());
222 // Collapse all points in the sweep direction
224 const direction sweepDir = sweepAxisSwitch();
226 masterGlobalProfile.replace(sweepDir, 0);
227 slaveGlobalProfile.replace(sweepDir, 0);
233 "tmp<pointField> MixingPlaneInterpolation::calcProfile()"
234 ) << "masterGlobalProfile: " << masterGlobalProfile << nl
235 << "slaveGlobalProfile: " << slaveGlobalProfile << endl;
238 // Find the smallest edge length from both patches.
239 // This length will control the size of the bins for the histograms
240 // we are about to build.
241 scalar masterMinEdgeLength = GREAT;
242 const edgeList& masterEdgeList = masterPatch_.edges();
244 forAll (masterEdgeList, mEi)
246 masterMinEdgeLength =
250 masterEdgeList[mEi].mag(masterPatch_.localPoints())
254 scalar slaveMinEdgeLength = GREAT;
255 const edgeList& slaveEdgeList = slavePatch_.edges();
257 forAll (slaveEdgeList, sEi)
263 slaveEdgeList[sEi].mag(slavePatch_.localPoints())
267 // There is no point classifying data to a resolution smaller than the
268 // largest of the two minimum edges found.
269 // This will drive the size of the smallest bin needed to construct the
270 // z and r histograms
271 scalar halfMinSizeBin =
272 Foam::max(masterMinEdgeLength, slaveMinEdgeLength)/2.0;
278 "tmp<pointField> MixingPlaneInterpolation::calcProfile()"
279 ) << "halfMinSizeBin: " << halfMinSizeBin << endl;
282 // Build master and slave histogram
283 profileHistogram masterHistogram;
284 profileHistogram slaveHistogram;
286 // stackingDir switch
287 const direction stackingDir = stackAxisSwitch();
290 forAll (masterGlobalProfile, mI)
292 updateProfileHistogram
295 masterGlobalProfile[mI],
302 forAll (slaveGlobalProfile, sI)
304 updateProfileHistogram
307 slaveGlobalProfile[sI],
316 forAllIter (profileHistogram, masterHistogram, zHi)
318 Info<< "master histo (z, n): (" << zHi->first << " "
319 << static_cast<int>(zHi->second.size()) << ")" << endl;
322 forAllIter (profileHistogram, slaveHistogram, zHi)
324 Info<< "slave histo (z, n): (" << zHi->first << " "
325 << static_cast<int>(zHi->second.size()) << ")" << endl;
329 pointField profileBeforeClip;
331 // Select which type of profile we need
332 switch (discretisationType_)
334 // To Do: add uniform mixing plane
338 profileBeforeClip = computeProfileFromHistograms
349 profileBeforeClip = computeProfileFromHistograms
360 profileBeforeClip = computeProfileFromHistograms
375 "tmp<pointField> MixingPlaneInterpolation<MasterPatch, "
376 "SlavePatch>::calcProfile() const"
377 ) << "Bad type of mixing plane discretisation: "
378 << discretisationNames_[discretisationType_]
379 << nl << "Available types are: " << nl
380 << MixingPlaneInterpolationName::discretisationNames_
381 << abort(FatalError);
385 // Remove interpolationProfile_ points located outside of either
386 // master/slave patch boundingBox,
387 // with the exception of the first and last profile points
389 // Martin to work here. HJ, 27/Jan/2011
403 // Expand the bounding box in the sweepAxis-wise direction
404 // Note: All points are collapsed to zero in sweepDir
405 // It is sufficient to expand the box by 1 in this direction
407 masterBB.min().replace(sweepDir, -1);
408 masterBB.max().replace(sweepDir, 1);
410 slaveBB.min().replace(sweepDir, -1);
411 slaveBB.max().replace(sweepDir, 1);
415 point(Foam::min(masterBB.min(), slaveBB.min()))
416 - point(SMALL, SMALL, SMALL),
417 point(Foam::max(masterBB.max(), slaveBB.max()))
418 + point(SMALL, SMALL, SMALL)
425 "tmp<pointField> MixingPlaneInterpolation<MasterPatch, "
426 "SlavePatch>::calcProfile() const"
427 ) << setprecision(12) << nl
428 << "masterBB: " << masterBB << nl
429 << "slaveBB: " << slaveBB << nl
430 << "globSpanBB: " << globSpanBB << nl
431 << "initial profile values: " << profileBeforeClip << endl;
434 // Iterate through profile, removing points located
435 // outside of either master/slave BB
437 tmp<pointField> tprofile(new pointField(profileBeforeClip.size()));
438 pointField& profile = tprofile();
441 forAll (profileBeforeClip, pI)
443 if (globSpanBB.contains(profileBeforeClip[pI]))
445 // We keep that profile point
446 profile[curIndex] = profileBeforeClip[pI];
447 curIndex++; // Next slot
455 "MixingPlaneInterpolation"
456 "<MasterPatch, SlavePatch>::"
457 "removeNonOverlappedProfilePoints"
458 ) << setprecision(12) << " Removing point: "
459 << profileBeforeClip[pI] << endl;
464 profile.setSize(curIndex);
466 if (profile.size() < 2)
470 "tmp<pointField> MixingPlaneInterpolation<MasterPatch, "
471 "SlavePatch>::calcProfile() const"
472 ) << "Lost all points in profile: " << profile
473 << abort(FatalError);
480 "MixingPlaneInterpolation<MasterPatch, SlavePatch>::"
481 "removeNonOverlappedProfilePoints"
482 ) << "cleaned-up profile values: " << profile << endl;
489 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
491 template<class MasterPatch, class SlavePatch>
492 const Foam::pointField&
493 MixingPlaneInterpolation<MasterPatch, SlavePatch>::interpolationProfile() const
495 if (interpolationProfile_.size() == 0)
497 // Not a user-defined profile: calculate as per algorithm
498 interpolationProfile_ = calcProfile();
501 return interpolationProfile_;
505 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
507 } // End namespace Foam
509 // ************************************************************************* //