Merge remote-tracking branch 'origin/nr/multiSolverFix' into nextRelease
[foam-extend-3.2.git] / src / dynamicMesh / topoChangerFvMesh / mixerFvMesh / mixerFvMesh.C
blobd9647877e40e3cc6667339638f259c31dec86e37
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright held by original author
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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
19     for more details.
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 "mixerFvMesh.H"
28 #include "Time.H"
29 #include "regionSplit.H"
30 #include "slidingInterface.H"
31 #include "mapPolyMesh.H"
32 #include "volMesh.H"
33 #include "addToRunTimeSelectionTable.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 namespace Foam
39     defineTypeNameAndDebug(mixerFvMesh, 0);
40     addToRunTimeSelectionTable(topoChangerFvMesh, mixerFvMesh, IOobject);
44 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
46 void Foam::mixerFvMesh::addZonesAndModifiers()
48     // Add zones and modifiers for motion action
49     if (cellZones().size() > 0)
50     {
51         Info<< "void mixerFvMesh::addZonesAndModifiers() : "
52             << "Zones and modifiers already present.  Skipping."
53             << endl;
55         // Check definition of the modifier
56         if
57         (
58             pointZones().size() > 0
59          || faceZones().size() > 0
60         )
61         {
62             if (topoChanger_.size() == 0)
63             {
64                 FatalErrorIn
65                 (
66                     "void mixerFvMesh::addZonesAndModifiers()"
67                 )   << "Mesh modifiers not read properly.  "
68                     << "pointZones = " <<  pointZones().size()
69                     << " faceZones = " << faceZones().size()
70                     << abort(FatalError);
71             }
72         }
74         return;
75     }
77     // Find patches and check sizes
79     // Moving slider
80     const word movingSliderName(dict_.subDict("slider").lookup("moving"));
81     label movingSliderIndex = boundaryMesh().findPatchID(movingSliderName);
83     if (movingSliderIndex < 0)
84     {
85         FatalErrorIn("void mixerFvMesh::addZonesAndModifiers() const")
86             << "Moving slider patch not found in boundary"
87             << abort(FatalError);
88     }
90     const word staticSliderName(dict_.subDict("slider").lookup("static"));
91     label staticSliderIndex = boundaryMesh().findPatchID(staticSliderName);
93     if (staticSliderIndex < 0)
94     {
95         FatalErrorIn("void mixerFvMesh::addZonesAndModifiers() const")
96             << "Static slider patch not found in boundary"
97             << abort(FatalError);
99     }
101     const polyPatch& movingSlider = boundaryMesh()[movingSliderIndex];
102     const polyPatch& staticSlider = boundaryMesh()[staticSliderIndex];
104     List<pointZone*> pz;
105     List<faceZone*> fz;
107     bool addSlider = false;
109     if (movingSlider.size() > 0 && staticSlider.size() > 0)
110     {
111         addSlider = true;
113         pz.setSize(1);
114         fz.setSize(3);
116         Info<< "Time = " << time().timeName() << endl
117             << "Adding zones and modifiers to the mesh" << endl;
119         // Add zones
121         // Add an empty zone for cut points
123         pz[0] = new pointZone
124         (
125             "cutPointZone",
126             labelList(0),
127             0,
128             pointZones()
129         );
132         // Do face zones for slider
134         // Moving slider
135         labelList isf(movingSlider.size());
137         forAll (isf, i)
138         {
139             isf[i] = movingSlider.start() + i;
140         }
142         fz[0] = new faceZone
143         (
144             movingSliderName + "Zone",
145             isf,
146             boolList(movingSlider.size(), false),
147             0,
148             faceZones()
149         );
151         // Static slider
152         labelList osf(staticSlider.size());
154         forAll (osf, i)
155         {
156             osf[i] = staticSlider.start() + i;
157         }
159         fz[1] = new faceZone
160         (
161             staticSliderName + "Zone",
162             osf,
163             boolList(staticSlider.size(), false),
164             1,
165             faceZones()
166         );
168         // Add empty zone for cut faces
169         fz[2] = new faceZone
170         (
171             "cutFaceZone",
172             labelList(0),
173             boolList(0, false),
174             2,
175             faceZones()
176         );
177     }
179     // Add cell zone even if slider does not exist
181     List<cellZone*> cz(1);
183     // Mark every cell with its topological region
184     regionSplit rs(*this);
186     // Get the region of the cell containing the origin.
187     label originRegion = rs[findNearestCell(rotatingRegionMarker_)];
189     labelList movingCells(nCells());
190     label nMovingCells = 0;
192     forAll(rs, cellI)
193     {
194         if (rs[cellI] == originRegion)
195         {
196             movingCells[nMovingCells] = cellI;
197             nMovingCells++;
198         }
199     }
201     movingCells.setSize(nMovingCells);
202     Info << "Number of cells in the moving region: " << nMovingCells << endl;
204     cz[0] = new cellZone
205     (
206         "movingCells",
207         movingCells,
208         0,
209         cellZones()
210     );
212     Info << "Adding point, face and cell zones" << endl;
213     addZones(pz, fz, cz);
215     if (addSlider)
216     {
217         // Add a topology modifier
218         Info << "Adding topology modifiers" << endl;
219         topoChanger_.setSize(1);
221         topoChanger_.set
222         (
223             0,
224             new slidingInterface
225             (
226                 "mixerSlider",
227                 0,
228                 topoChanger_,
229                 staticSliderName + "Zone",
230                 movingSliderName + "Zone",
231                 "cutPointZone",
232                 "cutFaceZone",
233                 staticSliderName,
234                 movingSliderName,
235                 slidingInterface::INTEGRAL,   // Edge matching algorithm
236                 attachDetach_,                // Attach-detach action
237                 intersection::VISIBLE         // Projection algorithm
238             )
239         );
240     }
242     // Write mesh and modifiers
243     topoChanger_.writeOpt() = IOobject::AUTO_WRITE;
244     topoChanger_.write();
245     write();
249 bool Foam::mixerFvMesh::attached() const
251     bool result = false;
253     if (topoChanger_.size() > 0)
254     {
255         result = refCast<const slidingInterface>(topoChanger_[0]).attached();
256     }
258     reduce(result, orOp<bool>());
260     return result;
264 void Foam::mixerFvMesh::calcMovingMask() const
266     if (debug)
267     {
268         Info<< "void mixerFvMesh::calcMovingMask() const : "
269             << "Calculating point and cell masks"
270             << endl;
271     }
273     if (movingPointsMaskPtr_)
274     {
275         FatalErrorIn("void mixerFvMesh::calcMovingMask() const")
276             << "point mask already calculated"
277             << abort(FatalError);
278     }
280     // Set the point mask
281     movingPointsMaskPtr_ = new scalarField(allPoints().size(), 0);
282     scalarField& movingPointsMask = *movingPointsMaskPtr_;
284     const cellList& c = cells();
285     const faceList& f = allFaces();
287     const labelList& cellAddr =
288         cellZones()[cellZones().findZoneID("movingCells")];
290     forAll (cellAddr, cellI)
291     {
292         const cell& curCell = c[cellAddr[cellI]];
294         forAll (curCell, faceI)
295         {
296             // Mark all the points as moving
297             const face& curFace = f[curCell[faceI]];
299             forAll (curFace, pointI)
300             {
301                 movingPointsMask[curFace[pointI]] = 1;
302             }
303         }
304     }
306     if (topoChanger_.size() > 0)
307     {
308         // Topo changer present.  Use zones for motion
309         const word movingSliderZoneName
310         (
311             word(dict_.subDict("slider").lookup("moving")) + "Zone"
312         );
314         const labelList& movingSliderAddr =
315             faceZones()[faceZones().findZoneID(movingSliderZoneName)];
317         forAll (movingSliderAddr, faceI)
318         {
319             const face& curFace = f[movingSliderAddr[faceI]];
321             forAll (curFace, pointI)
322             {
323                 movingPointsMask[curFace[pointI]] = 1;
324             }
325         }
327         const word staticSliderZoneName
328         (
329             word(dict_.subDict("slider").lookup("static")) + "Zone"
330         );
332         const labelList& staticSliderAddr =
333             faceZones()[faceZones().findZoneID(staticSliderZoneName)];
335         forAll (staticSliderAddr, faceI)
336         {
337             const face& curFace = f[staticSliderAddr[faceI]];
339             forAll (curFace, pointI)
340             {
341                 movingPointsMask[curFace[pointI]] = 0;
342             }
343         }
344     }
348 // Return moving points mask.  Moving points marked with 1
349 const Foam::scalarField& Foam::mixerFvMesh::movingPointsMask() const
351     if (!movingPointsMaskPtr_)
352     {
353         calcMovingMask();
354     }
356     return *movingPointsMaskPtr_;
360 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
362 // Construct from components
363 Foam::mixerFvMesh::mixerFvMesh
365     const IOobject& io
368     topoChangerFvMesh(io),
369     dict_
370     (
371         IOdictionary
372         (
373             IOobject
374             (
375                 "dynamicMeshDict",
376                 time().constant(),
377                 *this,
378                 IOobject::MUST_READ,
379                 IOobject::NO_WRITE
380             )
381         ).subDict(typeName + "Coeffs")
382     ),
383     cs_
384     (
385         "coordinateSystem",
386         dict_.subDict("coordinateSystem")
387     ),
388     rpm_(readScalar(dict_.lookup("rpm"))),
389     rotatingRegionMarker_
390     (
391         dict_.lookupOrDefault<point>("rotatingRegionMarker", cs_.origin())
392     ),
393     attachDetach_(dict_.lookupOrDefault<bool>("attachDetach", false)),
394     movingPointsMaskPtr_(NULL)
396     // Make sure the coordinate system does not operate in degrees
397     // Bug fix, HJ, 3/Oct/2011
398     if (!cs_.inDegrees())
399     {
400         WarningIn("mixerFvMesh::mixerFvMesh(const IOobject& io)")
401             << "Mixer coordinate system is set to operate in radians.  "
402             << "Changing to rad for correct calculation of angular velocity."
403             << nl
404             << "To remove this message please add entry" << nl << nl
405             << "inDegrees true;" << nl << nl
406             << "to the specification of the coordinate system"
407             << endl;
409         cs_.inDegrees() = true;
410     }
412     Info<< "Rotating region marker point: " << rotatingRegionMarker_
413         << "  Attach-detach action = " << attachDetach_ << endl;
415     addZonesAndModifiers();
417     Info<< "Mixer mesh" << nl
418         << "    origin       : " << cs().origin() << nl
419         << "    axis         : " << cs().axis() << nl
420         << "    rpm          : " << rpm_ << nl
421         << "    marker       : " << rotatingRegionMarker_ << nl
422         << "    attach-detach: " << attachDetach_
423         << endl;
427 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
429 Foam::mixerFvMesh::~mixerFvMesh()
431     deleteDemandDrivenData(movingPointsMaskPtr_);
435 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
437 bool Foam::mixerFvMesh::update()
439     if (attached() && attachDetach_)
440     {
441         // Detach mesh
442         Info << "Detaching rotors" << endl;
443         autoPtr<mapPolyMesh> topoChangeMap = topoChanger_.changeMesh();
445         deleteDemandDrivenData(movingPointsMaskPtr_);
446     }
448     // Save old points
449     pointField oldPointsNew = allPoints();
451     // Move points.  Rotational speed needs to be converted from rpm
452     movePoints
453     (
454         cs_.globalPosition
455         (
456             cs_.localPosition(allPoints())
457           + vector(0, rpm_*360.0*time().deltaT().value()/60.0, 0)
458             *movingPointsMask()
459         )
460     );
462     autoPtr<mapPolyMesh> topoChangeMap = topoChanger_.changeMesh();
464     bool localMorphing = topoChangeMap->morphing();
465     bool globalMorphing = localMorphing;
467     reduce(globalMorphing, orOp<bool>());
469     if (globalMorphing)
470     {
471         Info << "Attaching rotors" << endl;
473         deleteDemandDrivenData(movingPointsMaskPtr_);
475         // Move the sliding interface points to correct position
476         if (localMorphing)
477         {
478             pointField mappedOldPointsNew(allPoints().size());
479             mappedOldPointsNew.map(oldPointsNew, topoChangeMap->pointMap());
481             movePoints(mappedOldPointsNew);
483             resetMotion();
484             setV0();
486             // Move the sliding interface points to correct position
487             movePoints(topoChangeMap->preMotionPoints());
488         }
489         else
490         {
491             pointField newPoints = allPoints();
492             movePoints(oldPointsNew);
494             resetMotion();
495             setV0();
497             // Move the sliding interface points to correct position
498             movePoints(newPoints);
499         }
500     }
502     return topoChangeMap->morphing();
506 // ************************************************************************* //