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