faMatrix.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) 2016-2017 Wikki Ltd
9  Copyright (C) 2019-2023 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 "areaFields.H"
30 #include "edgeFields.H"
32 #include "IndirectList.H"
33 #include "UniformList.H"
34 
35 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36 
37 template<class Type>
38 template<class Type2>
40 (
41  const labelUList& addr,
42  const Field<Type2>& pf,
43  Field<Type2>& intf
44 ) const
45 {
46  if (addr.size() != pf.size())
47  {
49  << "addressing (" << addr.size()
50  << ") and field (" << pf.size() << ") are different sizes"
51  << abort(FatalError);
52  }
53 
54  forAll(addr, faceI)
55  {
56  intf[addr[faceI]] += pf[faceI];
57  }
58 }
59 
60 
61 template<class Type>
62 template<class Type2>
64 (
65  const labelUList& addr,
66  const tmp<Field<Type2>>& tpf,
67  Field<Type2>& intf
68 ) const
69 {
70  addToInternalField(addr, tpf(), intf);
71  tpf.clear();
72 }
73 
74 
75 template<class Type>
76 template<class Type2>
78 (
79  const labelUList& addr,
80  const Field<Type2>& pf,
81  Field<Type2>& intf
82 ) const
83 {
84  if (addr.size() != pf.size())
85  {
87  << "addressing (" << addr.size()
88  << ") and field (" << pf.size() << ") are different sizes"
89  << abort(FatalError);
90  }
91 
92  forAll(addr, faceI)
93  {
94  intf[addr[faceI]] -= pf[faceI];
95  }
96 }
97 
98 
99 template<class Type>
100 template<class Type2>
102 (
103  const labelUList& addr,
104  const tmp<Field<Type2>>& tpf,
105  Field<Type2>& intf
106 ) const
107 {
108  subtractFromInternalField(addr, tpf(), intf);
109  tpf.clear();
110 }
111 
112 
113 template<class Type>
115 (
116  scalarField& diag,
117  const direction solveCmpt
118 ) const
119 {
120  forAll(internalCoeffs_, patchI)
121  {
122  addToInternalField
123  (
124  lduAddr().patchAddr(patchI),
125  internalCoeffs_[patchI].component(solveCmpt),
127  );
128  }
129 }
130 
131 
132 template<class Type>
134 {
135  forAll(internalCoeffs_, patchI)
136  {
137  addToInternalField
138  (
139  lduAddr().patchAddr(patchI),
140  cmptAv(internalCoeffs_[patchI]),
141  diag
142  );
143  }
144 }
145 
146 
147 template<class Type>
149 (
150  Field<Type>& source,
151  const bool couples
152 ) const
153 {
154  forAll(psi_.boundaryField(), patchI)
155  {
156  const faPatchField<Type>& ptf = psi_.boundaryField()[patchI];
157  const Field<Type>& pbc = boundaryCoeffs_[patchI];
158 
159  if (!ptf.coupled())
160  {
161  addToInternalField(lduAddr().patchAddr(patchI), pbc, source);
162  }
163  else if (couples)
164  {
165  tmp<Field<Type>> tpnf = ptf.patchNeighbourField();
166  const Field<Type>& pnf = tpnf();
167 
168  const labelUList& addr = lduAddr().patchAddr(patchI);
169 
170  forAll(addr, facei)
171  {
172  source[addr[facei]] += cmptMultiply(pbc[facei], pnf[facei]);
173  }
174  }
175  }
176 }
177 
178 
179 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
180 
181 template<class Type>
183 (
185  const dimensionSet& ds
186 )
187 :
188  lduMatrix(psi.mesh()),
189  psi_(psi),
190  dimensions_(ds),
191  source_(psi.size(), Zero),
192  internalCoeffs_(psi.mesh().boundary().size()),
193  boundaryCoeffs_(psi.mesh().boundary().size())
194 {
196  << "constructing faMatrix<Type> for field " << psi_.name()
197  << endl;
198 
199  // Initialise coupling coefficients
200  forAll(psi.mesh().boundary(), patchi)
201  {
202  internalCoeffs_.set
203  (
204  patchi,
205  new Field<Type>(psi.mesh().boundary()[patchi].size(), Zero)
206  );
207 
208  boundaryCoeffs_.set
209  (
210  patchi,
211  new Field<Type>(psi.mesh().boundary()[patchi].size(), Zero)
212  );
213  }
214 
215  // Update the boundary coefficients of psi without changing its event No.
216  auto& psiRef = psi_.constCast();
217 
218  const label currentStatePsi = psiRef.eventNo();
219  psiRef.boundaryFieldRef().updateCoeffs();
220  psiRef.eventNo() = currentStatePsi;
221 }
222 
223 
224 template<class Type>
226 :
227  lduMatrix(fam),
228  psi_(fam.psi_),
229  dimensions_(fam.dimensions_),
230  source_(fam.source_),
231  internalCoeffs_(fam.internalCoeffs_),
232  boundaryCoeffs_(fam.boundaryCoeffs_)
233 {
235  << "Copying faMatrix<Type> for field " << psi_.name() << endl;
236 
237  if (fam.faceFluxCorrectionPtr_)
238  {
239  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
240  (
241  *(fam.faceFluxCorrectionPtr_)
242  );
243  }
244 }
245 
246 
247 template<class Type>
248 Foam::faMatrix<Type>::faMatrix(const tmp<faMatrix<Type>>& tmat)
249 :
250  lduMatrix(tmat.constCast(), tmat.movable()),
251  psi_(tmat().psi_),
252  dimensions_(tmat().dimensions_),
253  source_(tmat.constCast().source_, tmat.movable()),
254  internalCoeffs_(tmat.constCast().internalCoeffs_, tmat.movable()),
255  boundaryCoeffs_(tmat.constCast().boundaryCoeffs_, tmat.movable())
256 {
258  << "Copy/Move faMatrix<Type> for field " << psi_.name() << endl;
259 
260  if (tmat().faceFluxCorrectionPtr_)
261  {
262  if (tmat.movable())
263  {
264  faceFluxCorrectionPtr_ =
265  std::move(tmat.constCast().faceFluxCorrectionPtr_);
266  }
267  else if (tmat().faceFluxCorrectionPtr_)
268  {
269  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
270  (
271  *(tmat().faceFluxCorrectionPtr_)
272  );
273  }
274  }
275 
276  tmat.clear();
277 }
278 
279 
280 // * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * * * //
281 
282 template<class Type>
284 {
286  << "Destroying faMatrix<Type> for field " << psi_.name() << endl;
287 }
289 
290 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
291 
292 template<class Type>
293 template<template<class> class ListType>
295 (
296  const labelUList& faceLabels,
297  const ListType<Type>& values
298 )
299 {
300 #if 0 /* Specific to foam-extend */
301  // Record face labels of eliminated equations
302  for (const label i : faceLabels)
303  {
304  this->eliminatedEqns().insert(i);
305  }
306 #endif
307 
308  const faMesh& mesh = psi_.mesh();
309 
310  const labelListList& edges = mesh.patch().faceEdges();
311  const labelUList& own = mesh.owner();
312  const labelUList& nei = mesh.neighbour();
313 
314  scalarField& Diag = diag();
315  Field<Type>& psi = psi_.constCast().primitiveFieldRef();
316 
317  // Following actions:
318  // - adjust local field psi
319  // - set local matrix to be diagonal (so adjust source)
320  // - cut connections to neighbours
321  // - make (on non-adjusted cells) contribution explicit
322 
323  if (symmetric() || asymmetric())
324  {
325  forAll(faceLabels, i)
326  {
327  const label facei = faceLabels[i];
328  const Type& value = values[i];
329 
330  for (const label edgei : edges[facei])
331  {
332  if (mesh.isInternalEdge(edgei))
333  {
334  if (symmetric())
335  {
336  if (facei == own[edgei])
337  {
338  source_[nei[edgei]] -= upper()[edgei]*value;
339  }
340  else
341  {
342  source_[own[edgei]] -= upper()[edgei]*value;
343  }
344 
345  upper()[edgei] = 0.0;
346  }
347  else
348  {
349  if (facei == own[edgei])
350  {
351  source_[nei[edgei]] -= lower()[edgei]*value;
352  }
353  else
354  {
355  source_[own[edgei]] -= upper()[edgei]*value;
356  }
357 
358  upper()[edgei] = 0.0;
359  lower()[edgei] = 0.0;
360  }
361  }
362  else
363  {
364  const label patchi = mesh.boundary().whichPatch(edgei);
365 
366  if (internalCoeffs_[patchi].size())
367  {
368  const label patchEdgei =
369  mesh.boundary()[patchi].whichEdge(edgei);
370 
371  internalCoeffs_[patchi][patchEdgei] = Zero;
372  boundaryCoeffs_[patchi][patchEdgei] = Zero;
373  }
374  }
375  }
376  }
377  }
378 
379  // Note: above loop might have affected source terms on adjusted cells
380  // so make sure to adjust them afterwards
381  forAll(faceLabels, i)
382  {
383  const label facei = faceLabels[i];
384  const Type& value = values[i];
385 
386  psi[facei] = value;
387  source_[facei] = value*Diag[facei];
388  }
389 }
390 
391 
392 template<class Type>
394 (
395  const labelUList& faceLabels,
396  const Type& value
397 )
398 {
399  this->setValuesFromList(faceLabels, UniformList<Type>(value));
400 }
401 
402 
403 template<class Type>
405 (
406  const labelUList& faceLabels,
407  const UList<Type>& values
408 )
409 {
410  this->setValuesFromList(faceLabels, values);
411 }
412 
413 
414 template<class Type>
416 (
417  const labelUList& faceLabels,
419 )
420 {
421  this->setValuesFromList(faceLabels, values);
422 }
423 
424 
425 template<class Type>
427 (
428  const label facei,
429  const Type& value,
430  const bool forceReference
431 )
432 {
433  if ((forceReference || psi_.needReference()) && facei >= 0)
434  {
435  if (Pstream::master())
436  {
437  source()[facei] += diag()[facei]*value;
438  diag()[facei] += diag()[facei];
439  }
440  }
441 }
442 
443 
444 template<class Type>
446 (
447  const labelUList& faceLabels,
448  const Type& value,
449  const bool forceReference
450 )
451 {
452  if (forceReference || psi_.needReference())
453  {
454  forAll(faceLabels, facei)
455  {
456  const label faceId = faceLabels[facei];
457  if (faceId >= 0)
458  {
459  source()[faceId] += diag()[faceId]*value;
460  diag()[faceId] += diag()[faceId];
461  }
462  }
463  }
464 }
465 
466 
467 template<class Type>
469 (
470  const labelUList& faceLabels,
471  const UList<Type>& values,
472  const bool forceReference
473 )
474 {
475  if (forceReference || psi_.needReference())
476  {
477  forAll(faceLabels, facei)
478  {
479  const label faceId = faceLabels[facei];
480  if (faceId >= 0)
481  {
482  source()[faceId] += diag()[faceId]*values[facei];
483  diag()[faceId] += diag()[faceId];
484  }
485  }
486  }
487 }
488 
489 
490 template<class Type>
491 void Foam::faMatrix<Type>::relax(const scalar alpha)
492 {
493  if (alpha <= 0)
494  {
495  return;
496  }
497 
498  Field<Type>& S = source();
499  scalarField& D = diag();
500 
501  // Store the current unrelaxed diagonal for use in updating the source
502  scalarField D0(D);
503 
504  // Calculate the sum-mag off-diagonal from the interior faces
505  scalarField sumOff(D.size(), Zero);
506  sumMagOffDiag(sumOff);
507 
508  // Handle the boundary contributions to the diagonal
509  forAll(psi_.boundaryField(), patchI)
510  {
511  const faPatchField<Type>& ptf = psi_.boundaryField()[patchI];
512 
513  if (ptf.size())
514  {
515  const labelUList& pa = lduAddr().patchAddr(patchI);
516  Field<Type>& iCoeffs = internalCoeffs_[patchI];
517 
518  if (ptf.coupled())
519  {
520  const Field<Type>& pCoeffs = boundaryCoeffs_[patchI];
521 
522  // For coupled boundaries add the diagonal and
523  // off-diagonal contributions
524  forAll(pa, face)
525  {
526  D[pa[face]] += component(iCoeffs[face], 0);
527  sumOff[pa[face]] += mag(component(pCoeffs[face], 0));
528  }
529  }
530  else
531  {
532  // For non-coupled boundaries subtract the diagonal
533  // contribution off-diagonal sum which avoids having to remove
534  // it from the diagonal later.
535  // Also add the source contribution from the relaxation
536  forAll(pa, face)
537  {
538  Type iCoeff0 = iCoeffs[face];
539  iCoeffs[face] = cmptMag(iCoeffs[face]);
540  sumOff[pa[face]] -= cmptMin(iCoeffs[face]);
541  iCoeffs[face] /= alpha;
542  S[pa[face]] +=
543  cmptMultiply(iCoeffs[face] - iCoeff0, psi_[pa[face]]);
544  }
545  }
546  }
547  }
548 
549  // Ensure the matrix is diagonally dominant...
550  max(D, D, sumOff);
551 
552  // ... then relax
553  D /= alpha;
554 
555  // Now remove the diagonal contribution from coupled boundaries
556  forAll(psi_.boundaryField(), patchI)
557  {
558  const faPatchField<Type>& ptf = psi_.boundaryField()[patchI];
559 
560  if (ptf.size())
561  {
562  const labelUList& pa = lduAddr().patchAddr(patchI);
563  Field<Type>& iCoeffs = internalCoeffs_[patchI];
564 
565  if (ptf.coupled())
566  {
567  forAll(pa, face)
568  {
569  D[pa[face]] -= component(iCoeffs[face], 0);
570  }
571  }
572  }
573  }
575  // Finally add the relaxation contribution to the source.
576  S += (D - D0)*psi_.primitiveField();
577 }
578 
579 
580 template<class Type>
582 {
583  scalar relaxCoeff = 0;
584 
585  if (psi_.mesh().relaxEquation(psi_.name(), relaxCoeff))
586  {
587  relax(relaxCoeff);
588  }
589  else
590  {
592  << "No relaxation specified for field " << psi_.name() << nl;
593  }
594 }
595 
596 
597 template<class Type>
599 {
600  auto tdiag = tmp<scalarField>::New(diag());
601  addCmptAvBoundaryDiag(tdiag.ref());
602  return tdiag;
603 }
604 
605 
606 template<class Type>
608 {
609  auto tAphi = areaScalarField::New
610  (
611  "A(" + psi_.name() + ')',
612  psi_.mesh(),
613  dimensions_/psi_.dimensions()/dimArea,
615  );
616 
617  tAphi.ref().primitiveFieldRef() = D()/psi_.mesh().S();
618  tAphi.ref().correctBoundaryConditions();
620  return tAphi;
621 }
622 
623 
624 template<class Type>
627 {
629  (
630  "H(" + psi_.name() + ')',
631  psi_.mesh(),
632  dimensions_/dimArea,
634  );
635  auto& Hphi = tHphi.ref();
636 
637  // Loop over field components
638  for (direction cmpt=0; cmpt<Type::nComponents; ++cmpt)
639  {
640  scalarField psiCmpt(psi_.primitiveField().component(cmpt));
641 
642  scalarField boundaryDiagCmpt(psi_.size(), Zero);
643  addBoundaryDiag(boundaryDiagCmpt, cmpt);
644  boundaryDiagCmpt.negate();
645  addCmptAvBoundaryDiag(boundaryDiagCmpt);
646 
647  Hphi.primitiveFieldRef().replace(cmpt, boundaryDiagCmpt*psiCmpt);
648  }
649 
650  Hphi.primitiveFieldRef() += lduMatrix::H(psi_.primitiveField()) + source_;
651  addBoundarySource(Hphi.primitiveFieldRef());
652 
653  Hphi.primitiveFieldRef() /= psi_.mesh().S();
656  return tHphi;
657 }
658 
659 
660 template<class Type>
663 {
664  if (!psi_.mesh().fluxRequired(psi_.name()))
665  {
667  << "flux requested but " << psi_.name()
668  << " not specified in the fluxRequired sub-dictionary of faSchemes"
669  << abort(FatalError);
670  }
671 
673  (
674  "flux(" + psi_.name() + ')',
675  psi_.mesh(),
676  dimensions()
677  );
678  auto& fieldFlux = tfieldFlux.ref();
679 
680  for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; ++cmpt)
681  {
682  fieldFlux.primitiveFieldRef().replace
683  (
684  cmpt,
685  lduMatrix::faceH(psi_.primitiveField().component(cmpt))
686  );
687  }
688 
689  FieldField<Field, Type> InternalContrib = internalCoeffs_;
690 
691  forAll(InternalContrib, patchI)
692  {
693  InternalContrib[patchI] =
695  (
696  InternalContrib[patchI],
697  psi_.boundaryField()[patchI].patchInternalField()
698  );
699  }
700 
701  FieldField<Field, Type> NeighbourContrib = boundaryCoeffs_;
702 
703  forAll(NeighbourContrib, patchI)
704  {
705  if (psi_.boundaryField()[patchI].coupled())
706  {
707  NeighbourContrib[patchI] =
709  (
710  NeighbourContrib[patchI],
711  psi_.boundaryField()[patchI].patchNeighbourField()
712  );
713  }
714  }
715 
716  forAll(fieldFlux.boundaryField(), patchI)
717  {
718  fieldFlux.boundaryFieldRef()[patchI] =
719  InternalContrib[patchI] - NeighbourContrib[patchI];
720  }
721 
722  if (faceFluxCorrectionPtr_)
723  {
724  fieldFlux += *faceFluxCorrectionPtr_;
725  }
727  return tfieldFlux;
728 }
729 
730 
731 template<class Type>
733 (
734  const word& name
735 ) const
736 {
737  return psi_.mesh().solverDict(name);
738 }
739 
740 
741 template<class Type>
743 {
744  return psi_.mesh().solverDict
745  (
746  psi_.name()
747  );
748 }
749 
750 
751 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
752 
753 template<class Type>
755 {
756  if (this == &famv)
757  {
758  return; // Self-assignment is a no-op
759  }
760 
761  if (&psi_ != &(famv.psi_))
762  {
764  << "different fields"
765  << abort(FatalError);
766  }
767 
768  lduMatrix::operator=(famv);
769  source_ = famv.source_;
770  internalCoeffs_ = famv.internalCoeffs_;
771  boundaryCoeffs_ = famv.boundaryCoeffs_;
772 
773  if (faceFluxCorrectionPtr_ && famv.faceFluxCorrectionPtr_)
774  {
775  *faceFluxCorrectionPtr_ = *famv.faceFluxCorrectionPtr_;
776  }
777  else if (famv.faceFluxCorrectionPtr_)
778  {
779  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
780  (
781  *famv.faceFluxCorrectionPtr_
782  );
783  }
784 }
785 
786 
787 template<class Type>
788 void Foam::faMatrix<Type>::operator=(const tmp<faMatrix<Type>>& tfamv)
789 {
790  operator=(tfamv());
791  tfamv.clear();
792 }
793 
794 
795 template<class Type>
797 {
799  source_.negate();
800  internalCoeffs_.negate();
801  boundaryCoeffs_.negate();
802 
803  if (faceFluxCorrectionPtr_)
804  {
805  faceFluxCorrectionPtr_->negate();
806  }
807 }
808 
809 
810 template<class Type>
811 void Foam::faMatrix<Type>::operator+=(const faMatrix<Type>& famv)
812 {
813  checkMethod(*this, famv, "+=");
814 
815  dimensions_ += famv.dimensions_;
816  lduMatrix::operator+=(famv);
817  source_ += famv.source_;
818  internalCoeffs_ += famv.internalCoeffs_;
819  boundaryCoeffs_ += famv.boundaryCoeffs_;
820 
821  if (faceFluxCorrectionPtr_ && famv.faceFluxCorrectionPtr_)
822  {
823  *faceFluxCorrectionPtr_ += *famv.faceFluxCorrectionPtr_;
824  }
825  else if (famv.faceFluxCorrectionPtr_)
826  {
827  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
828  (
829  *famv.faceFluxCorrectionPtr_
830  );
831  }
832 }
833 
834 
835 template<class Type>
836 void Foam::faMatrix<Type>::operator+=(const tmp<faMatrix<Type>>& tfamv)
837 {
838  operator+=(tfamv());
839  tfamv.clear();
840 }
841 
842 
843 template<class Type>
845 {
846  checkMethod(*this, famv, "+=");
847 
848  dimensions_ -= famv.dimensions_;
849  lduMatrix::operator-=(famv);
850  source_ -= famv.source_;
851  internalCoeffs_ -= famv.internalCoeffs_;
852  boundaryCoeffs_ -= famv.boundaryCoeffs_;
853 
854  if (faceFluxCorrectionPtr_ && famv.faceFluxCorrectionPtr_)
855  {
856  *faceFluxCorrectionPtr_ -= *famv.faceFluxCorrectionPtr_;
857  }
858  else if (famv.faceFluxCorrectionPtr_)
859  {
860  faceFluxCorrectionPtr_ = std::make_unique<faceFluxFieldType>
861  (
862  -*famv.faceFluxCorrectionPtr_
863  );
864  }
865 }
866 
867 
868 template<class Type>
869 void Foam::faMatrix<Type>::operator-=(const tmp<faMatrix<Type>>& tfamv)
870 {
871  operator-=(tfamv());
872  tfamv.clear();
873 }
874 
875 
876 template<class Type>
878 (
880 )
881 {
882  checkMethod(*this, su, "+=");
883  source() -= su.mesh().S()*su.field();
884 }
885 
886 
887 template<class Type>
889 (
891 )
892 {
893  operator+=(tsu());
894  tsu.clear();
895 }
896 
897 
898 template<class Type>
900 (
902 )
903 {
904  operator+=(tsu());
905  tsu.clear();
906 }
907 
908 
909 template<class Type>
911 (
913 )
914 {
915  checkMethod(*this, su, "-=");
916  source() += su.mesh().S()*su.field();
917 }
918 
919 
920 template<class Type>
922 (
924 )
925 {
926  operator-=(tsu());
927  tsu.clear();
928 }
929 
930 
931 template<class Type>
933 (
935 )
936 {
937  operator-=(tsu());
938  tsu.clear();
939 }
940 
941 
942 template<class Type>
944 (
945  const dimensioned<Type>& su
946 )
947 {
948  source() -= psi().mesh().S()*su;
949 }
950 
951 
952 template<class Type>
954 (
955  const dimensioned<Type>& su
956 )
957 {
958  source() += psi().mesh().S()*su;
959 }
960 
961 
962 template<class Type>
964 (
965  const areaScalarField::Internal& dsf
966 )
967 {
968  dimensions_ *= dsf.dimensions();
969  lduMatrix::operator*=(dsf.field());
970  source_ *= dsf.field();
971 
972  forAll(boundaryCoeffs_, patchi)
973  {
974  const scalarField pisf
975  (
976  dsf.mesh().boundary()[patchi].patchInternalField(dsf.field())
977  );
978  internalCoeffs_[patchi] *= pisf;
979  boundaryCoeffs_[patchi] *= pisf;
980  }
981 
982  if (faceFluxCorrectionPtr_)
983  {
985  << "cannot scale a matrix containing a faceFluxCorrection"
987  }
988 }
989 
990 
991 template<class Type>
993 (
994  const tmp<areaScalarField::Internal>& tfld
995 )
996 {
997  operator*=(tfld());
998  tfld.clear();
999 }
1000 
1001 
1002 template<class Type>
1004 (
1005  const tmp<areaScalarField>& tfld
1006 )
1007 {
1008  operator*=(tfld());
1009  tfld.clear();
1010 }
1011 
1012 
1013 template<class Type>
1015 (
1016  const dimensioned<scalar>& ds
1017 )
1018 {
1019  dimensions_ *= ds.dimensions();
1020  lduMatrix::operator*=(ds.value());
1021  source_ *= ds.value();
1022  internalCoeffs_ *= ds.value();
1023  boundaryCoeffs_ *= ds.value();
1024 
1025  if (faceFluxCorrectionPtr_)
1026  {
1027  *faceFluxCorrectionPtr_ *= ds.value();
1028  }
1030 
1031 
1032 // * * * * * * * * * * * * * * * Friend Functions * * * * * * * * * * * * * //
1033 
1034 template<class Type>
1035 void Foam::checkMethod
1036 (
1037  const faMatrix<Type>& mat1,
1038  const faMatrix<Type>& mat2,
1039  const char* op
1040 )
1041 {
1042  if (&mat1.psi() != &mat2.psi())
1043  {
1045  << "Incompatible fields for operation\n "
1046  << "[" << mat1.psi().name() << "] "
1047  << op
1048  << " [" << mat2.psi().name() << "]"
1049  << abort(FatalError);
1050  }
1051 
1052  if
1053  (
1055  && mat1.dimensions() != mat2.dimensions()
1056  )
1057  {
1059  << "Incompatible dimensions for operation\n "
1060  << "[" << mat1.psi().name() << mat1.dimensions()/dimArea << " ] "
1061  << op
1062  << " [" << mat2.psi().name() << mat2.dimensions()/dimArea << " ]"
1064  }
1065 }
1066 
1067 
1068 template<class Type>
1069 void Foam::checkMethod
1070 (
1071  const faMatrix<Type>& mat,
1072  const DimensionedField<Type, areaMesh>& fld,
1073  const char* op
1074 )
1075 {
1076  if
1077  (
1079  && mat.dimensions()/dimArea != fld.dimensions()
1080  )
1081  {
1083  << "Incompatible dimensions for operation\n "
1084  << "[" << mat.psi().name() << mat.dimensions()/dimArea << " ] "
1085  << op
1086  << " [" << fld.name() << fld.dimensions() << " ]"
1088  }
1089 }
1090 
1091 
1092 template<class Type>
1093 void Foam::checkMethod
1094 (
1095  const faMatrix<Type>& mat,
1096  const dimensioned<Type>& dt,
1097  const char* op
1098 )
1099 {
1100  if
1101  (
1103  && mat.dimensions()/dimArea != dt.dimensions()
1104  )
1105  {
1107  << "Incompatible dimensions for operation\n "
1108  << "[" << mat.psi().name() << mat.dimensions()/dimArea << " ] "
1109  << op
1110  << " [" << dt.name() << dt.dimensions() << " ]"
1111  << abort(FatalError);
1112  }
1113 }
1114 
1115 
1116 template<class Type>
1118 (
1119  faMatrix<Type>& mat,
1120  const dictionary& solverControls
1121 )
1122 {
1123  return mat.solve(solverControls);
1124 }
1125 
1126 
1127 template<class Type>
1129 (
1130  const tmp<faMatrix<Type>>& tmat,
1131  const dictionary& solverControls
1132 )
1133 {
1134  SolverPerformance<Type> solverPerf(tmat.constCast().solve(solverControls));
1135 
1136  tmat.clear();
1137 
1138  return solverPerf;
1139 }
1140 
1141 
1142 template<class Type>
1144 (
1145  faMatrix<Type>& mat,
1146  const word& name
1147 )
1148 {
1149  return mat.solve(name);
1150 }
1151 
1152 
1153 template<class Type>
1155 (
1156  const tmp<faMatrix<Type>>& tmat,
1157  const word& name
1158 )
1159 {
1160  SolverPerformance<Type> solverPerf(tmat.constCast().solve(name));
1161 
1162  tmat.clear();
1163 
1164  return solverPerf;
1165 }
1166 
1167 
1168 template<class Type>
1169 Foam::SolverPerformance<Type> Foam::solve(faMatrix<Type>& mat)
1170 {
1171  return mat.solve();
1172 }
1173 
1174 
1175 template<class Type>
1176 Foam::SolverPerformance<Type> Foam::solve(const tmp<faMatrix<Type>>& tmat)
1177 {
1178  SolverPerformance<Type> solverPerf(tmat.constCast().solve());
1179 
1180  tmat.clear();
1181 
1182  return solverPerf;
1183 }
1184 
1185 
1186 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
1187 
1188 template<class Type>
1189 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1190 (
1191  const faMatrix<Type>& A,
1192  const faMatrix<Type>& B
1193 )
1194 {
1195  checkMethod(A, B, "+");
1196  auto tC = tmp<faMatrix<Type>>::New(A);
1197  tC.ref() += B;
1198  return tC;
1199 }
1200 
1201 
1202 template<class Type>
1203 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1204 (
1205  const tmp<faMatrix<Type>>& tA,
1206  const faMatrix<Type>& B
1207 )
1208 {
1209  checkMethod(tA(), B, "+");
1210  tmp<faMatrix<Type>> tC(tA.ptr());
1211  tC.ref() += B;
1212  return tC;
1213 }
1214 
1215 
1216 template<class Type>
1217 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1218 (
1219  const faMatrix<Type>& A,
1220  const tmp<faMatrix<Type>>& tB
1221 )
1222 {
1223  checkMethod(A, tB(), "+");
1224  tmp<faMatrix<Type>> tC(tB.ptr());
1225  tC.ref() += A;
1226  return tC;
1227 }
1228 
1229 
1230 template<class Type>
1231 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1232 (
1233  const tmp<faMatrix<Type>>& tA,
1234  const tmp<faMatrix<Type>>& tB
1235 )
1236 {
1237  checkMethod(tA(), tB(), "+");
1238  tmp<faMatrix<Type>> tC(tA.ptr());
1239  tC.ref() += tB();
1240  tB.clear();
1241  return tC;
1242 }
1243 
1244 
1245 template<class Type>
1246 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1247 (
1248  const faMatrix<Type>& A
1249 )
1250 {
1251  auto tC = tmp<faMatrix<Type>>::New(A);
1252  tC.ref().negate();
1253  return tC;
1254 }
1255 
1256 
1257 template<class Type>
1258 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1259 (
1260  const tmp<faMatrix<Type>>& tA
1261 )
1262 {
1263  tmp<faMatrix<Type>> tC(tA.ptr());
1264  tC.ref().negate();
1265  return tC;
1266 }
1267 
1268 
1269 template<class Type>
1270 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1271 (
1272  const faMatrix<Type>& A,
1273  const faMatrix<Type>& B
1274 )
1275 {
1276  checkMethod(A, B, "-");
1277  auto tC = tmp<faMatrix<Type>>::New(A);
1278  tC.ref() -= B;
1279  return tC;
1280 }
1281 
1282 
1283 template<class Type>
1284 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1285 (
1286  const tmp<faMatrix<Type>>& tA,
1287  const faMatrix<Type>& B
1288 )
1289 {
1290  checkMethod(tA(), B, "-");
1291  tmp<faMatrix<Type>> tC(tA.ptr());
1292  tC.ref() -= B;
1293  return tC;
1294 }
1295 
1296 
1297 template<class Type>
1298 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1299 (
1300  const faMatrix<Type>& A,
1301  const tmp<faMatrix<Type>>& tB
1302 )
1303 {
1304  checkMethod(A, tB(), "-");
1305  tmp<faMatrix<Type>> tC(tB.ptr());
1306  tC.ref() -= A;
1307  tC.ref().negate();
1308  return tC;
1309 }
1310 
1311 
1312 template<class Type>
1313 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1314 (
1315  const tmp<faMatrix<Type>>& tA,
1316  const tmp<faMatrix<Type>>& tB
1317 )
1318 {
1319  checkMethod(tA(), tB(), "-");
1320  tmp<faMatrix<Type>> tC(tA.ptr());
1321  tC.ref() -= tB();
1322  tB.clear();
1323  return tC;
1324 }
1325 
1326 
1327 template<class Type>
1328 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1329 (
1330  const faMatrix<Type>& A,
1331  const faMatrix<Type>& B
1332 )
1333 {
1334  checkMethod(A, B, "==");
1335  return (A - B);
1336 }
1337 
1338 
1339 template<class Type>
1340 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1341 (
1342  const tmp<faMatrix<Type>>& tA,
1343  const faMatrix<Type>& B
1344 )
1345 {
1346  checkMethod(tA(), B, "==");
1347  return (tA - B);
1348 }
1349 
1350 
1351 template<class Type>
1352 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1353 (
1354  const faMatrix<Type>& A,
1355  const tmp<faMatrix<Type>>& tB
1356 )
1357 {
1358  checkMethod(A, tB(), "==");
1359  return (A - tB);
1360 }
1361 
1362 
1363 template<class Type>
1364 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1365 (
1366  const tmp<faMatrix<Type>>& tA,
1367  const tmp<faMatrix<Type>>& tB
1368 )
1369 {
1370  checkMethod(tA(), tB(), "==");
1371  return (tA - tB);
1372 }
1373 
1374 
1375 template<class Type>
1376 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1377 (
1378  const faMatrix<Type>& A,
1379  const DimensionedField<Type, areaMesh>& su
1380 )
1381 {
1382  checkMethod(A, su, "+");
1383  auto tC(A.clone());
1384  tC.ref().source() -= su.mesh().S()*su.field();
1385  return tC;
1386 }
1387 
1388 
1389 template<class Type>
1390 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1391 (
1392  const faMatrix<Type>& A,
1393  const tmp<DimensionedField<Type, areaMesh>>& tsu
1394 )
1395 {
1396  checkMethod(A, tsu(), "+");
1397  auto tC(A.clone());
1398  tC.ref().source() -= tsu().mesh().S()*tsu().field();
1399  tsu.clear();
1400  return tC;
1401 }
1402 
1403 
1404 template<class Type>
1405 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1406 (
1407  const faMatrix<Type>& A,
1408  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu
1409 )
1410 {
1411  checkMethod(A, tsu(), "+");
1412  auto tC(A.clone());
1413  tC.ref().source() -= tsu().mesh().S()*tsu().primitiveField();
1414  tsu.clear();
1415  return tC;
1416 }
1417 
1418 
1419 template<class Type>
1420 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1421 (
1422  const tmp<faMatrix<Type>>& tA,
1423  const DimensionedField<Type, areaMesh>& su
1424 )
1425 {
1426  checkMethod(tA(), su, "+");
1427  tmp<faMatrix<Type>> tC(tA.ptr());
1428  tC.ref().source() -= su.mesh().S()*su.field();
1429  return tC;
1430 }
1431 
1432 
1433 template<class Type>
1434 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1435 (
1436  const tmp<faMatrix<Type>>& tA,
1437  const tmp<DimensionedField<Type, areaMesh>>& tsu
1438 )
1439 {
1440  checkMethod(tA(), tsu(), "+");
1441  tmp<faMatrix<Type>> tC(tA.ptr());
1442  tC.ref().source() -= tsu().mesh().S()*tsu().field();
1443  tsu.clear();
1444  return tC;
1445 }
1446 
1447 
1448 template<class Type>
1449 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1450 (
1451  const tmp<faMatrix<Type>>& tA,
1452  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu
1453 )
1454 {
1455  checkMethod(tA(), tsu(), "+");
1456  tmp<faMatrix<Type>> tC(tA.ptr());
1457  tC.ref().source() -= tsu().mesh().S()*tsu().primitiveField();
1458  tsu.clear();
1459  return tC;
1460 }
1461 
1462 
1463 template<class Type>
1464 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1465 (
1466  const DimensionedField<Type, areaMesh>& su,
1467  const faMatrix<Type>& A
1468 )
1469 {
1470  checkMethod(A, su, "+");
1471  auto tC(A.clone());
1472  tC.ref().source() -= su.mesh().S()*su.field();
1473  return tC;
1474 }
1475 
1476 
1477 template<class Type>
1478 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1479 (
1480  const tmp<DimensionedField<Type, areaMesh>>& tsu,
1481  const faMatrix<Type>& A
1482 )
1483 {
1484  checkMethod(A, tsu(), "+");
1485  auto tC(A.clone());
1486  tC.ref().source() -= tsu().mesh().S()*tsu().field();
1487  tsu.clear();
1488  return tC;
1489 }
1490 
1491 
1492 template<class Type>
1493 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1494 (
1495  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu,
1496  const faMatrix<Type>& A
1497 )
1498 {
1499  checkMethod(A, tsu(), "+");
1500  auto tC(A.clone());
1501  tC.ref().source() -= tsu().mesh().S()*tsu().primitiveField();
1502  tsu.clear();
1503  return tC;
1504 }
1505 
1506 
1507 template<class Type>
1508 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1509 (
1510  const DimensionedField<Type, areaMesh>& su,
1511  const tmp<faMatrix<Type>>& tA
1512 )
1513 {
1514  checkMethod(tA(), su, "+");
1515  tmp<faMatrix<Type>> tC(tA.ptr());
1516  tC.ref().source() -= su.mesh().S()*su.field();
1517  return tC;
1518 }
1519 
1520 
1521 template<class Type>
1522 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1523 (
1524  const tmp<DimensionedField<Type, areaMesh>>& tsu,
1525  const tmp<faMatrix<Type>>& tA
1526 )
1527 {
1528  checkMethod(tA(), tsu(), "+");
1529  tmp<faMatrix<Type>> tC(tA.ptr());
1530  tC.ref().source() -= tsu().mesh().S()*tsu().field();
1531  tsu.clear();
1532  return tC;
1533 }
1534 
1535 
1536 template<class Type>
1537 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1538 (
1539  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu,
1540  const tmp<faMatrix<Type>>& tA
1541 )
1542 {
1543  checkMethod(tA(), tsu(), "+");
1544  tmp<faMatrix<Type>> tC(tA.ptr());
1545  tC.ref().source() -= tsu().mesh().S()*tsu().primitiveField();
1546  tsu.clear();
1547  return tC;
1548 }
1549 
1550 
1551 template<class Type>
1552 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1553 (
1554  const faMatrix<Type>& A,
1555  const DimensionedField<Type, areaMesh>& su
1556 )
1557 {
1558  checkMethod(A, su, "-");
1559  auto tC(A.clone());
1560  tC.ref().source() += su.mesh().S()*su.field();
1561  return tC;
1562 }
1563 
1564 
1565 template<class Type>
1566 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1567 (
1568  const faMatrix<Type>& A,
1569  const tmp<DimensionedField<Type, areaMesh>>& tsu
1570 )
1571 {
1572  checkMethod(A, tsu(), "-");
1573  auto tC(A.clone());
1574  tC.ref().source() += tsu().mesh().S()*tsu().field();
1575  tsu.clear();
1576  return tC;
1577 }
1578 
1579 
1580 template<class Type>
1581 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1582 (
1583  const faMatrix<Type>& A,
1584  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu
1585 )
1586 {
1587  checkMethod(A, tsu(), "-");
1588  auto tC(A.clone());
1589  tC.ref().source() += tsu().mesh().S()*tsu().primitiveField();
1590  tsu.clear();
1591  return tC;
1592 }
1593 
1594 
1595 template<class Type>
1596 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1597 (
1598  const tmp<faMatrix<Type>>& tA,
1599  const DimensionedField<Type, areaMesh>& su
1600 )
1601 {
1602  checkMethod(tA(), su, "-");
1603  tmp<faMatrix<Type>> tC(tA.ptr());
1604  tC.ref().source() += su.mesh().S()*su.field();
1605  return tC;
1606 }
1607 
1608 
1609 template<class Type>
1610 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1611 (
1612  const tmp<faMatrix<Type>>& tA,
1613  const tmp<DimensionedField<Type, areaMesh>>& tsu
1614 )
1615 {
1616  checkMethod(tA(), tsu(), "-");
1617  tmp<faMatrix<Type>> tC(tA.ptr());
1618  tC.ref().source() += tsu().mesh().S()*tsu().field();
1619  tsu.clear();
1620  return tC;
1621 }
1622 
1623 
1624 template<class Type>
1625 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1626 (
1627  const tmp<faMatrix<Type>>& tA,
1628  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu
1629 )
1630 {
1631  checkMethod(tA(), tsu(), "-");
1632  tmp<faMatrix<Type>> tC(tA.ptr());
1633  tC.ref().source() += tsu().mesh().S()*tsu().primitiveField();
1634  tsu.clear();
1635  return tC;
1636 }
1637 
1638 
1639 template<class Type>
1640 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1641 (
1642  const DimensionedField<Type, areaMesh>& su,
1643  const faMatrix<Type>& A
1644 )
1645 {
1646  checkMethod(A, su, "-");
1647  auto tC(A.clone());
1648  tC.ref().negate();
1649  tC.ref().source() -= su.mesh().S()*su.field();
1650  return tC;
1651 }
1652 
1653 
1654 template<class Type>
1655 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1656 (
1657  const tmp<DimensionedField<Type, areaMesh>>& tsu,
1658  const faMatrix<Type>& A
1659 )
1660 {
1661  checkMethod(A, tsu(), "-");
1662  auto tC(A.clone());
1663  tC.ref().negate();
1664  tC.ref().source() -= tsu().mesh().S()*tsu().field();
1665  tsu.clear();
1666  return tC;
1667 }
1668 
1669 
1670 template<class Type>
1671 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1672 (
1673  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu,
1674  const faMatrix<Type>& A
1675 )
1676 {
1677  checkMethod(A, tsu(), "-");
1678  auto tC(A.clone());
1679  tC.ref().negate();
1680  tC.ref().source() -= tsu().mesh().S()*tsu().primitiveField();
1681  tsu.clear();
1682  return tC;
1683 }
1684 
1685 
1686 template<class Type>
1687 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1688 (
1689  const DimensionedField<Type, areaMesh>& su,
1690  const tmp<faMatrix<Type>>& tA
1691 )
1692 {
1693  checkMethod(tA(), su, "-");
1694  tmp<faMatrix<Type>> tC(tA.ptr());
1695  tC.ref().negate();
1696  tC.ref().source() -= su.mesh().S()*su.field();
1697  return tC;
1698 }
1699 
1700 
1701 template<class Type>
1702 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1703 (
1704  const tmp<DimensionedField<Type, areaMesh>>& tsu,
1705  const tmp<faMatrix<Type>>& tA
1706 )
1707 {
1708  checkMethod(tA(), tsu(), "-");
1709  tmp<faMatrix<Type>> tC(tA.ptr());
1710  tC.ref().negate();
1711  tC.ref().source() -= tsu().mesh().S()*tsu().field();
1712  tsu.clear();
1713  return tC;
1714 }
1715 
1716 
1717 template<class Type>
1718 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1719 (
1720  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu,
1721  const tmp<faMatrix<Type>>& tA
1722 )
1723 {
1724  checkMethod(tA(), tsu(), "-");
1725  tmp<faMatrix<Type>> tC(tA.ptr());
1726  tC.ref().negate();
1727  tC.ref().source() -= tsu().mesh().S()*tsu().primitiveField();
1728  tsu.clear();
1729  return tC;
1730 }
1731 
1732 
1733 template<class Type>
1734 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1735 (
1736  const faMatrix<Type>& A,
1737  const dimensioned<Type>& su
1738 )
1739 {
1740  checkMethod(A, su, "+");
1741  auto tC(A.clone());
1742  tC.ref().source() -= su.value()*A.psi().mesh().S();
1743  return tC;
1744 }
1745 
1746 
1747 template<class Type>
1748 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1749 (
1750  const tmp<faMatrix<Type>>& tA,
1751  const dimensioned<Type>& su
1752 )
1753 {
1754  checkMethod(tA(), su, "+");
1755  tmp<faMatrix<Type>> tC(tA.ptr());
1756  tC.ref().source() -= su.value()*tC().psi().mesh().S();
1757  return tC;
1758 }
1759 
1760 
1761 template<class Type>
1762 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1763 (
1764  const dimensioned<Type>& su,
1765  const faMatrix<Type>& A
1766 )
1767 {
1768  checkMethod(A, su, "+");
1769  auto tC(A.clone());
1770  tC.ref().source() -= su.value()*A.psi().mesh().S();
1771  return tC;
1772 }
1773 
1774 
1775 template<class Type>
1776 Foam::tmp<Foam::faMatrix<Type>> Foam::operator+
1777 (
1778  const dimensioned<Type>& su,
1779  const tmp<faMatrix<Type>>& tA
1780 )
1781 {
1782  checkMethod(tA(), su, "+");
1783  tmp<faMatrix<Type>> tC(tA.ptr());
1784  tC.ref().source() -= su.value()*tC().psi().mesh().S();
1785  return tC;
1786 }
1787 
1788 
1789 template<class Type>
1790 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1791 (
1792  const faMatrix<Type>& A,
1793  const dimensioned<Type>& su
1794 )
1795 {
1796  checkMethod(A, su, "-");
1797  auto tC(A.clone());
1798  tC.ref().source() += su.value()*tC().psi().mesh().S();
1799  return tC;
1800 }
1801 
1802 
1803 template<class Type>
1804 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1805 (
1806  const tmp<faMatrix<Type>>& tA,
1807  const dimensioned<Type>& su
1808 )
1809 {
1810  checkMethod(tA(), su, "-");
1811  tmp<faMatrix<Type>> tC(tA.ptr());
1812  tC.ref().source() += su.value()*tC().psi().mesh().S();
1813  return tC;
1814 }
1815 
1816 
1817 template<class Type>
1818 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1819 (
1820  const dimensioned<Type>& su,
1821  const faMatrix<Type>& A
1822 )
1823 {
1824  checkMethod(A, su, "-");
1825  auto tC(A.clone());
1826  tC.ref().negate();
1827  tC.ref().source() -= su.value()*A.psi().mesh().S();
1828  return tC;
1829 }
1830 
1831 
1832 template<class Type>
1833 Foam::tmp<Foam::faMatrix<Type>> Foam::operator-
1834 (
1835  const dimensioned<Type>& su,
1836  const tmp<faMatrix<Type>>& tA
1837 )
1838 {
1839  checkMethod(tA(), su, "-");
1840  tmp<faMatrix<Type>> tC(tA.ptr());
1841  tC.ref().negate();
1842  tC.ref().source() -= su.value()*tC().psi().mesh().S();
1843  return tC;
1844 }
1845 
1846 
1847 template<class Type>
1848 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1849 (
1850  const faMatrix<Type>& A,
1851  const DimensionedField<Type, areaMesh>& su
1852 )
1853 {
1854  checkMethod(A, su, "==");
1855  auto tC(A.clone());
1856  tC.ref().source() += su.mesh().S()*su.field();
1857  return tC;
1858 }
1859 
1860 
1861 template<class Type>
1862 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1863 (
1864  const faMatrix<Type>& A,
1865  const tmp<DimensionedField<Type, areaMesh>>& tsu
1866 )
1867 {
1868  checkMethod(A, tsu(), "==");
1869  auto tC(A.clone());
1870  tC.ref().source() += tsu().mesh().S()*tsu().field();
1871  tsu.clear();
1872  return tC;
1873 }
1874 
1875 
1876 template<class Type>
1877 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1878 (
1879  const faMatrix<Type>& A,
1880  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu
1881 )
1882 {
1883  checkMethod(A, tsu(), "==");
1884  auto tC(A.clone());
1885  tC.ref().source() += tsu().mesh().S()*tsu().primitiveField();
1886  tsu.clear();
1887  return tC;
1888 }
1889 
1890 
1891 template<class Type>
1892 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1893 (
1894  const tmp<faMatrix<Type>>& tA,
1895  const DimensionedField<Type, areaMesh>& su
1896 )
1897 {
1898  checkMethod(tA(), su, "==");
1899  tmp<faMatrix<Type>> tC(tA.ptr());
1900  tC.ref().source() += su.mesh().S()*su.field();
1901  return tC;
1902 }
1903 
1904 
1905 template<class Type>
1906 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1907 (
1908  const tmp<faMatrix<Type>>& tA,
1909  const tmp<DimensionedField<Type, areaMesh>>& tsu
1910 )
1911 {
1912  checkMethod(tA(), tsu(), "==");
1913  tmp<faMatrix<Type>> tC(tA.ptr());
1914  tC.ref().source() += tsu().mesh().S()*tsu().field();
1915  tsu.clear();
1916  return tC;
1917 }
1918 
1919 
1920 template<class Type>
1921 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1922 (
1923  const tmp<faMatrix<Type>>& tA,
1924  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tsu
1925 )
1926 {
1927  checkMethod(tA(), tsu(), "==");
1928  tmp<faMatrix<Type>> tC(tA.ptr());
1929  tC.ref().source() += tsu().mesh().S()*tsu().primitiveField();
1930  tsu.clear();
1931  return tC;
1932 }
1933 
1934 
1935 template<class Type>
1936 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1937 (
1938  const faMatrix<Type>& A,
1939  const dimensioned<Type>& su
1940 )
1941 {
1942  checkMethod(A, su, "==");
1943  auto tC(A.clone());
1944  tC.ref().source() += A.psi().mesh().S()*su.value();
1945  return tC;
1946 }
1947 
1948 
1949 template<class Type>
1950 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1951 (
1952  const tmp<faMatrix<Type>>& tA,
1953  const dimensioned<Type>& su
1954 )
1955 {
1956  checkMethod(tA(), su, "==");
1957  tmp<faMatrix<Type>> tC(tA.ptr());
1958  tC.ref().source() += tC().psi().mesh().S()*su.value();
1959  return tC;
1960 }
1961 
1962 
1963 template<class Type>
1964 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1965 (
1966  const faMatrix<Type>& A,
1967  const Foam::zero
1968 )
1969 {
1970  return A;
1971 }
1972 
1973 
1974 template<class Type>
1975 Foam::tmp<Foam::faMatrix<Type>> Foam::operator==
1976 (
1977  const tmp<faMatrix<Type>>& tA,
1978  const Foam::zero
1979 )
1980 {
1981  return tA;
1982 }
1983 
1984 
1985 template<class Type>
1986 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
1987 (
1988  const areaScalarField::Internal& dsf,
1989  const faMatrix<Type>& A
1990 )
1991 {
1992  auto tC(A.clone());
1993  tC.ref() *= dsf;
1994  return tC;
1995 }
1996 
1997 
1998 template<class Type>
1999 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2000 (
2001  const tmp<areaScalarField::Internal>& tdsf,
2002  const faMatrix<Type>& A
2003 )
2004 {
2005  auto tC(A.clone());
2006  tC.ref() *= tdsf;
2007  return tC;
2008 }
2009 
2010 
2011 template<class Type>
2012 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2013 (
2014  const tmp<areaScalarField>& tvsf,
2015  const faMatrix<Type>& A
2016 )
2017 {
2018  auto tC(A.clone());
2019  tC.ref() *= tvsf;
2020  return tC;
2021 }
2022 
2023 
2024 template<class Type>
2025 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2026 (
2027  const areaScalarField::Internal& dsf,
2028  const tmp<faMatrix<Type>>& tA
2029 )
2030 {
2031  tmp<faMatrix<Type>> tC(tA.ptr());
2032  tC.ref() *= dsf;
2033  return tC;
2034 }
2035 
2036 
2037 template<class Type>
2038 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2039 (
2040  const tmp<areaScalarField::Internal>& tdsf,
2041  const tmp<faMatrix<Type>>& tA
2042 )
2043 {
2044  tmp<faMatrix<Type>> tC(tA.ptr());
2045  tC.ref() *= tdsf;
2046  return tC;
2047 }
2048 
2049 
2050 template<class Type>
2051 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2052 (
2053  const tmp<areaScalarField>& tvsf,
2054  const tmp<faMatrix<Type>>& tA
2055 )
2056 {
2057  tmp<faMatrix<Type>> tC(tA.ptr());
2058  tC.ref() *= tvsf;
2059  return tC;
2060 }
2061 
2062 
2063 template<class Type>
2064 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2065 (
2066  const dimensioned<scalar>& ds,
2067  const faMatrix<Type>& A
2068 )
2069 {
2070  auto tC(A.clone());
2071  tC.ref() *= ds;
2072  return tC;
2073 }
2074 
2075 
2076 template<class Type>
2077 Foam::tmp<Foam::faMatrix<Type>> Foam::operator*
2078 (
2079  const dimensioned<scalar>& ds,
2080  const tmp<faMatrix<Type>>& tA
2081 )
2082 {
2083  tmp<faMatrix<Type>> tC(tA.ptr());
2084  tC.ref() *= ds;
2085  return tC;
2086 }
2087 
2088 
2089 template<class Type>
2091 Foam::operator&
2092 (
2093  const faMatrix<Type>& M,
2094  const DimensionedField<Type, areaMesh>& psi
2095 )
2096 {
2098  (
2099  "M&" + psi.name(),
2100  psi.mesh(),
2101  M.dimensions()/dimArea,
2103  );
2104  auto& Mphi = tMphi.ref();
2105 
2106  // Loop over field components
2107  if (M.hasDiag())
2108  {
2109  for (direction cmpt=0; cmpt<pTraits<Type>::nComponents; cmpt++)
2110  {
2111  scalarField psiCmpt(psi.field().component(cmpt));
2112  scalarField boundaryDiagCmpt(M.diag());
2113  M.addBoundaryDiag(boundaryDiagCmpt, cmpt);
2114  Mphi.primitiveFieldRef().replace(cmpt, -boundaryDiagCmpt*psiCmpt);
2115  }
2116  }
2117  else
2118  {
2119  Mphi.primitiveFieldRef() = Zero;
2120  }
2121 
2122  Mphi.primitiveFieldRef() += M.lduMatrix::H(psi.field()) + M.source();
2123  M.addBoundarySource(Mphi.primitiveFieldRef());
2124 
2125  Mphi.primitiveFieldRef() /= -psi.mesh().S();
2126  Mphi.correctBoundaryConditions();
2127 
2128  return tMphi;
2129 }
2130 
2131 
2132 template<class Type>
2134 Foam::operator&
2135 (
2136  const faMatrix<Type>& M,
2137  const tmp<DimensionedField<Type, areaMesh>>& tpsi
2138 )
2139 {
2140  tmp<GeometricField<Type, faPatchField, areaMesh>> tMpsi = M & tpsi();
2141  tpsi.clear();
2142  return tMpsi;
2143 }
2144 
2145 
2146 template<class Type>
2148 Foam::operator&
2149 (
2150  const faMatrix<Type>& M,
2151  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tpsi
2152 )
2153 {
2154  tmp<GeometricField<Type, faPatchField, areaMesh>> tMpsi = M & tpsi();
2155  tpsi.clear();
2156  return tMpsi;
2157 }
2158 
2159 
2160 template<class Type>
2162 Foam::operator&
2163 (
2164  const tmp<faMatrix<Type>>& tM,
2165  const DimensionedField<Type, areaMesh>& psi
2166 )
2167 {
2168  tmp<GeometricField<Type, faPatchField, areaMesh>> tMpsi = tM() & psi;
2169  tM.clear();
2170  return tMpsi;
2171 }
2172 
2173 
2174 template<class Type>
2176 Foam::operator&
2177 (
2178  const tmp<faMatrix<Type>>& tM,
2179  const tmp<DimensionedField<Type, areaMesh>>& tpsi
2180 )
2181 {
2182  tmp<GeometricField<Type, faPatchField, areaMesh>> tMpsi = tM() & tpsi();
2183  tM.clear();
2184  tpsi.clear();
2185  return tMpsi;
2186 }
2187 
2188 
2189 template<class Type>
2191 Foam::operator&
2192 (
2193  const tmp<faMatrix<Type>>& tM,
2194  const tmp<GeometricField<Type, faPatchField, areaMesh>>& tpsi
2195 )
2196 {
2197  tmp<GeometricField<Type, faPatchField, areaMesh>> tMpsi = tM() & tpsi();
2198  tM.clear();
2199  tpsi.clear();
2200  return tMpsi;
2201 }
2202 
2203 
2204 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
2205 
2206 template<class Type>
2207 Foam::Ostream& Foam::operator<<(Ostream& os, const faMatrix<Type>& fam)
2208 {
2209  os << static_cast<const lduMatrix&>(fam) << nl
2210  << fam.dimensions_ << nl
2211  << fam.source_ << nl
2212  << fam.internalCoeffs_ << nl
2213  << fam.boundaryCoeffs_ << endl;
2214 
2216 
2217  return os;
2218 }
2219 
2220 
2221 // * * * * * * * * * * * * * * * * Solvers * * * * * * * * * * * * * * * * * //
2222 
2223 #include "faMatrixSolve.C"
2224 
2225 // ************************************************************************* //
void negate()
Inplace negate.
Definition: faMatrix.C:789
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
faceListList boundary
void setValues(const labelUList &faceLabels, const Type &value)
Set solution in given faces to the specified value and eliminate the corresponding equations from the...
Definition: faMatrix.C:387
void operator-=(const faMatrix< Type > &)
Definition: faMatrix.C:837
tmp< Field< Type > > faceH(const Field< Type > &) const
tmp< scalarField > D() const
Return the matrix diagonal.
Definition: faMatrix.C:591
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
uint8_t direction
Definition: direction.H:46
label faceId(-1)
tmp< DimensionedField< typename DimensionedField< Type, GeoMesh >::cmptType, GeoMesh >> cmptAv(const DimensionedField< Type, GeoMesh > &f1)
void operator+=(const faMatrix< Type > &)
Definition: faMatrix.C:804
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const dictionary & solverDict() const
Return the solver dictionary for psi.
Definition: faMatrix.C:735
UEqn relax()
faMatrix(const GeometricField< Type, faPatchField, areaMesh > &psi, const dimensionSet &ds)
Construct given a field to solve for.
Definition: faMatrix.C:176
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
const labelListList & faceEdges() const
#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 addToInternalField(const labelUList &addr, const Field< Type2 > &pf, Field< Type2 > &intf) const
Add patch contribution to internal field.
Definition: faMatrix.C:33
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
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
label eventNo() const noexcept
Event number at last update.
Definition: regIOobjectI.H:195
void addBoundaryDiag(scalarField &diag, const direction cmpt) const
Definition: faMatrix.C:108
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
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.
static const word & extrapolatedCalculatedType() noexcept
The type name for extrapolatedCalculated patch fields combines zero-gradient and calculated.
Definition: faPatchField.H:183
void setReferences(const labelUList &faceLabels, const Type &value, const bool forceReference=false)
Set reference level for solution.
Definition: faMatrix.C:439
Generic GeometricField class.
::Foam::direction nComponents(const expressions::valueTypeCode) noexcept
The number of components associated with given valueTypeCode.
Definition: exprTraits.C:40
Generic dimensioned Type class.
labelList faceLabels(nFaceLabels)
DimensionedField< scalar, areaMesh > Internal
The internal field type from which this GeometricField is derived.
void addBoundarySource(Field< Type > &source, const bool couples=true) const
Definition: faMatrix.C:142
UList< label > labelUList
A UList of labels.
Definition: UList.H:76
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:580
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
tmp< GeometricField< Type, faePatchField, edgeMesh > > flux() const
Return the face-flux field from the matrix.
Definition: faMatrix.C:655
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
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 > &)
void subtractFromInternalField(const labelUList &addr, const Field< Type2 > &pf, Field< Type2 > &intf) const
Subtract patch contribution from internal field.
Definition: faMatrix.C:71
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void relax()
Relax matrix (for steady-state solution).
Definition: faMatrix.C:574
void operator=(const faMatrix< Type > &)
Definition: faMatrix.C:747
Generic templated field type.
Definition: Field.H:63
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...
#define DebugInFunction
Report an information message using Foam::Info.
void checkMethod(const faMatrix< Type > &, const faMatrix< Type > &, const char *)
Definition: faMatrix.C:1029
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
tmp< GeometricField< Type, faPatchField, areaMesh > > H() const
Return the H operation source.
Definition: faMatrix.C:619
errorManip< error > abort(error &err)
Definition: errorManip.H:139
void setValuesFromList(const labelUList &faceLabels, const ListType< Type > &values)
Set solution in given faces to the specified values.
Definition: faMatrix.C:288
void operator=(const lduMatrix &)
Copy assignment.
SolverPerformance< Type > solve(faMatrix< Type > &, const dictionary &solverControls)
Solve returning the solution statistics given convergence tolerance.
static tmp< GeometricField< scalar, faPatchField, areaMesh > > New(const word &name, IOobjectOption::registerOption regOpt, const Mesh &mesh, const dimensionSet &dims, const word &patchFieldType=faPatchField< 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
void operator*=(const scalarField &)
this_type & constCast() const noexcept
Return non-const reference to this field.
OBJstream os(runTime.globalPath()/outputName)
#define FUNCTION_NAME
string upper(const std::string &s)
Return string copy transformed with std::toupper on each character.
tmp< areaScalarField > A() const
Return the central coefficient.
Definition: faMatrix.C:600
const labelUList & owner() const
Internal face owner. Note bypassing virtual mechanism so.
Definition: fvMesh.H:572
void setReference(const label facei, const Type &value, const bool forceReference=false)
Set reference level for solution.
Definition: faMatrix.C:420
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))
lduMatrix is a general matrix class in which the coefficients are stored as three arrays...
Definition: lduMatrix.H:80
Internal::FieldType & primitiveFieldRef(const bool updateAccessTime=true)
Return a reference to the internal field values.
Finite-Area matrix basic solvers.
static bool checking() noexcept
True if dimension checking is enabled (the usual default)
Definition: dimensionSet.H:241
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.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
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
A special matrix type and solver, designed for finite area solutions of scalar equations. Face addressing is used to make all matrix assembly and solution loops vectorise.
Definition: faMatricesFwd.H:37
string lower(const std::string &s)
Return string copy transformed with std::tolower on each character.
void correctBoundaryConditions()
Correct boundary field.
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:395
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
const GeometricField< Type, faPatchField, areaMesh > & psi() const
Definition: faMatrix.H:348
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< Field< Type > > H(const Field< Type > &) const
const dimensionedScalar & D
void operator-=(const lduMatrix &)
void addCmptAvBoundaryDiag(scalarField &diag) const
Definition: faMatrix.C:126
void operator+=(const lduMatrix &)
T * ptr() const
Return managed pointer for reuse, or clone() the object reference.
Definition: tmpI.H:256
A class for managing temporary objects.
Definition: HashPtrTable.H:50
void cmptMin(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
static const Foam::dimensionedScalar A("", Foam::dimPressure, 611.21)
Calculate the matrix for the second temporal derivative.
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
#define M(I)
static const Foam::dimensionedScalar B("", Foam::dimless, 18.678)
const dimensionSet dimArea(sqr(dimLength))
Definition: dimensionSets.H:57
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127
virtual ~faMatrix()
Destructor.
Definition: faMatrix.C:276