displacementLayeredMotionMotionSolver.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
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.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
29 #include "pointFields.H"
30 #include "PointEdgeWave.H"
31 #include "syncTools.H"
32 #include "Table.H"
33 #include "pointConstraints.H"
34 #include "polyTopoChangeMap.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
41 
43  (
47  );
48 }
49 
50 
51 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
52 
53 void Foam::displacementLayeredMotionMotionSolver::calcZoneMask
54 (
55  const label cellZoneI,
56  PackedBoolList& isZonePoint,
57  PackedBoolList& isZoneEdge
58 ) const
59 {
60  if (cellZoneI == -1)
61  {
62  isZonePoint.setSize(mesh().nPoints());
63  isZonePoint = 1;
64 
65  isZoneEdge.setSize(mesh().nEdges());
66  isZoneEdge = 1;
67  }
68  else
69  {
70  const cellZone& cz = mesh().cellZones()[cellZoneI];
71 
72  label nPoints = 0;
73  forAll(cz, i)
74  {
75  const labelList& cPoints = mesh().cellPoints(cz[i]);
76  forAll(cPoints, cPointi)
77  {
78  if (!isZonePoint[cPoints[cPointi]])
79  {
80  isZonePoint[cPoints[cPointi]] = 1;
81  nPoints++;
82  }
83  }
84  }
86  (
87  mesh(),
88  isZonePoint,
89  orEqOp<unsigned int>(),
90  0
91  );
92 
93 
94  // Mark edge inside cellZone
95  label nEdges = 0;
96  forAll(cz, i)
97  {
98  const labelList& cEdges = mesh().cellEdges(cz[i]);
99  forAll(cEdges, cEdgeI)
100  {
101  if (!isZoneEdge[cEdges[cEdgeI]])
102  {
103  isZoneEdge[cEdges[cEdgeI]] = 1;
104  nEdges++;
105  }
106  }
107  }
109  (
110  mesh(),
111  isZoneEdge,
112  orEqOp<unsigned int>(),
113  0
114  );
115 
116  if (debug)
117  {
118  Info<< "On cellZone " << cz.name()
119  << " marked " << returnReduce(nPoints, sumOp<label>())
120  << " points and " << returnReduce(nEdges, sumOp<label>())
121  << " edges." << endl;
122  }
123  }
124 }
125 
126 
127 // Find distance to starting point
128 void Foam::displacementLayeredMotionMotionSolver::walkStructured
129 (
130  const label cellZoneI,
131  const PackedBoolList& isZonePoint,
132  const PackedBoolList& isZoneEdge,
133  const labelList& seedPoints,
134  const vectorField& seedData,
135  scalarField& distance,
136  vectorField& data
137 ) const
138 {
139  List<pointEdgeStructuredWalk> seedInfo(seedPoints.size());
140 
141  forAll(seedPoints, i)
142  {
143  seedInfo[i] = pointEdgeStructuredWalk
144  (
145  points0()[seedPoints[i]], // location of data
146  points0()[seedPoints[i]], // previous location
147  0.0,
148  seedData[i]
149  );
150  }
151 
152  // Current info on points
153  List<pointEdgeStructuredWalk> allPointInfo(mesh().nPoints());
154 
155  // Mark points inside cellZone.
156  // Note that we use points0, not mesh.points()
157  // so as not to accumulate errors.
158  forAll(isZonePoint, pointi)
159  {
160  if (isZonePoint[pointi])
161  {
162  allPointInfo[pointi] = pointEdgeStructuredWalk
163  (
164  points0()[pointi], // location of data
165  vector::max, // not valid
166  0.0,
167  Zero // passive data
168  );
169  }
170  }
171 
172  // Current info on edges
173  List<pointEdgeStructuredWalk> allEdgeInfo(mesh().nEdges());
174 
175  // Mark edges inside cellZone
176  forAll(isZoneEdge, edgeI)
177  {
178  if (isZoneEdge[edgeI])
179  {
180  allEdgeInfo[edgeI] = pointEdgeStructuredWalk
181  (
182  mesh().edges()[edgeI].centre(points0()), // location of data
183  vector::max, // not valid
184  0.0,
185  Zero
186  );
187  }
188  }
189 
190  // Walk
191  PointEdgeWave<pointEdgeStructuredWalk> wallCalc
192  (
193  mesh(),
194  seedPoints,
195  seedInfo,
196 
197  allPointInfo,
198  allEdgeInfo,
199  mesh().globalData().nTotalPoints() // max iterations
200  );
201 
202  // Extract distance and passive data
203  forAll(allPointInfo, pointi)
204  {
205  if (isZonePoint[pointi])
206  {
207  distance[pointi] = allPointInfo[pointi].dist();
208  data[pointi] = allPointInfo[pointi].data();
209  }
210  }
211 }
212 
213 
214 // Evaluate faceZone patch
216 Foam::displacementLayeredMotionMotionSolver::faceZoneEvaluate
217 (
218  const faceZone& fz,
219  const labelList& meshPoints,
220  const dictionary& dict,
221  const PtrList<pointVectorField>& patchDisp,
222  const label patchi
223 ) const
224 {
225  tmp<vectorField> tfld(new vectorField(meshPoints.size()));
226  vectorField& fld = tfld.ref();
227 
228  const word type(dict.lookup("type"));
229 
230  if (type == "fixedValue")
231  {
232  fld = vectorField("value", dimLength, dict, meshPoints.size());
233  }
234  else if (type == "timeVaryingUniformFixedValue")
235  {
236  fld =
237  Function1s::Table<vector>
238  (
239  word::null,
240  mesh().time().userUnits(),
241  dimLength,
242  dict
243  ).value(mesh().time().value());
244  }
245  else if (type == "slip")
246  {
247  if ((patchi % 2) != 1)
248  {
250  << "FaceZone:" << fz.name()
251  << exit(FatalError);
252  }
253 
254  // Use field set by previous bc
255  fld = vectorField(patchDisp[patchi - 1], meshPoints);
256  }
257  else if (type == "follow")
258  {
259  // Only on boundary faces - follow boundary conditions
260  fld = vectorField(pointDisplacement_, meshPoints);
261  }
262  else if (type == "uniformFollow")
263  {
264  // Reads name of name of patch. Then get average point displacement on
265  // patch. That becomes the value of fld.
266  const word patchName(dict.lookup("patch"));
267  label patchID = mesh().boundaryMesh().findIndex(patchName);
268  pointField pdf
269  (
270  pointDisplacement_.boundaryField()[patchID].patchInternalField()
271  );
272  fld = gAverage(pdf);
273  }
274  else
275  {
277  << "Unknown faceZonePatch type " << type << " for faceZone "
278  << fz.name() << exit(FatalError);
279  }
280  return tfld;
281 }
282 
283 
284 void Foam::displacementLayeredMotionMotionSolver::cellZoneSolve
285 (
286  const label cellZoneI,
287  const dictionary& zoneDict
288 )
289 {
290  PackedBoolList isZonePoint(mesh().nPoints());
291  PackedBoolList isZoneEdge(mesh().nEdges());
292  calcZoneMask(cellZoneI, isZonePoint, isZoneEdge);
293 
294  const dictionary& patchesDict = zoneDict.subDict("boundaryField");
295 
296  if (patchesDict.size() != 2)
297  {
299  << "Two faceZones (patches) must be specified per cellZone. "
300  << " cellZone:" << cellZoneI
301  << " patches:" << patchesDict.toc()
302  << exit(FatalError);
303  }
304 
305  PtrList<scalarField> patchDist(patchesDict.size());
306  PtrList<pointVectorField> patchDisp(patchesDict.size());
307 
308  // Allocate the fields
309  label patchi = 0;
310  forAllConstIter(dictionary, patchesDict, patchiter)
311  {
312  const word& faceZoneName = patchiter().keyword();
313  label zoneI = mesh().faceZones().findIndex(faceZoneName);
314  if (zoneI == -1)
315  {
317  << "Cannot find faceZone " << faceZoneName
318  << endl << "Valid zones are " << mesh().faceZones().toc()
319  << exit(FatalError);
320  }
321 
322  // Determine the points of the faceZone within the cellZone
323  const faceZone& fz = mesh().faceZones()[zoneI];
324 
325  patchDist.set(patchi, new scalarField(mesh().nPoints()));
326  patchDisp.set
327  (
328  patchi,
329  new pointVectorField
330  (
331  IOobject
332  (
333  mesh().cellZones()[cellZoneI].name() + "_" + fz.name(),
334  mesh().time().name(),
335  mesh(),
338  false
339  ),
340  pointDisplacement_ // to inherit the boundary conditions
341  )
342  );
343 
344  patchi++;
345  }
346 
347 
348 
349  // 'correctBoundaryConditions'
350  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
351  // Loops over all the faceZones and walks their boundary values
352 
353  // Make sure we can pick up bc values from field
354  pointDisplacement_.correctBoundaryConditions();
355 
356  patchi = 0;
357  forAllConstIter(dictionary, patchesDict, patchiter)
358  {
359  const word& faceZoneName = patchiter().keyword();
360  const dictionary& faceZoneDict = patchiter().dict();
361 
362  // Determine the points of the faceZone within the cellZone
363  const faceZone& fz = mesh().faceZones()[faceZoneName];
364  const labelList& fzMeshPoints = fz.patch().meshPoints();
365  DynamicList<label> meshPoints(fzMeshPoints.size());
366  forAll(fzMeshPoints, i)
367  {
368  if (isZonePoint[fzMeshPoints[i]])
369  {
370  meshPoints.append(fzMeshPoints[i]);
371  }
372  }
373 
374  // Get initial value for all the faceZone points
375  tmp<vectorField> tseed = faceZoneEvaluate
376  (
377  fz,
378  meshPoints,
379  faceZoneDict,
380  patchDisp,
381  patchi
382  );
383 
384  if (debug)
385  {
386  Info<< "For cellZone:" << cellZoneI
387  << " for faceZone:" << fz.name()
388  << " nPoints:" << tseed().size()
389  << " have patchField:"
390  << " max:" << gMax(tseed())
391  << " min:" << gMin(tseed())
392  << " avg:" << gAverage(tseed())
393  << endl;
394  }
395 
396  // Set distance and transported value
397  walkStructured
398  (
399  cellZoneI,
400  isZonePoint,
401  isZoneEdge,
402 
403  meshPoints,
404  tseed,
405  patchDist[patchi],
406  patchDisp[patchi]
407  );
408 
409  // Implement real bc.
410  patchDisp[patchi].correctBoundaryConditions();
411 
412  patchi++;
413  }
414 
415 
416  // Solve
417  // ~~~~~
418 
419  if (debug)
420  {
421  // Normalised distance
422  pointScalarField distance
423  (
424  IOobject
425  (
426  mesh().cellZones()[cellZoneI].name() + ":distance",
427  mesh().time().name(),
428  mesh(),
431  false
432  ),
433  pointMesh::New(mesh()),
435  );
436 
437  forAll(distance, pointi)
438  {
439  scalar d1 = patchDist[0][pointi];
440  scalar d2 = patchDist[1][pointi];
441  if (d1 + d2 > small)
442  {
443  scalar s = d1/(d1 + d2);
444  distance[pointi] = s;
445  }
446  }
447 
448  Info<< "Writing " << pointScalarField::typeName
449  << distance.name() << " to "
450  << mesh().time().name() << endl;
451  distance.write();
452  }
453 
454 
455  const word interpolationScheme = zoneDict.lookup("interpolationScheme");
456 
457  if (interpolationScheme == "oneSided")
458  {
459  forAll(pointDisplacement_, pointi)
460  {
461  if (isZonePoint[pointi])
462  {
463  pointDisplacement_[pointi] = patchDisp[0][pointi];
464  }
465  }
466  }
467  else if (interpolationScheme == "linear")
468  {
469  forAll(pointDisplacement_, pointi)
470  {
471  if (isZonePoint[pointi])
472  {
473  scalar d1 = patchDist[0][pointi];
474  scalar d2 = patchDist[1][pointi];
475  scalar s = d1/(d1 + d2 + vSmall);
476 
477  const vector& pd1 = patchDisp[0][pointi];
478  const vector& pd2 = patchDisp[1][pointi];
479 
480  pointDisplacement_[pointi] = (1 - s)*pd1 + s*pd2;
481  }
482  }
483  }
484  else
485  {
487  << "Invalid interpolationScheme: " << interpolationScheme
488  << ". Valid schemes are 'oneSided' and 'linear'"
489  << exit(FatalError);
490  }
491 }
492 
493 
494 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
495 
498 (
499  const word& name,
500  const polyMesh& mesh,
501  const dictionary& dict
502 )
503 :
504  displacementMotionSolver(name, mesh, dict, typeName)
505 {}
506 
507 
508 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
509 
512 {}
513 
514 
515 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
516 
519 {
520  tmp<pointField> tcurPoints
521  (
522  points0() + pointDisplacement_.primitiveField()
523  );
524 
525  return tcurPoints;
526 }
527 
528 
530 {
531  // The points have moved so before interpolation update the motionSolver
532  movePoints(mesh().points());
533 
534  // Apply boundary conditions
535  pointDisplacement_.boundaryFieldRef().updateCoeffs();
536 
537  // Solve motion on all regions (=cellZones)
538  const dictionary& regionDicts = coeffDict().subDict("regions");
539  forAllConstIter(dictionary, regionDicts, regionIter)
540  {
541  const word& cellZoneName = regionIter().keyword();
542  const dictionary& regionDict = regionIter().dict();
543 
544  label zoneI = mesh().cellZones().findIndex(cellZoneName);
545 
546  Info<< "solving for zone: " << cellZoneName << endl;
547 
548  if (zoneI == -1)
549  {
551  << "Cannot find cellZone " << cellZoneName
552  << endl << "Valid zones are " << mesh().cellZones().toc()
553  << exit(FatalError);
554  }
555 
556  cellZoneSolve(zoneI, regionDict);
557  }
558 
559  // Update pointDisplacement for solved values
560  const pointConstraints& pcs =
561  pointConstraints::New(pointDisplacement_.mesh());
562  pcs.constrainDisplacement(pointDisplacement_, false);
563 }
564 
565 
567 (
568  const polyTopoChangeMap& map
569 )
570 {
572  << "Probably inconsistent with points0MotionSolver" << nl
573  << " Needs to be updated and tested."
574  << exit(FatalError);
575 
577 
578  const vectorField displacement(this->newPoints() - points0_);
579 
580  forAll(points0_, pointi)
581  {
582  const label oldPointi = map.pointMap()[pointi];
583 
584  if (oldPointi >= 0)
585  {
586  label masterPointi = map.reversePointMap()[oldPointi];
587 
588  if ((masterPointi != pointi))
589  {
590  // newly inserted point in this cellZone
591 
592  // need to set point0 so that it represents the position that
593  // it would have had if it had existed for all time
594  points0_[pointi] -= displacement[pointi];
595  }
596  }
597  }
598 }
599 
600 
601 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
Macros for easy insertion into run-time selection tables.
static pointMesh & New(const word &name, const polyMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
static const char *const typeName
Definition: Field.H:106
virtual Ostream & write(const char)=0
Write character.
static const Form max
Definition: VectorSpace.H:120
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:710
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:843
Mesh motion solver for an (multi-block) extruded fvMesh. Gets given the structure of the mesh blocks ...
virtual tmp< pointField > curPoints() const
Return point location obtained from the current motion field.
displacementLayeredMotionMotionSolver(const word &name, const polyMesh &, const dictionary &)
Construct from polyMesh and dictionary.
virtual void topoChange(const polyTopoChangeMap &)
Update topology.
Virtual base class for displacement motion solver.
Virtual base class for mesh motion solver.
Definition: motionSolver.H:57
const polyMesh & mesh() const
Return reference to mesh.
Definition: motionSolver.H:137
Application of (multi-)patch point constraints.
void constrainDisplacement(pointVectorField &displacement, const bool overrideValue=false) const
Apply boundary conditions (single-patch constraints),.
virtual void topoChange(const polyTopoChangeMap &)
Update local data for topology changes.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const cellZoneList & cellZones() const
Return cell zones.
Definition: polyMesh.H:452
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reversePointMap() const
Reverse point map.
const labelList & pointMap() const
Old point map.
const labelListList & cellEdges() const
const labelListList & cellPoints() const
static void syncPointList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh points.
static void syncEdgeList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh edges.
A class for managing temporary objects.
Definition: tmp.H:55
A class for handling words, derived from string.
Definition: word.H:62
static const word null
An empty word.
Definition: word.H:77
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
const pointField & points
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
List< label > labelList
A List of labels.
Definition: labelList.H:56
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
messageStream Info
const dimensionSet dimLength
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
PointField< scalar > pointScalarField
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
defineTypeNameAndDebug(combustionModel, 0)
PointField< vector > pointVectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Type gAverage(const FieldField< Field, Type > &f)
error FatalError
Type gMin(const FieldField< Field, Type > &f)
static const char nl
Definition: Ostream.H:266
Type gMax(const FieldField< Field, Type > &f)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
dictionary dict