cyclicAMIFvPatchField.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) 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 "cyclicAMIPolyPatch.H"
30 #include "mapDistributeBase.H"
31 #include "AMIInterpolation.H"
32 #include "fvMatrix.H"
33 #include "volFields.H"
34 
35 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
36 
37 template<class Type>
39 (
40  const fvPatch& p,
42 )
43 :
45  coupledFvPatchField<Type>(p, iF),
46  cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p)),
47  patchNeighbourFieldPtr_(nullptr)
48 {}
49 
50 
51 template<class Type>
53 (
54  const fvPatch& p,
56  const dictionary& dict
57 )
58 :
60  coupledFvPatchField<Type>(p, iF, dict, IOobjectOption::NO_READ),
61  cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p, dict)),
62  patchNeighbourFieldPtr_(nullptr)
63 {
64  if (!isA<cyclicAMIFvPatch>(p))
65  {
67  << "\n patch type '" << p.type()
68  << "' not constraint type '" << typeName << "'"
69  << "\n for patch " << p.name()
70  << " of field " << this->internalField().name()
71  << " in file " << this->internalField().objectPath()
72  << exit(FatalIOError);
73  }
74 
75  if (cacheNeighbourField())
76  {
77  // Handle neighbour value first, before any evaluate()
78  const auto* hasNeighbValue =
79  dict.findEntry("neighbourValue", keyType::LITERAL);
80 
81  if (hasNeighbValue)
82  {
83  patchNeighbourFieldPtr_.reset
84  (
85  new Field<Type>(*hasNeighbValue, p.size())
86  );
87  }
88  }
89 
90  // Use 'value' supplied, or evaluate (if coupled) or set to internal field
91  if (!this->readValueEntry(dict))
92  {
93  if (this->coupled())
94  {
95  this->evaluate(UPstream::commsTypes::nonBlocking);
96  }
97  else
98  {
99  this->extrapolateInternal(); // Zero-gradient patch values
100  }
101  }
102 }
103 
104 
105 template<class Type>
107 (
108  const cyclicAMIFvPatchField<Type>& ptf,
109  const fvPatch& p,
110  const DimensionedField<Type, volMesh>& iF,
111  const fvPatchFieldMapper& mapper
112 )
113 :
114  cyclicAMILduInterfaceField(),
115  coupledFvPatchField<Type>(ptf, p, iF, mapper),
116  cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p)),
117  patchNeighbourFieldPtr_(nullptr)
118 {
119  //if (ptf.patchNeighbourFieldPtr_ && cacheNeighbourField())
120  //{
121  // patchNeighbourFieldPtr_.reset
122  // (
123  // new Field<Type>(ptf.patchNeighbourFieldPtr_(), mapper)
124  // );
125  //}
126 
127  if (!isA<cyclicAMIFvPatch>(this->patch()))
128  {
130  << "\n patch type '" << p.type()
131  << "' not constraint type '" << typeName << "'"
132  << "\n for patch " << p.name()
133  << " of field " << this->internalField().name()
134  << " in file " << this->internalField().objectPath()
135  << exit(FatalError);
136  }
137  if (debug && !ptf.all_ready())
138  {
140  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
142  }
143 }
144 
145 
146 template<class Type>
148 (
149  const cyclicAMIFvPatchField<Type>& ptf
150 )
151 :
152  cyclicAMILduInterfaceField(),
153  coupledFvPatchField<Type>(ptf),
154  cyclicAMIPatch_(ptf.cyclicAMIPatch_),
155  patchNeighbourFieldPtr_(nullptr)
156 {
157  if (debug && !ptf.all_ready())
158  {
160  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
162  }
163 }
164 
165 
166 template<class Type>
168 (
169  const cyclicAMIFvPatchField<Type>& ptf,
170  const DimensionedField<Type, volMesh>& iF
171 )
172 :
173  cyclicAMILduInterfaceField(),
174  coupledFvPatchField<Type>(ptf, iF),
175  cyclicAMIPatch_(ptf.cyclicAMIPatch_),
176  patchNeighbourFieldPtr_(nullptr)
177 {
178  if (debug && !ptf.all_ready())
179  {
181  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
182  << abort(FatalError);
183  }
184 }
185 
186 
187 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
188 
189 template<class Type>
191 {
192  int done = 0;
193 
194  if
195  (
196  UPstream::finishedRequests
197  (
198  recvRequests_.start(),
199  recvRequests_.size()
200  )
201  )
202  {
203  recvRequests_.clear();
204  ++done;
205  }
206 
207  if
208  (
209  UPstream::finishedRequests
210  (
211  sendRequests_.start(),
212  sendRequests_.size()
213  )
214  )
215  {
216  sendRequests_.clear();
217  ++done;
218  }
219 
220  return (done == 2);
221 }
222 
223 
224 template<class Type>
226 {
227  if
228  (
229  UPstream::finishedRequests
230  (
231  recvRequests_.start(),
232  recvRequests_.size()
233  )
234  )
235  {
236  recvRequests_.clear();
237 
238  if
239  (
240  UPstream::finishedRequests
241  (
242  sendRequests_.start(),
243  sendRequests_.size()
244  )
245  )
246  {
247  sendRequests_.clear();
248  }
249 
250  return true;
251  }
252 
253  return false;
254 }
255 
256 
257 
258 template<class Type>
260 (
261  const fvPatchFieldMapper& mapper
262 )
263 {
265  patchNeighbourFieldPtr_.reset(nullptr);
266 }
267 
268 
269 template<class Type>
271 (
272  const fvPatchField<Type>& ptf,
273  const labelList& addr
274 )
275 {
277  patchNeighbourFieldPtr_.reset(nullptr);
278 }
279 
280 
281 template<class Type>
284 (
285  const Field<Type>& iField
286 ) const
287 {
288  // By pass polyPatch to get nbrId. Instead use cyclicAMIFvPatch virtual
289  // neighbPatch()
290  const cyclicAMIFvPatch& neighbPatch = cyclicAMIPatch_.neighbPatch();
291  const labelUList& nbrFaceCells = neighbPatch.faceCells();
292 
293  Field<Type> pnf(iField, nbrFaceCells);
294  Field<Type> defaultValues;
295 
296  if (cyclicAMIPatch_.applyLowWeightCorrection())
297  {
298  defaultValues = Field<Type>(iField, cyclicAMIPatch_.faceCells());
299  }
300 
301  tmp<Field<Type>> tpnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
302 
303  if (doTransform())
304  {
305  transform(tpnf.ref(), forwardT(), tpnf());
306  }
307 
308  return tpnf;
309 }
310 
311 
312 template<class Type>
314 {
315  return
316  (
317  GeometricField<Type, fvPatchField, volMesh>::Boundary::localConsistency
318  != 0
319  );
320 }
321 
322 
323 template<class Type>
326 {
327  if (this->ownerAMI().distributed() && cacheNeighbourField())
328  {
329  if (!this->ready())
330  {
332  << "Outstanding recv request(s) on patch "
333  << cyclicAMIPatch_.name()
334  << " field " << this->internalField().name()
335  << abort(FatalError);
336  }
337 
338  const auto& fvp = this->patch();
339 
340  if
341  (
342  patchNeighbourFieldPtr_
343  && !fvp.boundaryMesh().mesh().upToDatePoints(this->internalField())
344  )
345  {
346  //DebugPout
347  // << "cyclicAMIFvPatchField::patchNeighbourField() :"
348  // << " field:" << this->internalField().name()
349  // << " patch:" << fvp.name()
350  // << " CLEARING patchNeighbourField"
351  // << endl;
352  patchNeighbourFieldPtr_.reset(nullptr);
353  }
354 
355  // Initialise if not done in construct-from-dictionary
356  if (!patchNeighbourFieldPtr_)
357  {
358  //DebugPout
359  // << "cyclicAMIFvPatchField::patchNeighbourField() :"
360  // << " field:" << this->internalField().name()
361  // << " patch:" << fvp.name()
362  // << " caching patchNeighbourField"
363  // << endl;
364 
365  // Do interpolation and store result
366  patchNeighbourFieldPtr_.reset
367  (
368  patchNeighbourField(this->primitiveField()).ptr()
369  );
370  }
371  else
372  {
373  // Have cached value. Check
374  //if (debug)
375  //{
376  // tmp<Field<Type>> tpnf
377  // (
378  // patchNeighbourField(this->primitiveField())
379  // );
380  // if (tpnf() != patchNeighbourFieldPtr_())
381  // {
382  // FatalErrorInFunction
383  // << "On field " << this->internalField().name()
384  // << " patch " << fvp.name() << endl
385  // << "Cached patchNeighbourField :"
386  // << flatOutput(patchNeighbourFieldPtr_()) << endl
387  // << "Calculated patchNeighbourField:"
388  // << flatOutput(tpnf()) << exit(FatalError);
389  // }
390  //}
391  }
392 
393  return patchNeighbourFieldPtr_();
394  }
395  else
396  {
397  // Do interpolation
398  return patchNeighbourField(this->primitiveField());
399  }
400 }
401 
402 
403 template<class Type>
406 {
407  const GeometricField<Type, fvPatchField, volMesh>& fld =
408  static_cast<const GeometricField<Type, fvPatchField, volMesh>&>
409  (
410  this->primitiveField()
411  );
412 
413  return refCast<const cyclicAMIFvPatchField<Type>>
414  (
415  fld.boundaryField()[cyclicAMIPatch_.neighbPatchID()]
416  );
417 }
418 
419 
420 template<class Type>
422 (
423  const Pstream::commsTypes commsType
424 )
425 {
426  if (!this->updated())
427  {
428  this->updateCoeffs();
429  }
430 
431  if (this->ownerAMI().distributed() && cacheNeighbourField())
432  {
433  //DebugPout
434  // << "*** cyclicAMIFvPatchField::initEvaluate() :"
435  // << " field:" << this->internalField().name()
436  // << " patch:" << this->patch().name()
437  // << " sending patchNeighbourField"
438  // << endl;
439 
440  if (commsType != UPstream::commsTypes::nonBlocking)
441  {
442  // Invalidate old field - or flag as fatal?
443  patchNeighbourFieldPtr_.reset(nullptr);
444  return;
445  }
446 
447  // Start sending
448 
449  // By-pass polyPatch to get nbrId. Instead use cyclicAMIFvPatch virtual
450  // neighbPatch()
451  const cyclicAMIFvPatch& neighbPatch = cyclicAMIPatch_.neighbPatch();
452  const labelUList& nbrFaceCells = neighbPatch.faceCells();
453  const Field<Type> pnf(this->primitiveField(), nbrFaceCells);
454 
455  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
456 
457  cpp.initInterpolate
458  (
459  pnf,
460  sendRequests_,
461  sendBufs_,
462  recvRequests_,
463  recvBufs_
464  );
465  }
466 }
467 
468 
469 template<class Type>
471 (
472  const Pstream::commsTypes commsType
473 )
474 {
475  if (!this->updated())
476  {
477  this->updateCoeffs();
478  }
479 
480  const auto& AMI = this->ownerAMI();
481 
482  if (AMI.distributed() && cacheNeighbourField())
483  {
484  // Calculate patchNeighbourField
485  if (commsType != UPstream::commsTypes::nonBlocking)
486  {
488  << "Can only evaluate distributed AMI with nonBlocking"
489  << exit(FatalError);
490  }
491 
492  patchNeighbourFieldPtr_.reset(nullptr);
493 
494  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
495 
496  Field<Type> defaultValues;
497  if (AMI.applyLowWeightCorrection())
498  {
499  defaultValues = this->patchInternalField();
500  }
501 
502  //DebugPout
503  // << "*** cyclicAMIFvPatchField::evaluate() :"
504  // << " field:" << this->internalField().name()
505  // << " patch:" << this->patch().name()
506  // << " receiving&caching patchNeighbourField"
507  // << endl;
508 
509  patchNeighbourFieldPtr_.reset
510  (
511  cpp.interpolate
512  (
513  Field<Type>::null(), // Not used for distributed
514  recvRequests_,
515  recvBufs_,
516  defaultValues
517  ).ptr()
518  );
519  auto& patchNeighbourField = patchNeighbourFieldPtr_.ref();
520 
521  if (doTransform())
522  {
523  // In-place transform
524  transform(patchNeighbourField, forwardT(), patchNeighbourField);
525  }
526  }
527 
528  // Use patchNeighbourField() and patchInternalField() to obtain face value
530 }
531 
532 
533 template<class Type>
535 (
536  solveScalarField& result,
537  const bool add,
538  const lduAddressing& lduAddr,
539  const label patchId,
540  const solveScalarField& psiInternal,
541  const scalarField& coeffs,
542  const direction cmpt,
543  const Pstream::commsTypes commsType
544 ) const
545 {
546  if (this->ownerAMI().distributed())
547  {
548  // Start sending
549  if (commsType != UPstream::commsTypes::nonBlocking)
550  {
552  << "Can only evaluate distributed AMI with nonBlocking"
553  << exit(FatalError);
554  }
555 
556  const labelUList& nbrFaceCells =
557  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
558 
559  solveScalarField pnf(psiInternal, nbrFaceCells);
560 
561  // Transform according to the transformation tensors
562  transformCoupleField(pnf, cmpt);
563 
564  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
565 
566  cpp.initInterpolate
567  (
568  pnf,
569  sendRequests_,
570  scalarSendBufs_,
571  recvRequests_,
572  scalarRecvBufs_
573  );
574  }
575 }
576 
577 
578 template<class Type>
580 (
581  solveScalarField& result,
582  const bool add,
583  const lduAddressing& lduAddr,
584  const label patchId,
585  const solveScalarField& psiInternal,
586  const scalarField& coeffs,
587  const direction cmpt,
588  const Pstream::commsTypes commsType
589 ) const
590 {
591  //DebugPout<< "cyclicAMIFvPatchField::updateInterfaceMatrix() :"
592  // << " field:" << this->internalField().name()
593  // << " patch:" << this->patch().name()
594  // << endl;
595 
596  const labelUList& faceCells = lduAddr.patchAddr(patchId);
597 
598  const auto& AMI = this->ownerAMI();
599 
600  solveScalarField pnf;
601 
602  if (AMI.distributed())
603  {
604  if (commsType != UPstream::commsTypes::nonBlocking)
605  {
607  << "Can only evaluate distributed AMI with nonBlocking"
608  << exit(FatalError);
609  }
610 
611  solveScalarField defaultValues;
612  if (AMI.applyLowWeightCorrection())
613  {
614  defaultValues = solveScalarField(psiInternal, faceCells);
615  }
616 
617  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
618 
619  pnf =
620  cpp.interpolate
621  (
622  solveScalarField::null(), // Not used for distributed
623  recvRequests_,
624  scalarRecvBufs_,
625  defaultValues
626  );
627  }
628  else
629  {
630  solveScalarField defaultValues;
631  if (cyclicAMIPatch_.applyLowWeightCorrection())
632  {
633  defaultValues = solveScalarField(psiInternal, faceCells);
634  }
635 
636  const labelUList& nbrFaceCells =
637  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
638 
639  pnf = solveScalarField(psiInternal, nbrFaceCells);
640 
641  // Transform according to the transformation tensors
642  transformCoupleField(pnf, cmpt);
643 
644  pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
645  }
646 
647  // Multiply the field by coefficients and add into the result
648  this->addToInternalField(result, !add, faceCells, coeffs, pnf);
649 }
650 
651 
652 template<class Type>
654 (
655  Field<Type>& result,
656  const bool add,
657  const lduAddressing& lduAddr,
658  const label patchId,
659  const Field<Type>& psiInternal,
660  const scalarField& coeffs,
661  const Pstream::commsTypes commsType
662 ) const
663 {
664  const auto& AMI = this->ownerAMI();
665 
666  if (AMI.distributed())
667  {
668  if (commsType != UPstream::commsTypes::nonBlocking)
669  {
671  << "Can only evaluate distributed AMI with nonBlocking"
672  << exit(FatalError);
673  }
674 
675  const labelUList& nbrFaceCells =
676  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
677 
678  Field<Type> pnf(psiInternal, nbrFaceCells);
679 
680  // Transform according to the transformation tensors
681  transformCoupleField(pnf);
682 
683  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
684 
685  cpp.initInterpolate
686  (
687  pnf,
688  sendRequests_,
689  sendBufs_,
690  recvRequests_,
691  recvBufs_
692  );
693  }
694 }
695 
696 
697 template<class Type>
699 (
700  Field<Type>& result,
701  const bool add,
702  const lduAddressing& lduAddr,
703  const label patchId,
704  const Field<Type>& psiInternal,
705  const scalarField& coeffs,
706  const Pstream::commsTypes commsType
707 ) const
708 {
709  //DebugPout<< "cyclicAMIFvPatchField::updateInterfaceMatrix() :"
710  // << " field:" << this->internalField().name()
711  // << " patch:" << this->patch().name()
712  // << endl;
713 
714  const labelUList& faceCells = lduAddr.patchAddr(patchId);
715 
716  const auto& AMI = this->ownerAMI();
717 
718  Field<Type> pnf;
719 
720  if (AMI.distributed())
721  {
722  if (commsType != UPstream::commsTypes::nonBlocking)
723  {
725  << "Can only evaluate distributed AMI with nonBlocking"
726  << exit(FatalError);
727  }
728 
729  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
730 
731  Field<Type> defaultValues;
732  if (AMI.applyLowWeightCorrection())
733  {
734  defaultValues = Field<Type>(psiInternal, faceCells);
735  }
736 
737  pnf =
738  cpp.interpolate
739  (
740  Field<Type>::null(), // Not used for distributed
741  recvRequests_,
742  recvBufs_,
743  defaultValues
744  );
745  }
746  else
747  {
748  const labelUList& nbrFaceCells =
749  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
750 
751  pnf = Field<Type>(psiInternal, nbrFaceCells);
752 
753  // Transform according to the transformation tensors
754  transformCoupleField(pnf);
755 
756  Field<Type> defaultValues;
757  if (cyclicAMIPatch_.applyLowWeightCorrection())
758  {
759  defaultValues = Field<Type>(psiInternal, faceCells);
760  }
761 
762  pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
763  }
764 
765  // Multiply the field by coefficients and add into the result
766  this->addToInternalField(result, !add, faceCells, coeffs, pnf);
767 }
768 
769 
770 template<class Type>
772 (
773  fvMatrix<Type>& matrix,
774  const label mat,
775  const direction cmpt
776 )
777 {
778  if (this->cyclicAMIPatch().owner())
779  {
780  const label index = this->patch().index();
781 
782  const label globalPatchID =
783  matrix.lduMeshAssembly().patchLocalToGlobalMap()[mat][index];
784 
785  const Field<scalar> intCoeffsCmpt
786  (
787  matrix.internalCoeffs()[globalPatchID].component(cmpt)
788  );
789 
790  const Field<scalar> boundCoeffsCmpt
791  (
792  matrix.boundaryCoeffs()[globalPatchID].component(cmpt)
793  );
794 
795  tmp<Field<scalar>> tintCoeffs(coeffs(matrix, intCoeffsCmpt, mat));
796  tmp<Field<scalar>> tbndCoeffs(coeffs(matrix, boundCoeffsCmpt, mat));
797  const Field<scalar>& intCoeffs = tintCoeffs.ref();
798  const Field<scalar>& bndCoeffs = tbndCoeffs.ref();
799 
800  const labelUList& u = matrix.lduAddr().upperAddr();
801  const labelUList& l = matrix.lduAddr().lowerAddr();
802 
803  label subFaceI = 0;
804 
805  const labelList& faceMap =
806  matrix.lduMeshAssembly().faceBoundMap()[mat][index];
807 
808  forAll (faceMap, j)
809  {
810  label globalFaceI = faceMap[j];
811 
812  const scalar boundCorr = -bndCoeffs[subFaceI];
813  const scalar intCorr = -intCoeffs[subFaceI];
814 
815  matrix.upper()[globalFaceI] += boundCorr;
816  matrix.diag()[u[globalFaceI]] -= intCorr;
817  matrix.diag()[l[globalFaceI]] -= boundCorr;
818 
819  if (matrix.asymmetric())
820  {
821  matrix.lower()[globalFaceI] += intCorr;
822  }
823  subFaceI++;
824  }
825 
826  // Set internalCoeffs and boundaryCoeffs in the assembly matrix
827  // on clyclicAMI patches to be used in the individual matrix by
828  // matrix.flux()
829  if (matrix.psi(mat).mesh().fluxRequired(this->internalField().name()))
830  {
831  matrix.internalCoeffs().set
832  (
833  globalPatchID, intCoeffs*pTraits<Type>::one
834  );
835  matrix.boundaryCoeffs().set
836  (
837  globalPatchID, bndCoeffs*pTraits<Type>::one
838  );
839 
840  const label nbrPathID =
841  cyclicAMIPatch_.cyclicAMIPatch().neighbPatchID();
842 
843  const label nbrGlobalPatchID =
844  matrix.lduMeshAssembly().patchLocalToGlobalMap()
845  [mat][nbrPathID];
846 
847  matrix.internalCoeffs().set
848  (
849  nbrGlobalPatchID, intCoeffs*pTraits<Type>::one
850  );
851  matrix.boundaryCoeffs().set
852  (
853  nbrGlobalPatchID, bndCoeffs*pTraits<Type>::one
854  );
855  }
856  }
857 }
858 
859 
860 template<class Type>
863 (
864  fvMatrix<Type>& matrix,
865  const Field<scalar>& coeffs,
866  const label mat
867 ) const
868 {
869  const label index(this->patch().index());
870 
871  const label nSubFaces
872  (
873  matrix.lduMeshAssembly().cellBoundMap()[mat][index].size()
874  );
875 
876  auto tmapCoeffs = tmp<Field<scalar>>::New(nSubFaces, Zero);
877  auto& mapCoeffs = tmapCoeffs.ref();
878 
879  const scalarListList& srcWeight =
880  cyclicAMIPatch_.cyclicAMIPatch().AMI().srcWeights();
881 
882  label subFaceI = 0;
883  forAll(*this, faceI)
884  {
885  const scalarList& w = srcWeight[faceI];
886  for(label i=0; i<w.size(); i++)
887  {
888  const label localFaceId =
889  matrix.lduMeshAssembly().facePatchFaceMap()[mat][index][subFaceI];
890  mapCoeffs[subFaceI] = w[i]*coeffs[localFaceId];
891  subFaceI++;
892  }
893  }
894 
895  return tmapCoeffs;
896 }
897 
898 
899 template<class Type>
900 template<class Type2>
902 (
903  const refPtr<mapDistribute>& mapPtr,
904  const labelListList& stencil,
905  const Type2& data,
906  List<Type2>& expandedData
907 )
908 {
909  expandedData.resize_nocopy(stencil.size());
910  if (mapPtr)
911  {
912  Type2 work(data);
913  mapPtr().distribute(work);
914 
915  forAll(stencil, facei)
916  {
917  const labelList& slots = stencil[facei];
918  expandedData[facei].push_back
919  (
920  UIndirectList<typename Type2::value_type>(work, slots)
921  );
922  }
923  }
924  else
925  {
926  forAll(stencil, facei)
927  {
928  const labelList& slots = stencil[facei];
929  expandedData[facei].push_back
930  (
931  UIndirectList<typename Type2::value_type>(data, slots)
932  );
933  }
934  }
935 }
936 
937 
938 template<class Type>
939 void Foam::cyclicAMIFvPatchField<Type>::write(Ostream& os) const
940 {
942  fvPatchField<Type>::writeValueEntry(os);
943 
944  if (patchNeighbourFieldPtr_)
945  {
946  patchNeighbourFieldPtr_->writeEntry("neighbourValue", os);
947  }
948 }
949 
950 
951 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
952 
953 template<class Type>
955 (
956  const fvPatchField<Type>& ptf
957 )
958 {
960 
961  //Pout<< "cyclicAMIFvPatchField::operator= :"
962  // << " field:" << this->internalField().name()
963  // << " patch:" << this->patch().name()
964  // << " copying from field:" << ptf.internalField().name()
965  // << endl;
966 
967  const auto* cycPtr = isA<cyclicAMIFvPatchField<Type>>(ptf);
968  if (cycPtr)
969  {
970  const auto& cyc = *cycPtr;
971  if
972  (
973  cyc.patchNeighbourFieldPtr_
974  && cyc.patchNeighbourFieldPtr_->size() == this->size()
975  )
976  {
977  const auto& cycPnf = cyc.patchNeighbourFieldPtr_();
978  if (patchNeighbourFieldPtr_)
979  {
980  // Copy values
981  patchNeighbourFieldPtr_() = cycPnf;
982  }
983  else
984  {
985  // Copy values
986  patchNeighbourFieldPtr_.reset(new Field<Type>(cycPnf));
987  }
988  }
989  else
990  {
991  patchNeighbourFieldPtr_.reset(nullptr);
992  }
993  }
994  else
995  {
996  patchNeighbourFieldPtr_.reset(nullptr);
997  }
998 }
999 
1000 
1001 template<class Type>
1003 (
1004  const fvPatchField<Type>& ptf
1005 )
1006 {
1008 
1009  //Pout<< "cyclicAMIFvPatchField::operator== :"
1010  // << " field:" << this->internalField().name()
1011  // << " patch:" << this->patch().name()
1012  // << " copying from field:" << ptf.internalField().name()
1013  // << endl;
1014 
1015  const auto* cycPtr = isA<cyclicAMIFvPatchField<Type>>(ptf);
1016  if (cycPtr)
1017  {
1018  const auto& cyc = *cycPtr;
1019  if
1020  (
1021  cyc.patchNeighbourFieldPtr_
1022  && cyc.patchNeighbourFieldPtr_->size() == this->size()
1023  )
1024  {
1025  const auto& cycPnf = cyc.patchNeighbourFieldPtr_();
1026  if (patchNeighbourFieldPtr_)
1027  {
1028  // Copy values
1029  patchNeighbourFieldPtr_() = cycPnf;
1030  }
1031  else
1032  {
1033  // Copy values
1034  patchNeighbourFieldPtr_.reset(new Field<Type>(cycPnf));
1035  }
1036  }
1037  else
1038  {
1039  patchNeighbourFieldPtr_.reset(nullptr);
1040  }
1041  }
1042  else
1043  {
1044  patchNeighbourFieldPtr_.reset(nullptr);
1045  }
1046 }
1047 
1048 
1049 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
label patchId(-1)
dictionary dict
uint8_t direction
Definition: direction.H:46
virtual bool ready() const
Are all (receive) data available?
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
Field< solveScalar > solveScalarField
commsTypes
Communications types.
Definition: UPstream.H:72
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
virtual void initInterfaceMatrixUpdate(solveScalarField &result, const bool add, const lduAddressing &lduAddr, const label patchId, const solveScalarField &psiInternal, const scalarField &coeffs, const direction cmpt, const Pstream::commsTypes commsType) const
Initialise neighbour matrix update.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual void manipulateMatrix(fvMatrix< Type > &m, const label iMatrix, const direction cmpt)
Manipulate matrix.
const lduPrimitiveMeshAssembly & lduMeshAssembly()
Return optional lduAdressing.
Definition: fvMatrix.H:476
Cyclic patch for Arbitrary Mesh Interface (AMI)
Type & refCast(U &obj)
A dynamic_cast (for references). Generates a FatalError on failed casts and uses the virtual type() m...
Definition: typeInfo.H:159
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:70
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.
Abstract base class with a fat-interface to all derived classes covering all possible ways in which t...
virtual void autoMap(const fvPatchFieldMapper &)
Map (and resize as needed) from self given a mapping object.
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:175
Smooth ATC in cells next to a set of patches supplied by type.
Definition: faceCells.H:52
scalarField & upper()
Definition: lduMatrix.C:208
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:227
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
virtual void initEvaluate(const Pstream::commsTypes commsType)
Initialise the evaluation of the patch field.
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
virtual void updateInterfaceMatrix(solveScalarField &result, const bool add, const lduAddressing &lduAddr, const label patchId, const solveScalarField &psiInternal, const scalarField &coeffs, const direction cmpt, const Pstream::commsTypes commsType) const
Update result field based on interface functionality.
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
Abstract base class for cyclic AMI coupled interfaces.
const GeometricField< Type, fvPatchField, volMesh > & psi(const label i=0) const
Return psi.
Definition: fvMatrix.H:485
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
List< scalarList > scalarListList
List of scalarList.
Definition: scalarList.H:35
virtual void write(Ostream &os) const
Write.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual void evaluate(const Pstream::commsTypes commsType)
Evaluate the patch field.
A FieldMapper for finite-volume patch fields.
string evaluate(label fieldWidth, const std::string &s, size_t pos=0, size_t len=std::string::npos)
String evaluation with specified (positive, non-zero) field width.
virtual const labelUList & patchAddr(const label patchNo) const =0
Return patch to internal addressing given patch number.
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
errorManip< error > abort(error &err)
Definition: errorManip.H:139
Abstract base class for coupled patches.
virtual tmp< Field< Type > > patchNeighbourField() const
Return neighbour coupled internal cell data.
bool asymmetric() const noexcept
Definition: lduMatrix.H:791
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const lduAddressing & lduAddr() const
Return the LDU addressing.
Definition: lduMatrix.H:734
virtual const cyclicAMIFvPatch & neighbPatch() const
Return a reference to the neighbour patch.
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:627
scalarField & lower()
Definition: lduMatrix.C:179
A simple container of IOobject preferences. Can also be used for general handling of read/no-read/rea...
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
Definition: areaFieldsFwd.H:42
const std::string patch
OpenFOAM patch number as a std::string.
const cyclicAMIFvPatchField< Type > & neighbourPatchField() const
Return reference to neighbour patchField.
const FieldField< Field, Type > & internalCoeffs() const noexcept
fvBoundary scalar field containing pseudo-matrix coeffs for internal cells
Definition: fvMatrix.H:547
The class contains the addressing required by the lduMatrix: upper, lower and losort.
const FieldField< Field, Type > & boundaryCoeffs() const noexcept
fvBoundary scalar field containing pseudo-matrix coeffs for boundary cells
Definition: fvMatrix.H:565
cyclicAMIFvPatchField(const fvPatch &, const DimensionedField< Type, volMesh > &)
Construct from patch and internal field.
virtual void rmap(const fvPatchField< Type > &, const labelList &)
Reverse map the given fvPatchField onto this fvPatchField.
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
tmp< faMatrix< Type > > operator==(const faMatrix< Type > &, const faMatrix< Type > &)
scalarField & diag()
Definition: lduMatrix.C:197
bool coupled
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
This boundary condition enforces a cyclic condition between a pair of boundaries, whereby communicati...
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127