fvcSurfaceOps.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) 2024 M.Janssens
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "fvcSurfaceOps.H"
29 #include "fvMesh.H"
30 
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35 
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
37 
38 namespace fvc
39 {
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 
43 template<class Type, class ResultType, class CellToFaceOp>
44 void surfaceSum
45 (
46  const surfaceScalarField& lambdas,
48  const CellToFaceOp& cop,
51 )
52 {
53  const fvMesh& mesh = vf.mesh();
54  const auto& Sf = mesh.Sf();
55  const auto& P = mesh.owner();
56  const auto& N = mesh.neighbour();
57 
58  const auto& vfi = vf.primitiveField();
59  auto& sfi = result.primitiveFieldRef();
60 
61  // See e.g. surfaceInterpolationScheme<Type>::dotInterpolate
62 
63  // Internal field
64  {
65  const auto& Sfi = Sf.primitiveField();
66  const auto& lambda = lambdas.primitiveField();
67 
68  for (label facei=0; facei<P.size(); facei++)
69  {
70  const label ownCelli = P[facei];
71  const label neiCelli = N[facei];
72 
73  const ResultType faceVal
74  (
75  cop
76  (
77  Sfi[facei],
78  lambda[facei],
79  vfi[ownCelli],
80  vfi[neiCelli]
81  )
82  );
83  sfi[ownCelli] += faceVal;
84  sfi[neiCelli] -= faceVal;
85  }
86  }
87 
88 
89  // Boundary field
90  {
91  forAll(mesh.boundary(), patchi)
92  {
93  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
94  const auto& pSf = Sf.boundaryField()[patchi];
95  const auto& pvf = vf.boundaryField()[patchi];
96  const auto& pLambda = lambdas.boundaryField()[patchi];
97 
98  if (pvf.coupled())
99  {
100  auto tpnf(pvf.patchNeighbourField());
101  auto& pnf = tpnf();
102 
103  for (label facei=0; facei<pFaceCells.size(); facei++)
104  {
105  // Interpolate between owner-side and neighbour-side values
106  const ResultType faceVal
107  (
108  cop
109  (
110  pSf[facei],
111  pLambda[facei],
112  vfi[pFaceCells[facei]],
113  pnf[facei]
114  )
115  );
116 
117  sfi[pFaceCells[facei]] += faceVal;
118  }
119  }
120  else
121  {
122  for (label facei=0; facei<pFaceCells.size(); facei++)
123  {
124  // Use patch value only
125  const ResultType faceVal
126  (
127  cop
128  (
129  pSf[facei],
130  scalar(1.0),
131  pvf[facei],
132  pTraits<Type>::zero // not used
133  )
134  );
135  sfi[pFaceCells[facei]] += faceVal;
136  }
137  }
138  }
139  }
140 
142  {
144  }
145 }
146 
147 
148 template<class Type, class FType, class ResultType, class CellToFaceOp>
149 void surfaceSum
150 (
151  const surfaceScalarField& lambdas,
152  const GeometricField<Type, fvPatchField, volMesh>& vf,
153  const GeometricField<FType, fvsPatchField, surfaceMesh>& sadd,
154  const CellToFaceOp& cop,
155  GeometricField<ResultType, fvPatchField, volMesh>& result,
156  const bool doCorrectBoundaryConditions
157 )
158 {
159  const fvMesh& mesh = vf.mesh();
160  const auto& Sf = mesh.Sf();
161  const auto& P = mesh.owner();
162  const auto& N = mesh.neighbour();
163 
164  const auto& vfi = vf.primitiveField();
165  auto& sfi = result.primitiveFieldRef();
166 
167  // See e.g. surfaceInterpolationScheme<Type>::dotInterpolate
168 
169  // Internal field
170  {
171  const auto& Sfi = Sf.primitiveField();
172  const auto& lambda = lambdas.primitiveField();
173  const auto& saddi = sadd.primitiveField();
174 
175  for (label facei=0; facei<P.size(); facei++)
176  {
177  const label ownCelli = P[facei];
178  const label neiCelli = N[facei];
179 
180  const ResultType faceVal
181  (
182  cop
183  (
184  Sfi[facei],
185  lambda[facei],
186  vfi[ownCelli],
187  vfi[neiCelli],
188 
189  saddi[facei] // additional face value
190  )
191  );
192  sfi[ownCelli] += faceVal;
193  sfi[neiCelli] -= faceVal;
194  }
195  }
196 
197 
198  // Boundary field
199  {
200  forAll(mesh.boundary(), patchi)
201  {
202  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
203  const auto& pSf = Sf.boundaryField()[patchi];
204  const auto& pvf = vf.boundaryField()[patchi];
205  const auto& pLambda = lambdas.boundaryField()[patchi];
206  const auto& psadd = sadd.boundaryField()[patchi];
207 
208  if (pvf.coupled())
209  {
210  auto tpnf(pvf.patchNeighbourField());
211  auto& pnf = tpnf();
212 
213  for (label facei=0; facei<pFaceCells.size(); facei++)
214  {
215  // Interpolate between owner-side and neighbour-side values
216  const ResultType faceVal
217  (
218  cop
219  (
220  pSf[facei],
221  pLambda[facei],
222  vfi[pFaceCells[facei]],
223  pnf[facei],
224  psadd[facei]
225  )
226  );
227 
228  sfi[pFaceCells[facei]] += faceVal;
229  }
230  }
231  else
232  {
233  for (label facei=0; facei<pFaceCells.size(); facei++)
234  {
235  // Use patch value only
236  const ResultType faceVal
237  (
238  cop
239  (
240  pSf[facei],
241  scalar(1.0),
242  pvf[facei],
243  pTraits<Type>::zero, // not used
244 
245  psadd[facei]
246  )
247  );
248  sfi[pFaceCells[facei]] += faceVal;
249  }
250  }
251  }
252  }
253 
255  {
256  result.correctBoundaryConditions();
257  }
258 }
259 
260 
261 template
262 <
263  class Type,
264  class FType0,
265  class FType1,
266  class ResultType,
267  class CellToFaceOp
268 >
269 void surfaceSum
270 (
271  const surfaceScalarField& lambdas,
273 
276 
277  const CellToFaceOp& cop,
279  const bool doCorrectBoundaryConditions
280 )
281 {
282  const fvMesh& mesh = vf.mesh();
283  const auto& Sf = mesh.Sf();
284  const auto& P = mesh.owner();
285  const auto& N = mesh.neighbour();
286 
287  const auto& vfi = vf.primitiveField();
288  auto& resulti = result.primitiveFieldRef();
289 
290  // See e.g. surfaceInterpolationScheme<Type>::dotInterpolate
291 
292  // Internal field
293  {
294  const auto& Sfi = Sf.primitiveField();
295  const auto& lambda = lambdas.primitiveField();
296  const auto& sf0i = sf0.primitiveField();
297  const auto& sf1i = sf1.primitiveField();
298 
299  for (label facei=0; facei<P.size(); facei++)
300  {
301  const label ownCelli = P[facei];
302  const label neiCelli = N[facei];
303 
304  const ResultType faceVal
305  (
306  cop
307  (
308  Sfi[facei],
309 
310  lambda[facei],
311  vfi[ownCelli],
312  vfi[neiCelli],
313 
314  sf0i[facei], // additional face value
315  sf1i[facei] // additional face value
316  )
317  );
318  resulti[ownCelli] += faceVal;
319  resulti[neiCelli] -= faceVal;
320  }
321  }
322 
323 
324  // Boundary field
325  {
326  forAll(mesh.boundary(), patchi)
327  {
328  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
329  const auto& pSf = Sf.boundaryField()[patchi];
330  const auto& pvf = vf.boundaryField()[patchi];
331  const auto& pLambda = lambdas.boundaryField()[patchi];
332  const auto& psf0 = sf0.boundaryField()[patchi];
333  const auto& psf1 = sf1.boundaryField()[patchi];
334 
335  if (pvf.coupled())
336  {
337  auto tpnf(pvf.patchNeighbourField());
338  auto& pnf = tpnf();
339 
340  for (label facei=0; facei<pFaceCells.size(); facei++)
341  {
342  // Interpolate between owner-side and neighbour-side values
343  const ResultType faceVal
344  (
345  cop
346  (
347  pSf[facei],
348 
349  pLambda[facei],
350  vfi[pFaceCells[facei]],
351  pnf[facei],
352 
353  psf0[facei],
354  psf1[facei]
355  )
356  );
357 
358  resulti[pFaceCells[facei]] += faceVal;
359  }
360  }
361  else
362  {
363  for (label facei=0; facei<pFaceCells.size(); facei++)
364  {
365  // Use patch value only
366  const ResultType faceVal
367  (
368  cop
369  (
370  pSf[facei],
371  scalar(1.0),
372  pvf[facei],
373  pTraits<Type>::zero, // not used
374 
375  psf0[facei],
376  psf1[facei]
377  )
378  );
379  resulti[pFaceCells[facei]] += faceVal;
380  }
381  }
382  }
383  }
384 
386  {
388  }
389 }
390 
391 
392 template<class Type, class ResultType, class CombineOp>
393 void GaussOp
394 (
395  const surfaceScalarField& lambdas,
396  const GeometricField<Type, fvPatchField, volMesh>& vf,
397  const CombineOp& cop,
398  GeometricField<ResultType, fvPatchField, volMesh>& result
399 )
400 {
401  const fvMesh& mesh = vf.mesh();
402 
403  // Sum contributions
404  surfaceSum(lambdas, vf, cop, result, false);
405 
406  auto& sfi = result.primitiveFieldRef();
407  sfi /= mesh.V();
409  result.correctBoundaryConditions();
410 }
411 
412 
413 template<class Type, class ResultType, class CombineOp>
414 void surfaceOp
415 (
417  const surfaceVectorField& ownLs,
418  const surfaceVectorField& neiLs,
419  const CombineOp& cop,
421 )
422 {
423  const fvMesh& mesh = vf.mesh();
424  const auto& Sf = mesh.Sf();
425  const auto& P = mesh.owner();
426  const auto& N = mesh.neighbour();
427 
428  const auto& vfi = vf.primitiveField();
429  auto& sfi = result.primitiveFieldRef();
430 
431  // Internal field
432  {
433  const auto& Sfi = Sf.primitiveField();
434 
435  for (label facei=0; facei<P.size(); facei++)
436  {
437  const label ownCelli = P[facei];
438  const label neiCelli = N[facei];
439 
440  const Type faceVal
441  (
442  cop
443  (
444  Sfi[facei], // needed?
445  vfi[ownCelli],
446  vfi[neiCelli]
447  )
448  );
449  sfi[ownCelli] += ownLs[facei]*faceVal;
450  sfi[neiCelli] -= neiLs[facei]*faceVal;
451  }
452  }
453 
454 
455  // Boundary field
456  {
457  forAll(mesh.boundary(), patchi)
458  {
459  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
460  const auto& pSf = Sf.boundaryField()[patchi];
461  const auto& pvf = vf.boundaryField()[patchi];
462  const auto& pOwnLs = ownLs.boundaryField()[patchi];
463 
464  if (pvf.coupled())
465  {
466  auto tpnf(pvf.patchNeighbourField());
467  auto& pnf = tpnf();
468 
469  for (label facei=0; facei<pFaceCells.size(); facei++)
470  {
471  const Type faceVal
472  (
473  cop
474  (
475  pSf[facei], // needed?
476  vfi[pFaceCells[facei]],
477  pnf[facei]
478  )
479  );
480 
481  sfi[pFaceCells[facei]] += pOwnLs[facei]*faceVal;
482  }
483  }
484  else
485  {
486  for (label facei=0; facei<pFaceCells.size(); facei++)
487  {
488  const Type faceVal
489  (
490  cop
491  (
492  pSf[facei],
493  vfi[pFaceCells[facei]],
494  pvf[facei]
495  )
496  );
497  sfi[pFaceCells[facei]] += pOwnLs[facei]*faceVal;
498  }
499  }
500  }
501  }
503  result.correctBoundaryConditions();
504 }
505 
506 
507 template<class Type, class ResultType, class CellToFaceOp>
508 void surfaceSnSum
509 (
510  const surfaceScalarField& deltaCoeffs,
512 
513  const CellToFaceOp& cop,
514 
516  const bool doCorrectBoundaryConditions
517 )
518 {
519  const fvMesh& mesh = vf.mesh();
520  const auto& Sf = mesh.Sf();
521  const auto& P = mesh.owner();
522  const auto& N = mesh.neighbour();
523 
524  const auto& vfi = vf.primitiveField();
525  auto& sfi = result.primitiveFieldRef();
526 
527  // Internal field
528  {
529  const auto& Sfi = Sf.primitiveField();
530  const auto& dc = deltaCoeffs.primitiveField();
531 
532  for (label facei=0; facei<P.size(); facei++)
533  {
534  const label ownCelli = P[facei];
535  const label neiCelli = N[facei];
536 
537  const ResultType faceVal
538  (
539  cop
540  (
541  Sfi[facei], // area vector
542  dc[facei], // delta coefficients
543  vfi[ownCelli],
544  vfi[neiCelli]
545  )
546  );
547  sfi[ownCelli] += faceVal;
548  sfi[neiCelli] -= faceVal;
549  }
550  }
551 
552 
553  // Boundary field
554  {
555  forAll(mesh.boundary(), patchi)
556  {
557  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
558  const auto& pSf = Sf.boundaryField()[patchi];
559  const auto& pvf = vf.boundaryField()[patchi];
560  const auto& pdc = deltaCoeffs.boundaryField()[patchi];
561 
562  if (pvf.coupled())
563  {
564  auto tpnf(pvf.patchNeighbourField());
565  auto& pnf = tpnf();
566 
567  for (label facei=0; facei<pFaceCells.size(); facei++)
568  {
569  const label ownCelli = pFaceCells[facei];
570 
571  // Interpolate between owner-side and neighbour-side values
572  const ResultType faceVal
573  (
574  cop
575  (
576  pSf[facei], // area vector
577  pdc[facei],
578  vfi[ownCelli],
579  pnf[facei]
580  )
581  );
582 
583  sfi[ownCelli] += faceVal;
584  }
585  }
586  else
587  {
588  auto tpnf(pvf.snGrad());
589  auto& pnf = tpnf();
590 
591  for (label facei=0; facei<pFaceCells.size(); facei++)
592  {
593  const label ownCelli = pFaceCells[facei];
594 
595  // Use patch value only
596  const ResultType faceVal
597  (
598  cop
599  (
600  pSf[facei], // area vector
601  scalar(1.0), // use 100% of pnf
602  pTraits<Type>::zero,
603  pnf[facei]
604  )
605  );
606  sfi[ownCelli] += faceVal;
607  }
608  }
609  }
610  }
611 
613  {
615  }
616 }
617 
618 
619 template<class Type, class ResultType, class CellToFaceOp>
620 void surfaceSnSum
621 (
622  const surfaceScalarField& deltaCoeffs,
623  const GeometricField<Type, fvPatchField, volMesh>& vf,
624  const GeometricField<Type, fvsPatchField, surfaceMesh>& sadd,
625 
626  const CellToFaceOp& cop,
627 
628  GeometricField<ResultType, fvPatchField, volMesh>& result,
629  const bool doCorrectBoundaryConditions
630 )
631 {
632  const fvMesh& mesh = vf.mesh();
633  const auto& Sf = mesh.Sf();
634  const auto& P = mesh.owner();
635  const auto& N = mesh.neighbour();
636 
637  const auto& vfi = vf.primitiveField();
638  auto& sfi = result.primitiveFieldRef();
639 
640  // Internal field
641  {
642  const auto& Sfi = Sf.primitiveField();
643  const auto& dc = deltaCoeffs.primitiveField();
644  const auto& saddi = sadd.primitiveField();
645 
646  for (label facei=0; facei<P.size(); facei++)
647  {
648  const label ownCelli = P[facei];
649  const label neiCelli = N[facei];
650 
651  const ResultType faceVal
652  (
653  cop
654  (
655  Sfi[facei], // area vector
656  dc[facei], // delta coefficients
657  vfi[ownCelli],
658  vfi[neiCelli],
659  saddi[facei] // face addition value
660  )
661  );
662  sfi[ownCelli] += faceVal;
663  sfi[neiCelli] -= faceVal;
664  }
665  }
666 
667 
668  // Boundary field
669  {
670  forAll(mesh.boundary(), patchi)
671  {
672  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
673  const auto& pSf = Sf.boundaryField()[patchi];
674  const auto& pvf = vf.boundaryField()[patchi];
675  const auto& pdc = deltaCoeffs.boundaryField()[patchi];
676  const auto& psadd = sadd.boundaryField()[patchi];
677 
678  if (pvf.coupled())
679  {
680  auto tpnf(pvf.patchNeighbourField());
681  auto& pnf = tpnf();
682 
683  for (label facei=0; facei<pFaceCells.size(); facei++)
684  {
685  const label ownCelli = pFaceCells[facei];
686 
687  // Interpolate between owner-side and neighbour-side values
688  const ResultType faceVal
689  (
690  cop
691  (
692  pSf[facei], // area vector
693  pdc[facei],
694  vfi[ownCelli],
695  pnf[facei],
696  psadd[facei]
697  )
698  );
699 
700  sfi[ownCelli] += faceVal;
701  }
702  }
703  else
704  {
705  auto tpnf(pvf.snGrad());
706  auto& pnf = tpnf();
707 
708  for (label facei=0; facei<pFaceCells.size(); facei++)
709  {
710  const label ownCelli = pFaceCells[facei];
711 
712  // Use patch value only
713  const ResultType faceVal
714  (
715  cop
716  (
717  pSf[facei], // area vector
718  scalar(1.0), // use 100% of pnf
719  pTraits<Type>::zero,
720  pnf[facei],
721  psadd[facei]
722  )
723  );
724  sfi[ownCelli] += faceVal;
725  }
726  }
727  }
728  }
729 
731  {
732  result.correctBoundaryConditions();
733  }
734 }
735 
736 
737 template<class Type, class GType, class ResultType, class CellToFaceOp>
738 void surfaceSnSum
739 (
740  const surfaceScalarField& gammaWeights,
741  const GeometricField<GType, fvPatchField, volMesh>& gamma,
742 
743  const surfaceScalarField& deltaCoeffs,
744  const GeometricField<Type, fvPatchField, volMesh>& vf,
745 
746  const CellToFaceOp& cop,
747 
748  GeometricField<ResultType, fvPatchField, volMesh>& result,
749  const bool doCorrectBoundaryConditions
750 )
751 {
752  const fvMesh& mesh = vf.mesh();
753  const auto& Sf = mesh.Sf();
754  const auto& P = mesh.owner();
755  const auto& N = mesh.neighbour();
756 
757  const auto& gammai = gamma.primitiveField();
758  const auto& vfi = vf.primitiveField();
759  auto& sfi = result.primitiveFieldRef();
760 
761  // Internal field
762  {
763  const auto& Sfi = Sf.primitiveField();
764  const auto& weights = gammaWeights.primitiveField();
765  const auto& dc = deltaCoeffs.primitiveField();
766 
767  for (label facei=0; facei<P.size(); facei++)
768  {
769  const label ownCelli = P[facei];
770  const label neiCelli = N[facei];
771 
772  const ResultType faceVal
773  (
774  cop
775  (
776  Sfi[facei], // area vector
777 
778  weights[facei], // interpolation weights
779  gammai[ownCelli],
780  gammai[neiCelli],
781 
782  dc[facei], // delta coefficients
783  vfi[ownCelli],
784  vfi[neiCelli]
785  )
786  );
787  sfi[ownCelli] += faceVal;
788  sfi[neiCelli] -= faceVal;
789  }
790  }
791 
792 
793  // Boundary field
794  {
795  forAll(mesh.boundary(), patchi)
796  {
797  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
798  const auto& pSf = Sf.boundaryField()[patchi];
799  const auto& pvf = vf.boundaryField()[patchi];
800  const auto& pdc = deltaCoeffs.boundaryField()[patchi];
801  const auto& pweights = gammaWeights.boundaryField()[patchi];
802  const auto& pgamma = gamma.boundaryField()[patchi];
803 
804  if (pvf.coupled())
805  {
806  auto tpnf(pvf.patchNeighbourField());
807  auto& pnf = tpnf();
808  auto tgammanf(pgamma.patchNeighbourField());
809  auto& gammanf = tgammanf();
810 
811  for (label facei=0; facei<pFaceCells.size(); facei++)
812  {
813  const label ownCelli = pFaceCells[facei];
814 
815  // Interpolate between owner-side and neighbour-side values
816  const ResultType faceVal
817  (
818  cop
819  (
820  pSf[facei], // area vector
821 
822  pweights[facei],
823  gammai[ownCelli],
824  gammanf[facei],
825 
826  pdc[facei],
827  vfi[ownCelli],
828  pnf[facei]
829  )
830  );
831 
832  sfi[ownCelli] += faceVal;
833  }
834  }
835  else
836  {
837  auto tpnf(pvf.snGrad());
838  auto& pnf = tpnf();
839 
840  for (label facei=0; facei<pFaceCells.size(); facei++)
841  {
842  const label ownCelli = pFaceCells[facei];
843 
844  // Use patch value only
845  const ResultType faceVal
846  (
847  cop
848  (
849  pSf[facei], // area vector
850 
851  scalar(1.0),
852  pgamma[facei],
853  pTraits<GType>::zero, // not used
854 
855 
856  scalar(1.0), // use 100% of pnf
857  pTraits<Type>::zero,
858  pnf[facei]
859  )
860  );
861  sfi[ownCelli] += faceVal;
862  }
863  }
864  }
865  }
866 
868  {
869  result.correctBoundaryConditions();
870  }
871 }
872 
873 
874 template<class Type, class GType, class ResultType, class CellToFaceOp>
875 void surfaceSnSum
876 (
877  const surfaceScalarField& gammaWeights,
878  const GeometricField<GType, fvPatchField, volMesh>& gamma,
879 
880  const surfaceScalarField& deltaCoeffs,
881  const GeometricField<Type, fvPatchField, volMesh>& vf,
882 
883  const GeometricField<Type, fvsPatchField, surfaceMesh>& sadd,
884 
885  const CellToFaceOp& cop,
886 
887  GeometricField<ResultType, fvPatchField, volMesh>& result,
888  const bool doCorrectBoundaryConditions
889 )
890 {
891  const fvMesh& mesh = vf.mesh();
892  const auto& Sf = mesh.Sf();
893  const auto& P = mesh.owner();
894  const auto& N = mesh.neighbour();
895 
896  const auto& gammai = gamma.primitiveField();
897  const auto& vfi = vf.primitiveField();
898  auto& sfi = result.primitiveFieldRef();
899 
900  // Internal field
901  {
902  const auto& Sfi = Sf.primitiveField();
903  const auto& weights = gammaWeights.primitiveField();
904  const auto& dc = deltaCoeffs.primitiveField();
905  const auto& saddi = sadd.primitiveField();
906 
907  for (label facei=0; facei<P.size(); facei++)
908  {
909  const label ownCelli = P[facei];
910  const label neiCelli = N[facei];
911 
912  const ResultType faceVal
913  (
914  cop
915  (
916  Sfi[facei], // area vector
917 
918  weights[facei], // interpolation weights
919  gammai[ownCelli],
920  gammai[neiCelli],
921 
922  dc[facei], // delta coefficients
923  vfi[ownCelli],
924  vfi[neiCelli],
925 
926  saddi[facei] // face addition value
927  )
928  );
929  sfi[ownCelli] += faceVal;
930  sfi[neiCelli] -= faceVal;
931  }
932  }
933 
934 
935  // Boundary field
936  {
937  forAll(mesh.boundary(), patchi)
938  {
939  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
940  const auto& pSf = Sf.boundaryField()[patchi];
941  const auto& pvf = vf.boundaryField()[patchi];
942  const auto& pdc = deltaCoeffs.boundaryField()[patchi];
943  const auto& pweights = gammaWeights.boundaryField()[patchi];
944  const auto& pgamma = gamma.boundaryField()[patchi];
945  const auto& psadd = sadd.boundaryField()[patchi];
946 
947  if (pvf.coupled())
948  {
949  auto tpnf(pvf.patchNeighbourField());
950  auto& pnf = tpnf();
951  auto tgammanf(pgamma.patchNeighbourField());
952  auto& gammanf = tgammanf();
953 
954  for (label facei=0; facei<pFaceCells.size(); facei++)
955  {
956  const label ownCelli = pFaceCells[facei];
957 
958  // Interpolate between owner-side and neighbour-side values
959  const ResultType faceVal
960  (
961  cop
962  (
963  pSf[facei], // area vector
964 
965  pweights[facei],
966  gammai[ownCelli],
967  gammanf[facei],
968 
969  pdc[facei],
970  vfi[ownCelli],
971  pnf[facei],
972 
973  psadd[facei]
974  )
975  );
976 
977  sfi[ownCelli] += faceVal;
978  }
979  }
980  else
981  {
982  auto tpnf(pvf.snGrad());
983  auto& pnf = tpnf();
984 
985  for (label facei=0; facei<pFaceCells.size(); facei++)
986  {
987  const label ownCelli = pFaceCells[facei];
988 
989  // Use patch value only
990  const ResultType faceVal
991  (
992  cop
993  (
994  pSf[facei], // area vector
995 
996  scalar(1.0),
997  pgamma[facei],
998  pTraits<GType>::zero, // not used
999 
1000 
1001  scalar(1.0), // use 100% of pnf
1002  pTraits<Type>::zero,
1003  pnf[facei],
1004 
1005  psadd[facei]
1006  )
1007  );
1008  sfi[ownCelli] += faceVal;
1009  }
1010  }
1011  }
1012  }
1013 
1015  {
1016  result.correctBoundaryConditions();
1017  }
1018 }
1019 
1020 
1021 template
1022 <
1023  class Type,
1024  class GType0,
1025  class GType1,
1026  class ResultType,
1027  class CellToFaceOp
1028 >
1029 void surfaceSnSum
1030 (
1031  const surfaceScalarField& gammaWeights,
1034 
1035  const surfaceScalarField& deltaCoeffs,
1037 
1038  const CellToFaceOp& cop,
1039 
1041  const bool doCorrectBoundaryConditions
1042 )
1043 {
1044  const fvMesh& mesh = vf.mesh();
1045  const auto& Sf = mesh.Sf();
1046  const auto& P = mesh.owner();
1047  const auto& N = mesh.neighbour();
1048 
1049  const auto& gamma0i = gamma0.primitiveField();
1050  const auto& gamma1i = gamma1.primitiveField();
1051  const auto& vfi = vf.primitiveField();
1052  auto& sfi = result.primitiveFieldRef();
1053 
1054  // Internal field
1055  {
1056  const auto& Sfi = Sf.primitiveField();
1057  const auto& weights = gammaWeights.primitiveField();
1058  const auto& dc = deltaCoeffs.primitiveField();
1059 
1060  for (label facei=0; facei<P.size(); facei++)
1061  {
1062  const label ownCelli = P[facei];
1063  const label neiCelli = N[facei];
1064 
1065  const ResultType faceVal
1066  (
1067  cop
1068  (
1069  Sfi[facei], // area vector
1070 
1071  weights[facei], // interpolation weights
1072 
1073  gamma0i[ownCelli],
1074  gamma0i[neiCelli],
1075 
1076  gamma1i[ownCelli],
1077  gamma1i[neiCelli],
1078 
1079  dc[facei], // delta coefficients
1080  vfi[ownCelli],
1081  vfi[neiCelli]
1082  )
1083  );
1084  sfi[ownCelli] += faceVal;
1085  sfi[neiCelli] -= faceVal;
1086  }
1087  }
1088 
1089 
1090  // Boundary field
1091  {
1092  forAll(mesh.boundary(), patchi)
1093  {
1094  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
1095  const auto& pSf = Sf.boundaryField()[patchi];
1096  const auto& pvf = vf.boundaryField()[patchi];
1097  const auto& pdc = deltaCoeffs.boundaryField()[patchi];
1098  const auto& pweights = gammaWeights.boundaryField()[patchi];
1099  const auto& pgamma0 = gamma0.boundaryField()[patchi];
1100  const auto& pgamma1 = gamma1.boundaryField()[patchi];
1101 
1102  if (pvf.coupled())
1103  {
1104  auto tpnf(pvf.patchNeighbourField());
1105  auto& pnf = tpnf();
1106  auto tgamma0nf(pgamma0.patchNeighbourField());
1107  auto& gamma0nf = tgamma0nf();
1108  auto tgamma1nf(pgamma1.patchNeighbourField());
1109  auto& gamma1nf = tgamma1nf();
1110 
1111  for (label facei=0; facei<pFaceCells.size(); facei++)
1112  {
1113  const label ownCelli = pFaceCells[facei];
1114 
1115  // Interpolate between owner-side and neighbour-side values
1116  const ResultType faceVal
1117  (
1118  cop
1119  (
1120  pSf[facei], // area vector
1121 
1122  pweights[facei],
1123 
1124  gamma0i[ownCelli],
1125  gamma0nf[facei],
1126 
1127  gamma1i[ownCelli],
1128  gamma1nf[facei],
1129 
1130  pdc[facei],
1131  vfi[ownCelli],
1132  pnf[facei]
1133  )
1134  );
1135 
1136  sfi[ownCelli] += faceVal;
1137  }
1138  }
1139  else
1140  {
1141  auto tpnf(pvf.snGrad());
1142  auto& pnf = tpnf();
1143 
1144  for (label facei=0; facei<pFaceCells.size(); facei++)
1145  {
1146  const label ownCelli = pFaceCells[facei];
1147 
1148  // Use patch value only
1149  const ResultType faceVal
1150  (
1151  cop
1152  (
1153  pSf[facei], // area vector
1154 
1155  scalar(1.0),
1156 
1157  pgamma0[facei],
1158  pTraits<GType0>::zero, // not used
1159 
1160  pgamma1[facei],
1161  pTraits<GType1>::zero, // not used
1162 
1163  scalar(1.0), // use 100% of pnf
1165  pnf[facei]
1166  )
1167  );
1168  sfi[ownCelli] += faceVal;
1169  }
1170  }
1171  }
1172  }
1173 
1175  {
1177  }
1178 }
1179 
1180 
1181 template<class Type, class FType, class ResultType, class CellToFaceOp>
1182 void interpolate
1183 (
1184  const surfaceScalarField& weights,
1185  const GeometricField<Type, fvPatchField, volMesh>& vf,
1186  const GeometricField<FType, fvsPatchField, surfaceMesh>& sf,
1187  const CellToFaceOp& cop,
1188  GeometricField<ResultType, fvsPatchField, surfaceMesh>& result
1189 )
1190 {
1191  const fvMesh& mesh = vf.mesh();
1192  const auto& Sf = mesh.Sf();
1193  const auto& P = mesh.owner();
1194  const auto& N = mesh.neighbour();
1195 
1196  const auto& vfi = vf.primitiveField();
1197 
1198  // Internal field
1199  {
1200  const auto& Sfi = Sf.primitiveField();
1201  const auto& weight = weights.primitiveField();
1202  const auto& sfi = sf.primitiveField();
1203 
1204  auto& resulti = result.primitiveFieldRef();
1205 
1206  for (label facei=0; facei<P.size(); facei++)
1207  {
1208  const label ownCelli = P[facei];
1209  const label neiCelli = N[facei];
1210 
1211  cop
1212  (
1213  Sfi[facei],
1214 
1215  weight[facei],
1216  vfi[ownCelli],
1217  vfi[neiCelli],
1218 
1219  sfi[facei],
1220 
1221  resulti[facei]
1222  );
1223  }
1224  }
1225 
1226 
1227  // Boundary field
1228  {
1229  forAll(mesh.boundary(), patchi)
1230  {
1231  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
1232  const auto& pSf = Sf.boundaryField()[patchi];
1233  const auto& pvf = vf.boundaryField()[patchi];
1234  const auto& pweight = weights.boundaryField()[patchi];
1235  const auto& psf = sf.boundaryField()[patchi];
1236  auto& presult = result.boundaryFieldRef()[patchi];
1237 
1238  if (pvf.coupled())
1239  {
1240  auto tpnf(pvf.patchNeighbourField());
1241  auto& pnf = tpnf();
1242 
1243  for (label facei=0; facei<pFaceCells.size(); facei++)
1244  {
1245  // Interpolate between owner-side and neighbour-side values
1246  cop
1247  (
1248  pSf[facei],
1249 
1250  pweight[facei],
1251  vfi[pFaceCells[facei]],
1252  pnf[facei],
1253 
1254  psf[facei],
1255 
1256  presult[facei]
1257  );
1258  }
1259  }
1260  else
1261  {
1262  for (label facei=0; facei<pFaceCells.size(); facei++)
1263  {
1264  // Use patch value only
1265  cop
1266  (
1267  pSf[facei],
1268 
1269  scalar(1.0),
1270  pvf[facei],
1271  pTraits<Type>::zero, // not used
1272 
1273  psf[facei],
1274 
1275  presult[facei]
1276  );
1277  }
1278  }
1279  }
1280  }
1281 }
1282 template
1284  class Type0,
1285  class Type1,
1286  class ResultType,
1287  class CellToFaceOp
1288 >
1289 void interpolate
1290 (
1291  const surfaceScalarField& weights,
1294  const CellToFaceOp& cop,
1296 )
1297 {
1298  const fvMesh& mesh = vf0.mesh();
1299  const auto& Sf = mesh.Sf();
1300  const auto& P = mesh.owner();
1301  const auto& N = mesh.neighbour();
1302 
1303  const auto& vf0i = vf0.primitiveField();
1304  const auto& vf1i = vf1.primitiveField();
1305 
1306  // Internal field
1307  {
1308  const auto& Sfi = Sf.primitiveField();
1309  const auto& weight = weights.primitiveField();
1310 
1311  auto& resulti = result.primitiveFieldRef();
1312 
1313  for (label facei=0; facei<P.size(); facei++)
1314  {
1315  const label ownCelli = P[facei];
1316  const label neiCelli = N[facei];
1317 
1318  cop
1319  (
1320  Sfi[facei],
1321 
1322  weight[facei],
1323 
1324  vf0i[ownCelli],
1325  vf0i[neiCelli],
1326 
1327  vf1i[ownCelli],
1328  vf1i[neiCelli],
1329 
1330  resulti[facei]
1331  );
1332  }
1333  }
1334 
1335 
1336  // Boundary field
1337  {
1338  forAll(mesh.boundary(), patchi)
1339  {
1340  const auto& pFaceCells = mesh.boundary()[patchi].faceCells();
1341  const auto& pSf = Sf.boundaryField()[patchi];
1342  const auto& pvf0 = vf0.boundaryField()[patchi];
1343  const auto& pvf1 = vf1.boundaryField()[patchi];
1344  const auto& pweight = weights.boundaryField()[patchi];
1345  auto& presult = result.boundaryFieldRef()[patchi];
1346 
1347  if (pvf0.coupled() || pvf1.coupled())
1348  {
1349  auto tpnf0(pvf0.patchNeighbourField());
1350  auto& pnf0 = tpnf0();
1351 
1352  auto tpnf1(pvf1.patchNeighbourField());
1353  auto& pnf1 = tpnf1();
1354 
1355  for (label facei=0; facei<pFaceCells.size(); facei++)
1356  {
1357  // Interpolate between owner-side and neighbour-side values
1358  cop
1359  (
1360  pSf[facei],
1361 
1362  pweight[facei],
1363 
1364  vf0i[pFaceCells[facei]],
1365  pnf0[facei],
1366 
1367  vf1i[pFaceCells[facei]],
1368  pnf1[facei],
1369 
1370  presult[facei]
1371  );
1372  }
1373  }
1374  else
1375  {
1376  for (label facei=0; facei<pFaceCells.size(); facei++)
1377  {
1378  // Use patch value only
1379  cop
1380  (
1381  pSf[facei],
1382 
1383  scalar(1.0),
1384 
1385  pvf0[facei],
1386  pTraits<Type0>::zero, // not used
1387 
1388  pvf1[facei],
1389  pTraits<Type1>::zero, // not used
1390 
1391  presult[facei]
1392  );
1393  }
1394  }
1395  }
1396  }
1397 }
1398 
1399 
1400 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1401 
1402 } // End namespace fvc
1403 
1404 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
1405 
1406 } // End namespace Foam
1407 
1408 // ************************************************************************* //
const Internal::FieldType & primitiveField() const noexcept
Return a const-reference to the internal field values.
A traits class, which is primarily used for primitives and vector-space.
Definition: pTraits.H:61
static void doCorrectBoundaryConditions(bool correctBCs, VolumeField< Type > &field)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
dynamicFvMesh & mesh
dimensionedScalar lambda("lambda", dimTime/sqr(dimLength), laminarTransport)
void surfaceOp(const GeometricField< Type, fvPatchField, volMesh > &vf, const surfaceVectorField &ownLs, const surfaceVectorField &neiLs, const CombineOp &cop, GeometricField< ResultType, fvPatchField, volMesh > &result)
static tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > interpolate(const GeometricField< Type, fvPatchField, volMesh > &tvf, const surfaceScalarField &faceFlux, Istream &schemeData)
Interpolate field onto faces using scheme given by Istream.
const Vector< label > N(dict.get< Vector< label >>("N"))
void surfaceSnSum(const surfaceScalarField &deltaCoeffs, const GeometricField< Type, fvPatchField, volMesh > &vf, const CellToFaceOp &cop, GeometricField< ResultType, fvPatchField, volMesh > &result, const bool doCorrectBoundaryConditions)
sum of snGrad
Surface integrate surfaceField creating a volField. Surface sum a surfaceField creating a volField...
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
const Mesh & mesh() const noexcept
Return const reference to mesh.
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
void correctBoundaryConditions()
Correct boundary field.
tmp< GeometricField< Type, fvPatchField, volMesh > > surfaceSum(const GeometricField< Type, fvsPatchField, surfaceMesh > &ssf)
const scalar gamma
Definition: EEqn.H:9
GeometricField< scalar, fvsPatchField, surfaceMesh > surfaceScalarField
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
void GaussOp(const surfaceScalarField &lambdas, const GeometricField< Type, fvPatchField, volMesh > &vf, const CombineOp &cop, GeometricField< ResultType, fvPatchField, volMesh > &result)
Namespace for OpenFOAM.