1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 Class of static functions to calculate implicit finite element derivatives
29 \*---------------------------------------------------------------------------*/
32 #include "tetCellList.H"
33 #include "tetPointRef.H"
34 #include "SquareMatrix.H"
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
44 tmp<tetFemMatrix<Type> > tetFem::laplacian
46 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
49 elementScalarField Gamma
59 dimensionedScalar("1", dimless, 1.0)
62 return tetFem::laplacian(Gamma, vf);
67 tmp<tetFemMatrix<Type> > tetFem::laplacian
69 const elementScalarField& gamma,
70 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
73 const tetPolyMesh& mesh = vf.mesh();
75 tmp<tetFemMatrix<Type> > tfem
77 new tetFemMatrix<Type>
80 gamma.dimensions()*vf.dimensions()/dimLength/dimLength
83 tetFemMatrix<Type>& fem = tfem();
85 // Get reference to upper and diagonal
86 scalarField& u = fem.upper();
87 scalarField& d = fem.diag();
89 // In order to avoid excessive memory allocation and copying,
90 // matrix coefficients and addressing are retrieved using a buffer.
93 // Get reference to ldu addressing
94 const lduAddressing& lduAddr = fem.lduAddr();
95 const unallocLabelList& ownerStart = lduAddr.ownerStartAddr();
96 const unallocLabelList& neighbour = lduAddr.upperAddr();
98 // Create local-to-global and global-to-local addressing arrays
99 labelList localToGlobalBuffer(mesh.maxNPointsForCell());
100 labelList globalToLocalBuffer(lduAddr.size(), -1);
102 SquareMatrix<scalar> denseMatrix
104 mesh.maxNPointsForCell(),
108 for (label cellI = 0; cellI < mesh.nCells(); cellI++)
110 scalar curGamma = gamma[cellI];
120 mesh.gradNiDotGradNj(cellI, denseMatrix, globalToLocalBuffer);
122 // Insertion and clearing of the dense matrix is done together!
124 for (label localI = 0; localI < nCellPoints; localI++)
126 label globalI = localToGlobalBuffer[localI];
128 // Insert the diagonal
129 d[globalI] += curGamma*denseMatrix[localI][localI];
131 // Zero out the coefficient after insertion
132 denseMatrix[localI][localI] = 0;
134 // Insert the off-diagonal.
135 // Here, look for the known global neighbours of the point
136 // using ldu owner start and grab their local index using
137 // globalToLocalAddressing. Then insert at the correct
138 // place in the global matrix
139 label startLabel = ownerStart[globalI];
140 label endLabel = ownerStart[globalI + 1];
144 label globalJEdge = startLabel;
145 globalJEdge < endLabel;
149 label localJ = globalToLocalBuffer[neighbour[globalJEdge]];
151 // Not all neighbour of globalI are in the dense
152 // matrix; only if the global-to-local coefficient is not -1
155 // It is unknown if the localI or localJ is lower:
156 // that depends on how the local points have been
157 // selected. Therefore, the matrix (which is
158 // symmetric!) needs to be "folded"
161 denseMatrix[min(localI, localJ)][max(localI, localJ)];
163 // Zero out the coefficient after insertion
164 denseMatrix[min(localI, localJ)][max(localI, localJ)] = 0;
169 // Clear addressing for element
184 tmp<tetFemMatrix<Type> > tetFem::smoother
186 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
189 tmp<tetFemMatrix<Type> > tfem
191 new tetFemMatrix<Type>
197 tetFemMatrix<Type>& fem = tfem();
208 tmp<tetFemMatrix<Type> > tetFem::laplacian
210 const dimensionedScalar& gamma,
211 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
214 elementScalarField Gamma
227 return tetFem::laplacian(Gamma, vf);
232 tmp<tetFemMatrix<Type> > tetFem::laplacianTranspose
234 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
237 elementScalarField Gamma
242 vf.time().constant(),
247 dimensionedScalar("1", dimless, 1.0)
250 return tetFem::laplacianTranspose(Gamma, vf);
255 tmp<tetFemMatrix<Type> > tetFem::laplacianTranspose
257 const elementScalarField& gamma,
258 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
261 const tetPolyMesh& mesh = vf.mesh();
263 tmp<tetFemMatrix<Type> > tfem
265 new tetFemMatrix<Type>
268 gamma.dimensions()*vf.dimensions()/dimLength/dimLength
271 tetFemMatrix<Type>& fem = tfem();
273 // Get reference to internal field
274 const Field<Type>& psi = fem.psi().internalField();
276 // Get reference to upper and diagonal
277 scalarField& u = fem.upper();
278 scalarField& d = fem.diag();
279 Field<Type>& source = fem.source();
281 // In order to avoid excessive memory allocation and copying,
282 // matrix coefficients and addressing are retrieved using a buffer.
285 // Get reference to ldu addressing
286 const lduAddressing& lduAddr = fem.lduAddr();
287 const unallocLabelList& ownerStart = lduAddr.ownerStartAddr();
288 const unallocLabelList& neighbour = lduAddr.upperAddr();
290 // Create local-to-global and global-to-local addressing arrays
291 labelList localToGlobalBuffer(mesh.maxNPointsForCell());
292 labelList globalToLocalBuffer(lduAddr.size(), -1);
294 SquareMatrix<tensor> denseMatrix
296 mesh.maxNPointsForCell(),
300 for (label cellI = 0; cellI < mesh.nCells(); cellI++)
302 scalar curGamma = gamma[cellI];
312 mesh.gradNiGradNj(cellI, denseMatrix, globalToLocalBuffer);
314 // Insertion and clearing of the dense matrix is done together!
316 for (label localI = 0; localI < nCellPoints; localI++)
318 label globalI = localToGlobalBuffer[localI];
320 tensor& curDiagCoeff = denseMatrix[localI][localI];
322 // Insert the diagonal
323 d[globalI] += curGamma*tr(curDiagCoeff);
332 // Zero out the coefficient after insertion
333 curDiagCoeff = tensor::zero;
335 // Insert the off-diagonal.
336 // Here, look for the known global neighbours of the point
337 // using ldu owner start and grab their local index using
338 // globalToLocalAddressing. Then insert at the correct
339 // place in the global matrix
340 label startLabel = ownerStart[globalI];
341 label endLabel = ownerStart[globalI + 1];
345 label globalJEdge = startLabel;
346 globalJEdge < endLabel;
350 label globalJ = neighbour[globalJEdge];
351 label localJ = globalToLocalBuffer[globalJ];
353 // Not all neighbour of globalI are in the dense
354 // matrix; only if the global-to-local coefficient is not -1
357 // It is unknown if the localI or localJ is lower:
358 // that depends on how the local points have been
359 // selected. Therefore, the matrix (which is
360 // symmetric!) needs to be "folded"
361 tensor& curOffDiagCoeff =
362 denseMatrix[min(localI, localJ)][max(localI, localJ)];
364 u[globalJEdge] += curGamma*tr(curOffDiagCoeff);
369 tr(curOffDiagCoeff)*I
371 ).T() & psi[globalJ];
376 tr(curOffDiagCoeff)*I
380 curOffDiagCoeff = tensor::zero;
385 // Clear addressing for element
400 tmp<tetFemMatrix<Type> > tetFem::laplacianTranspose
402 const dimensionedScalar& gamma,
403 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
406 elementScalarField Gamma
419 return tetFem::laplacianTranspose(Gamma, vf);
424 tmp<tetFemMatrix<Type> > tetFem::laplacianTrace
426 const elementScalarField& gamma,
427 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
430 const tetPolyMesh& mesh = vf.mesh();
432 tmp<tetFemMatrix<Type> > tfem
434 new tetFemMatrix<Type>
437 gamma.dimensions()*vf.dimensions()/dimLength/dimLength
440 tetFemMatrix<Type>& fem = tfem();
442 // Get reference to internal field
443 const Field<Type>& psi = fem.psi().internalField();
445 // Get reference to upper, diagonal and source
446 scalarField& u = fem.upper();
447 scalarField& d = fem.diag();
448 Field<Type>& source = fem.source();
450 // In order to avoid excessive memory allocation and copying,
451 // matrix coefficients and addressing are retrieved using a buffer.
454 // Get reference to ldu addressing
455 const lduAddressing& lduAddr = fem.lduAddr();
456 const unallocLabelList& ownerStart = lduAddr.ownerStartAddr();
457 const unallocLabelList& neighbour = lduAddr.upperAddr();
459 // Create local-to-global and global-to-local addressing arrays
460 labelList localToGlobalBuffer(mesh.maxNPointsForCell());
461 labelList globalToLocalBuffer(lduAddr.size(), -1);
463 SquareMatrix<tensor> denseMatrix
465 mesh.maxNPointsForCell(),
469 for (label cellI = 0; cellI < mesh.nCells(); cellI++)
471 scalar curGamma = gamma[cellI];
481 mesh.gradNiGradNj(cellI, denseMatrix, globalToLocalBuffer);
483 // Insertion and clearing of the dense matrix is done together!
485 for (label localI = 0; localI < nCellPoints; localI++)
487 label globalI = localToGlobalBuffer[localI];
489 tensor& curDiagCoeff = denseMatrix[localI][localI];
491 d[globalI] += curGamma*tr(curDiagCoeff);
495 ((tr(curDiagCoeff)*I - curDiagCoeff) & psi[globalI]);
497 // Zero out the coefficient after insertion
498 curDiagCoeff = tensor::zero;
500 // Insert the off-diagonal.
501 // Here, look for the known global neighbours of the point
502 // using ldu owner start and grab their local index using
503 // globalToLocalAddressing. Then insert at the correct
504 // place in the global matrix
505 label startLabel = ownerStart[globalI];
506 label endLabel = ownerStart[globalI + 1];
510 label globalJEdge = startLabel;
511 globalJEdge < endLabel;
515 label globalJ = neighbour[globalJEdge];
516 label localJ = globalToLocalBuffer[globalJ];
518 // Not all neighbour of globalI are in the dense
519 // matrix; only if the global-to-local coefficient is not -1
522 // It is unknown if the localI or localJ is lower:
523 // that depends on how the local points have been
524 // selected. Therefore, the matrix (which is
525 // symmetric!) needs to be "folded"
526 tensor& curOffDiagCoeff =
527 denseMatrix[min(localI, localJ)][max(localI, localJ)];
529 u[globalJEdge] += curGamma*tr(curOffDiagCoeff);
534 (tr(curOffDiagCoeff)*I - curOffDiagCoeff)
541 (tr(curOffDiagCoeff)*I - curOffDiagCoeff).T()
545 curOffDiagCoeff = tensor::zero;
550 // Clear addressing for element
565 tmp<tetFemMatrix<Type> > tetFem::laplacianTrace
567 const dimensionedScalar& gamma,
568 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
571 elementScalarField Gamma
584 return tetFem::laplacianTrace(Gamma, vf);
589 tmp<tetFemMatrix<Type> > tetFem::laplacianTrace
591 GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
594 elementScalarField Gamma
604 dimensionedScalar("1", dimless, 1.0)
607 return tetFem::laplacianTrace(Gamma, vf);
611 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
613 } // End namespace Foam
615 // ************************************************************************* //