projectFace.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) 2016 OpenFOAM Foundation
9  Copyright (C) 2019-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 
29 #include "projectFace.H"
30 #include "unitConversion.H"
32 #include "blockDescriptor.H"
33 #include "OBJstream.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40 namespace blockFaces
41 {
44 }
45 }
46 
47 
48 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 
50 const Foam::searchableSurface& Foam::blockFaces::projectFace::lookupSurface
51 (
52  const searchableSurfaces& geometry,
53  Istream& is
54 ) const
55 {
56  const word name(is);
57 
58  for (const searchableSurface& geom : geometry)
59  {
60  if (geom.name() == name)
61  {
62  return geom;
63  }
64  }
65 
67  << "Cannot find surface " << name << " in geometry"
68  << exit(FatalIOError);
69 
70  return geometry[0];
71 }
72 
73 
74 Foam::label Foam::blockFaces::projectFace::index
75 (
76  const labelPair& n,
77  const labelPair& coord
78 )
79 {
80  return coord.first() + coord.second()*n.first();
81 }
82 
83 
84 void Foam::blockFaces::projectFace::calcLambdas
85 (
86  const labelPair& n,
87  const pointField& points,
88  scalarField& lambdaI,
89  scalarField& lambdaJ
90 ) const
91 {
92  lambdaI.setSize(points.size());
93  lambdaI = 0.0;
94  lambdaJ.setSize(points.size());
95  lambdaJ = 0.0;
96 
97  for (label i = 1; i < n.first(); i++)
98  {
99  for (label j = 1; j < n.second(); j++)
100  {
101  label ij = index(n, labelPair(i, j));
102  label iMin1j = index(n, labelPair(i-1, j));
103  lambdaI[ij] = lambdaI[iMin1j] + mag(points[ij]-points[iMin1j]);
104 
105  label ijMin1 = index(n, labelPair(i, j-1));
106  lambdaJ[ij] = lambdaJ[ijMin1] + mag(points[ij]-points[ijMin1]);
107  }
108  }
109 
110  for (label i = 1; i < n.first(); i++)
111  {
112  label ijLast = index(n, labelPair(i, n.second()-1));
113  for (label j = 1; j < n.second(); j++)
114  {
115  label ij = index(n, labelPair(i, j));
116  lambdaJ[ij] /= lambdaJ[ijLast];
117  }
118  }
119  for (label j = 1; j < n.second(); j++)
120  {
121  label iLastj = index(n, labelPair(n.first()-1, j));
122  for (label i = 1; i < n.first(); i++)
123  {
124  label ij = index(n, labelPair(i, j));
125  lambdaI[ij] /= lambdaI[iLastj];
126  }
127  }
128 }
129 
130 
131 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
132 
133 Foam::blockFaces::projectFace::projectFace
134 (
135  const dictionary& dict,
136  const label index,
137  const searchableSurfaces& geometry,
138  Istream& is
139 )
140 :
141  blockFace(dict, index, is),
142  surface_(lookupSurface(geometry, is))
143 {}
144 
145 
146 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
147 
149 (
150  const blockDescriptor& desc,
151  const label blockFacei,
153 ) const
154 {
155  // For debugging to tag the output
156  static label fIter = 0;
157 
158  autoPtr<OBJstream> debugStr;
159  if (debug)
160  {
161  debugStr.reset
162  (
163  new OBJstream("projectFace_" + Foam::name(fIter++) + ".obj")
164  );
165  Info<< "Face:" << blockFacei << " on block:" << desc.blockShape()
166  << " with verts:" << desc.vertices()
167  << " writing lines from start points"
168  << " to projected points to " << debugStr().name() << endl;
169  }
170 
171 
172  // Find out range of vertices in face
173  labelPair n(-1, -1);
174  switch (blockFacei)
175  {
176  case 0:
177  case 1:
178  {
179  n.first() = desc.density().y() + 1;
180  n.second() = desc.density().z() + 1;
181  }
182  break;
183 
184  case 2:
185  case 3:
186  {
187  n.first() = desc.density().x() + 1;
188  n.second() = desc.density().z() + 1;
189  }
190  break;
191 
192  case 4:
193  case 5:
194  {
195  n.first() = desc.density().x() + 1;
196  n.second() = desc.density().y() + 1;
197  }
198  break;
199  }
200 
201 
202  // Calculate initial normalised edge lengths (= u,v coordinates)
203  scalarField lambdaI(points.size(), Zero);
204  scalarField lambdaJ(points.size(), Zero);
205  calcLambdas(n, points, lambdaI, lambdaJ);
206 
207 
208  // Upper limit for number of iterations
209  const label maxIter = 10;
210  // Residual tolerance
211  const scalar relTol = 0.1;
212 
213  scalar initialResidual = 0.0;
214  scalar iResidual = 0.0;
215  scalar jResidual = 0.0;
216 
217  for (label iter = 0; iter < maxIter; iter++)
218  {
219  // Do projection
220  {
221  List<pointIndexHit> hits;
222  scalarField nearestDistSqr
223  (
224  points.size(),
225  magSqr(points[0] - points[points.size()-1])
226  );
227  surface_.findNearest(points, nearestDistSqr, hits);
228 
229  forAll(hits, i)
230  {
231  if (hits[i].hit())
232  {
233  if (debugStr)
234  {
235  debugStr().writeLine(points[i], hits[i].point());
236  }
237  points[i] = hits[i].point();
238  }
239  }
240  }
241 
242  if (debug)
243  {
244  Pout<< "Iter:" << iter << " initialResidual:" << initialResidual
245  << " iResidual+jResidual:" << iResidual+jResidual << endl;
246  }
247 
248 
249  if
250  (
251  iter > 0
252  && (
253  initialResidual < ROOTVSMALL
254  || ((iResidual+jResidual)/initialResidual < relTol)
255  )
256  )
257  {
258  break;
259  }
260 
261 
262  // Predict along i
263  vectorField residual(points.size(), Zero);
264 
265  // Work arrays for interpolation
266  labelList indices;
267  scalarField weights;
268  for (label j = 1; j < n.second()-1; j++)
269  {
270  // Calculate actual lamdba along constant j line
271  scalarField projLambdas(n.first());
272  projLambdas[0] = 0.0;
273  for (label i = 1; i < n.first(); i++)
274  {
275  label ij = index(n, labelPair(i, j));
276  label iMin1j = index(n, labelPair(i-1, j));
277  projLambdas[i] =
278  projLambdas[i-1]
279  +mag(points[ij]-points[iMin1j]);
280  }
281  projLambdas /= projLambdas.last();
282 
283  linearInterpolationWeights interpolator(projLambdas);
284 
285  for (label i = 1; i < n.first()-1; i++)
286  {
287  label ij = index(n, labelPair(i, j));
288 
289  interpolator.valueWeights(lambdaI[ij], indices, weights);
290 
291  point predicted(Zero);
292  forAll(indices, indexi)
293  {
294  label ptIndex = index(n, labelPair(indices[indexi], j));
295  predicted += weights[indexi]*points[ptIndex];
296  }
297  residual[ij] = predicted-points[ij];
298  }
299  }
300 
301  if (debugStr)
302  {
303  forAll(points, i)
304  {
305  const point predicted(points[i] + residual[i]);
306  debugStr().writeLine(points[i], predicted);
307  }
308  }
309 
310  iResidual = sum(mag(residual));
311 
312  // Update points before doing j. Note: is this needed? Complicates
313  // residual checking.
314  points += residual;
315 
316 
317  // Predict along j
318  residual = vector::zero;
319  for (label i = 1; i < n.first()-1; i++)
320  {
321  // Calculate actual lamdba along constant i line
322  scalarField projLambdas(n.second());
323  projLambdas[0] = 0.0;
324  for (label j = 1; j < n.second(); j++)
325  {
326  label ij = index(n, labelPair(i, j));
327  label ijMin1 = index(n, labelPair(i, j-1));
328  projLambdas[j] =
329  projLambdas[j-1]
330  +mag(points[ij]-points[ijMin1]);
331  }
332 
333  projLambdas /= projLambdas.last();
334 
335  linearInterpolationWeights interpolator(projLambdas);
336 
337  for (label j = 1; j < n.second()-1; j++)
338  {
339  label ij = index(n, labelPair(i, j));
340 
341  interpolator.valueWeights(lambdaJ[ij], indices, weights);
342 
343  point predicted(Zero);
344  forAll(indices, indexi)
345  {
346  label ptIndex = index(n, labelPair(i, indices[indexi]));
347  predicted += weights[indexi]*points[ptIndex];
348  }
349  residual[ij] = predicted-points[ij];
350  }
351  }
352 
353  if (debugStr)
354  {
355  forAll(points, i)
356  {
357  const point predicted(points[i] + residual[i]);
358  debugStr().writeLine(points[i], predicted);
359  }
360  }
361 
362  jResidual = sum(mag(residual));
363 
364  if (iter == 0)
365  {
366  initialResidual = iResidual + jResidual;
367  }
368 
369  points += residual;
370  }
371 }
372 
373 
374 // ************************************************************************* //
dictionary dict
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
defineTypeNameAndDebug(projectFace, 0)
Unit conversion functions.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
Takes the description of the block and the list of curved edges and creates a list of points on edges...
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
const Cmpt & y() const noexcept
Access to the vector y component.
Definition: Vector.H:140
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
const cellShape & blockShape() const noexcept
Return the block shape.
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
const pointField & vertices() const noexcept
Reference to point field defining the block mesh.
virtual void project(const blockDescriptor &, const label blockFacei, pointField &points) const
Project the given points onto the surface.
Definition: projectFace.C:142
Container for searchableSurfaces. The collection is specified as a dictionary. For example...
const labelVector & density() const noexcept
The mesh density (number of cells) in the i,j,k directions.
An OFstream that keeps track of vertices and provides convenience output methods for OBJ files...
Definition: OBJstream.H:55
const Cmpt & x() const noexcept
Access to the vector x component.
Definition: Vector.H:135
int debug
Static debugging option.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
Define a curved face.
Definition: blockFace.H:53
const Cmpt & z() const noexcept
Access to the vector z component.
Definition: Vector.H:145
vector point
Point is a vector.
Definition: point.H:37
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
Projects the given set of face points onto the selected surface of the geometry provided as a searcha...
Definition: projectFace.H:50
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
Field< vector > vectorField
Specialisation of Field<T> for vector.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
List< label > labelList
A List of labels.
Definition: List.H:62
addToRunTimeSelectionTable(blockFace, projectFace, Istream)
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Namespace for OpenFOAM.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127