immersedBoundaryFvPatchLeastSquaresFit.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | foam-extend: Open Source CFD
4  \\ / O peration | Version: 3.2
5  \\ / A nd | Web: http://www.foam-extend.org
6  \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9  This file is part of foam-extend.
10 
11  foam-extend 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 3 of the License, or (at your
14  option) any later version.
15 
16  foam-extend is distributed in the hope that it will be useful, but
17  WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "fvMesh.H"
28 #include "volFields.H"
29 
30 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
31 
33 {
34  if (debug)
35  {
36  Info<< "immersedBoundaryFvPatch::makeInvDirichletMatrices() : "
37  << "making immersed boundary inverse matrices"
38  << endl;
39  }
40 
41  // It is an error to attempt to recalculate
42  // if the pointer is already set
44  {
46  (
47  "void immersedBoundaryFvPatch::makeInvDirichletMatrices()"
48  ) << "immersed boundary inverse least squares matrices already exist"
49  << abort(FatalError);
50  }
51 
52  // Get addressing
53  const labelList& ibc = ibCells();
54  const labelListList& ibcc = ibCellCells();
55  const List<List<labelPair> >& ibcProcC = ibCellProcCells();
56  const vectorField& ibp = ibPoints();
57 
61 
62  const vectorField& C = mesh_.C().internalField();
63 
64  scalarField conditionNumber(ibc.size(), 0.0);
65 
66  // Initialize maxRowSum for debug
67  scalar maxRowSum = 0.0;
68 
70 
71  label nCoeffs = 5;
72 
73  if (mesh_.nGeometricD() == 3)
74  {
75  nCoeffs += 4;
76  }
77 
78  forAll (idm, cellI)
79  {
80  const labelList& interpCells = ibcc[cellI];
81  const List<labelPair>& interpProcCells = ibcProcC[cellI];
82 
84  (
85  interpCells.size()
86  + interpProcCells.size(),
88  );
89 
90  if (allPoints.size() < nCoeffs)
91  {
93  (
94  "void immersedBoundaryFvPatch::makeInvDirichletMatrices()"
95  ) << "allPoints.size() < " << nCoeffs << " : "
96  << allPoints.size() << abort(FatalError);
97  }
98 
99  label pointID = 0;
100 
101  // Cells
102  for (label i = 0; i < interpCells.size(); i++)
103  {
104  allPoints[pointID++] = C[interpCells[i]];
105  }
106 
107  // Processor cells
108  for (label i = 0; i < interpProcCells.size(); i++)
109  {
110  allPoints[pointID++] =
111  procC
112  [
113  interpProcCells[i].first()
114  ]
115  [
116  interpProcCells[i].second()
117  ];
118  }
119 
120  // Weights calculation
121 
122  vector origin = C[ibc[cellI]];
123 
124  scalarField curDist = mag(allPoints - origin);
125 
126  // Calculate weights
127  scalarField W =
128  0.5*
129  (
130  1
131  + cos(mathematicalConstant::pi*curDist/(1.1*max(curDist)))
132  );
133 
134  idm.set
135  (
136  cellI,
138  (
139  nCoeffs,
140  allPoints.size(),
141  0.0
142  )
143  );
144  scalarRectangularMatrix& curMatrix = idm[cellI];
145 
147  (
148  allPoints.size(),
149  nCoeffs,
150  0.0
151  );
152 
153  origin = ibp[cellI];
154 
155  for(label i = 0; i < allPoints.size(); i++)
156  {
157  scalar X = allPoints[i].x() - origin.x();
158  scalar Y = allPoints[i].y() - origin.y();
159 
160  label coeff = 0;
161  M[i][coeff++] = X;
162  M[i][coeff++] = Y;
163  M[i][coeff++] = X*Y;
164  M[i][coeff++] = sqr(X);
165  M[i][coeff++] = sqr(Y);
166 
167  if (mesh_.nGeometricD() == 3)
168  {
169  scalar Z = allPoints[i].z() - origin.z();
170  M[i][coeff++] = Z;
171  M[i][coeff++] = X*Z;
172  M[i][coeff++] = Y*Z;
173  M[i][coeff++] = sqr(Z);
174  }
175  }
176 
177  for (label i = 0; i < M.n(); i++)
178  {
179  for (label j = 0; j < M.m(); j++)
180  {
181  M[i][j] *= W[i];
182  }
183  }
184 
185  scalarSquareMatrix lsM(nCoeffs, 0.0);
186 
187  for (label i = 0; i < lsM.n(); i++)
188  {
189  for (label j = 0; j < lsM.m(); j++)
190  {
191  for (label k=0; k<M.n(); k++)
192  {
193  lsM[i][j] += M[k][i]*M[k][j];
194  }
195  }
196  }
197 
198  if (debug)
199  {
200  // Calculate matrix norm
201  maxRowSum = 0.0;
202 
203  for (label i = 0; i < lsM.n(); i++)
204  {
205  scalar curRowSum = 0.0;
206 
207  for (label j = 0; j < lsM.m(); j++)
208  {
209  curRowSum += lsM[i][j];
210  }
211 
212  if (curRowSum > maxRowSum)
213  {
214  maxRowSum = curRowSum;
215  }
216  }
217 
218  conditionNumber[cellI] = maxRowSum;
219  }
220 
221  // Calculate inverse
222  scalarSquareMatrix invLsM = lsM.LUinvert();
223 
224  for (label i = 0; i < lsM.n(); i++)
225  {
226  for (label j = 0; j < M.n(); j++)
227  {
228  for (label k = 0; k < lsM.n(); k++)
229  {
230  curMatrix[i][j] += invLsM[i][k]*M[j][k]*W[j];
231  }
232  }
233  }
234 
235  if (debug)
236  {
237  // Calculate condition number
238  maxRowSum = 0.0;
239 
240  for (label i = 0; i < lsM.n(); i++)
241  {
242  scalar curRowSum = 0.0;
243 
244  for (label j = 0; j < lsM.m(); j++)
245  {
246  curRowSum += invLsM[i][j];
247  }
248 
249  if (curRowSum > maxRowSum)
250  {
251  maxRowSum = curRowSum;
252  }
253  }
254 
255  conditionNumber[cellI] *= maxRowSum;
256 
257  InfoIn
258  (
259  "void immersedBoundaryFvPatch::"
260  "makeInvDirichletMatrices() const"
261  ) << "Max Dirichlet matrix condition number: "
262  << gMax(conditionNumber) << endl;
263  }
264  }
265 }
266 
267 
269 {
270  if (debug)
271  {
272  Info<< "immersedBoundaryFvPatch::makeInvNeumannMatrices() : "
273  << "making immersed boundary inverse least sqares matrices"
274  << endl;
275  }
276 
277  // It is an error to attempt to recalculate
278  // if the pointer is already set
279  if (invNeumannMatricesPtr_)
280  {
281  FatalErrorIn("immersedBoundaryFvPatch::makeInvNeumannMatrices()")
282  << "immersed boundary inverse least squares matrices already exist"
283  << abort(FatalError);
284  }
285 
286  // Get addressing
287  const labelList& ibc = ibCells();
288  const labelListList& ibcc = ibCellCells();
289  const List<List<labelPair> >& ibcProcC = ibCellProcCells();
290  const vectorField& ibp = ibPoints();
291 
292  // Note: the algorithm is originally written with inward-facing normals
293  // and subsequently changed: IB surface normals point outwards
294  // HJ, 21/May/2012
295  const vectorField& ibn = ibNormals();
296 
297  invNeumannMatricesPtr_ =
299  PtrList<scalarRectangularMatrix>& inm = *invNeumannMatricesPtr_;
300 
301  const vectorField& C = mesh_.C().internalField();
302 
303  scalarField conditionNumber(ibc.size(), 0);
304 
305  // Initialize maxRowSum for debug
306  scalar maxRowSum = 0.0;
307 
308  const FieldField<Field, vector>& procC = ibProcCentres();
309 
310  label nCoeffs = 6;
311 
312  if (mesh_.nGeometricD() == 3)
313  {
314  nCoeffs += 4;
315  }
316 
317  forAll (inm, cellI)
318  {
319  const labelList& interpCells = ibcc[cellI];
320  const List<labelPair>& interpProcCells = ibcProcC[cellI];
321 
323  (
324  interpCells.size() + 1
325  + interpProcCells.size(),
327  );
328 
329  label pointID = 0;
330 
331  // Cells
332  for (label i = 0; i < interpCells.size(); i++)
333  {
334  allPoints[pointID++] = C[interpCells[i]];
335  }
336 
337  // IB point
338  allPoints[pointID++] = ibp[cellI];
339 
340  // Processor cells
341  for (label i = 0; i < interpProcCells.size(); i++)
342  {
343  allPoints[pointID++] =
344  procC
345  [
346  interpProcCells[i].first()
347  ]
348  [
349  interpProcCells[i].second()
350  ];
351  }
352 
353  // Weights calculation
354 
355  vector origin = C[ibc[cellI]];
356 
357  scalarField curR = mag(allPoints - origin);
358 
359  // Calculate weights
360  scalarField W = 1 - curR/(1.1*max(curR));
361 
362 
363  inm.set
364  (
365  cellI,
367  (
368  nCoeffs,
369  allPoints.size(),
370  0.0
371  )
372  );
373  scalarRectangularMatrix& curMatrix = inm[cellI];
374 
376  (
377  allPoints.size(),
378  nCoeffs,
379  0.0
380  );
381 
382  pointID = 0;
383  origin = ibp[cellI];
384  for (label i = 0; i < interpCells.size(); i++)
385  {
386  scalar X = allPoints[pointID].x() - origin.x();
387  scalar Y = allPoints[pointID].y() - origin.y();
388 
389  M[pointID][0] = 1.0;
390  M[pointID][1] = X;
391  M[pointID][2] = Y;
392  M[pointID][3] = X*Y;
393  M[pointID][4] = sqr(X);
394  M[pointID][5] = sqr(Y);
395 
396  if (mesh_.nGeometricD() == 3)
397  {
398  scalar Z = allPoints[pointID].z() - origin.z();
399 
400  M[pointID][6] = Z;
401  M[pointID][7] = X*Z;
402  M[pointID][8] = Y*Z;
403  M[pointID][9] = sqr(Z);
404  }
405 
406  pointID++;
407  }
408 
409  scalar X = allPoints[pointID].x() - origin.x();
410  scalar Y = allPoints[pointID].y() - origin.y();
411 
412  M[pointID][0] = 0;
413  M[pointID][1] = -ibn[cellI].x();
414  M[pointID][2] = -ibn[cellI].y();
415  M[pointID][3] =
416  (
417  -ibn[cellI].x()*Y
418  - ibn[cellI].y()*X
419  );
420  M[pointID][4] = -2*ibn[cellI].x()*X;
421  M[pointID][5] = -2*ibn[cellI].y()*Y;
422 
423  if (mesh_.nGeometricD() == 3)
424  {
425  scalar Z = allPoints[pointID].z() - origin.z();
426 
427  M[pointID][6] = -ibn[cellI].z();
428  M[pointID][7] =
429  (
430  -ibn[cellI].x()*Z
431  - ibn[cellI].z()*X
432  );
433  M[pointID][8] =
434  (
435  -ibn[cellI].y()*Z
436  - ibn[cellI].z()*Y
437  );
438  M[pointID][9] = -2*ibn[cellI].z()*Z;
439  }
440 
441  pointID++;
442 
443  for(label i = 0; i < interpProcCells.size(); i++)
444  {
445  scalar X = allPoints[pointID].x() - origin.x();
446  scalar Y = allPoints[pointID].y() - origin.y();
447 
448  M[pointID][0] = 1.0;
449  M[pointID][1] = X;
450  M[pointID][2] = Y;
451  M[pointID][3] = X*Y;
452  M[pointID][4] = sqr(X);
453  M[pointID][5] = sqr(Y);
454 
455  if (mesh_.nGeometricD() == 3)
456  {
457  scalar Z = allPoints[pointID].z() - origin.z();
458 
459  M[pointID][6] = Z;
460  M[pointID][7] = X*Z;
461  M[pointID][8] = Y*Z;
462  M[pointID][9] = sqr(Z);
463  }
464 
465  pointID++;
466  }
467 
468  for (label i = 0; i < M.n(); i++)
469  {
470  for (label j = 0; j < M.m(); j++)
471  {
472  M[i][j] *= W[i];
473  }
474  }
475 
476  scalarSquareMatrix lsM(nCoeffs, 0.0);
477 
478  for (label i = 0; i < lsM.n(); i++)
479  {
480  for (label j = 0; j < lsM.m(); j++)
481  {
482  for (label k = 0; k < M.n(); k++)
483  {
484  lsM[i][j] += M[k][i]*M[k][j];
485  }
486  }
487  }
488 
489  // Calculate matrix norm
490  if (debug)
491  {
492  maxRowSum = 0.0;
493 
494  for (label i = 0; i < lsM.n(); i++)
495  {
496  scalar curRowSum = 0.0;
497 
498  for (label j = 0; j < lsM.m(); j++)
499  {
500  curRowSum += lsM[i][j];
501  }
502 
503  if (curRowSum > maxRowSum)
504  {
505  maxRowSum = curRowSum;
506  }
507  }
508 
509  conditionNumber[cellI] = maxRowSum;
510  }
511 
512  // Calculate inverse
513  scalarSquareMatrix invLsM = lsM.LUinvert();
514 
515  for (label i = 0; i < lsM.n(); i++)
516  {
517  for (label j = 0; j < M.n(); j++)
518  {
519  for (label k = 0; k < lsM.n(); k++)
520  {
521  curMatrix[i][j] += invLsM[i][k]*M[j][k]*W[j];
522  }
523  }
524  }
525 
526  // Calculate condition number
527  if (debug)
528  {
529  maxRowSum = 0.0;
530 
531  for (label i = 0; i < lsM.n(); i++)
532  {
533  scalar curRowSum = 0.0;
534 
535  for (label j = 0; j < lsM.m(); j++)
536  {
537  curRowSum += invLsM[i][j];
538  }
539 
540  if (curRowSum > maxRowSum)
541  {
542  maxRowSum = curRowSum;
543  }
544  }
545 
546  conditionNumber[cellI] *= maxRowSum;
547 
548  if (conditionNumber[cellI] > 1e6)
549  {
550  labelList CC = interpCells;
551  sort(CC);
552 
553  Info<< "Condition = " << conditionNumber[cellI] << nl
554  << "cell cells: " << CC
555  << "M = " << lsM
556  << endl;
557  }
558 
559  InfoIn
560  (
561  "void immersedBoundaryFvPatch::makeInvNeumannMatrices() const"
562  ) << "Max Neumann matrix condition number: "
563  << gMax(conditionNumber) << endl;
564  }
565  }
566 }
567 
568 
571 {
572  if (!invDirichletMatricesPtr_)
573  {
574  makeInvDirichletMatrices();
575  }
576 
577  return *invDirichletMatricesPtr_;
578 }
579 
580 
583 {
584  if (!invNeumannMatricesPtr_)
585  {
586  makeInvNeumannMatrices();
587  }
588 
589  return *invNeumannMatricesPtr_;
590 }
591 
592 
593 // ************************************************************************* //
volFields.H
Foam::Matrix::m
label m() const
Return the number of columns.
Definition: MatrixI.H:63
InfoIn
#define InfoIn(functionName)
Report a information message using Foam::Info.
Definition: messageStream.H:276
Foam::Vector< scalar >::zero
static const Vector zero
Definition: Vector.H:80
Foam::FieldField
Generic field type.
Definition: FieldField.H:51
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::immersedBoundaryFvPatch::ibCellProcCells
const List< List< labelPair > > & ibCellProcCells() const
Return neighbour cell addressing.
Definition: immersedBoundaryFvPatch.C:2436
Foam::polyMesh::nGeometricD
label nGeometricD() const
Return the number of valid geometric dimensions in the mesh.
Definition: polyMesh.C:795
Foam::immersedBoundaryFvPatch::mesh_
const fvMesh & mesh_
Finite volume mesh reference.
Definition: immersedBoundaryFvPatch.H:76
Foam::immersedBoundaryFvPatch::invNeumannMatrices
const PtrList< scalarRectangularMatrix > & invNeumannMatrices() const
Get inverse Neumann interpolation matrix.
Definition: immersedBoundaryFvPatchLeastSquaresFit.C:582
Foam::immersedBoundaryFvPatch::invDirichletMatricesPtr_
PtrList< scalarRectangularMatrix > * invDirichletMatricesPtr_
Inverse interpolation matrices for Dirichlet BC at the IB.
Definition: immersedBoundaryFvPatch.H:194
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::Matrix::n
label n() const
Return the number of rows.
Definition: MatrixI.H:56
Foam::PtrList::set
bool set(const label) const
Is element set.
Foam::label
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
Foam::Field
Pre-declare SubField and related Field type.
Definition: Field.H:57
Foam::immersedBoundaryFvPatch::ibCells
const labelList & ibCells() const
Return list of fluid cells next to immersed boundary (IB cells)
Definition: immersedBoundaryFvPatch.C:2289
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::GeometricField::internalField
InternalField & internalField()
Return internal field.
Definition: GeometricField.C:724
Foam::PtrList
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:61
Foam::RectangularMatrix< scalar >
Foam::Vector::x
const Cmpt & x() const
Definition: VectorI.H:65
Foam::FatalError
error FatalError
Foam::immersedBoundaryFvPatch::makeInvDirichletMatrices
void makeInvDirichletMatrices() const
Make inverse Dirichlet interpolation matrices.
Definition: immersedBoundaryFvPatchLeastSquaresFit.C:32
Foam::C::C
C()
Construct null.
Definition: C.C:41
fvMesh.H
Foam::Vector::z
const Cmpt & z() const
Definition: VectorI.H:77
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:131
coeff
const scalar coeff[]
Definition: Test-Polynomial.C:38
Foam::immersedBoundaryFvPatch::makeInvNeumannMatrices
void makeInvNeumannMatrices() const
Make inverse Neumann interpolation matrices.
Definition: immersedBoundaryFvPatchLeastSquaresFit.C:268
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::SquareMatrix< scalar >
Foam::immersedBoundaryFvPatch::ibCellCells
const labelListList & ibCellCells() const
Return IB cell extended stencil.
Definition: immersedBoundaryFvPatch.C:2400
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:49
Foam::fvMesh::C
const volVectorField & C() const
Return cell centres as volVectorField.
Definition: fvMeshGeometry.C:369
Foam::Vector< scalar >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
M
#define M(I)
k
label k
Boltzmann constant.
Definition: LISASMDCalcMethod2.H:41
Foam::constant::mathematical::pi
const scalar pi(M_PI)
Foam::immersedBoundaryFvPatch::ibPoints
const vectorField & ibPoints() const
Return IB points.
Definition: immersedBoundaryFvPatch.C:2355
Foam::Vector::y
const Cmpt & y() const
Definition: VectorI.H:71
immersedBoundaryFvPatch.H
FatalErrorIn
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:313
Foam::DelaunayMeshTools::allPoints
tmp< pointField > allPoints(const Triangulation &t)
Extract all points in vertex-index order.
Foam::sort
void sort(UList< T > &)
Definition: UList.C:107
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::C
Graphite solid properties.
Definition: C.H:57
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:562
Y
PtrList< volScalarField > & Y
Definition: createFields.H:36
Foam::immersedBoundaryFvPatch::ibProcCentres
const FieldField< Field, vector > & ibProcCentres() const
Return neighbour proc centres.
Definition: immersedBoundaryFvPatch.C:2412
Foam::immersedBoundaryFvPatch::invDirichletMatrices
const PtrList< scalarRectangularMatrix > & invDirichletMatrices() const
Get inverse Dirichlet interpolation matrix.
Definition: immersedBoundaryFvPatchLeastSquaresFit.C:570
Foam::cos
dimensionedScalar cos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:256