fvMatrix.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2016-2024 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 "volFields.H"
30 #include "surfaceFields.H"
33 #include "coupledFvPatchFields.H"
34 #include "IndirectList.H"
35 #include "UniformList.H"
36 #include "demandDrivenData.H"
37 
38 #include "cyclicFvPatchField.H"
39 #include "cyclicAMIFvPatchField.H"
40 #include "cyclicACMIFvPatchField.H"
41 
43 
44 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
45 
46 template<class Type>
47 template<class Type2>
49 (
50  const labelUList& addr,
51  const Field<Type2>& pf,
52  Field<Type2>& intf
53 ) const
54 {
55  if (addr.size() != pf.size())
56  {
58  << "addressing (" << addr.size()
59  << ") and field (" << pf.size() << ") are different sizes" << endl
60  << abort(FatalError);
61  }
62 
63  forAll(addr, facei)
64  {
65  intf[addr[facei]] += pf[facei];
66  }
67 }
68 
69 
70 template<class Type>
71 template<class Type2>
73 (
74  const labelUList& addr,
75  const tmp<Field<Type2>>& tpf,
76  Field<Type2>& intf
77 ) const
78 {
79  addToInternalField(addr, tpf(), intf);
80  tpf.clear();
81 }
82 
83 
84 template<class Type>
85 template<class Type2>
87 (
88  const labelUList& addr,
89  const Field<Type2>& pf,
90  Field<Type2>& intf
91 ) const
92 {
93  if (addr.size() != pf.size())
94  {
96  << "addressing (" << addr.size()
97  << ") and field (" << pf.size() << ") are different sizes" << endl
98  << abort(FatalError);
99  }
100 
101  forAll(addr, facei)
102  {
103  intf[addr[facei]] -= pf[facei];
104  }
105 }
106 
107 
108 template<class Type>
109 template<class Type2>
111 (
112  const labelUList& addr,
113  const tmp<Field<Type2>>& tpf,
114  Field<Type2>& intf
115 ) const
116 {
117  subtractFromInternalField(addr, tpf(), intf);
118  tpf.clear();
119 }
120 
121 
122 template<class Type>
124 (
125  scalarField& diag,
126  const direction solveCmpt
127 ) const
128 {
129  for (label fieldi = 0; fieldi < nMatrices(); ++fieldi)
130  {
131  const auto& bpsi = this->psi(fieldi).boundaryField();
132 
133  forAll(bpsi, ptfi)
134  {
135  const label patchi = globalPatchID(fieldi, ptfi);
136 
137  if (patchi != -1)
138  {
139  addToInternalField
140  (
141  lduAddr().patchAddr(patchi),
142  internalCoeffs_[patchi].component(solveCmpt),
143  diag
144  );
145  }
146  }
147  }
148 }
149 
150 
151 template<class Type>
153 {
154  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
155  {
156  const auto& bpsi = this->psi(fieldi).boundaryField();
157 
158  forAll(bpsi, ptfi)
159  {
160  const label patchi = globalPatchID(fieldi, ptfi);
161  if (patchi != -1)
162  {
163  addToInternalField
164  (
165  lduAddr().patchAddr(patchi),
166  cmptAv(internalCoeffs_[patchi]),
167  diag
168  );
169  }
170  }
171  }
172 }
173 
174 
175 template<class Type>
177 (
178  Field<Type>& source,
179  const bool couples
180 ) const
181 {
182  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
183  {
184  const auto& bpsi = this->psi(fieldi).boundaryField();
185 
186  forAll(bpsi, ptfi)
187  {
188  const fvPatchField<Type>& ptf = bpsi[ptfi];
189 
190  const label patchi = globalPatchID(fieldi, ptfi);
191 
192  if (patchi != -1)
193  {
194  const Field<Type>& pbc = boundaryCoeffs_[patchi];
195 
196  if (!ptf.coupled())
197  {
198  addToInternalField
199  (
200  lduAddr().patchAddr(patchi),
201  pbc,
202  source
203  );
204  }
205  else if (couples)
206  {
207  const tmp<Field<Type>> tpnf = ptf.patchNeighbourField();
208  const Field<Type>& pnf = tpnf();
209 
210  const labelUList& addr = lduAddr().patchAddr(patchi);
211 
212  forAll(addr, facei)
213  {
214  source[addr[facei]] +=
215  cmptMultiply(pbc[facei], pnf[facei]);
216  }
217  }
218  }
219  }
220  }
221 }
222 
223 
224 template<class Type>
225 template<template<class> class ListType>
227 (
228  const labelUList& cellLabels,
229  const ListType<Type>& values
230 )
231 {
232  const fvMesh& mesh = psi_.mesh();
233 
234  const cellList& cells = mesh.cells();
235  const labelUList& own = mesh.owner();
236  const labelUList& nei = mesh.neighbour();
237 
238  scalarField& Diag = diag();
239  Field<Type>& psi =
240  const_cast
241  <
242  GeometricField<Type, fvPatchField, volMesh>&
243  >(psi_).primitiveFieldRef();
244 
245 
246  // Following actions:
247  // - adjust local field psi
248  // - set local matrix to be diagonal (so adjust source)
249  // - cut connections to neighbours
250  // - make (on non-adjusted cells) contribution explicit
251 
252  if (symmetric() || asymmetric())
253  {
254  forAll(cellLabels, i)
255  {
256  const label celli = cellLabels[i];
257  const Type& value = values[i];
258 
259  for (const label facei : cells[celli])
260  {
261  const label patchi = mesh.boundaryMesh().patchID(facei);
262 
263  if (patchi == -1)
264  {
265  if (symmetric())
266  {
267  if (celli == own[facei])
268  {
269  source_[nei[facei]] -= upper()[facei]*value;
270  }
271  else
272  {
273  source_[own[facei]] -= upper()[facei]*value;
274  }
275 
276  upper()[facei] = 0.0;
277  }
278  else
279  {
280  if (celli == own[facei])
281  {
282  source_[nei[facei]] -= lower()[facei]*value;
283  }
284  else
285  {
286  source_[own[facei]] -= upper()[facei]*value;
287  }
288 
289  upper()[facei] = 0.0;
290  lower()[facei] = 0.0;
291  }
292  }
293  else
294  {
295  if (internalCoeffs_[patchi].size())
296  {
297  const label patchFacei =
298  mesh.boundaryMesh()[patchi].whichFace(facei);
299 
300  internalCoeffs_[patchi][patchFacei] = Zero;
301  boundaryCoeffs_[patchi][patchFacei] = Zero;
302  }
303  }
304  }
305  }
306  }
307 
308  // Note: above loop might have affected source terms on adjusted cells
309  // so make sure to adjust them afterwards
310  forAll(cellLabels, i)
311  {
312  const label celli = cellLabels[i];
313  const Type& value = values[i];
314 
315  psi[celli] = value;
316  source_[celli] = value*Diag[celli];
317  }
318 }
319 
320 
321 template<class Type>
322 bool Foam::fvMatrix<Type>::checkImplicit(const label fieldi)
323 {
324  const auto& bpsi = this->psi(fieldi).boundaryField();
325 
326  word idName;
327  forAll(bpsi, patchi)
328  {
329  if (bpsi[patchi].useImplicit())
330  {
331  if (debug)
332  {
333  Pout<< "fvMatrix<Type>::checkImplicit "
334  << " field:" << this->psi(fieldi).name()
335  << " on mesh:"
336  << this->psi(fieldi).mesh().name()
337  << " patch:" << bpsi[patchi].patch().name()
338  << endl;
339  }
340 
341  idName += Foam::name(patchi);
342  useImplicit_ = true;
343  }
344  }
345 
346  if (useImplicit_)
347  {
348  lduAssemblyName_ = word("lduAssembly") + idName;
349  }
350 
351  return !idName.empty();
352 }
353 
354 
355 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
356 
357 template<class Type>
359 (
361  const dimensionSet& ds
362 )
363 :
364  lduMatrix(psi.mesh()),
365  psi_(psi),
366  useImplicit_(false),
367  lduAssemblyName_(),
368  nMatrix_(0),
369  dimensions_(ds),
370  source_(psi.size(), Zero),
371  internalCoeffs_(psi.mesh().boundary().size()),
372  boundaryCoeffs_(psi.mesh().boundary().size())
373 {
375  << "Constructing fvMatrix<Type> for field " << psi_.name() << endl;
376 
377  checkImplicit();
378 
379  forAll(psi.mesh().boundary(), patchi)
380  {
381  internalCoeffs_.set
382  (
383  patchi,
384  new Field<Type>(psi.mesh().boundary()[patchi].size(), Zero)
385  );
386 
387  boundaryCoeffs_.set
388  (
389  patchi,
390  new Field<Type>(psi.mesh().boundary()[patchi].size(), Zero)
391  );
392  }
393 
394  auto& psiRef = this->psi(0);
395  const label currentStatePsi = psiRef.eventNo();
396  psiRef.boundaryFieldRef().updateCoeffs();
397  psiRef.eventNo() = currentStatePsi;
398 }
399 
400 
401 template<class Type>
403 :
404  lduMatrix(fvm),
405  psi_(fvm.psi_),
406  useImplicit_(fvm.useImplicit_),
407  lduAssemblyName_(fvm.lduAssemblyName_),
408  nMatrix_(fvm.nMatrix_),
409  dimensions_(fvm.dimensions_),
410  source_(fvm.source_),
411  internalCoeffs_(fvm.internalCoeffs_),
412  boundaryCoeffs_(fvm.boundaryCoeffs_)
413 {
415  << "Copying fvMatrix<Type> for field " << psi_.name() << endl;
416 
417  if (fvm.faceFluxCorrectionPtr_)
418  {
419  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
420  (
421  *(fvm.faceFluxCorrectionPtr_)
422  );
423  }
424 }
425 
426 
427 template<class Type>
428 Foam::fvMatrix<Type>::fvMatrix(const tmp<fvMatrix<Type>>& tmat)
429 :
430  lduMatrix(tmat.constCast(), tmat.movable()),
431  psi_(tmat().psi_),
432  useImplicit_(tmat().useImplicit_),
433  lduAssemblyName_(tmat().lduAssemblyName_),
434  nMatrix_(tmat().nMatrix_),
435  dimensions_(tmat().dimensions_),
436  source_(tmat.constCast().source_, tmat.movable()),
437  internalCoeffs_(tmat.constCast().internalCoeffs_, tmat.movable()),
438  boundaryCoeffs_(tmat.constCast().boundaryCoeffs_, tmat.movable())
439 {
441  << "Copy/move fvMatrix<Type> for field " << psi_.name() << endl;
442 
443  if (tmat().faceFluxCorrectionPtr_)
444  {
445  if (tmat.movable())
446  {
447  faceFluxCorrectionPtr_ =
448  std::move(tmat.constCast().faceFluxCorrectionPtr_);
449  }
450  else if (tmat().faceFluxCorrectionPtr_)
451  {
452  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
453  (
454  *(tmat().faceFluxCorrectionPtr_)
455  );
456  }
457  }
458 
459  tmat.clear();
460 }
461 
462 
463 // * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * * * //
464 
465 template<class Type>
467 {
469  << "Destroying fvMatrix<Type> for field " << psi_.name() << endl;
470 
471  subMatrices_.clear();
472 }
473 
474 
475 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
476 
477 template<class Type>
479 (
480  lduInterfaceFieldPtrsList& interfaces,
481  PtrDynList<lduInterfaceField>& newInterfaces
482 )
483 {
484  interfaces.setSize(internalCoeffs_.size());
485  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
486  {
487  const auto& bpsi = this->psi(fieldi).boundaryField();
488  lduInterfaceFieldPtrsList fieldInterfaces(bpsi.scalarInterfaces());
489 
490  forAll (fieldInterfaces, patchi)
491  {
492  label globalPatchID = lduMeshPtr()->patchMap()[fieldi][patchi];
493 
494  if (globalPatchID != -1)
495  {
496  if (fieldInterfaces.set(patchi))
497  {
498  if (isA<cyclicLduInterfaceField>(bpsi[patchi]))
499  {
500  newInterfaces.append
501  (
503  (
504  refCast<const fvPatch>
505  (
506  lduMeshPtr()->interfaces()[globalPatchID]
507  ),
508  bpsi[patchi].internalField()
509  )
510  );
511  interfaces.set(globalPatchID, &newInterfaces.last());
512 
513  }
514  else if (isA<cyclicAMILduInterfaceField>(bpsi[patchi]))
515  {
516  newInterfaces.append
517  (
519  (
520  refCast<const fvPatch>
521  (
522  lduMeshPtr()->interfaces()[globalPatchID]
523  ),
524  bpsi[patchi].internalField()
525  )
526  );
527  interfaces.set(globalPatchID, &newInterfaces.last());
528  }
529  else if (isA<cyclicACMILduInterfaceField>(bpsi[patchi]))
530  {
531  newInterfaces.append
532  (
534  (
535  refCast<const fvPatch>
536  (
537  lduMeshPtr()->interfaces()[globalPatchID]
538  ),
539  bpsi[patchi].internalField()
540  )
541  );
542  interfaces.set(globalPatchID, &newInterfaces.last());
543  }
544  else
545  {
546  interfaces.set(globalPatchID, &fieldInterfaces[patchi]);
547  }
548  }
549  }
550  }
551  }
552 }
553 
554 
555 template<class Type>
557 (
558  label fieldi,
559  const FieldField<Field, Type>& fluxContrib,
560  FieldField<Field, Type>& contrib,
561  bool internal
562 ) const
563 {
564  const lduPrimitiveMeshAssembly* ptr = lduMeshPtr();
565 
566  const labelList& patchMap = ptr->patchMap()[fieldi];
567 
568  forAll(contrib, patchi)
569  {
570  const label globalPtchId = patchMap[patchi];
571 
572  if (globalPtchId != -1)
573  {
574  // Cache contrib before overwriting
575  const Field<Type> saveContrib(fluxContrib[globalPtchId]);
576  contrib[patchi].setSize(psi_.boundaryField()[patchi].size()),
577  contrib[patchi] = pTraits<Type>::zero;
578 
579  if (internal)
580  {
581  contrib[patchi] =
583  (
584  saveContrib,
585  psi_.boundaryField()[patchi].patchInternalField()
586  );
587  }
588  else
589  {
590  if (this->psi(fieldi).boundaryField()[patchi].coupled())
591  {
592  contrib[patchi] =
594  (
595  saveContrib,
596  psi_.boundaryField()[patchi].patchNeighbourField()
597  );
598  }
599  }
600  }
601  else if (globalPtchId == -1)
602  {
603  const polyPatch& pp =
604  this->psi(fieldi).mesh().boundaryMesh()[patchi];
605 
606  if (pp.masterImplicit())
607  {
608  label virtualPatch =
609  ptr->patchLocalToGlobalMap()[fieldi][patchi];
610 
611  const label nbrPatchId = pp.neighbPolyPatchID();
612 
613  // Copy contrib before overwriting
614  const Field<Type> saveContrib(fluxContrib[virtualPatch]);
615 
616  Field<Type>& coeffs = contrib[patchi];
617  Field<Type>& nbrCoeffs = contrib[nbrPatchId];
618 
619  coeffs.setSize(psi_.boundaryField()[patchi].size());
620  nbrCoeffs.setSize(psi_.boundaryField()[nbrPatchId].size());
621 
622  coeffs = pTraits<Type>::zero;
623  nbrCoeffs = pTraits<Type>::zero;
624 
625  // nrb cells
626  const labelList& nbrCellIds =
627  ptr->cellBoundMap()[fieldi][patchi];
628 
629  const labelList& cellIds =
630  ptr->cellBoundMap()[fieldi][nbrPatchId];
631 
632  const GeometricField<Type, fvPatchField, volMesh>& psi =
633  this->psi(fieldi);
634 
635  forAll(saveContrib, subFaceI)
636  {
637  const label faceId =
638  ptr->facePatchFaceMap()[fieldi][patchi][subFaceI];
639  const label nbrFaceId =
640  ptr->facePatchFaceMap()[fieldi][nbrPatchId][subFaceI];
641 
642  const label nbrCellId = nbrCellIds[subFaceI];
643  const label cellId = cellIds[subFaceI];
644 
645  if (internal)
646  {
647  coeffs[faceId] +=
648  cmptMultiply(saveContrib[subFaceI], psi[cellId]);
649 
650  nbrCoeffs[nbrFaceId] +=
651  cmptMultiply(saveContrib[subFaceI], psi[nbrCellId]);
652  }
653  else //boundary
654  {
655  coeffs[faceId] +=
656  cmptMultiply(saveContrib[subFaceI], psi[nbrCellId]);
657 
658  nbrCoeffs[nbrFaceId] +=
659  cmptMultiply(saveContrib[subFaceI], psi[cellId]);
660  }
661  }
662  }
663  }
664  }
665 }
666 
667 
668 template<class Type>
670 {
671  // If it is a multi-fvMatrix needs correct internalCoeffs and
672  // boundaryCoeffs size
673  if (nMatrix_ > 0)
674  {
675  label interfaceI(0);
676  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
677  {
678  const auto& psi = this->psi(fieldi);
679 
680  forAll(psi.mesh().boundary(), patchi)
681  {
682  interfaceI++;
683  }
684  }
685  internalCoeffs_.setSize(interfaceI);
686  boundaryCoeffs_.setSize(interfaceI);
687 
688  interfaceI = 0;
689  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
690  {
691  const auto& psi = this->psi(fieldi);
692 
693  forAll(psi.mesh().boundary(), patchi)
694  {
695  internalCoeffs_.set
696  (
697  interfaceI,
698  new Field<Type>(psi.mesh().boundary()[patchi].size(), Zero)
699  );
700 
701  boundaryCoeffs_.set
702  (
703  interfaceI,
704  new Field<Type>(psi.mesh().boundary()[patchi].size(), Zero)
705  );
706  interfaceI++;
707  }
708  }
709  }
710 
711  for (label i=0; i < nMatrices(); ++i)
712  {
713  const auto& bpsi = this->psi(i).boundaryField();
714 
715  // Cache to-be implicit internal/boundary
716  FieldField<Field, Type> boundary(bpsi.size());
717  FieldField<Field, Type> internal(bpsi.size());
718 
719  label implicit = 0;
720  forAll(bpsi, patchI)
721  {
722  label globalPatchId = lduMeshPtr()->patchMap()[i][patchI];
723  if (globalPatchId == -1)
724  {
725  boundary.set
726  (
727  implicit,
728  matrix(i).boundaryCoeffs()[patchI].clone()
729  );
730  internal.set
731  (
732  implicit,
733  matrix(i).internalCoeffs()[patchI].clone()
734  );
735  implicit++;
736  }
737  }
738 
739  // Update non-implicit patches (re-order)
740  forAll(bpsi, patchI)
741  {
742  label globalPatchId = lduMeshPtr()->patchMap()[i][patchI];
743  if (globalPatchId != -1)
744  {
745  if (matrix(i).internalCoeffs().set(patchI))
746  {
747  internalCoeffs_.set
748  (
749  globalPatchId,
750  matrix(i).internalCoeffs()[patchI].clone()
751  );
752  }
753 
754  if (matrix(i).boundaryCoeffs().set(patchI))
755  {
756  boundaryCoeffs_.set
757  (
758  globalPatchId,
759  matrix(i).boundaryCoeffs()[patchI].clone()
760  );
761  }
762  }
763  }
764 
765  // Store implicit patches at the end of the list
766  implicit = 0;
767  forAll(bpsi, patchI)
768  {
769  label globalPatchId = lduMeshPtr()->patchMap()[i][patchI];
770  if (globalPatchId == -1)
771  {
772  const label implicitPatchId =
773  lduMeshPtr()->patchLocalToGlobalMap()[i][patchI];
774 
775  internalCoeffs_.set
776  (
777  implicitPatchId, internal[implicit].clone()
778  );
779  boundaryCoeffs_.set
780  (
781  implicitPatchId, boundary[implicit].clone()
782  );
783 
784  implicit++;
785  }
786  }
787  }
788 
789 // forAll(internalCoeffs_, patchI)
790 // {
791 // DebugVar(patchI)
792 // DebugVar(internalCoeffs_[patchI])
793 // DebugVar(boundaryCoeffs_[patchI])
794 // }
795 }
796 
797 
798 template<class Type>
800 {
801  for (label i=0; i < nMatrices(); ++i)
802  {
803  forAll(psi(i).boundaryField(), patchI)
804  {
805  label globalPatchId = lduMeshPtr()->patchMap()[i][patchI];
806 
807  if (globalPatchId == -1)
808  {
809  psi(i).boundaryFieldRef()[patchI].manipulateMatrix
810  (
811  *this,
812  i,
813  cmp
814  );
815  }
816  }
817  }
818 }
819 
820 
821 template<class Type>
823 {
824  const labelListList& faceMap = lduMeshPtr()->faceMap();
825  const labelList& cellMap = lduMeshPtr()->cellOffsets();
826 
827  label newFaces = lduMeshPtr()->lduAddr().upperAddr().size();
828  label newCells = lduMeshPtr()->lduAddr().size();
829 
830  scalarField lowerAssemb(newFaces, Zero);
831  scalarField upperAssemb(newFaces, Zero);
832  scalarField diagAssemb(newCells, Zero);
833  Field<Type> sourceAssemb(newCells, Zero);
834 
835  bool asymmetricAssemby = false;
836  for (label i=0; i < nMatrices(); ++i)
837  {
838  if (matrix(i).asymmetric())
839  {
840  asymmetricAssemby = true;
841  }
842  }
843  // Move append contents into intermediate list
844  for (label i=0; i < nMatrices(); ++i)
845  {
846  if (asymmetricAssemby)
847  {
848  const scalarField lowerSub(matrix(i).lower());
849  forAll(lowerSub, facei)
850  {
851  lowerAssemb[faceMap[i][facei]] = lowerSub[facei];
852  }
853  }
854 
855  const scalarField upperSub(matrix(i).upper());
856  const scalarField diagSub(matrix(i).diag());
857  const Field<Type> sourceSub(matrix(i).source());
858 
859  forAll(upperSub, facei)
860  {
861  upperAssemb[faceMap[i][facei]] = upperSub[facei];
862  }
863 
864  forAll(diagSub, celli)
865  {
866  const label globalCelli = cellMap[i] + celli;
867  diagAssemb[globalCelli] = diagSub[celli];
868  sourceAssemb[globalCelli] = sourceSub[celli];
869  }
870  }
871 
872  if (asymmetricAssemby)
873  {
874  lower().setSize(newFaces, Zero);
875  lower() = lowerAssemb;
876  }
877  upper().setSize(newFaces, Zero);
878  upper() = upperAssemb;
879 
880  diag().setSize(newCells, Zero);
881  diag() = diagAssemb;
883  source().setSize(newCells, Zero);
884  source() = sourceAssemb;
885 }
886 
887 
888 template<class Type>
890 {
891  return
892  (
893  psi_.mesh().thisDb().objectRegistry::template getObjectPtr
894  <
896  > (lduAssemblyName_)
897  );
898 }
899 
900 
901 template<class Type>
903 {
904  return
905  (
906  psi_.mesh().thisDb().objectRegistry::template cfindObject
907  <
909  > (lduAssemblyName_)
910  );
911 }
912 
913 
914 template<class Type>
916 {
917  lduPrimitiveMeshAssembly* ptr = lduMeshPtr();
918 
919  IOobject io
920  (
921  lduAssemblyName_,
922  psi_.mesh().time().timeName(),
923  psi_.mesh().thisDb(),
927  );
928 
929  UPtrList<lduMesh> uMeshPtr(nMatrices());
930 
932  uFieldPtr(nMatrices());
933 
934  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
935  {
936  const fvMesh& meshi = this->psi(fieldi).mesh();
937  uMeshPtr.set
938  (
939  fieldi,
940  &const_cast<fvMesh&>(meshi)
941  );
942  uFieldPtr.set(fieldi, &this->psi(fieldi));
943  }
944 
945  if (!ptr)
946  {
947  lduPrimitiveMeshAssembly* lduAssemMeshPtr =
948  new lduPrimitiveMeshAssembly(io, uMeshPtr);
949 
950  lduAssemMeshPtr->store();
951  lduAssemMeshPtr->update(uFieldPtr);
952 
953  Info
954  << "Creating lduPrimitiveAssembly: " << lduAssemblyName_ << endl;
955  }
956  else if
957  (
958  psi_.mesh().changing() && !psi_.mesh().upToDatePoints(*ptr)
959  )
960  {
961  // Clear losortPtr_, ownerStartPtr_, losortStartPtr_
962  ptr->lduAddr().clearOut();
963  ptr->update(uFieldPtr);
964  psi_.mesh().setUpToDatePoints(*ptr);
965 
966  Info
967  << "Updating lduPrimitiveAssembly: " << lduAssemblyName_ << endl;
968  }
969  else
970  {
971  Info
972  << "Using lduPrimitiveAssembly: " << lduAssemblyName_ << endl;
973  }
974 }
975 
976 
977 template<class Type>
979 (
980  const labelUList& cellLabels,
981  const Type& value
982 )
983 {
984  this->setValuesFromList(cellLabels, UniformList<Type>(value));
985 }
986 
987 
988 template<class Type>
990 (
991  const labelUList& cellLabels,
992  const UList<Type>& values
993 )
994 {
995  this->setValuesFromList(cellLabels, values);
996 }
997 
998 
999 template<class Type>
1001 (
1002  const labelUList& cellLabels,
1004 )
1006  this->setValuesFromList(cellLabels, values);
1007 }
1008 
1009 
1010 template<class Type>
1012 (
1013  const label celli,
1014  const Type& value,
1015  const bool forceReference
1016 )
1017 {
1018  if ((forceReference || psi_.needReference()) && celli >= 0)
1019  {
1020  source()[celli] += diag()[celli]*value;
1021  diag()[celli] += diag()[celli];
1022  }
1023 }
1024 
1025 
1026 template<class Type>
1028 (
1029  const labelUList& cellLabels,
1030  const Type& value,
1031  const bool forceReference
1032 )
1033 {
1034  if (forceReference || psi_.needReference())
1035  {
1036  forAll(cellLabels, celli)
1037  {
1038  const label cellId = cellLabels[celli];
1039  if (cellId >= 0)
1040  {
1041  source()[cellId] += diag()[cellId]*value;
1042  diag()[cellId] += diag()[cellId];
1043  }
1044  }
1045  }
1046 }
1047 
1048 
1049 template<class Type>
1051 (
1052  const labelUList& cellLabels,
1053  const UList<Type>& values,
1054  const bool forceReference
1055 )
1056 {
1057  if (forceReference || psi_.needReference())
1058  {
1059  forAll(cellLabels, celli)
1060  {
1061  const label cellId = cellLabels[celli];
1062  if (cellId >= 0)
1063  {
1064  source()[cellId] += diag()[cellId]*values[celli];
1065  diag()[cellId] += diag()[cellId];
1066  }
1067  }
1068  }
1069 }
1070 
1071 
1072 template<class Type>
1073 void Foam::fvMatrix<Type>::addFvMatrix(fvMatrix& matrix)
1074 {
1075  subMatrices_.append(matrix.clone());
1076  ++nMatrix_;
1077 
1078  if (dimensions_ != matrix.dimensions())
1079  {
1081  << "incompatible dimensions for matrix addition "
1082  << endl << " "
1083  << "[" << dimensions_ << " ] "
1084  << " [" << matrix.dimensions() << " ]"
1085  << abort(FatalError);
1086  }
1087 
1088  for (label fieldi = 0; fieldi < nMatrices(); fieldi++)
1089  {
1090  if (checkImplicit(fieldi))
1091  {
1092  break;
1093  }
1094  }
1096  internalCoeffs_.clear();
1097  boundaryCoeffs_.clear();
1098 }
1099 
1100 
1101 template<class Type>
1102 void Foam::fvMatrix<Type>::relax(const scalar alpha)
1103 {
1104  if (alpha <= 0)
1105  {
1106  return;
1107  }
1108 
1110  << "Relaxing " << psi_.name() << " by " << alpha << endl;
1111 
1112  Field<Type>& S = source();
1113  scalarField& D = diag();
1114 
1115  // Store the current unrelaxed diagonal for use in updating the source
1116  scalarField D0(D);
1117 
1118  // Calculate the sum-mag off-diagonal from the interior faces
1119  scalarField sumOff(D.size(), Zero);
1120  sumMagOffDiag(sumOff);
1121 
1122  // Handle the boundary contributions to the diagonal
1123  forAll(psi_.boundaryField(), patchi)
1124  {
1125  const fvPatchField<Type>& ptf = psi_.boundaryField()[patchi];
1126 
1127  if (ptf.size())
1128  {
1129  const labelUList& pa = lduAddr().patchAddr(patchi);
1130  Field<Type>& iCoeffs = internalCoeffs_[patchi];
1131 
1132  if (ptf.coupled())
1133  {
1134  const Field<Type>& pCoeffs = boundaryCoeffs_[patchi];
1135 
1136  // For coupled boundaries add the diagonal and
1137  // off-diagonal contributions
1138  forAll(pa, face)
1139  {
1140  D[pa[face]] += component(iCoeffs[face], 0);
1141  sumOff[pa[face]] += mag(component(pCoeffs[face], 0));
1142  }
1143  }
1144  else
1145  {
1146  // For non-coupled boundaries add the maximum magnitude diagonal
1147  // contribution to ensure stability
1148  forAll(pa, face)
1149  {
1150  D[pa[face]] += cmptMax(cmptMag(iCoeffs[face]));
1151  }
1152  }
1153  }
1154  }
1155 
1156 
1157  if (debug)
1158  {
1159  // Calculate amount of non-dominance.
1160  label nNon = 0;
1161  scalar maxNon = 0.0;
1162  scalar sumNon = 0.0;
1163  forAll(D, celli)
1164  {
1165  scalar d = (sumOff[celli] - D[celli])/mag(D[celli]);
1166 
1167  if (d > 0)
1168  {
1169  nNon++;
1170  maxNon = max(maxNon, d);
1171  sumNon += d;
1172  }
1173  }
1174 
1175  reduce(nNon, sumOp<label>(), UPstream::msgType(), psi_.mesh().comm());
1176  reduce
1177  (
1178  maxNon,
1179  maxOp<scalar>(),
1181  psi_.mesh().comm()
1182  );
1183  reduce
1184  (
1185  sumNon,
1186  sumOp<scalar>(),
1188  psi_.mesh().comm()
1189  );
1190  sumNon /= returnReduce
1191  (
1192  D.size(),
1193  sumOp<label>(),
1195  psi_.mesh().comm()
1196  );
1197 
1199  << "Matrix dominance test for " << psi_.name() << nl
1200  << " number of non-dominant cells : " << nNon << nl
1201  << " maximum relative non-dominance : " << maxNon << nl
1202  << " average relative non-dominance : " << sumNon << nl
1203  << endl;
1204  }
1205 
1206 
1207  // Ensure the matrix is diagonally dominant...
1208  // Assumes that the central coefficient is positive and ensures it is
1209  forAll(D, celli)
1210  {
1211  D[celli] = max(mag(D[celli]), sumOff[celli]);
1212  }
1213 
1214  // ... then relax
1215  D /= alpha;
1216 
1217  // Now remove the diagonal contribution from coupled boundaries
1218  forAll(psi_.boundaryField(), patchi)
1219  {
1220  const fvPatchField<Type>& ptf = psi_.boundaryField()[patchi];
1221 
1222  if (ptf.size())
1223  {
1224  const labelUList& pa = lduAddr().patchAddr(patchi);
1225  Field<Type>& iCoeffs = internalCoeffs_[patchi];
1226 
1227  if (ptf.coupled())
1228  {
1229  forAll(pa, face)
1230  {
1231  D[pa[face]] -= component(iCoeffs[face], 0);
1232  }
1233  }
1234  else
1235  {
1236  forAll(pa, face)
1237  {
1238  D[pa[face]] -= cmptMin(iCoeffs[face]);
1239  }
1240  }
1241  }
1242  }
1244  // Finally add the relaxation contribution to the source.
1245  S += (D - D0)*psi_.primitiveField();
1246 }
1247 
1248 
1249 template<class Type>
1251 {
1252  word name = psi_.select
1253  (
1254  psi_.mesh().data().isFinalIteration()
1255  );
1256 
1257  scalar relaxCoeff = 0;
1258 
1259  if (psi_.mesh().relaxEquation(name, relaxCoeff))
1260  {
1261  relax(relaxCoeff);
1262  }
1263 }
1264 
1265 
1266 template<class Type>
1268 (
1269  typename GeometricField<Type, fvPatchField, volMesh>::
1270  Boundary& bFields
1271 )
1272 {
1273  forAll(bFields, patchi)
1274  {
1275  bFields[patchi].manipulateMatrix(*this);
1276  }
1277 }
1278 
1279 
1280 template<class Type>
1282 {
1283  auto tdiag = tmp<scalarField>::New(diag());
1284  addCmptAvBoundaryDiag(tdiag.ref());
1285  return tdiag;
1286 }
1287 
1288 
1289 template<class Type>
1291 {
1293 
1294  forAll(psi_.boundaryField(), patchi)
1295  {
1296  const fvPatchField<Type>& ptf = psi_.boundaryField()[patchi];
1297 
1298  if (!ptf.coupled() && ptf.size())
1299  {
1300  addToInternalField
1301  (
1302  lduAddr().patchAddr(patchi),
1303  internalCoeffs_[patchi],
1304  tdiag.ref()
1305  );
1306  }
1307  }
1308 
1309  return tdiag;
1310 }
1311 
1312 
1313 template<class Type>
1315 {
1316  auto tAphi = volScalarField::New
1317  (
1318  "A(" + psi_.name() + ')',
1319  psi_.mesh(),
1320  dimensions_/psi_.dimensions()/dimVol,
1322  );
1323 
1324  tAphi.ref().primitiveFieldRef() = D()/psi_.mesh().V();
1325  tAphi.ref().correctBoundaryConditions();
1327  return tAphi;
1328 }
1329 
1330 
1331 template<class Type>
1334 {
1336  (
1337  "H(" + psi_.name() + ')',
1338  psi_.mesh(),
1339  dimensions_/dimVol,
1341  );
1342  auto& Hphi = tHphi.ref();
1343 
1344  // Loop over field components
1345  for (direction cmpt=0; cmpt<Type::nComponents; cmpt++)
1346  {
1347  scalarField psiCmpt(psi_.primitiveField().component(cmpt));
1348 
1349  scalarField boundaryDiagCmpt(psi_.size(), Zero);
1350  addBoundaryDiag(boundaryDiagCmpt, cmpt);
1351  boundaryDiagCmpt.negate();
1352  addCmptAvBoundaryDiag(boundaryDiagCmpt);
1353 
1354  Hphi.primitiveFieldRef().replace(cmpt, boundaryDiagCmpt*psiCmpt);
1355  }
1356 
1357  Hphi.primitiveFieldRef() += lduMatrix::H(psi_.primitiveField()) + source_;
1358  addBoundarySource(Hphi.primitiveFieldRef());
1359 
1360  Hphi.primitiveFieldRef() /= psi_.mesh().V();
1362 
1363  typename Type::labelType validComponents
1364  (
1365  psi_.mesh().template validComponents<Type>()
1366  );
1367 
1368  for (direction cmpt=0; cmpt<Type::nComponents; cmpt++)
1369  {
1370  if (validComponents[cmpt] == -1)
1371  {
1372  Hphi.replace
1373  (
1374  cmpt,
1376  );
1377  }
1378  }
1379 
1380  return tHphi;
1381 }
1382 
1383 
1384 template<class Type>
1386 {
1387  auto tH1 = volScalarField::New
1388  (
1389  "H(1)",
1390  psi_.mesh(),
1391  dimensions_/(dimVol*psi_.dimensions()),
1393  );
1394  auto& H1_ = tH1.ref();
1395 
1396  H1_.primitiveFieldRef() = lduMatrix::H1();
1397 
1398  forAll(psi_.boundaryField(), patchi)
1399  {
1400  const fvPatchField<Type>& ptf = psi_.boundaryField()[patchi];
1401 
1402  if (ptf.coupled() && ptf.size())
1403  {
1404  addToInternalField
1405  (
1406  lduAddr().patchAddr(patchi),
1407  boundaryCoeffs_[patchi].component(0),
1408  H1_
1409  );
1410  }
1411  }
1412 
1413  H1_.primitiveFieldRef() /= psi_.mesh().V();
1414  H1_.correctBoundaryConditions();
1415 
1416  return tH1;
1417 }
1418 
1419 
1420 template<class Type>
1423 flux() const
1424 {
1425  if (!psi_.mesh().fluxRequired(psi_.name()))
1426  {
1428  << "flux requested but " << psi_.name()
1429  << " not specified in the fluxRequired sub-dictionary"
1430  " of fvSchemes."
1431  << abort(FatalError);
1432  }
1433 
1434  if (nMatrices() > 1)
1435  {
1437  << "Flux requested but " << psi_.name()
1438  << " can't handle multiple fvMatrix."
1439  << abort(FatalError);
1440  }
1441 
1443  (
1444  "flux(" + psi_.name() + ')',
1445  psi_.mesh(),
1446  dimensions()
1447  );
1448  auto& fieldFlux = tfieldFlux.ref();
1449 
1450  fieldFlux.setOriented();
1451 
1452  for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; cmpt++)
1453  {
1454  fieldFlux.primitiveFieldRef().replace
1455  (
1456  cmpt,
1457  lduMatrix::faceH(psi_.primitiveField().component(cmpt))
1458  );
1459  }
1460 
1461  FieldField<Field, Type> InternalContrib = internalCoeffs_;
1462 
1463  label fieldi = 0;
1464  if (!useImplicit_)
1465  {
1466  forAll(InternalContrib, patchi)
1467  {
1468  InternalContrib[patchi] =
1469  cmptMultiply
1470  (
1471  InternalContrib[patchi],
1472  psi_.boundaryField()[patchi].patchInternalField()
1473  );
1474  }
1475  }
1476  else
1477  {
1478  FieldField<Field, Type> fluxInternalContrib(internalCoeffs_);
1479 
1480  mapContributions(fieldi, fluxInternalContrib, InternalContrib, true);
1481  }
1482 
1483  FieldField<Field, Type> NeighbourContrib = boundaryCoeffs_;
1484 
1485  if (!useImplicit_)
1486  {
1487  forAll(NeighbourContrib, patchi)
1488  {
1489  if (psi_.boundaryField()[patchi].coupled())
1490  {
1491  NeighbourContrib[patchi] =
1492  cmptMultiply
1493  (
1494  NeighbourContrib[patchi],
1495  psi_.boundaryField()[patchi].patchNeighbourField()
1496  );
1497  }
1498  }
1499  }
1500  else
1501  {
1502  FieldField<Field, Type> fluxBoundaryContrib(boundaryCoeffs_);
1503 
1504  mapContributions(fieldi, fluxBoundaryContrib, NeighbourContrib, false);
1505  }
1506 
1507  typename GeometricField<Type, fvsPatchField, surfaceMesh>::
1508  Boundary& ffbf = fieldFlux.boundaryFieldRef();
1509 
1510  forAll(ffbf, patchi)
1511  {
1512  ffbf[patchi] = InternalContrib[patchi] - NeighbourContrib[patchi];
1513  //DebugVar(gSum(ffbf[patchi]))
1514  }
1515 
1516  if (faceFluxCorrectionPtr_)
1517  {
1518  fieldFlux += *faceFluxCorrectionPtr_;
1519  }
1521  return tfieldFlux;
1522 }
1523 
1524 
1525 template<class Type>
1527 (
1528  const word& name
1529 ) const
1530 {
1531  return psi_.mesh().solverDict(name);
1532 }
1533 
1534 
1535 template<class Type>
1537 {
1538  return psi_.mesh().solverDict
1539  (
1540  psi_.select(psi_.mesh().data().isFinalIteration())
1541  );
1542 }
1543 
1544 
1545 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1546 
1547 template<class Type>
1549 {
1550  if (this == &fvmv)
1551  {
1552  return; // Self-assignment is a no-op
1553  }
1554 
1555  if (&psi_ != &(fvmv.psi_))
1556  {
1558  << "different fields"
1559  << abort(FatalError);
1560  }
1561 
1562  dimensions_ = fvmv.dimensions_;
1563  lduMatrix::operator=(fvmv);
1564  source_ = fvmv.source_;
1565  internalCoeffs_ = fvmv.internalCoeffs_;
1566  boundaryCoeffs_ = fvmv.boundaryCoeffs_;
1567 
1568  if (faceFluxCorrectionPtr_ && fvmv.faceFluxCorrectionPtr_)
1569  {
1570  *faceFluxCorrectionPtr_ = *fvmv.faceFluxCorrectionPtr_;
1571  }
1572  else if (fvmv.faceFluxCorrectionPtr_)
1573  {
1574  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
1575  (
1576  *fvmv.faceFluxCorrectionPtr_
1577  );
1578  }
1580  useImplicit_ = fvmv.useImplicit_;
1581  lduAssemblyName_ = fvmv.lduAssemblyName_;
1582 }
1583 
1584 
1585 template<class Type>
1588  operator=(tfvmv());
1589  tfvmv.clear();
1590 }
1591 
1592 
1593 template<class Type>
1595 {
1597  source_.negate();
1598  internalCoeffs_.negate();
1599  boundaryCoeffs_.negate();
1600 
1601  if (faceFluxCorrectionPtr_)
1602  {
1603  faceFluxCorrectionPtr_->negate();
1604  }
1605 }
1606 
1607 
1608 template<class Type>
1609 void Foam::fvMatrix<Type>::operator+=(const fvMatrix<Type>& fvmv)
1610 {
1611  checkMethod(*this, fvmv, "+=");
1612 
1613  dimensions_ += fvmv.dimensions_;
1614  lduMatrix::operator+=(fvmv);
1615  source_ += fvmv.source_;
1616  internalCoeffs_ += fvmv.internalCoeffs_;
1617  boundaryCoeffs_ += fvmv.boundaryCoeffs_;
1618 
1619  useImplicit_ = fvmv.useImplicit_;
1620  lduAssemblyName_ = fvmv.lduAssemblyName_;
1621  nMatrix_ = fvmv.nMatrix_;
1622 
1623  if (faceFluxCorrectionPtr_ && fvmv.faceFluxCorrectionPtr_)
1624  {
1625  *faceFluxCorrectionPtr_ += *fvmv.faceFluxCorrectionPtr_;
1626  }
1627  else if (fvmv.faceFluxCorrectionPtr_)
1628  {
1629  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
1630  (
1631  *fvmv.faceFluxCorrectionPtr_
1632  );
1633  }
1634 }
1635 
1636 
1637 template<class Type>
1638 void Foam::fvMatrix<Type>::operator+=(const tmp<fvMatrix<Type>>& tfvmv)
1640  operator+=(tfvmv());
1641  tfvmv.clear();
1642 }
1643 
1644 
1645 template<class Type>
1647 {
1648  checkMethod(*this, fvmv, "-=");
1649 
1650  dimensions_ -= fvmv.dimensions_;
1651  lduMatrix::operator-=(fvmv);
1652  source_ -= fvmv.source_;
1653  internalCoeffs_ -= fvmv.internalCoeffs_;
1654  boundaryCoeffs_ -= fvmv.boundaryCoeffs_;
1655 
1656  useImplicit_ = fvmv.useImplicit_;
1657  lduAssemblyName_ = fvmv.lduAssemblyName_;
1658  nMatrix_ = fvmv.nMatrix_;
1659 
1660  if (faceFluxCorrectionPtr_ && fvmv.faceFluxCorrectionPtr_)
1661  {
1662  *faceFluxCorrectionPtr_ -= *fvmv.faceFluxCorrectionPtr_;
1663  }
1664  else if (fvmv.faceFluxCorrectionPtr_)
1665  {
1666  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
1667  (
1668  -*fvmv.faceFluxCorrectionPtr_
1669  );
1670  }
1671 }
1672 
1673 
1674 template<class Type>
1675 void Foam::fvMatrix<Type>::operator-=(const tmp<fvMatrix<Type>>& tfvmv)
1676 {
1677  operator-=(tfvmv());
1678  tfvmv.clear();
1679 }
1680 
1681 
1682 template<class Type>
1684 (
1686 )
1687 {
1688  checkMethod(*this, su, "+=");
1689  source() -= su.mesh().V()*su.field();
1690 }
1691 
1692 
1693 template<class Type>
1695 (
1697 )
1698 {
1699  operator+=(tsu());
1700  tsu.clear();
1701 }
1702 
1703 
1704 template<class Type>
1706 (
1708 )
1709 {
1710  operator+=(tsu());
1711  tsu.clear();
1712 }
1713 
1714 
1715 template<class Type>
1717 (
1719 )
1720 {
1721  checkMethod(*this, su, "-=");
1722  source() += su.mesh().V()*su.field();
1723 }
1724 
1725 
1726 template<class Type>
1728 (
1730 )
1731 {
1732  operator-=(tsu());
1733  tsu.clear();
1734 }
1735 
1736 
1737 template<class Type>
1739 (
1741 )
1742 {
1743  operator-=(tsu());
1744  tsu.clear();
1745 }
1746 
1747 
1748 template<class Type>
1750 (
1751  const dimensioned<Type>& su
1752 )
1754  source() -= psi().mesh().V()*su;
1755 }
1756 
1757 
1758 template<class Type>
1760 (
1761  const dimensioned<Type>& su
1762 )
1764  source() += psi().mesh().V()*su;
1765 }
1766 
1767 
1768 template<class Type>
1770 (
1771  const volScalarField::Internal& dsf
1772 )
1773 {
1774  dimensions_ *= dsf.dimensions();
1775  lduMatrix::operator*=(dsf.field());
1776  source_ *= dsf.field();
1777 
1778  forAll(boundaryCoeffs_, patchi)
1779  {
1780  scalarField pisf
1781  (
1782  dsf.mesh().boundary()[patchi].patchInternalField(dsf.field())
1783  );
1784 
1785  internalCoeffs_[patchi] *= pisf;
1786  boundaryCoeffs_[patchi] *= pisf;
1787  }
1788 
1789  if (faceFluxCorrectionPtr_)
1790  {
1792  << "cannot scale a matrix containing a faceFluxCorrection"
1794  }
1795 }
1796 
1797 
1798 template<class Type>
1800 (
1801  const tmp<volScalarField::Internal>& tfld
1802 )
1803 {
1804  operator*=(tfld());
1805  tfld.clear();
1806 }
1807 
1808 
1809 template<class Type>
1811 (
1812  const tmp<volScalarField>& tfld
1813 )
1814 {
1815  operator*=(tfld());
1816  tfld.clear();
1817 }
1818 
1819 
1820 template<class Type>
1822 (
1823  const dimensioned<scalar>& ds
1824 )
1825 {
1826  dimensions_ *= ds.dimensions();
1827  lduMatrix::operator*=(ds.value());
1828  source_ *= ds.value();
1829  internalCoeffs_ *= ds.value();
1830  boundaryCoeffs_ *= ds.value();
1831 
1832  if (faceFluxCorrectionPtr_)
1833  {
1834  *faceFluxCorrectionPtr_ *= ds.value();
1835  }
1837 
1838 
1839 // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
1840 
1841 template<class Type>
1842 void Foam::checkMethod
1843 (
1844  const fvMatrix<Type>& mat1,
1845  const fvMatrix<Type>& mat2,
1846  const char* op
1847 )
1848 {
1849  if (&mat1.psi() != &mat2.psi())
1850  {
1852  << "Incompatible fields for operation\n "
1853  << "[" << mat1.psi().name() << "] "
1854  << op
1855  << " [" << mat2.psi().name() << "]"
1856  << abort(FatalError);
1857  }
1858 
1859  if
1860  (
1862  && mat1.dimensions() != mat2.dimensions()
1863  )
1864  {
1866  << "Incompatible dimensions for operation\n "
1867  << "[" << mat1.psi().name() << mat1.dimensions()/dimVolume << " ] "
1868  << op
1869  << " [" << mat2.psi().name() << mat2.dimensions()/dimVolume << " ]"
1871  }
1872 }
1873 
1874 
1875 template<class Type>
1876 void Foam::checkMethod
1877 (
1878  const fvMatrix<Type>& mat,
1879  const DimensionedField<Type, volMesh>& fld,
1880  const char* op
1881 )
1882 {
1883  if
1884  (
1886  && mat.dimensions()/dimVolume != fld.dimensions()
1887  )
1888  {
1890  << "Incompatible dimensions for operation\n "
1891  << "[" << mat.psi().name() << mat.dimensions()/dimVolume << " ] "
1892  << op
1893  << " [" << fld.name() << fld.dimensions() << " ]"
1895  }
1896 }
1897 
1898 
1899 template<class Type>
1900 void Foam::checkMethod
1901 (
1902  const fvMatrix<Type>& mat,
1903  const dimensioned<Type>& dt,
1904  const char* op
1905 )
1906 {
1907  if
1908  (
1910  && mat.dimensions()/dimVolume != dt.dimensions()
1911  )
1912  {
1914  << "Incompatible dimensions for operation\n "
1915  << "[" << mat.psi().name() << mat.dimensions()/dimVolume << " ] "
1916  << op
1917  << " [" << dt.name() << dt.dimensions() << " ]"
1918  << abort(FatalError);
1919  }
1920 }
1921 
1922 
1923 template<class Type>
1925 (
1926  fvMatrix<Type>& mat,
1927  const dictionary& solverControls
1928 )
1929 {
1930  return mat.solve(solverControls);
1931 }
1932 
1933 template<class Type>
1935 (
1936  const tmp<fvMatrix<Type>>& tmat,
1937  const dictionary& solverControls
1938 )
1939 {
1940  SolverPerformance<Type> solverPerf(tmat.constCast().solve(solverControls));
1941 
1942  tmat.clear();
1943 
1944  return solverPerf;
1945 }
1946 
1947 
1948 template<class Type>
1950 (
1951  fvMatrix<Type>& mat,
1952  const word& name
1953 )
1954 {
1955  return mat.solve(name);
1956 }
1957 
1958 template<class Type>
1960 (
1961  const tmp<fvMatrix<Type>>& tmat,
1962  const word& name
1963 )
1964 {
1965  SolverPerformance<Type> solverPerf(tmat.constCast().solve(name));
1966 
1967  tmat.clear();
1968 
1969  return solverPerf;
1970 }
1971 
1972 
1973 template<class Type>
1974 Foam::SolverPerformance<Type> Foam::solve(fvMatrix<Type>& mat)
1975 {
1976  return mat.solve();
1977 }
1978 
1979 template<class Type>
1980 Foam::SolverPerformance<Type> Foam::solve(const tmp<fvMatrix<Type>>& tmat)
1981 {
1982  SolverPerformance<Type> solverPerf(tmat.constCast().solve());
1983 
1984  tmat.clear();
1985 
1986  return solverPerf;
1987 }
1988 
1989 
1990 template<class Type>
1992 (
1993  const fvMatrix<Type>& A
1994 )
1995 {
1996  tmp<Foam::fvMatrix<Type>> tAcorr = A - (A & A.psi());
1997 
1998  // Delete the faceFluxCorrection from the correction matrix
1999  // as it does not have a clear meaning or purpose
2000  tAcorr.ref().faceFluxCorrectionPtr(nullptr);
2001 
2002  return tAcorr;
2003 }
2004 
2005 
2006 template<class Type>
2008 (
2009  const tmp<fvMatrix<Type>>& tA
2010 )
2011 {
2012  tmp<Foam::fvMatrix<Type>> tAcorr = tA - (tA() & tA().psi());
2013 
2014  // Delete the faceFluxCorrection from the correction matrix
2015  // as it does not have a clear meaning or purpose
2016  tAcorr.ref().faceFluxCorrectionPtr(nullptr);
2017 
2018  return tAcorr;
2019 }
2020 
2021 
2022 // * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
2023 
2024 template<class Type>
2025 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2026 (
2027  const fvMatrix<Type>& A,
2028  const fvMatrix<Type>& B
2029 )
2030 {
2031  checkMethod(A, B, "==");
2032  return (A - B);
2033 }
2034 
2035 template<class Type>
2036 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2037 (
2038  const tmp<fvMatrix<Type>>& tA,
2039  const fvMatrix<Type>& B
2040 )
2041 {
2042  checkMethod(tA(), B, "==");
2043  return (tA - B);
2044 }
2045 
2046 template<class Type>
2047 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2048 (
2049  const fvMatrix<Type>& A,
2050  const tmp<fvMatrix<Type>>& tB
2051 )
2052 {
2053  checkMethod(A, tB(), "==");
2054  return (A - tB);
2055 }
2056 
2057 template<class Type>
2058 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2059 (
2060  const tmp<fvMatrix<Type>>& tA,
2061  const tmp<fvMatrix<Type>>& tB
2062 )
2063 {
2064  checkMethod(tA(), tB(), "==");
2065  return (tA - tB);
2066 }
2067 
2068 template<class Type>
2069 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2070 (
2071  const fvMatrix<Type>& A,
2072  const DimensionedField<Type, volMesh>& su
2073 )
2074 {
2075  checkMethod(A, su, "==");
2076  auto tC = tmp<fvMatrix<Type>>::New(A);
2077  tC.ref().source() += su.mesh().V()*su.field();
2078  return tC;
2079 }
2080 
2081 template<class Type>
2082 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2083 (
2084  const fvMatrix<Type>& A,
2085  const tmp<DimensionedField<Type, volMesh>>& tsu
2086 )
2087 {
2088  checkMethod(A, tsu(), "==");
2089  auto tC = tmp<fvMatrix<Type>>::New(A);
2090  tC.ref().source() += tsu().mesh().V()*tsu().field();
2091  tsu.clear();
2092  return tC;
2093 }
2094 
2095 template<class Type>
2096 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2097 (
2098  const fvMatrix<Type>& A,
2099  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu
2100 )
2101 {
2102  checkMethod(A, tsu(), "==");
2103  auto tC = tmp<fvMatrix<Type>>::New(A);
2104  tC.ref().source() += tsu().mesh().V()*tsu().primitiveField();
2105  tsu.clear();
2106  return tC;
2107 }
2108 
2109 template<class Type>
2110 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2111 (
2112  const tmp<fvMatrix<Type>>& tA,
2113  const DimensionedField<Type, volMesh>& su
2114 )
2115 {
2116  checkMethod(tA(), su, "==");
2117  tmp<fvMatrix<Type>> tC(tA.ptr());
2118  tC.ref().source() += su.mesh().V()*su.field();
2119  return tC;
2120 }
2121 
2122 template<class Type>
2123 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2124 (
2125  const tmp<fvMatrix<Type>>& tA,
2126  const tmp<DimensionedField<Type, volMesh>>& tsu
2127 )
2128 {
2129  checkMethod(tA(), tsu(), "==");
2130  tmp<fvMatrix<Type>> tC(tA.ptr());
2131  tC.ref().source() += tsu().mesh().V()*tsu().field();
2132  tsu.clear();
2133  return tC;
2134 }
2135 
2136 template<class Type>
2137 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2138 (
2139  const tmp<fvMatrix<Type>>& tA,
2140  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu
2141 )
2142 {
2143  checkMethod(tA(), tsu(), "==");
2144  tmp<fvMatrix<Type>> tC(tA.ptr());
2145  tC.ref().source() += tsu().mesh().V()*tsu().primitiveField();
2146  tsu.clear();
2147  return tC;
2148 }
2149 
2150 template<class Type>
2151 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2152 (
2153  const fvMatrix<Type>& A,
2154  const dimensioned<Type>& su
2155 )
2156 {
2157  checkMethod(A, su, "==");
2158  auto tC = tmp<fvMatrix<Type>>::New(A);
2159  tC.ref().source() += A.psi().mesh().V()*su.value();
2160  return tC;
2161 }
2162 
2163 template<class Type>
2164 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2165 (
2166  const tmp<fvMatrix<Type>>& tA,
2167  const dimensioned<Type>& su
2168 )
2169 {
2170  checkMethod(tA(), su, "==");
2171  tmp<fvMatrix<Type>> tC(tA.ptr());
2172  tC.ref().source() += tC().psi().mesh().V()*su.value();
2173  return tC;
2174 }
2175 
2176 template<class Type>
2177 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2178 (
2179  const fvMatrix<Type>& A,
2180  const Foam::zero
2181 )
2182 {
2183  return A;
2184 }
2185 
2186 
2187 template<class Type>
2188 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator==
2189 (
2190  const tmp<fvMatrix<Type>>& tA,
2191  const Foam::zero
2192 )
2193 {
2194  return tA;
2195 }
2196 
2197 
2198 template<class Type>
2199 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2200 (
2201  const fvMatrix<Type>& A
2202 )
2203 {
2204  auto tC = tmp<fvMatrix<Type>>::New(A);
2205  tC.ref().negate();
2206  return tC;
2207 }
2208 
2209 template<class Type>
2210 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2211 (
2212  const tmp<fvMatrix<Type>>& tA
2213 )
2214 {
2215  tmp<fvMatrix<Type>> tC(tA.ptr());
2216  tC.ref().negate();
2217  return tC;
2218 }
2219 
2220 
2221 template<class Type>
2222 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2223 (
2224  const fvMatrix<Type>& A,
2225  const fvMatrix<Type>& B
2226 )
2227 {
2228  checkMethod(A, B, "+");
2229  auto tC = tmp<fvMatrix<Type>>::New(A);
2230  tC.ref() += B;
2231  return tC;
2232 }
2233 
2234 template<class Type>
2235 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2236 (
2237  const tmp<fvMatrix<Type>>& tA,
2238  const fvMatrix<Type>& B
2239 )
2240 {
2241  checkMethod(tA(), B, "+");
2242  tmp<fvMatrix<Type>> tC(tA.ptr());
2243  tC.ref() += B;
2244  return tC;
2245 }
2246 
2247 template<class Type>
2248 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2249 (
2250  const fvMatrix<Type>& A,
2251  const tmp<fvMatrix<Type>>& tB
2252 )
2253 {
2254  checkMethod(A, tB(), "+");
2255  tmp<fvMatrix<Type>> tC(tB.ptr());
2256  tC.ref() += A;
2257  return tC;
2258 }
2259 
2260 template<class Type>
2261 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2262 (
2263  const tmp<fvMatrix<Type>>& tA,
2264  const tmp<fvMatrix<Type>>& tB
2265 )
2266 {
2267  checkMethod(tA(), tB(), "+");
2268  tmp<fvMatrix<Type>> tC(tA.ptr());
2269  tC.ref() += tB();
2270  tB.clear();
2271  return tC;
2272 }
2273 
2274 template<class Type>
2275 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2276 (
2277  const fvMatrix<Type>& A,
2278  const DimensionedField<Type, volMesh>& su
2279 )
2280 {
2281  checkMethod(A, su, "+");
2282  auto tC = tmp<fvMatrix<Type>>::New(A);
2283  tC.ref().source() -= su.mesh().V()*su.field();
2284  return tC;
2285 }
2286 
2287 template<class Type>
2288 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2289 (
2290  const fvMatrix<Type>& A,
2291  const tmp<DimensionedField<Type, volMesh>>& tsu
2292 )
2293 {
2294  checkMethod(A, tsu(), "+");
2295  auto tC = tmp<fvMatrix<Type>>::New(A);
2296  tC.ref().source() -= tsu().mesh().V()*tsu().field();
2297  tsu.clear();
2298  return tC;
2299 }
2300 
2301 template<class Type>
2302 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2303 (
2304  const fvMatrix<Type>& A,
2305  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu
2306 )
2307 {
2308  checkMethod(A, tsu(), "+");
2309  auto tC = tmp<fvMatrix<Type>>::New(A);
2310  tC.ref().source() -= tsu().mesh().V()*tsu().primitiveField();
2311  tsu.clear();
2312  return tC;
2313 }
2314 
2315 template<class Type>
2316 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2317 (
2318  const tmp<fvMatrix<Type>>& tA,
2319  const DimensionedField<Type, volMesh>& su
2320 )
2321 {
2322  checkMethod(tA(), su, "+");
2323  tmp<fvMatrix<Type>> tC(tA.ptr());
2324  tC.ref().source() -= su.mesh().V()*su.field();
2325  return tC;
2326 }
2327 
2328 template<class Type>
2329 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2330 (
2331  const tmp<fvMatrix<Type>>& tA,
2332  const tmp<DimensionedField<Type, volMesh>>& tsu
2333 )
2334 {
2335  checkMethod(tA(), tsu(), "+");
2336  tmp<fvMatrix<Type>> tC(tA.ptr());
2337  tC.ref().source() -= tsu().mesh().V()*tsu().field();
2338  tsu.clear();
2339  return tC;
2340 }
2341 
2342 template<class Type>
2343 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2344 (
2345  const tmp<fvMatrix<Type>>& tA,
2346  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu
2347 )
2348 {
2349  checkMethod(tA(), tsu(), "+");
2350  tmp<fvMatrix<Type>> tC(tA.ptr());
2351  tC.ref().source() -= tsu().mesh().V()*tsu().primitiveField();
2352  tsu.clear();
2353  return tC;
2354 }
2355 
2356 template<class Type>
2357 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2358 (
2359  const DimensionedField<Type, volMesh>& su,
2360  const fvMatrix<Type>& A
2361 )
2362 {
2363  checkMethod(A, su, "+");
2364  auto tC = tmp<fvMatrix<Type>>::New(A);
2365  tC.ref().source() -= su.mesh().V()*su.field();
2366  return tC;
2367 }
2368 
2369 template<class Type>
2370 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2371 (
2372  const tmp<DimensionedField<Type, volMesh>>& tsu,
2373  const fvMatrix<Type>& A
2374 )
2375 {
2376  checkMethod(A, tsu(), "+");
2377  auto tC = tmp<fvMatrix<Type>>::New(A);
2378  tC.ref().source() -= tsu().mesh().V()*tsu().field();
2379  tsu.clear();
2380  return tC;
2381 }
2382 
2383 template<class Type>
2384 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2385 (
2386  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu,
2387  const fvMatrix<Type>& A
2388 )
2389 {
2390  checkMethod(A, tsu(), "+");
2391  auto tC = tmp<fvMatrix<Type>>::New(A);
2392  tC.ref().source() -= tsu().mesh().V()*tsu().primitiveField();
2393  tsu.clear();
2394  return tC;
2395 }
2396 
2397 template<class Type>
2398 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2399 (
2400  const DimensionedField<Type, volMesh>& su,
2401  const tmp<fvMatrix<Type>>& tA
2402 )
2403 {
2404  checkMethod(tA(), su, "+");
2405  tmp<fvMatrix<Type>> tC(tA.ptr());
2406  tC.ref().source() -= su.mesh().V()*su.field();
2407  return tC;
2408 }
2409 
2410 template<class Type>
2411 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2412 (
2413  const tmp<DimensionedField<Type, volMesh>>& tsu,
2414  const tmp<fvMatrix<Type>>& tA
2415 )
2416 {
2417  checkMethod(tA(), tsu(), "+");
2418  tmp<fvMatrix<Type>> tC(tA.ptr());
2419  tC.ref().source() -= tsu().mesh().V()*tsu().field();
2420  tsu.clear();
2421  return tC;
2422 }
2423 
2424 template<class Type>
2425 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2426 (
2427  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu,
2428  const tmp<fvMatrix<Type>>& tA
2429 )
2430 {
2431  checkMethod(tA(), tsu(), "+");
2432  tmp<fvMatrix<Type>> tC(tA.ptr());
2433  tC.ref().source() -= tsu().mesh().V()*tsu().primitiveField();
2434  tsu.clear();
2435  return tC;
2436 }
2437 
2438 
2439 template<class Type>
2440 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2441 (
2442  const fvMatrix<Type>& A,
2443  const fvMatrix<Type>& B
2444 )
2445 {
2446  checkMethod(A, B, "-");
2447  auto tC = tmp<fvMatrix<Type>>::New(A);
2448  tC.ref() -= B;
2449  return tC;
2450 }
2451 
2452 template<class Type>
2453 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2454 (
2455  const tmp<fvMatrix<Type>>& tA,
2456  const fvMatrix<Type>& B
2457 )
2458 {
2459  checkMethod(tA(), B, "-");
2460  tmp<fvMatrix<Type>> tC(tA.ptr());
2461  tC.ref() -= B;
2462  return tC;
2463 }
2464 
2465 template<class Type>
2466 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2467 (
2468  const fvMatrix<Type>& A,
2469  const tmp<fvMatrix<Type>>& tB
2470 )
2471 {
2472  checkMethod(A, tB(), "-");
2473  tmp<fvMatrix<Type>> tC(tB.ptr());
2474  tC.ref() -= A;
2475  tC.ref().negate();
2476  return tC;
2477 }
2478 
2479 template<class Type>
2480 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2481 (
2482  const tmp<fvMatrix<Type>>& tA,
2483  const tmp<fvMatrix<Type>>& tB
2484 )
2485 {
2486  checkMethod(tA(), tB(), "-");
2487  tmp<fvMatrix<Type>> tC(tA.ptr());
2488  tC.ref() -= tB();
2489  tB.clear();
2490  return tC;
2491 }
2492 
2493 template<class Type>
2494 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2495 (
2496  const fvMatrix<Type>& A,
2497  const DimensionedField<Type, volMesh>& su
2498 )
2499 {
2500  checkMethod(A, su, "-");
2501  auto tC = tmp<fvMatrix<Type>>::New(A);
2502  tC.ref().source() += su.mesh().V()*su.field();
2503  return tC;
2504 }
2505 
2506 template<class Type>
2507 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2508 (
2509  const fvMatrix<Type>& A,
2510  const tmp<DimensionedField<Type, volMesh>>& tsu
2511 )
2512 {
2513  checkMethod(A, tsu(), "-");
2514  auto tC = tmp<fvMatrix<Type>>::New(A);
2515  tC.ref().source() += tsu().mesh().V()*tsu().field();
2516  tsu.clear();
2517  return tC;
2518 }
2519 
2520 template<class Type>
2521 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2522 (
2523  const fvMatrix<Type>& A,
2524  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu
2525 )
2526 {
2527  checkMethod(A, tsu(), "-");
2528  auto tC = tmp<fvMatrix<Type>>::New(A);
2529  tC.ref().source() += tsu().mesh().V()*tsu().primitiveField();
2530  tsu.clear();
2531  return tC;
2532 }
2533 
2534 template<class Type>
2535 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2536 (
2537  const tmp<fvMatrix<Type>>& tA,
2538  const DimensionedField<Type, volMesh>& su
2539 )
2540 {
2541  checkMethod(tA(), su, "-");
2542  tmp<fvMatrix<Type>> tC(tA.ptr());
2543  tC.ref().source() += su.mesh().V()*su.field();
2544  return tC;
2545 }
2546 
2547 template<class Type>
2548 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2549 (
2550  const tmp<fvMatrix<Type>>& tA,
2551  const tmp<DimensionedField<Type, volMesh>>& tsu
2552 )
2553 {
2554  checkMethod(tA(), tsu(), "-");
2555  tmp<fvMatrix<Type>> tC(tA.ptr());
2556  tC.ref().source() += tsu().mesh().V()*tsu().field();
2557  tsu.clear();
2558  return tC;
2559 }
2560 
2561 template<class Type>
2562 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2563 (
2564  const tmp<fvMatrix<Type>>& tA,
2565  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu
2566 )
2567 {
2568  checkMethod(tA(), tsu(), "-");
2569  tmp<fvMatrix<Type>> tC(tA.ptr());
2570  tC.ref().source() += tsu().mesh().V()*tsu().primitiveField();
2571  tsu.clear();
2572  return tC;
2573 }
2574 
2575 template<class Type>
2576 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2577 (
2578  const DimensionedField<Type, volMesh>& su,
2579  const fvMatrix<Type>& A
2580 )
2581 {
2582  checkMethod(A, su, "-");
2583  auto tC = tmp<fvMatrix<Type>>::New(A);
2584  tC.ref().negate();
2585  tC.ref().source() -= su.mesh().V()*su.field();
2586  return tC;
2587 }
2588 
2589 template<class Type>
2590 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2591 (
2592  const tmp<DimensionedField<Type, volMesh>>& tsu,
2593  const fvMatrix<Type>& A
2594 )
2595 {
2596  checkMethod(A, tsu(), "-");
2597  auto tC = tmp<fvMatrix<Type>>::New(A);
2598  tC.ref().negate();
2599  tC.ref().source() -= tsu().mesh().V()*tsu().field();
2600  tsu.clear();
2601  return tC;
2602 }
2603 
2604 template<class Type>
2605 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2606 (
2607  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu,
2608  const fvMatrix<Type>& A
2609 )
2610 {
2611  checkMethod(A, tsu(), "-");
2612  auto tC = tmp<fvMatrix<Type>>::New(A);
2613  tC.ref().negate();
2614  tC.ref().source() -= tsu().mesh().V()*tsu().primitiveField();
2615  tsu.clear();
2616  return tC;
2617 }
2618 
2619 template<class Type>
2620 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2621 (
2622  const DimensionedField<Type, volMesh>& su,
2623  const tmp<fvMatrix<Type>>& tA
2624 )
2625 {
2626  checkMethod(tA(), su, "-");
2627  tmp<fvMatrix<Type>> tC(tA.ptr());
2628  tC.ref().negate();
2629  tC.ref().source() -= su.mesh().V()*su.field();
2630  return tC;
2631 }
2632 
2633 template<class Type>
2634 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2635 (
2636  const tmp<DimensionedField<Type, volMesh>>& tsu,
2637  const tmp<fvMatrix<Type>>& tA
2638 )
2639 {
2640  checkMethod(tA(), tsu(), "-");
2641  tmp<fvMatrix<Type>> tC(tA.ptr());
2642  tC.ref().negate();
2643  tC.ref().source() -= tsu().mesh().V()*tsu().field();
2644  tsu.clear();
2645  return tC;
2646 }
2647 
2648 template<class Type>
2649 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2650 (
2651  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tsu,
2652  const tmp<fvMatrix<Type>>& tA
2653 )
2654 {
2655  checkMethod(tA(), tsu(), "-");
2656  tmp<fvMatrix<Type>> tC(tA.ptr());
2657  tC.ref().negate();
2658  tC.ref().source() -= tsu().mesh().V()*tsu().primitiveField();
2659  tsu.clear();
2660  return tC;
2661 }
2662 
2663 template<class Type>
2664 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2665 (
2666  const fvMatrix<Type>& A,
2667  const dimensioned<Type>& su
2668 )
2669 {
2670  checkMethod(A, su, "+");
2671  auto tC = tmp<fvMatrix<Type>>::New(A);
2672  tC.ref().source() -= su.value()*A.psi().mesh().V();
2673  return tC;
2674 }
2675 
2676 template<class Type>
2677 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2678 (
2679  const tmp<fvMatrix<Type>>& tA,
2680  const dimensioned<Type>& su
2681 )
2682 {
2683  checkMethod(tA(), su, "+");
2684  tmp<fvMatrix<Type>> tC(tA.ptr());
2685  tC.ref().source() -= su.value()*tC().psi().mesh().V();
2686  return tC;
2687 }
2688 
2689 template<class Type>
2690 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2691 (
2692  const dimensioned<Type>& su,
2693  const fvMatrix<Type>& A
2694 )
2695 {
2696  checkMethod(A, su, "+");
2697  auto tC = tmp<fvMatrix<Type>>::New(A);
2698  tC.ref().source() -= su.value()*A.psi().mesh().V();
2699  return tC;
2700 }
2701 
2702 template<class Type>
2703 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator+
2704 (
2705  const dimensioned<Type>& su,
2706  const tmp<fvMatrix<Type>>& tA
2707 )
2708 {
2709  checkMethod(tA(), su, "+");
2710  tmp<fvMatrix<Type>> tC(tA.ptr());
2711  tC.ref().source() -= su.value()*tC().psi().mesh().V();
2712  return tC;
2713 }
2714 
2715 template<class Type>
2716 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2717 (
2718  const fvMatrix<Type>& A,
2719  const dimensioned<Type>& su
2720 )
2721 {
2722  checkMethod(A, su, "-");
2723  auto tC = tmp<fvMatrix<Type>>::New(A);
2724  tC.ref().source() += su.value()*tC().psi().mesh().V();
2725  return tC;
2726 }
2727 
2728 template<class Type>
2729 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2730 (
2731  const tmp<fvMatrix<Type>>& tA,
2732  const dimensioned<Type>& su
2733 )
2734 {
2735  checkMethod(tA(), su, "-");
2736  tmp<fvMatrix<Type>> tC(tA.ptr());
2737  tC.ref().source() += su.value()*tC().psi().mesh().V();
2738  return tC;
2739 }
2740 
2741 template<class Type>
2742 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2743 (
2744  const dimensioned<Type>& su,
2745  const fvMatrix<Type>& A
2746 )
2747 {
2748  checkMethod(A, su, "-");
2749  auto tC = tmp<fvMatrix<Type>>::New(A);
2750  tC.ref().negate();
2751  tC.ref().source() -= su.value()*A.psi().mesh().V();
2752  return tC;
2753 }
2754 
2755 template<class Type>
2756 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator-
2757 (
2758  const dimensioned<Type>& su,
2759  const tmp<fvMatrix<Type>>& tA
2760 )
2761 {
2762  checkMethod(tA(), su, "-");
2763  tmp<fvMatrix<Type>> tC(tA.ptr());
2764  tC.ref().negate();
2765  tC.ref().source() -= su.value()*tC().psi().mesh().V();
2766  return tC;
2767 }
2768 
2769 
2770 template<class Type>
2771 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2772 (
2773  const volScalarField::Internal& dsf,
2774  const fvMatrix<Type>& A
2775 )
2776 {
2777  auto tC = tmp<fvMatrix<Type>>::New(A);
2778  tC.ref() *= dsf;
2779  return tC;
2780 }
2781 
2782 template<class Type>
2783 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2784 (
2785  const tmp<volScalarField::Internal>& tdsf,
2786  const fvMatrix<Type>& A
2787 )
2788 {
2789  auto tC = tmp<fvMatrix<Type>>::New(A);
2790  tC.ref() *= tdsf;
2791  return tC;
2792 }
2793 
2794 template<class Type>
2795 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2796 (
2797  const tmp<volScalarField>& tvsf,
2798  const fvMatrix<Type>& A
2799 )
2800 {
2801  auto tC = tmp<fvMatrix<Type>>::New(A);
2802  tC.ref() *= tvsf;
2803  return tC;
2804 }
2805 
2806 template<class Type>
2807 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2808 (
2809  const volScalarField::Internal& dsf,
2810  const tmp<fvMatrix<Type>>& tA
2811 )
2812 {
2813  tmp<fvMatrix<Type>> tC(tA.ptr());
2814  tC.ref() *= dsf;
2815  return tC;
2816 }
2817 
2818 template<class Type>
2819 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2820 (
2821  const tmp<volScalarField::Internal>& tdsf,
2822  const tmp<fvMatrix<Type>>& tA
2823 )
2824 {
2825  tmp<fvMatrix<Type>> tC(tA.ptr());
2826  tC.ref() *= tdsf;
2827  return tC;
2828 }
2829 
2830 template<class Type>
2831 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2832 (
2833  const tmp<volScalarField>& tvsf,
2834  const tmp<fvMatrix<Type>>& tA
2835 )
2836 {
2837  tmp<fvMatrix<Type>> tC(tA.ptr());
2838  tC.ref() *= tvsf;
2839  return tC;
2840 }
2841 
2842 template<class Type>
2843 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2844 (
2845  const dimensioned<scalar>& ds,
2846  const fvMatrix<Type>& A
2847 )
2848 {
2849  auto tC = tmp<fvMatrix<Type>>::New(A);
2850  tC.ref() *= ds;
2851  return tC;
2852 }
2853 
2854 template<class Type>
2855 Foam::tmp<Foam::fvMatrix<Type>> Foam::operator*
2856 (
2857  const dimensioned<scalar>& ds,
2858  const tmp<fvMatrix<Type>>& tA
2859 )
2860 {
2861  tmp<fvMatrix<Type>> tC(tA.ptr());
2862  tC.ref() *= ds;
2863  return tC;
2864 }
2865 
2866 
2867 template<class Type>
2869 Foam::operator&
2870 (
2871  const fvMatrix<Type>& M,
2872  const DimensionedField<Type, volMesh>& psi
2873 )
2874 {
2876  (
2877  "M&" + psi.name(),
2878  psi.mesh(),
2879  M.dimensions()/dimVol,
2881  );
2882  auto& Mphi = tMphi.ref();
2883 
2884  // Loop over field components
2885  if (M.hasDiag())
2886  {
2887  for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; cmpt++)
2888  {
2889  scalarField psiCmpt(psi.field().component(cmpt));
2890  scalarField boundaryDiagCmpt(M.diag());
2891  M.addBoundaryDiag(boundaryDiagCmpt, cmpt);
2892  Mphi.primitiveFieldRef().replace(cmpt, -boundaryDiagCmpt*psiCmpt);
2893  }
2894  }
2895  else
2896  {
2897  Mphi.primitiveFieldRef() = Zero;
2898  }
2899 
2900  Mphi.primitiveFieldRef() += M.lduMatrix::H(psi.field()) + M.source();
2901  M.addBoundarySource(Mphi.primitiveFieldRef());
2902 
2903  Mphi.primitiveFieldRef() /= -psi.mesh().V();
2904  Mphi.correctBoundaryConditions();
2905 
2906  return tMphi;
2907 }
2908 
2909 template<class Type>
2911 Foam::operator&
2912 (
2913  const fvMatrix<Type>& M,
2914  const tmp<DimensionedField<Type, volMesh>>& tpsi
2915 )
2916 {
2917  tmp<GeometricField<Type, fvPatchField, volMesh>> tMpsi = M & tpsi();
2918  tpsi.clear();
2919  return tMpsi;
2920 }
2921 
2922 template<class Type>
2924 Foam::operator&
2925 (
2926  const fvMatrix<Type>& M,
2927  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tpsi
2928 )
2929 {
2930  tmp<GeometricField<Type, fvPatchField, volMesh>> tMpsi = M & tpsi();
2931  tpsi.clear();
2932  return tMpsi;
2933 }
2934 
2935 template<class Type>
2937 Foam::operator&
2938 (
2939  const tmp<fvMatrix<Type>>& tM,
2940  const DimensionedField<Type, volMesh>& psi
2941 )
2942 {
2943  tmp<GeometricField<Type, fvPatchField, volMesh>> tMpsi = tM() & psi;
2944  tM.clear();
2945  return tMpsi;
2946 }
2947 
2948 template<class Type>
2950 Foam::operator&
2951 (
2952  const tmp<fvMatrix<Type>>& tM,
2953  const tmp<DimensionedField<Type, volMesh>>& tpsi
2954 )
2955 {
2956  tmp<GeometricField<Type, fvPatchField, volMesh>> tMpsi = tM() & tpsi();
2957  tM.clear();
2958  tpsi.clear();
2959  return tMpsi;
2960 }
2961 
2962 template<class Type>
2964 Foam::operator&
2965 (
2966  const tmp<fvMatrix<Type>>& tM,
2967  const tmp<GeometricField<Type, fvPatchField, volMesh>>& tpsi
2968 )
2969 {
2970  tmp<GeometricField<Type, fvPatchField, volMesh>> tMpsi = tM() & tpsi();
2971  tM.clear();
2972  tpsi.clear();
2973  return tMpsi;
2974 }
2975 
2976 
2977 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
2978 
2979 template<class Type>
2980 Foam::Ostream& Foam::operator<<(Ostream& os, const fvMatrix<Type>& fvm)
2981 {
2982  os << static_cast<const lduMatrix&>(fvm) << nl
2983  << fvm.dimensions_ << nl
2984  << fvm.source_ << nl
2985  << fvm.internalCoeffs_ << nl
2986  << fvm.boundaryCoeffs_ << endl;
2987 
2989 
2990  return os;
2991 }
2992 
2993 
2994 // * * * * * * * * * * * * * * * * Solvers * * * * * * * * * * * * * * * * * //
2995 
2996 #include "fvMatrixSolve.C"
2997 
2998 // ************************************************************************* //
void mapContributions(label fieldi, const FieldField< Field, Type > &fluxContrib, FieldField< Field, Type > &contrib, bool internal) const
Add internal and boundary contribution to local patches.
Definition: fvMatrix.C:550
Foam::surfaceFields.
void addToInternalField(const labelUList &addr, const Field< Type2 > &pf, Field< Type2 > &intf) const
Add patch contribution to internal field.
Definition: fvMatrix.C:42
faceListList boundary
void update(UPtrList< GeometricField< Type, fvPatchField, volMesh >> &psis)
Update mappings.
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
tmp< Field< Type > > faceH(const Field< Type > &) const
virtual bool coupled() const
True if the patch field is coupled.
Definition: fvPatchField.H:253
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
void cmptMax(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
void setValuesFromList(const labelUList &cellLabels, const ListType< Type > &values)
Set solution in given cells to the specified values.
Definition: fvMatrix.C:220
uint8_t direction
Definition: direction.H:46
label faceId(-1)
T & last()
Return reference to the last element of the list.
Definition: UPtrList.H:861
void addBoundaryDiag(scalarField &diag, const direction cmpt) const
Definition: fvMatrix.C:117
void createOrUpdateLduPrimitiveAssembly()
Create or update ldu assembly.
Definition: fvMatrix.C:908
List< cell > cellList
List of cell.
Definition: cellListFwd.H:39
tmp< DimensionedField< typename DimensionedField< Type, GeoMesh >::cmptType, GeoMesh >> cmptAv(const DimensionedField< Type, GeoMesh > &f1)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
UEqn relax()
void relax()
Relax matrix (for steady-state solution).
Definition: fvMatrix.C:1243
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:45
void negate()
Inplace negate.
Definition: fvMatrix.C:1587
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Definition: tmpI.H:235
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:493
void addCmptAvBoundaryDiag(scalarField &diag) const
Definition: fvMatrix.C:145
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
void setReference(const label celli, const Type &value, const bool forceReference=false)
Set reference level for solution.
Definition: fvMatrix.C:1005
void manipulateMatrix(direction cmp)
Manipulate matrix.
Definition: fvMatrix.C:792
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
tmp< GeometricField< Type, fvPatchField, volMesh > > H() const
Return the H operation source.
Definition: fvMatrix.C:1326
A traits class, which is primarily used for primitives and vector-space.
Definition: pTraits.H:75
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
void operator-=(const fvMatrix< Type > &)
Definition: fvMatrix.C:1639
Abstract base class with a fat-interface to all derived classes covering all possible ways in which t...
const dimensionSet dimVol(dimVolume)
Older spelling for dimVolume.
Definition: dimensionSets.H:65
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
Definition: stringOps.C:1187
bool checkImplicit(const label fieldi=0)
Name the implicit assembly addressing.
Definition: fvMatrix.C:315
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1252
Generic GeometricField class.
This boundary condition enforces a cyclic condition between a pair of boundaries, whereby communicati...
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
Generic dimensioned Type class.
tmp< volScalarField > H1() const
Return H(1)
Definition: fvMatrix.C:1378
Ignore writing from objectRegistry::writeObject()
void subtractFromInternalField(const labelUList &addr, const Field< Type2 > &pf, Field< Type2 > &intf) const
Subtract patch contribution from internal field.
Definition: fvMatrix.C:80
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
DimensionedField< scalar, volMesh > Internal
The internal field type from which this GeometricField is derived.
tmp< scalarField > H1() const
conserve primitiveFieldRef()+
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
tmp< scalarField > D() const
Return the matrix scalar diagonal.
Definition: fvMatrix.C:1274
void operator=(const fvMatrix< Type > &)
Definition: fvMatrix.C:1541
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
const dimensionSet dimVolume(pow3(dimLength))
Definition: dimensionSets.H:58
Dimension set for the base types, which can be used to implement rigorous dimension checking for alge...
Definition: dimensionSet.H:105
void diag(pointPatchField< vector > &, const pointPatchField< tensor > &)
const GeometricField< Type, fvPatchField, volMesh > & psi(const label i=0) const
Return psi.
Definition: fvMatrix.H:485
void setSize(const label n)
Alias for resize()
Definition: List.H:320
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const cellShapeList & cells
void addFvMatrix(fvMatrix< Type > &matrix)
Add fvMatrix.
Definition: fvMatrix.C:1066
Generic templated field type.
Definition: Field.H:62
void setInterfaces(lduInterfaceFieldPtrsList &, PtrDynList< lduInterfaceField > &newInterfaces)
Set interfaces.
Definition: fvMatrix.C:472
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
SolverPerformance is the class returned by the LduMatrix solver containing performance statistics...
void setReferences(const labelUList &cellLabels, const Type &value, const bool forceReference=false)
Set reference level for solution.
Definition: fvMatrix.C:1021
#define DebugInFunction
Report an information message using Foam::Info.
void checkMethod(const faMatrix< Type > &, const faMatrix< Type > &, const char *)
Definition: faMatrix.C:1034
virtual const lduAddressing & lduAddr() const
Return ldu addressing.
virtual ~fvMatrix()
Destructor.
Definition: fvMatrix.C:459
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
A special matrix type and solver, designed for finite volume solutions of scalar equations. Face addressing is used to make all matrix assembly and solution loops vectorise.
Definition: fvPatchField.H:64
void transferFvMatrixCoeffs()
Transfer lower, upper, diag and source to this fvMatrix.
Definition: fvMatrix.C:815
errorManip< error > abort(error &err)
Definition: errorManip.H:139
void operator=(const lduMatrix &)
Copy assignment.
SolverPerformance< Type > solve(faMatrix< Type > &, const dictionary &solverControls)
Solve returning the solution statistics given convergence tolerance.
This boundary condition enforces a cyclic condition between a pair of boundaries. ...
static tmp< GeometricField< scalar, fvPatchField, volMesh > > New(const word &name, IOobjectOption::registerOption regOpt, const Mesh &mesh, const dimensionSet &dims, const word &patchFieldType=fvPatchField< scalar >::calculatedType())
Return tmp field (NO_READ, NO_WRITE) from name, mesh, dimensions and patch type. [Takes current timeN...
dimensioned< Type > cmptMultiply(const dimensioned< Type > &, const dimensioned< Type > &)
void cmptMag(FieldField< Field, Type > &cf, const FieldField< Field, Type > &f)
const Mesh & mesh() const noexcept
Return mesh.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
fvMatrix(const GeometricField< Type, fvPatchField, volMesh > &psi, const dimensionSet &ds)
Construct given a field to solve for.
Definition: fvMatrix.C:352
void operator*=(const scalarField &)
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
An assembly of lduMatrix that is specific inter-region coupling through mapped patches.
A dynamically resizable PtrList with allocation management.
Definition: PtrDynList.H:48
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const Field< Type > & field() const noexcept
Return const-reference to the field values.
lduPrimitiveMeshAssembly * lduMeshPtr()
Access to lduPrimitiveMeshAssembly.
Definition: fvMatrix.C:882
void operator+=(const fvMatrix< Type > &)
Definition: fvMatrix.C:1602
tmp< Field< Type > > DD() const
Return the matrix Type diagonal.
Definition: fvMatrix.C:1283
Template functions to aid in the implementation of demand driven data.
lduMatrix is a general matrix class in which the coefficients are stored as three arrays...
Definition: lduMatrix.H:80
tmp< volScalarField > A() const
Return the central coefficient.
Definition: fvMatrix.C:1307
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
Definition: stringOps.C:1171
static bool checking() noexcept
True if dimension checking is enabled (the usual default)
Definition: dimensionSet.H:241
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:52
label cellId
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
Nothing to be read.
A single value that is represented as a list with an operator[] to access the value. This can be useful for templated operations expecting a list accessor.
Definition: UniformList.H:48
Boundary & boundaryFieldRef(const bool updateAccessTime=true)
Return a reference to the boundary field.
void correctBoundaryConditions()
Correct boundary field.
messageStream Info
Information stream (stdout output on master, null elsewhere)
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
void addBoundarySource(Field< Type > &source, const bool couples=true) const
Definition: fvMatrix.C:170
void clear() const noexcept
If object pointer points to valid object: delete object and set pointer to nullptr.
Definition: tmpI.H:289
const volScalarField & psi
tmp< GeometricField< Type, fvsPatchField, surfaceMesh > > flux() const
Return the face-flux field from the matrix.
Definition: fvMatrix.C:1416
void setValues(const labelUList &cellLabels, const Type &value)
Set solution in given cells to the specified value and eliminate the corresponding equations from the...
Definition: fvMatrix.C:972
void boundaryManipulate(typename GeometricField< Type, fvPatchField, volMesh >::Boundary &values)
Manipulate based on a boundary field.
Definition: fvMatrix.C:1261
tmp< Field< Type > > H(const Field< Type > &) const
const dimensionedScalar & D
void operator-=(const lduMatrix &)
void operator+=(const lduMatrix &)
T * ptr() const
Return managed pointer for reuse, or clone() the object reference.
Definition: tmpI.H:256
List< label > labelList
A List of labels.
Definition: List.H:62
void clearOut()
Clear additional addressing.
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
A class for managing temporary objects.
Definition: HashPtrTable.H:50
void setSize(const label n)
Alias for resize()
Definition: UPtrList.H:840
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
static const word & extrapolatedCalculatedType() noexcept
The type name for extrapolatedCalculated patch fields combines zero-gradient and calculated.
Definition: fvPatchField.H:213
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
static const Foam::dimensionedScalar A("", Foam::dimPressure, 611.21)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
Request registration (bool: true)
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
void setBounAndInterCoeffs()
Manipulate boundary/internal coeffs for coupling.
Definition: fvMatrix.C:662
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
#define M(I)
This boundary condition enforces a cyclic condition between a pair of boundaries, whereby communicati...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
static const Foam::dimensionedScalar B("", Foam::dimless, 18.678)
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
const dimensionSet & dimensions() const noexcept
Return dimensions.
const dictionary & solverDict() const
Return the solver dictionary for psi, taking into account finalIteration.
Definition: fvMatrix.C:1529
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie...
Definition: UPtrList.H:366
#define InfoInFunction
Report an information message using Foam::Info.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
void append(autoPtr< T > &ptr)
Move append an element to the end of the list.
Definition: PtrDynList.H:377
void replace(const direction d, const GeometricField< cmptType, PatchField, GeoMesh > &gcf)
Replace specified field component with content from another field.