smoothAlignmentSolver.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) 2013-2022 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 
26 #include "smoothAlignmentSolver.H"
27 
28 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
29 
30 template<class Triangulation, class Type>
31 Foam::tmp<Foam::Field<Type>> Foam::smoothAlignmentSolver::filterFarPoints
32 (
33  const Triangulation& mesh,
34  const Field<Type>& field
35 )
36 {
37  tmp<Field<Type>> tNewField(new Field<Type>(field.size()));
38  Field<Type>& newField = tNewField();
39 
40  label added = 0;
41  label count = 0;
42 
43  for
44  (
45  typename Triangulation::Finite_vertices_iterator vit =
46  mesh.finite_vertices_begin();
47  vit != mesh.finite_vertices_end();
48  ++vit
49  )
50  {
51  if (vit->real())
52  {
53  newField[added++] = field[count];
54  }
55 
56  count++;
57  }
58 
59  newField.resize(added);
60 
61  return tNewField;
62 }
63 
64 
65 template<class Triangulation>
67 Foam::smoothAlignmentSolver::buildReferredMap
68 (
69  const Triangulation& mesh,
70  labelList& indices
71 )
72 {
73  globalIndex globalIndexing(mesh.vertexCount());
74 
75  DynamicList<label> dynIndices(mesh.vertexCount()/10);
76 
77  for
78  (
79  typename Triangulation::Finite_vertices_iterator vit =
80  mesh.finite_vertices_begin();
81  vit != mesh.finite_vertices_end();
82  ++vit
83  )
84  {
85  if (vit->referred())
86  {
87  dynIndices.append
88  (
89  globalIndexing.toGlobal(vit->procIndex(), vit->index())
90  );
91  }
92  }
93 
94  indices.transfer(dynIndices);
95 
96  List<Map<label>> compactMap;
97  return autoPtr<distributionMap>
98  (
99  new distributionMap
100  (
101  globalIndexing,
102  indices,
103  compactMap
104  )
105  );
106 }
107 
108 
109 template<class Triangulation>
110 Foam::autoPtr<Foam::distributionMap> Foam::smoothAlignmentSolver::buildMap
111 (
112  const Triangulation& mesh,
113  labelListList& pointPoints
114 )
115 {
116  pointPoints.setSize(mesh.vertexCount());
117 
118  globalIndex globalIndexing(mesh.vertexCount());
119 
120  for
121  (
122  typename Triangulation::Finite_vertices_iterator vit =
123  mesh.finite_vertices_begin();
124  vit != mesh.finite_vertices_end();
125  ++vit
126  )
127  {
128  if (!vit->real())
129  {
130  continue;
131  }
132 
133  std::list<typename Triangulation::Vertex_handle> adjVerts;
134  mesh.finite_adjacent_vertices(vit, std::back_inserter(adjVerts));
135 
136  DynamicList<label> indices(adjVerts.size());
137 
138  for
139  (
140  typename std::list<typename Triangulation::Vertex_handle>::
141  const_iterator adjVertI = adjVerts.begin();
142  adjVertI != adjVerts.end();
143  ++adjVertI
144  )
145  {
146  typename Triangulation::Vertex_handle vh = *adjVertI;
147 
148  if (!vh->farPoint())
149  {
150  indices.append
151  (
152  globalIndexing.toGlobal(vh->procIndex(), vh->index())
153  );
154  }
155  }
156 
157  pointPoints[vit->index()].transfer(indices);
158  }
159 
160  List<Map<label>> compactMap;
161  return autoPtr<distributionMap>
162  (
163  new distributionMap
164  (
165  globalIndexing,
166  pointPoints,
167  compactMap
168  )
169  );
170 }
171 
172 
173 template<class Triangulation>
174 Foam::tmp<Foam::triadField> Foam::smoothAlignmentSolver::buildAlignmentField
175 (
176  const Triangulation& mesh
177 )
178 {
179  tmp<triadField> tAlignments
180  (
181  new triadField(mesh.vertexCount(), triad::unset)
182  );
183  triadField& alignments = tAlignments.ref();
184 
185  for
186  (
187  typename Triangulation::Finite_vertices_iterator vit =
188  mesh.finite_vertices_begin();
189  vit != mesh.finite_vertices_end();
190  ++vit
191  )
192  {
193  if (!vit->real())
194  {
195  continue;
196  }
197 
198  alignments[vit->index()] = vit->alignment();
199  }
200 
201  return tAlignments;
202 }
203 
204 
205 template<class Triangulation>
206 Foam::tmp<Foam::pointField> Foam::smoothAlignmentSolver::buildPointField
207 (
208  const Triangulation& mesh
209 )
210 {
211  tmp<pointField> tPoints
212  (
213  new pointField(mesh.vertexCount(), point(great, great, great))
214  );
215  pointField& points = tPoints.ref();
216 
217  for
218  (
219  typename Triangulation::Finite_vertices_iterator vit =
220  mesh.finite_vertices_begin();
221  vit != mesh.finite_vertices_end();
222  ++vit
223  )
224  {
225  if (!vit->real())
226  {
227  continue;
228  }
229 
230  points[vit->index()] = topoint(vit->point());
231  }
232 
233  return tPoints;
234 }
235 
236 
237 void Foam::smoothAlignmentSolver::applyBoundaryConditions
238 (
239  const triad& fixedAlignment,
240  triad& t
241 ) const
242 {
243  label nFixed = 0;
244 
245  forAll(fixedAlignment, dirI)
246  {
247  if (fixedAlignment.set(dirI))
248  {
249  nFixed++;
250  }
251  }
252 
253  if (nFixed == 1)
254  {
255  forAll(fixedAlignment, dirI)
256  {
257  if (fixedAlignment.set(dirI))
258  {
259  t.align(fixedAlignment[dirI]);
260  }
261  }
262  }
263  else if (nFixed == 2)
264  {
265  forAll(fixedAlignment, dirI)
266  {
267  if (fixedAlignment.set(dirI))
268  {
269  t[dirI] = fixedAlignment[dirI];
270  }
271  else
272  {
273  t[dirI] = triad::unset[dirI];
274  }
275  }
276 
277  t.orthogonalise();
278  }
279  else if (nFixed == 3)
280  {
281  forAll(fixedAlignment, dirI)
282  {
283  if (fixedAlignment.set(dirI))
284  {
285  t[dirI] = fixedAlignment[dirI];
286  }
287  }
288  }
289 }
290 
291 
292 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
293 
294 Foam::smoothAlignmentSolver::smoothAlignmentSolver(cellShapeControlMesh& mesh)
295 :
296  mesh_(mesh)
297 {}
298 
299 
300 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
301 
303 {}
304 
305 
306 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
307 
309 (
310  const label maxSmoothingIterations
311 )
312 {
313  scalar minResidual = 0;
314 
315  labelListList pointPoints;
316  autoPtr<distributionMap> meshDistributor = buildMap
317  (
318  mesh_,
319  pointPoints
320  );
321 
322  triadField alignments(buildAlignmentField(mesh_));
323  pointField points(buildPointField(mesh_));
324 
325  // Setup the sizes and alignments on each point
326  triadField fixedAlignments(mesh_.vertexCount(), triad::unset);
327 
328  for
329  (
330  CellSizeDelaunay::Finite_vertices_iterator vit =
331  mesh_.finite_vertices_begin();
332  vit != mesh_.finite_vertices_end();
333  ++vit
334  )
335  {
336  if (vit->real())
337  {
338  fixedAlignments[vit->index()] = vit->alignment();
339  }
340  }
341 
342  Info<< nl << "Smoothing alignments" << endl;
343 
344 
345  for (label iter = 0; iter < maxSmoothingIterations; iter++)
346  {
347  Info<< "Iteration " << iter;
348 
349  meshDistributor().distribute(points);
350  meshDistributor().distribute(fixedAlignments);
351  meshDistributor().distribute(alignments);
352 
353  scalar residual = 0;
354 
355  triadField triadAv(alignments.size(), triad::unset);
356 
357  forAll(pointPoints, pI)
358  {
359  const labelList& pPoints = pointPoints[pI];
360 
361  if (pPoints.empty())
362  {
363  continue;
364  }
365 
366  triad& newTriad = triadAv[pI];
367 
368  forAll(pPoints, adjPointi)
369  {
370  const label adjPointIndex = pPoints[adjPointi];
371 
372  scalar dist = mag(points[pI] - points[adjPointIndex]);
373 
374  triad tmpTriad = alignments[adjPointIndex];
375 
376  for (direction dir = 0; dir < 3; dir++)
377  {
378  if (tmpTriad.set(dir))
379  {
380  tmpTriad[dir] *= 1.0/(dist + small);
381  }
382  }
383 
384  newTriad += tmpTriad;
385  }
386  }
387 
388  // Update the alignment field
389  forAll(alignments, pI)
390  {
391  const triad& oldTriad = alignments[pI];
392  triad& newTriad = triadAv[pI];
393 
394  newTriad.normalise();
395  newTriad.orthogonalise();
396 
397  // Enforce the boundary conditions
398  const triad& fixedAlignment = fixedAlignments[pI];
399 
400  applyBoundaryConditions
401  (
402  fixedAlignment,
403  newTriad
404  );
405 
406  newTriad = newTriad.sortxyz();
407 
408  // Residual Calculation
409  for (direction dir = 0; dir < 3; ++dir)
410  {
411  if
412  (
413  newTriad.set(dir)
414  && oldTriad.set(dir)
415  && !fixedAlignment.set(dir)
416  )
417  {
418  residual += diff(oldTriad, newTriad);
419  }
420  }
421 
422  alignments[pI] = newTriad;
423  }
424 
425  reduce(residual, sumOp<scalar>());
426 
427  Info<< ", Residual = "
428  << residual
429  /returnReduce(points.size(), sumOp<label>())
430  << endl;
431 
432  if (iter > 0 && residual <= minResidual)
433  {
434  break;
435  }
436  }
437 
438  meshDistributor().distribute(alignments);
439 
440  for
441  (
442  CellSizeDelaunay::Finite_vertices_iterator vit =
443  mesh_.finite_vertices_begin();
444  vit != mesh_.finite_vertices_end();
445  ++vit
446  )
447  {
448  if (vit->real())
449  {
450  vit->alignment() = alignments[vit->index()];
451  }
452  }
453 
454  labelList referredPoints;
455  autoPtr<distributionMap> referredDistributor = buildReferredMap
456  (
457  mesh_,
458  referredPoints
459  );
460 
461  alignments.setSize(mesh_.vertexCount());
462  referredDistributor().distribute(alignments);
463 
464  label referredI = 0;
465  for
466  (
467  CellSizeDelaunay::Finite_vertices_iterator vit =
468  mesh_.finite_vertices_begin();
469  vit != mesh_.finite_vertices_end();
470  ++vit
471  )
472  {
473  if (vit->referred())
474  {
475  vit->alignment() = alignments[referredPoints[referredI++]];
476  }
477  }
478 }
479 
480 
481 // ************************************************************************* //
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
scalar diff(const triad &A, const triad &B)
Return a quantity of the difference between two triads.
Definition: triad.C:403
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
pointFromPoint topoint(const Point &P)
void smoothAlignments(const label maxSmoothingIterations)
Smooth the alignments on the mesh.
uint8_t direction
Definition: direction.H:45
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
label count(const ListType &l, typename ListType::const_reference x)
Count the number of occurrences of a value in a list.
void orthogonalise()
Orthogonalise this triad so that it is ortho-normal.
Definition: triad.C:108
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
const pointField & points
static const triad unset
Definition: triad.H:99
smoothAlignmentSolver(cellShapeControlMesh &mesh)
Construct null.
List< label > labelList
A List of labels.
Definition: labelList.H:56
Field< triad > triadField
Specialisation of Field<T> for triad.
Definition: triadField.H:49
static const char nl
Definition: Ostream.H:260
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
label vertexCount() const
Return the vertex count (the next unique vertex index)
vector point
Point is a vector.
Definition: point.H:41
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
A class for managing temporary objects.
Definition: PtrList.H:53
~smoothAlignmentSolver()
Destructor.