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 Mixing plane class dealing with transfer of data between two
29 Martin Beaudoin, Hydro-Quebec, 2009. All rights reserved
32 Hrvoje Jasak, Wikki Ltd.
34 \*---------------------------------------------------------------------------*/
36 #include "MixingPlaneInterpolationTemplate.H"
37 #include "demandDrivenData.H"
38 #include "PrimitivePatchTemplate.H"
40 #include "transform.H"
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 //- Find and fix the patch faces that have cylindrical points coordinates in
50 // contact with or split on both sides of the -180/+180 degree
51 // axis eg: [-179,+179]
53 // The cure is simple: we first find the problematic faces, (there might be
54 // none), then we modify only their angle coordinate in
55 // order to bring the whole face across the angle = +0 axis instead.
56 // This is a simple shift in cylindrical coordinates,
57 // but also a pure rotation in cartesian space for the faces.
59 // Since the only objective for these localCoordFaces is to create a patch for
60 // constructing a temporary GGI in cylindrical coordinate
61 // space, a single shift will have no effect whatsoever on the GGI weights
62 // because we are using 360 degrees face ribbons for the other
65 // By doing so, we will obvioulsy mess up the clean topology of the original
66 // cylindrical coordinates patch by shifting around a few faces;
67 // but keep in mind the only topology necessary for the GGI is the faces
68 // topology. A bunch of arbitrary located faces is as good as a bunch
69 // of cleanly laid-out faces into a regular patch. By only shifting the face
70 // along the angle axis, the face topology is preserved.
72 // Another interesting side-effect of this procedure is that it will cut
73 // a 360 degrees patch along the -180/+180 axis, leaving two un-connected
74 // "right-side" and "left-side" edges when switching the patch points to
75 // cylindrical coordinates.
76 template<class MasterPatch, class SlavePatch>
78 MixingPlaneInterpolation<MasterPatch, SlavePatch>::correctStraddlingFaces
80 faceList& localCoordFaces,
81 pointField& localCoordFacesPoint
84 // Memorize the list of displaced points so we can add them once at the
85 // end. This minimizes the
86 // memory reallocation necessary if we would do it one at a time instead.
88 typedef std::map<label, point> labelPointMap;
90 labelPointMap newFacePoints;
92 label newPointLabel = localCoordFacesPoint.size();
94 // Collect data on span limiting from coordinate system
95 coordinateSystem::spanInfo spanLimited = cs_.spanLimited();
96 boundBox spanBounds = cs_.spanBounds();
98 const direction sweepDir = sweepAxisSwitch();
100 // If there are no limits on both sides of the span,
101 // adjustment can be skipped
104 !spanLimited[sweepDir].first()
105 || !spanLimited[sweepDir].second()
112 // Check if coordinate system is limited in spanwise range
113 scalar maxSpan = spanBounds.max().component(sweepDir);
117 Info<< "Fixing span straddle in direction " << sweepDir
118 << " for span " << maxSpan << endl;
122 forAll (localCoordFaces, sFi)
126 scalarField pointsAngleValues =
127 localCoordFaces[sFi].points
130 ).component(sweepDir);
132 for (label i = 0; i < pointsAngleValues.size(); i++)
134 for (label j = i + 1; j < pointsAngleValues.size(); j++)
136 // We shift away any faces in contact with the
141 mag(pointsAngleValues[i] - pointsAngleValues[j])
144 || (mag(mag(pointsAngleValues[i]) - maxSpan)) < VSMALL
145 || (mag(mag(pointsAngleValues[j]) - maxSpan)) < VSMALL
148 // We need to correct this
149 // Grab the original points labels
150 labelList pointLbls = localCoordFaces[sFi];
152 forAll (pointLbls, ptI)
154 point ptCoord = localCoordFacesPoint[pointLbls[ptI]];
156 // Switch point across the +0 angle axis
157 if (ptCoord[sweepDir] < 0.0)
159 ptCoord[sweepDir] = ptCoord[sweepDir] + maxSpan;
163 ptCoord[sweepDir] = ptCoord[sweepDir] - maxSpan;
166 // Memorize data in order to reallocate
167 // localCoordFacesPoint only once
170 std::pair<label, point>(newPointLabel, ptCoord)
173 // Memorize the new point label right away for this
174 // face and increment index for the next
175 localCoordFaces[sFi][ptI] = newPointLabel++;
177 // Done with this face
184 if (!faceIsOk) break;
188 // Transfer the new points information into localCoordFacesPoint using
189 // only one reallocation
190 // We probably have point duplicates here; no big deal...
191 localCoordFacesPoint.setSize
193 localCoordFacesPoint.size() + newFacePoints.size()
196 forAllIter(labelPointMap, newFacePoints, nPi)
198 // First == label, Second == point
199 localCoordFacesPoint[nPi->first] = nPi->second;
204 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
206 template<class MasterPatch, class SlavePatch>
208 MixingPlaneInterpolation<MasterPatch, SlavePatch>::
209 calcTransformedPatches() const
213 transformedMasterPatchPtr_
214 || transformedShadowPatchPtr_
219 "void MixingPlaneInterpolation::calcTransformedPatches() const"
220 ) << "Patches already calculated"
221 << abort(FatalError);
224 // Duplicate the master/slave patch faces
225 faceList masterFaces = masterPatch_.localFaces();
226 faceList slaveFaces = slavePatch_.localFaces();
228 // Let's compute the patches coordinates values in mixing coordinates
229 pointField masterPointsLocalCoord =
230 cs_.localPosition(masterPatch_.localPoints());
232 pointField slavePointsLocalCoord =
233 cs_.localPosition(slavePatch_.localPoints());
235 // Next, we need to find and fix the patch faces that have straddled
237 // Note: The face indices and the local coordinates and the
238 // number of points may be modified within correctStraddlingFaces
241 correctStraddlingFaces(masterFaces, masterPointsLocalCoord);
242 correctStraddlingFaces(slaveFaces, slavePointsLocalCoord);
248 "MixingPlaneInterpolation<MasterPatch, SlavePatch>::"
249 "calcTransformedPatches()"
250 ) << "masterPointsLocalCoord: "
251 << masterPointsLocalCoord << nl
252 << "slavePointsLocalCoord: "
253 << slavePointsLocalCoord << endl;
256 // Create the local coords patches
258 transformedMasterPatchPtr_ =
262 masterPointsLocalCoord
265 transformedShadowPatchPtr_ =
269 slavePointsLocalCoord
274 template<class MasterPatch, class SlavePatch>
276 MixingPlaneInterpolation<MasterPatch, SlavePatch>::calcMixingPlanePatch() const
278 if (mixingPlanePatchPtr_)
282 "void MixingPlaneInterpolation<MasterPatch, SlavePatch>::"
283 "calcMixingPlanePatch() const"
284 ) << "Circumferential average patch alreacy calculated"
285 << abort(FatalError);
288 const pointField& profile = this->interpolationProfile();
290 // Create patch from profile
292 // Grab the bounding boxes of master and slave
296 transformedMasterPatch().localPoints(),
302 transformedShadowPatch().localPoints(),
306 // Collect data on span limiting from coordinate system
307 coordinateSystem::spanInfo spanLimited = cs_.spanLimited();
308 boundBox spanBounds = cs_.spanBounds();
310 const direction sweepDir = sweepAxisSwitch();
312 // Get span from bounding boxes
316 masterBB.min()[sweepDir],
317 slaveBB.min()[sweepDir]
323 masterBB.max()[sweepDir],
324 slaveBB.max()[sweepDir]
331 "MixingPlaneInterpolation<MasterPatch, SlavePatch>::"
332 "calcMixingPlanePatch() const"
333 ) << "minSpan from patch BB : " << minSpan << nl
334 << "maxSpan from patch BB : " << maxSpan << endl;
337 // Correct for limited span
338 if (spanLimited[sweepDir].first())
340 minSpan = spanBounds.min()[sweepDir];
343 if (spanLimited[sweepDir].second())
345 maxSpan = spanBounds.max()[sweepDir];
352 "MixingPlaneInterpolation<MasterPatch, SlavePatch>::"
353 "calcMixingPlanePatch() const"
354 ) << "minSpan after checking spanLimited: " << minSpan << nl
355 << "maxSpan after checking spanLimited: " << maxSpan << endl;
358 label nRibbons = profile.size() - 1;
360 // Points for averaging patch in the local coordinate system
361 pointField mixingPatchPoints(2*nRibbons + 2);
362 label nextPointID = 0;
364 faceList mixingPatchFaces(nRibbons);
365 scalarField mixingPatchFacesArea(nRibbons);
367 // Insert lower bound points and expand to bounds
368 mixingPatchPoints[0] = profile[0];
369 mixingPatchPoints[0].replace(sweepDir, minSpan);
371 mixingPatchPoints[1] = profile[0];
372 mixingPatchPoints[1].replace(sweepDir, maxSpan);
376 // Create patch faces
377 forAll (mixingPatchFaces, fI)
380 // Add top bound points and expand to bounds
381 mixingPatchPoints[nextPointID] = profile[fI + 1];
382 mixingPatchPoints[nextPointID].replace(sweepDir, minSpan);
385 mixingPatchPoints[nextPointID] = profile[fI + 1];
386 mixingPatchPoints[nextPointID].replace(sweepDir, maxSpan);
391 curFace[1] = fi2 + 1;
392 curFace[2] = fi2 + 3;
393 curFace[3] = fi2 + 2;
395 mixingPatchFaces[fI] = curFace;
398 mixingPlanePatchPtr_ =
410 "MixingPlaneInterpolation<MasterPatch, SlavePatch>::"
411 "calcMixingPlanePatch() const"
413 << *mixingPlanePatchPtr_ << nl
414 << "mixingPatch.points : "
415 << mixingPlanePatchPtr_->points() << endl;
420 template<class MasterPatch, class SlavePatch>
422 MixingPlaneInterpolation<MasterPatch, SlavePatch>::clearTransfomedPatches()
424 deleteDemandDrivenData(transformedMasterPatchPtr_);
425 deleteDemandDrivenData(transformedShadowPatchPtr_);
429 template<class MasterPatch, class SlavePatch>
431 MixingPlaneInterpolation<MasterPatch, SlavePatch>::clearMixingPlanePatch()
433 deleteDemandDrivenData(mixingPlanePatchPtr_);
437 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
439 } // End namespace Foam
441 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
444 // ************************************************************************* //