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 "motionSmoother.H"
28 #include "twoDPointCorrector.H"
31 #include "fixedValuePointPatchFields.H"
32 #include "pointConstraint.H"
33 #include "syncTools.H"
34 #include "meshTools.H"
40 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(motionSmoother, 0);
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 // From pointPatchInterpolation
50 void Foam::motionSmoother::makePatchPatchAddressing()
54 Pout<< "motionSmoother::makePatchPatchAddressing() : "
55 << "constructing boundary addressing"
59 const polyBoundaryMesh& bm = mesh_.boundaryMesh();
60 const pointBoundaryMesh& pbm = pMesh_.boundary();
62 // first count the total number of patch-patch points
64 label nPatchPatchPoints = 0;
68 if(!isA<emptyPolyPatch>(bm[patchi]))
70 nPatchPatchPoints += bm[patchi].boundaryPoints().size();
75 // Go through all patches and mark up the external edge points
76 Map<label> patchPatchPointSet(2*nPatchPatchPoints);
78 labelList patchPatchPoints(nPatchPatchPoints);
80 List<pointConstraint> patchPatchPointConstraints(nPatchPatchPoints);
86 if(!isA<emptyPolyPatch>(bm[patchi]))
88 const labelList& bp = bm[patchi].boundaryPoints();
89 const labelList& meshPoints = bm[patchi].meshPoints();
93 label ppp = meshPoints[bp[pointi]];
95 Map<label>::iterator iter = patchPatchPointSet.find(ppp);
97 if (iter == patchPatchPointSet.end())
99 patchPatchPointSet.insert(ppp, pppi);
100 patchPatchPoints[pppi] = ppp;
101 pbm[patchi].applyConstraint
104 patchPatchPointConstraints[pppi]
110 pbm[patchi].applyConstraint
113 patchPatchPointConstraints[iter()]
120 nPatchPatchPoints = pppi;
121 patchPatchPoints.setSize(nPatchPatchPoints);
122 patchPatchPointConstraints.setSize(nPatchPatchPoints);
124 patchPatchPointConstraintPoints_.setSize(nPatchPatchPoints);
125 patchPatchPointConstraintTensors_.setSize(nPatchPatchPoints);
127 label nConstraints = 0;
129 forAll(patchPatchPointConstraints, i)
131 if (patchPatchPointConstraints[i].first() != 0)
133 patchPatchPointConstraintPoints_[nConstraints] =
136 patchPatchPointConstraintTensors_[nConstraints] =
137 patchPatchPointConstraints[i].constraintTransformation();
143 patchPatchPointConstraintPoints_.setSize(nConstraints);
144 patchPatchPointConstraintTensors_.setSize(nConstraints);
149 OFstream str(mesh_.db().path()/"constraintPoints.obj");
151 Pout<< "Dumping " << patchPatchPointConstraintPoints_.size()
152 << " constraintPoints to " << str.name() << endl;
153 forAll(patchPatchPointConstraintPoints_, i)
155 label pointI = patchPatchPointConstraintPoints_[i];
157 meshTools::writeOBJ(str, mesh_.points()[pointI]);
160 Pout<< "motionSmoother::makePatchPatchAddressing() : "
161 << "finished constructing boundary addressing"
167 void Foam::motionSmoother::checkFld(const pointScalarField& fld)
171 const scalar val = fld[pointI];
173 if ((val > -GREAT) && (val < GREAT))
177 FatalErrorIn("motionSmoother::checkFld")
178 << "Problem : point:" << pointI << " value:" << val
179 << abort(FatalError);
185 Foam::labelHashSet Foam::motionSmoother::getPoints
187 const labelHashSet& faceLabels
190 labelHashSet usedPoints(mesh_.nPoints()/100);
192 forAllConstIter(labelHashSet, faceLabels, iter)
194 const face& f = mesh_.faces()[iter.key()];
198 usedPoints.insert(f[fp]);
206 // Smooth on selected points (usually patch points)
207 void Foam::motionSmoother::minSmooth
209 const PackedBoolList& isAffectedPoint,
210 const labelList& meshPoints,
211 const pointScalarField& fld,
212 pointScalarField& newFld
215 tmp<pointScalarField> tavgFld = avg
218 scalarField(mesh_.nEdges(), 1.0), // uniform weighting
219 false // fld is not position.
221 const pointScalarField& avgFld = tavgFld();
223 forAll(meshPoints, i)
225 label pointI = meshPoints[i];
226 if (isAffectedPoint.get(pointI) == 1)
231 0.5*fld[pointI] + 0.5*avgFld[pointI]
236 newFld.correctBoundaryConditions();
237 applyCornerConstraints(newFld);
241 // Smooth on all internal points
242 void Foam::motionSmoother::minSmooth
244 const PackedBoolList& isAffectedPoint,
245 const pointScalarField& fld,
246 pointScalarField& newFld
249 tmp<pointScalarField> tavgFld = avg
252 scalarField(mesh_.nEdges(), 1.0), // uniform weighting
253 false // fld is not position.
255 const pointScalarField& avgFld = tavgFld();
259 if (isAffectedPoint.get(pointI) == 1 && isInternalPoint(pointI))
264 0.5*fld[pointI] + 0.5*avgFld[pointI]
269 newFld.correctBoundaryConditions();
270 applyCornerConstraints(newFld);
274 // Scale on selected points
275 void Foam::motionSmoother::scaleField
277 const labelHashSet& pointLabels,
279 pointScalarField& fld
282 forAllConstIter(labelHashSet, pointLabels, iter)
284 if (isInternalPoint(iter.key()))
286 fld[iter.key()] *= scale;
289 fld.correctBoundaryConditions();
290 applyCornerConstraints(fld);
294 // Scale on selected points (usually patch points)
295 void Foam::motionSmoother::scaleField
297 const labelList& meshPoints,
298 const labelHashSet& pointLabels,
300 pointScalarField& fld
303 forAll(meshPoints, i)
305 label pointI = meshPoints[i];
307 if (pointLabels.found(pointI))
309 fld[pointI] *= scale;
315 bool Foam::motionSmoother::isInternalPoint(const label pointI) const
317 return isInternalPoint_.get(pointI) == 1;
321 void Foam::motionSmoother::getAffectedFacesAndPoints
323 const label nPointIter,
324 const faceSet& wrongFaces,
326 labelList& affectedFaces,
327 PackedBoolList& isAffectedPoint
330 isAffectedPoint.setSize(mesh_.nPoints());
333 faceSet nbrFaces(mesh_, "checkFaces", wrongFaces);
335 // Find possible points influenced by nPointIter iterations of
336 // scaling and smoothing by doing pointCellpoint walk.
337 // Also update faces-to-be-checked to extend one layer beyond the points
338 // that will get updated.
340 for (label i = 0; i < nPointIter; i++)
342 pointSet nbrPoints(mesh_, "grownPoints", getPoints(nbrFaces.toc()));
344 forAllConstIter(pointSet, nbrPoints, iter)
346 const labelList& pCells = mesh_.pointCells(iter.key());
348 forAll(pCells, pCellI)
350 const cell& cFaces = mesh_.cells()[pCells[pCellI]];
352 forAll(cFaces, cFaceI)
354 nbrFaces.insert(cFaces[cFaceI]);
358 nbrFaces.sync(mesh_);
360 if (i == nPointIter - 2)
362 forAllConstIter(faceSet, nbrFaces, iter)
364 const face& f = mesh_.faces()[iter.key()];
367 isAffectedPoint.set(f[fp], 1);
373 affectedFaces = nbrFaces.toc();
377 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
379 Foam::motionSmoother::motionSmoother
383 indirectPrimitivePatch& pp,
384 const labelList& adaptPatchIDs,
385 const dictionary& paramDict
391 adaptPatchIDs_(adaptPatchIDs),
392 paramDict_(paramDict),
398 mesh_.time().timeName(),
410 mesh_.time().timeName(),
416 dimensionedScalar("scale", dimless, 1.0)
418 oldPoints_(mesh_.points()),
419 isInternalPoint_(mesh_.nPoints(), 1),
420 twoDCorrector_(mesh_)
426 Foam::motionSmoother::motionSmoother
429 indirectPrimitivePatch& pp,
430 const labelList& adaptPatchIDs,
431 const pointVectorField& displacement,
432 const dictionary& paramDict
436 pMesh_(const_cast<pointMesh&>(displacement.mesh())),
438 adaptPatchIDs_(adaptPatchIDs),
439 paramDict_(paramDict),
445 mesh_.time().timeName(),
457 mesh_.time().timeName(),
463 dimensionedScalar("scale", dimless, 1.0)
465 oldPoints_(mesh_.points()),
466 isInternalPoint_(mesh_.nPoints(), 1),
467 twoDCorrector_(mesh_)
473 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
475 Foam::motionSmoother::~motionSmoother()
479 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
481 const Foam::polyMesh& Foam::motionSmoother::mesh() const
487 const Foam::pointMesh& Foam::motionSmoother::pMesh() const
493 const Foam::indirectPrimitivePatch& Foam::motionSmoother::patch() const
499 const Foam::labelList& Foam::motionSmoother::adaptPatchIDs() const
501 return adaptPatchIDs_;
505 const Foam::dictionary& Foam::motionSmoother::paramDict() const
511 Foam::pointVectorField& Foam::motionSmoother::displacement()
513 return displacement_;
517 const Foam::pointVectorField& Foam::motionSmoother::displacement() const
519 return displacement_;
523 const Foam::pointScalarField& Foam::motionSmoother::scale() const
529 const Foam::pointField& Foam::motionSmoother::oldPoints() const
535 void Foam::motionSmoother::correct()
537 oldPoints_ = mesh_.points();
541 // No need to update twoDmotion corrector since only holds edge labels
542 // which will remain the same as before. So unless the mesh was distorted
543 // severely outside of motionSmoother there will be no need.
547 void Foam::motionSmoother::setDisplacement(pointField& patchDisp)
549 // See comment in .H file about shared points.
550 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
552 forAll(patches, patchI)
554 const polyPatch& pp = patches[patchI];
558 const labelList& meshPoints = pp.meshPoints();
560 forAll(meshPoints, i)
562 displacement_[meshPoints[i]] = vector::zero;
567 const labelList& ppMeshPoints = pp_.meshPoints();
569 // Set internal point data from displacement on combined patch points.
570 forAll(ppMeshPoints, patchPointI)
572 displacement_[ppMeshPoints[patchPointI]] = patchDisp[patchPointI];
575 // Adapt the fixedValue bc's (i.e. copy internal point data to
576 // boundaryField for all affected patches)
577 forAll(adaptPatchIDs_, i)
579 label patchI = adaptPatchIDs_[i];
581 displacement_.boundaryField()[patchI] ==
582 displacement_.boundaryField()[patchI].patchInternalField();
585 // Make consistent with non-adapted bc's by evaluating those now and
586 // resetting the displacement from the values.
587 // Note that we're just doing a correctBoundaryConditions with
588 // fixedValue bc's first.
589 labelHashSet adaptPatchSet(adaptPatchIDs_);
591 const lduSchedule& patchSchedule = mesh_.globalData().patchSchedule();
593 forAll(patchSchedule, patchEvalI)
595 label patchI = patchSchedule[patchEvalI].patch;
597 if (!adaptPatchSet.found(patchI))
599 if (patchSchedule[patchEvalI].init)
601 displacement_.boundaryField()[patchI]
602 .initEvaluate(Pstream::scheduled);
606 displacement_.boundaryField()[patchI]
607 .evaluate(Pstream::scheduled);
612 // Multi-patch constraints
613 applyCornerConstraints(displacement_);
615 // Correct for problems introduced by corner constraints
616 syncTools::syncPointList
620 maxMagEqOp(), // combine op
621 vector::zero, // null value
622 false // no separation
625 // Adapt the fixedValue bc's (i.e. copy internal point data to
626 // boundaryField for all affected patches) to take the changes caused
627 // by multi-corner constraints into account.
628 forAll(adaptPatchIDs_, i)
630 label patchI = adaptPatchIDs_[i];
632 displacement_.boundaryField()[patchI] ==
633 displacement_.boundaryField()[patchI].patchInternalField();
638 OFstream str(mesh_.db().path()/"changedPoints.obj");
640 forAll(ppMeshPoints, patchPointI)
642 const vector& newDisp = displacement_[ppMeshPoints[patchPointI]];
644 if (mag(newDisp-patchDisp[patchPointI]) > SMALL)
646 const point& pt = mesh_.points()[ppMeshPoints[patchPointI]];
648 meshTools::writeOBJ(str, pt);
650 //Pout<< "Point:" << pt
651 // << " oldDisp:" << patchDisp[patchPointI]
652 // << " newDisp:" << newDisp << endl;
655 Pout<< "Written " << nVerts << " points that are changed to file "
656 << str.name() << endl;
659 // Now reset input displacement
660 forAll(ppMeshPoints, patchPointI)
662 patchDisp[patchPointI] = displacement_[ppMeshPoints[patchPointI]];
667 // correctBoundaryConditions with fixedValue bc's first.
668 void Foam::motionSmoother::correctBoundaryConditions
670 pointVectorField& displacement
673 labelHashSet adaptPatchSet(adaptPatchIDs_);
675 const lduSchedule& patchSchedule = mesh_.globalData().patchSchedule();
677 // 1. evaluate on adaptPatches
678 forAll(patchSchedule, patchEvalI)
680 label patchI = patchSchedule[patchEvalI].patch;
682 if (adaptPatchSet.found(patchI))
684 if (patchSchedule[patchEvalI].init)
686 displacement.boundaryField()[patchI]
687 .initEvaluate(Pstream::blocking);
691 displacement.boundaryField()[patchI]
692 .evaluate(Pstream::blocking);
698 // 2. evaluate on non-AdaptPatches
699 forAll(patchSchedule, patchEvalI)
701 label patchI = patchSchedule[patchEvalI].patch;
703 if (!adaptPatchSet.found(patchI))
705 if (patchSchedule[patchEvalI].init)
707 displacement.boundaryField()[patchI]
708 .initEvaluate(Pstream::blocking);
712 displacement.boundaryField()[patchI]
713 .evaluate(Pstream::blocking);
718 // Multi-patch constraints
719 applyCornerConstraints(displacement);
721 // Correct for problems introduced by corner constraints
722 syncTools::syncPointList
726 maxMagEqOp(), // combine op
727 vector::zero, // null value
728 false // no separation
733 Foam::tmp<Foam::scalarField> Foam::motionSmoother::movePoints
735 pointField& newPoints
738 // Correct for 2-D motion
739 if (twoDCorrector_.required())
741 Info<< "Correct-ing 2-D mesh motion";
743 if (mesh_.globalData().parallel())
745 WarningIn("motionSmoother::movePoints(pointField& newPoints)")
746 << "2D mesh-motion probably not correct in parallel" << endl;
749 // We do not want to move 3D planes so project all points onto those
750 const pointField& oldPoints = mesh_.points();
751 const edgeList& edges = mesh_.edges();
753 const labelList& neIndices = twoDCorrector().normalEdgeIndices();
754 const vector& pn = twoDCorrector().planeNormal();
758 const edge& e = edges[neIndices[i]];
760 point& pStart = newPoints[e.start()];
762 pStart += pn*(pn & (oldPoints[e.start()] - pStart));
764 point& pEnd = newPoints[e.end()];
766 pEnd += pn*(pn & (oldPoints[e.end()] - pEnd));
769 // Correct tangentially
770 twoDCorrector_.correctPoints(newPoints);
771 Info<< " ...done" << endl;
776 Pout<< "motionSmoother::movePoints : testing sync of newPoints."
781 minEqOp<point>(), // combine op
782 vector(GREAT,GREAT,GREAT), // null
787 tmp<scalarField> tsweptVol = mesh_.movePoints(newPoints);
789 pp_.movePoints(mesh_.points());
795 Foam::scalar Foam::motionSmoother::setErrorReduction
797 const scalar errorReduction
800 scalar oldErrorReduction = readScalar(paramDict_.lookup("errorReduction"));
802 paramDict_.remove("errorReduction");
803 paramDict_.add("errorReduction", errorReduction);
805 return oldErrorReduction;
809 bool Foam::motionSmoother::scaleMesh
811 labelList& checkFaces,
812 const bool smoothMesh,
813 const label nAllowableErrors
816 List<labelPair> emptyBaffles;
827 bool Foam::motionSmoother::scaleMesh
829 labelList& checkFaces,
830 const List<labelPair>& baffles,
831 const bool smoothMesh,
832 const label nAllowableErrors
847 bool Foam::motionSmoother::scaleMesh
849 labelList& checkFaces,
850 const List<labelPair>& baffles,
851 const dictionary& paramDict,
852 const dictionary& meshQualityDict,
853 const bool smoothMesh,
854 const label nAllowableErrors
857 if (!smoothMesh && adaptPatchIDs_.empty())
859 FatalErrorIn("motionSmoother::scaleMesh(const bool")
860 << "You specified both no movement on the internal mesh points"
861 << " (smoothMesh = false)" << nl
862 << "and no movement on the patch (adaptPatchIDs is empty)" << nl
863 << "Hence nothing to adapt."
869 // Had a problem with patches moved non-synced. Check transformations.
870 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
872 Pout<< "Entering scaleMesh : coupled patches:" << endl;
873 forAll(patches, patchI)
875 if (patches[patchI].coupled())
877 const coupledPolyPatch& pp =
878 refCast<const coupledPolyPatch>(patches[patchI]);
880 Pout<< '\t' << patchI << '\t' << pp.name()
881 << " parallel:" << pp.parallel()
882 << " separated:" << pp.separated()
883 << " forwardT:" << pp.forwardT().size()
889 const scalar errorReduction =
890 readScalar(paramDict.lookup("errorReduction"));
891 const label nSmoothScale =
892 readLabel(paramDict.lookup("nSmoothScale"));
895 // Note: displacement_ should already be synced already from setDisplacement
896 // but just to make sure.
897 syncTools::syncPointList
902 vector::zero, // null value
903 false // no separation
906 // Set newPoints as old + scale*displacement
907 pointField newPoints;
909 // Create overall displacement with same b.c.s as displacement_
910 pointVectorField totalDisplacement
915 mesh_.time().timeName(),
921 scale_*displacement_,
922 displacement_.boundaryField().types()
924 correctBoundaryConditions(totalDisplacement);
928 Pout<< "scaleMesh : testing sync of totalDisplacement" << endl;
933 vector::zero, // null value
938 newPoints = oldPoints_ + totalDisplacement.internalField();
941 Info<< "Moving mesh using diplacement scaling :"
942 << " min:" << gMin(scale_.internalField())
943 << " max:" << gMax(scale_.internalField())
948 movePoints(newPoints);
950 // Check. Returns parallel number of incorrect faces.
951 faceSet wrongFaces(mesh_, "wrongFaces", mesh_.nFaces()/100+100);
952 checkMesh(false, mesh_, meshQualityDict, checkFaces, baffles, wrongFaces);
954 if (returnReduce(wrongFaces.size(), sumOp<label>()) <= nAllowableErrors)
960 // Sync across coupled faces by extending the set.
961 wrongFaces.sync(mesh_);
964 // if errorReduction is set to zero, extend wrongFaces
965 // to face-Cell-faces to ensure quick return to previously valid mesh
967 if (mag(errorReduction) < SMALL)
969 labelHashSet newWrongFaces(wrongFaces);
970 forAllConstIter(labelHashSet, wrongFaces, iter)
972 label own = mesh_.faceOwner()[iter.key()];
973 const cell& ownFaces = mesh_.cells()[own];
975 forAll(ownFaces, cfI)
977 newWrongFaces.insert(ownFaces[cfI]);
980 if (iter.key() < mesh_.nInternalFaces())
982 label nei = mesh_.faceNeighbour()[iter.key()];
983 const cell& neiFaces = mesh_.cells()[nei];
985 forAll(neiFaces, cfI)
987 newWrongFaces.insert(neiFaces[cfI]);
991 wrongFaces.transfer(newWrongFaces);
992 wrongFaces.sync(mesh_);
996 // Find out points used by wrong faces and scale displacement.
997 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
999 pointSet usedPoints(mesh_, "usedPoints", getPoints(wrongFaces));
1000 usedPoints.sync(mesh_);
1004 // Grow a few layers to determine
1005 // - points to be smoothed
1006 // - faces to be checked in next iteration
1007 PackedBoolList isAffectedPoint(mesh_.nPoints());
1008 getAffectedFacesAndPoints
1010 nSmoothScale, // smoothing iterations
1011 wrongFaces, // error faces
1018 Pout<< "Faces in error:" << wrongFaces.size()
1019 << " with points:" << usedPoints.size()
1023 if (adaptPatchIDs_.size())
1025 // Scale conflicting patch points
1026 scaleField(pp_.meshPoints(), usedPoints, errorReduction, scale_);
1030 // Scale conflicting internal points
1031 scaleField(usedPoints, errorReduction, scale_);
1034 for (label i = 0; i < nSmoothScale; i++)
1036 if (adaptPatchIDs_.size())
1038 // Smooth patch values
1039 pointScalarField oldScale(scale_);
1051 // Smooth internal values
1052 pointScalarField oldScale(scale_);
1053 minSmooth(isAffectedPoint, oldScale, scale_);
1058 syncTools::syncPointList
1063 -GREAT, // null value
1064 false // no separation
1070 Pout<< "scale_ after smoothing :"
1071 << " min:" << Foam::gMin(scale_)
1072 << " max:" << Foam::gMax(scale_)
1081 void Foam::motionSmoother::updateMesh()
1083 const pointBoundaryMesh& patches = pMesh_.boundary();
1085 // Check whether displacement has fixed value b.c. on adaptPatchID
1086 forAll(adaptPatchIDs_, i)
1088 label patchI = adaptPatchIDs_[i];
1092 !isA<fixedValuePointPatchVectorField>
1094 displacement_.boundaryField()[patchI]
1100 "motionSmoother::motionSmoother"
1101 ) << "Patch " << patches[patchI].name()
1102 << " has wrong boundary condition "
1103 << displacement_.boundaryField()[patchI].type()
1104 << " on field " << displacement_.name() << nl
1105 << "Only type allowed is "
1106 << fixedValuePointPatchVectorField::typeName
1107 << exit(FatalError);
1112 // Determine internal points. Note that for twoD there are no internal
1113 // points so we use the points of adaptPatchIDs instead
1115 twoDCorrector_.updateMesh();
1117 const labelList& meshPoints = pp_.meshPoints();
1119 forAll(meshPoints, i)
1121 isInternalPoint_.set(meshPoints[i], 0);
1124 // Calculate master edge addressing
1125 isMasterEdge_ = syncTools::getMasterEdges(mesh_);
1127 makePatchPatchAddressing();
1131 // Specialisation of applyCornerConstraints for scalars because
1132 // no constraint need be applied
1134 void Foam::motionSmoother::applyCornerConstraints<Foam::scalar>
1136 GeometricField<scalar, pointPatchField, pointMesh>& pf
1141 // ************************************************************************* //