surfaceAlignedSBRStressFvMotionSolver.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2015 OpenFOAM Foundation
9  Copyright (C) 2015-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
31 #include "pointIndexHit.H"
32 #include "processorPolyPatch.H"
33 #include "fvmLaplacian.H"
34 #include "fvcDiv.H"
35 #include "surfaceInterpolate.H"
36 #include "unitConversion.H"
37 #include "motionDiffusivity.H"
38 #include "fvcSmooth.H"
39 #include "pointMVCWeight.H"
40 #include "dimensionedSymmTensor.H"
41 #include "quaternion.H"
42 #include "fvOptions.H"
43 
44 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 
46 namespace Foam
47 {
48  defineTypeNameAndDebug(surfaceAlignedSBRStressFvMotionSolver, 0);
49 
51  (
52  motionSolver,
53  surfaceAlignedSBRStressFvMotionSolver,
54  dictionary
55  );
56 }
57 
58 
59 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
60 
61 Foam::surfaceAlignedSBRStressFvMotionSolver::
62 surfaceAlignedSBRStressFvMotionSolver
63 (
64  const polyMesh& mesh,
65  const IOdictionary& dict
66 )
67 :
69  surfaceNames_(coeffDict().lookup("surfaces")),
70  surfaceMesh_(surfaceNames_.size()),
71  cellRot_
72  (
73  IOobject
74  (
75  "cellRot",
76  fvMesh_.time().timeName(),
77  fvMesh_,
78  IOobject::NO_READ,
79  IOobject::NO_WRITE
80  ),
81  fvMesh_,
83  ),
84  maxAng_(coeffDict().getOrDefault<scalar>("maxAng", 80)),
85  minAng_(coeffDict().getOrDefault<scalar>("minAng", 20)),
86  accFactor_(coeffDict().getOrDefault<scalar>("accFactor", 1)),
87  smoothFactor_(coeffDict().getOrDefault<scalar>("smoothFactor", 0.9)),
88  nNonOrthogonalCorr_(coeffDict().get<label>("nNonOrthogonalCorr")),
89  pointDisplacement_(pointDisplacement()),
90  sigmaD_
91  (
92  IOobject
93  (
94  "sigmaD",
95  fvMesh_.time().timeName(),
96  fvMesh_,
97  IOobject::READ_IF_PRESENT,
98  IOobject::NO_WRITE
99  ),
100  fvMesh_,
102  ),
103  minSigmaDiff_(coeffDict().getOrDefault<scalar>("minSigmaDiff", 1e-4))
104 {
105  forAll(surfaceNames_, i)
106  {
107  surfaceMesh_.set
108  (
109  i,
110  new triSurfaceMesh
111  (
112  IOobject
113  (
114  surfaceNames_[i],
115  mesh.time().constant(),
116  "triSurface",
117  mesh.time(),
120  )
121  )
122  );
123  }
124 }
125 
126 
127 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
128 
131 {}
132 
133 
134 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
135 
136 
137 void Foam::surfaceAlignedSBRStressFvMotionSolver::calculateCellRot()
138 {
139  cellRot_.primitiveFieldRef() = Zero;
140  pointDisplacement_.primitiveFieldRef() = Zero;
141 
142  // Find intersections
143  pointField start(fvMesh_.nInternalFaces());
144  pointField end(start.size());
145 
146  const vectorField& Cc = fvMesh_.cellCentres();
147  const polyBoundaryMesh& pbm = fvMesh_.boundaryMesh();
148 
149  for (label faceI = 0; faceI < fvMesh_.nInternalFaces(); faceI++)
150  {
151  start[faceI] = Cc[fvMesh_.faceOwner()[faceI]];
152  end[faceI] = Cc[fvMesh_.faceNeighbour()[faceI]];
153  }
154 
155  DynamicList<label> hitCells;
156 
157  forAll(surfaceMesh_, surfi)
158  {
159  List<pointIndexHit> hit(start.size());
160  surfaceMesh_[surfi].findLineAny(start, end, hit);
161 
162  labelField pointsCount(fvMesh_.nPoints(), 1);
163 
164  const vectorField& nf = surfaceMesh_[surfi].faceNormals();
165 
166  const vectorField& SfMesh = fvMesh_.faceAreas();
167 
168  const vectorField nSfMesh(SfMesh/mag(SfMesh));
169 
170  DynamicList<label> cellsHit;
171 
172  forAll(hit, facei)
173  {
174  if (hit[facei].hit())
175  {
176  label rotCellId(-1);
177  const vector& hitPoint = hit[facei].point();
178 
179  if (fvMesh_.isInternalFace(facei))
180  {
181  const point& ownCc = Cc[fvMesh_.faceOwner()[facei]];
182  const point& nbrCc = Cc[fvMesh_.faceNeighbour()[facei]];
183 
184  if (hitPoint.distSqr(ownCc) < hitPoint.distSqr(nbrCc))
185  {
186  rotCellId = fvMesh_.faceOwner()[facei];
187  }
188  else
189  {
190  rotCellId = fvMesh_.faceNeighbour()[facei];
191  }
192  }
193  else
194  {
195  label patchi = pbm.whichPatch(facei);
196  if (isA<processorPolyPatch>(pbm[patchi]))
197  {
198  const point& ownCc = Cc[fvMesh_.faceOwner()[facei]];
199 
200  const vector cCentreOne = ownCc - hitPoint;
201 
202  const vector nbrCc =
203  refCast<const processorPolyPatch>(pbm[patchi])
204  .neighbFaceCellCentres()[facei];
205 
206  const vector cCentreTwo = nbrCc - hitPoint;
207 
208  if (cCentreOne < cCentreTwo)
209  {
210  rotCellId = fvMesh_.faceOwner()[facei];
211  }
212  }
213  }
214 
215  // Note: faces on boundaries that get hit are not included as
216  // the pointDisplacement on boundaries is usually zero for
217  // this solver.
218 
219  // Search for closest direction on faces on mesh
220  // and surface normal.
221  if (rotCellId != -1)
222  {
223  const labelList& cFaces = fvMesh_.cells()[rotCellId];
224 
225  scalar cosMax(-GREAT);
226  label faceId(-1);
227  forAll(cFaces, k)
228  {
229  scalar tmp =
230  mag(nf[hit[facei].index()] & nSfMesh[cFaces[k]]);
231 
232  if (tmp > cosMax)
233  {
234  cosMax = tmp;
235  faceId = cFaces[k];
236  }
237  }
238  if
239  (
240  faceId != -1
241  &&
242  (
243  ::cos(degToRad(minAng_)) > cosMax
244  || cosMax > ::cos(degToRad(maxAng_))
245 
246  )
247  )
248  {
249  cellRot_[rotCellId] =
250  nSfMesh[faceId]^nf[hit[facei].index()];
251 
252  const scalar magRot = mag(cellRot_[rotCellId]);
253 
254  if (magRot > 0)
255  {
256  const scalar theta = ::asin(magRot);
257  quaternion q(cellRot_[rotCellId]/magRot, theta);
258  const tensor R = q.R();
259  const labelList& cPoints =
260  fvMesh_.cellPoints(rotCellId);
261 
262  forAll(cPoints, j)
263  {
264  const label pointId = cPoints[j];
265 
266  pointsCount[pointId]++;
267 
268  const vector pointPos =
269  fvMesh_.points()[pointId];
270 
271  pointDisplacement_[pointId] +=
272  (R & (pointPos - hitPoint))
273  - (pointPos - hitPoint);
274  }
275  }
276  }
277  }
278  }
279  }
280 
281  vectorField& pd = pointDisplacement_.primitiveFieldRef();
282  forAll(pd, pointi)
283  {
284  vector& point = pd[pointi];
285  point /= pointsCount[pointi];
286  }
287  }
288 }
289 
290 
292 {
293  // The points have moved so before interpolation update
294  // the motionSolver accordingly
295  this->movePoints(fvMesh_.points());
296 
297  volVectorField& cellDisp = cellDisplacement();
298 
299  diffusivity().correct();
300 
301  // Calculate rotations on surface intersection
302  calculateCellRot();
303 
304  auto tUd = volVectorField::New
305  (
306  "Ud",
308  fvMesh_,
310  cellMotionBoundaryTypes<vector>
311  (
312  pointDisplacement().boundaryField()
313  )
314  );
315  auto& Ud = tUd.ref();
316 
317  const vectorList& C = fvMesh_.C();
318  forAll(Ud, i)
319  {
320  pointMVCWeight pointInter(fvMesh_, C[i], i);
321  Ud[i] = pointInter.interpolate(pointDisplacement_);
322  }
323 
324  volScalarField Udx(Ud.component(vector::X));
325  fvc::smooth(Udx, smoothFactor_);
326 
327  volScalarField Udy(Ud.component(vector::Y));
328  fvc::smooth(Udy, smoothFactor_);
329 
330  volScalarField Udz(Ud.component(vector::Z));
331  fvc::smooth(Udz, smoothFactor_);
332 
333  Ud.replace(vector::X, Udx);
334  Ud.replace(vector::Y, Udy);
335  Ud.replace(vector::Z, Udz);
336 
337  const volTensorField gradD("gradD", fvc::grad(Ud));
338 
339  auto tmu = volScalarField::New
340  (
341  "mu",
343  fvMesh_,
345  );
346  auto& mu = tmu.ref();
347 
348  const scalarList& V = fvMesh_.V();
349  mu.primitiveFieldRef() = (1.0/V);
350 
351  const volScalarField lambda(-mu);
352 
353  const volSymmTensorField newSigmaD
354  (
355  mu*twoSymm(gradD) + (lambda*I)*tr(gradD)
356  );
357 
358  const volSymmTensorField magNewSigmaD(sigmaD_ + accFactor_*newSigmaD);
359 
360  const scalar diffSigmaD =
361  gSum(mag(sigmaD_.oldTime().primitiveField()))
362  - gSum(mag(magNewSigmaD.primitiveField()));
363 
364  if (mag(diffSigmaD) > minSigmaDiff_)
365  {
366  sigmaD_ = magNewSigmaD;
367  }
368 
369  const dimensionedScalar oneViscosity("viscosity", dimViscosity, 1.0);
370 
371  const surfaceScalarField Df(oneViscosity*diffusivity().operator()());
372 
373  pointDisplacement_.boundaryFieldRef().updateCoeffs();
374 
375  fv::options& fvOptions(fv::options::New(fvMesh_));
376 
377  const volTensorField gradCd(fvc::grad(cellDisp));
378 
379  for (int nonOrth=0; nonOrth<=nNonOrthogonalCorr_; nonOrth++)
380  {
381  fvVectorMatrix DEqn
382  (
384  (
385  2*Df*fvc::interpolate(mu),
386  cellDisp,
387  "laplacian(diffusivity,cellDisplacement)"
388  )
389  + fvc::div
390  (
391  Df*
392  (
394  * (fvMesh_.Sf() & fvc::interpolate(gradCd.T() - gradCd))
395  - fvc::interpolate(lambda)*fvMesh_.Sf()
396  * fvc::interpolate(tr(gradCd))
397  )
398  )
399  ==
400  oneViscosity*fvc::div(sigmaD_)
401  + fvOptions(cellDisp)
402  );
403 
404  fvOptions.constrain(DEqn);
405 
406  // Note: solve uncoupled
407  DEqn.solveSegregatedOrCoupled();
408 
409  fvOptions.correct(cellDisp);
410  }
411 }
412 
413 
414 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
void correct(GeometricField< Type, PatchField, GeoMesh > &field)
Apply correction to field.
GeometricField< symmTensor, fvPatchField, volMesh > volSymmTensorField
Definition: volFieldsFwd.H:84
const polyBoundaryMesh & pbm
dictionary dict
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:48
tmp< GeometricField< typename outerProduct< vector, Type >::type, fvPatchField, volMesh >> grad(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcGrad.C:47
label faceId(-1)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
GeometricField< tensor, fvPatchField, volMesh > volTensorField
Definition: volFieldsFwd.H:88
tmp< GeometricField< Type, fvPatchField, volMesh > > div(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
Definition: fvcDiv.C:42
Unit conversion functions.
const dimensionSet dimViscosity
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Tensor< scalar > tensor
Definition: symmTensor.H:57
Calculate the matrix for the laplacian of the field.
label k
Boltzmann constant.
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
List< vector > vectorList
List of vector.
Definition: vectorList.H:32
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
Lookup type of boundary radiation properties.
Definition: lookup.H:57
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:76
dimensionedScalar asin(const dimensionedScalar &ds)
Macros for easy insertion into run-time selection tables.
dimensionedSymmTensor twoSymm(const dimensionedSymmTensor &dt)
void smooth(volScalarField &field, const scalar coeff)
Definition: fvcSmooth.C:37
fv::options & fvOptions
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
IOoject and searching on triSurface.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:72
word timeName
Definition: getTimeIndex.H:3
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
dynamicFvMesh & mesh
Type gSum(const FieldField< Field, Type > &f)
dimensionedScalar cos(const dimensionedScalar &ds)
static const Identity< scalar > I
Definition: Identity.H:100
dimensionedScalar lambda("lambda", dimTime/sqr(dimLength), laminarTransport)
dimensionedScalar tr(const dimensionedSphericalTensor &dt)
const fvMesh & mesh() const
Return reference to the fvMesh to be moved.
Vector< scalar > vector
Definition: vector.H:57
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
static tmp< GeometricField< vector, fvPatchField, volMesh > > New(const word &name, IOobjectOption::registerOption regOpt, const Mesh &mesh, const dimensionSet &dims, const word &patchFieldType=fvPatchField< vector >::calculatedType())
Return tmp field (NO_READ, NO_WRITE) from name, mesh, dimensions and patch type. [Takes current timeN...
Calculate the divergence of the given field.
void constrain(fvMatrix< Type > &eqn)
Apply constraints to equation.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:112
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
defineTypeNameAndDebug(combustionModel, 0)
volScalarField & C
static tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > interpolate(const GeometricField< Type, fvPatchField, volMesh > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
const dimensionedScalar mu
Atomic mass unit.
vector point
Point is a vector.
Definition: point.H:37
#define R(A, B, C, D, E, F, K, M)
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
tmp< fvMatrix< Type > > laplacian(const GeometricField< Type, fvPatchField, volMesh > &vf, const word &name)
Definition: fvmLaplacian.C:41
PtrList< volScalarField > & Y
fvMatrix< vector > fvVectorMatrix
Definition: fvMatricesFwd.H:40
Mesh motion solver for an fvMesh. Based on solving the cell-centre solid-body rotation stress equatio...
Field< vector > vectorField
Specialisation of Field<T> for vector.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
List< label > labelList
A List of labels.
Definition: List.H:62
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
static options & New(const fvMesh &mesh)
Construct fvOptions and register to database if not present.
Definition: fvOptions.C:96
constexpr scalar degToRad(const scalar deg) noexcept
Conversion from degrees to radians.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
Provides functions smooth spread and sweep which use the FaceCellWave algorithm to smooth and redistr...
Do not request registration (bool: false)
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127