fixed writing out entries in advective bc
[OpenFOAM-1.6-ext.git] / src / tetDecompositionFiniteElement / tetFemMethod / tetFem.C
blob9d2dbb8493619e9659a48443ee6e74574f32dd5e
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright held by original author
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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
19     for more details.
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
25 Description
26     Class of static functions to calculate implicit finite element derivatives
27     returning a matrix.
29 \*---------------------------------------------------------------------------*/
31 #include "tetCell.H"
32 #include "tetCellList.H"
33 #include "tetPointRef.H"
34 #include "SquareMatrix.H"
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 namespace Foam
41 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
43 template<class Type>
44 tmp<tetFemMatrix<Type> > tetFem::laplacian
46     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
49     elementScalarField Gamma
50     (
51         IOobject
52         (
53             "gamma",
54             vf.time().constant(),
55             vf.db(),
56             IOobject::NO_READ
57         ),
58         vf.mesh(),
59         dimensionedScalar("1", dimless, 1.0)
60     );
62     return tetFem::laplacian(Gamma, vf);
66 template<class Type>
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
76     (
77         new tetFemMatrix<Type>
78         (
79             vf,
80             gamma.dimensions()*vf.dimensions()/dimLength/dimLength
81         )
82     );
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.
91     // 
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
103     (
104         mesh.maxNPointsForCell(),
105         0
106     );
108     for (label cellI = 0; cellI < mesh.nCells(); cellI++)
109     {
110         scalar curGamma = gamma[cellI];
112         label nCellPoints =
113             mesh.addressing
114             (
115                 cellI,
116                 localToGlobalBuffer,
117                 globalToLocalBuffer
118             );
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++)
125         {
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];
142             for
143             (
144                 label globalJEdge = startLabel;
145                 globalJEdge < endLabel;
146                 globalJEdge++
147             )
148             {
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
153                 if (localJ > -1)
154                 {
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"
159                     u[globalJEdge] +=
160                         curGamma*
161                         denseMatrix[min(localI, localJ)][max(localI, localJ)];
163                     // Zero out the coefficient after insertion
164                     denseMatrix[min(localI, localJ)][max(localI, localJ)] = 0;
165                 }
166             }
167         }
169         // Clear addressing for element
170         mesh.clearAddressing
171         (
172             cellI,
173             nCellPoints,
174             localToGlobalBuffer,
175             globalToLocalBuffer
176         );
177     }
179     return tfem;
183 template<class Type>
184 tmp<tetFemMatrix<Type> > tetFem::smoother
186     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
189     tmp<tetFemMatrix<Type> > tfem
190     (
191         new tetFemMatrix<Type>
192         (
193             vf,
194             vf.dimensions()
195         )
196     );
197     tetFemMatrix<Type>& fem = tfem();
199     fem.upper() = 1.0;
201     fem.negSumDiag();
203     return tfem;
207 template<class Type>
208 tmp<tetFemMatrix<Type> > tetFem::laplacian
210     const dimensionedScalar& gamma,
211     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
214     elementScalarField Gamma
215     (
216         IOobject
217         (
218             "gamma",
219             vf.instance(),
220             vf.db(),
221             IOobject::NO_READ
222         ),
223         vf.mesh(),
224         gamma
225     );
227     return tetFem::laplacian(Gamma, vf);
231 template<class Type>
232 tmp<tetFemMatrix<Type> > tetFem::laplacianTranspose
234     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
237     elementScalarField Gamma
238     (
239         IOobject
240         (
241             "gamma",
242             vf.time().constant(),
243             vf.db(),
244             IOobject::NO_READ
245         ),
246         vf.mesh(),
247         dimensionedScalar("1", dimless, 1.0)
248     );
250     return tetFem::laplacianTranspose(Gamma, vf);
254 template<class Type>
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
264     (
265         new tetFemMatrix<Type>
266         (
267             vf,
268             gamma.dimensions()*vf.dimensions()/dimLength/dimLength
269         )
270     );
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.
283     // 
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
295     (
296         mesh.maxNPointsForCell(),
297         tensor::zero
298     );
300     for (label cellI = 0; cellI < mesh.nCells(); cellI++)
301     {
302         scalar curGamma = gamma[cellI];
304         label nCellPoints =
305             mesh.addressing
306             (
307                 cellI,
308                 localToGlobalBuffer,
309                 globalToLocalBuffer
310             );
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++)
317         {
318             label globalI = localToGlobalBuffer[localI];
320             tensor& curDiagCoeff = denseMatrix[localI][localI];
322             // Insert the diagonal
323             d[globalI] += curGamma*tr(curDiagCoeff);
325             source[globalI] +=
326                 psi[globalI] &
327                 (
328                     tr(curDiagCoeff)*I
329                   - curDiagCoeff
330                 )*curGamma;
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];
343             for
344             (
345                 label globalJEdge = startLabel;
346                 globalJEdge < endLabel;
347                 globalJEdge++
348             )
349             {
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
355                 if (localJ > -1)
356                 {
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);
366                     source[globalI] +=
367                         curGamma*
368                         (
369                             tr(curOffDiagCoeff)*I
370                           - curOffDiagCoeff
371                         ).T() & psi[globalJ];
373                     source[globalJ] +=
374                         curGamma*
375                         (
376                             tr(curOffDiagCoeff)*I
377                           - curOffDiagCoeff
378                         ) & psi[globalI];
380                     curOffDiagCoeff = tensor::zero;
381                 }
382             }
383         }
385         // Clear addressing for element
386         mesh.clearAddressing
387         (
388             cellI,
389             nCellPoints,
390             localToGlobalBuffer,
391             globalToLocalBuffer
392         );
393     }
395     return tfem;
399 template<class Type>
400 tmp<tetFemMatrix<Type> > tetFem::laplacianTranspose
402     const dimensionedScalar& gamma,
403     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
406     elementScalarField Gamma
407     (
408         IOobject
409         (
410             gamma.name(),
411             vf.instance(),
412             vf.db(),
413             IOobject::NO_READ
414         ),
415         vf.mesh(),
416         gamma
417     );
419     return tetFem::laplacianTranspose(Gamma, vf);
423 template<class Type>
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
433     (
434         new tetFemMatrix<Type>
435         (
436             vf,
437             gamma.dimensions()*vf.dimensions()/dimLength/dimLength
438         )
439     );
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.
452     // HJ, date deleted
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
464     (
465         mesh.maxNPointsForCell(),
466         tensor::zero
467     );
469     for (label cellI = 0; cellI < mesh.nCells(); cellI++)
470     {
471         scalar curGamma = gamma[cellI];
473         label nCellPoints =
474             mesh.addressing
475             (
476                 cellI,
477                 localToGlobalBuffer,
478                 globalToLocalBuffer
479             );
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++)
486         {
487             label globalI = localToGlobalBuffer[localI];
489             tensor& curDiagCoeff = denseMatrix[localI][localI];
491             d[globalI] += curGamma*tr(curDiagCoeff);
493             source[globalI] +=
494                 curGamma*
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];
508             for
509             (
510                 label globalJEdge = startLabel;
511                 globalJEdge < endLabel;
512                 globalJEdge++
513             )
514             {
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
520                 if (localJ > -1)
521                 {
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);
531                     source[globalI] += 
532                         curGamma*
533                         (
534                             (tr(curOffDiagCoeff)*I - curOffDiagCoeff)
535                           & psi[globalJ]
536                         );
538                     source[globalJ] +=
539                         curGamma*
540                         (
541                             (tr(curOffDiagCoeff)*I - curOffDiagCoeff).T()
542                           & psi[globalI]
543                         );
545                     curOffDiagCoeff = tensor::zero;
546                 }
547             }
548         }
550         // Clear addressing for element
551         mesh.clearAddressing
552         (
553             cellI,
554             nCellPoints,
555             localToGlobalBuffer,
556             globalToLocalBuffer
557         );
558     }
560     return tfem;
564 template<class Type>
565 tmp<tetFemMatrix<Type> > tetFem::laplacianTrace
567     const dimensionedScalar& gamma,
568     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
571     elementScalarField Gamma
572     (
573         IOobject
574         (
575             gamma.name(),
576             vf.instance(),
577             vf.db(),
578             IOobject::NO_READ
579         ),
580         vf.mesh(),
581         gamma
582     );
584     return tetFem::laplacianTrace(Gamma, vf);
588 template<class Type>
589 tmp<tetFemMatrix<Type> > tetFem::laplacianTrace
591     GeometricField<Type, tetPolyPatchField, tetPointMesh>& vf
594     elementScalarField Gamma
595     (
596         IOobject
597         (
598             "1",
599             vf.instance(),
600             vf.db(),
601             IOobject::NO_READ
602         ),
603         vf.mesh(),
604         dimensionedScalar("1", dimless, 1.0)
605     );
607     return tetFem::laplacianTrace(Gamma, vf);
611 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
613 } // End namespace Foam
615 // ************************************************************************* //