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-2025 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  // Tricky: avoid call to evaluate without call to initEvaluate.
96  // For now just disable the localConsistency to make it use the
97  // old logic (ultimately calls the fully self contained
98  // patchNeighbourField)
99 
100  const auto oldConsistency = FieldBase::localBoundaryConsistency(0);
101 
102  this->evaluate(UPstream::commsTypes::nonBlocking);
103 
104  FieldBase::localBoundaryConsistency(oldConsistency);
105  }
106  else
107  {
108  this->extrapolateInternal(); // Zero-gradient patch values
109  }
110  }
111 }
112 
113 
114 template<class Type>
116 (
117  const cyclicAMIFvPatchField<Type>& ptf,
118  const fvPatch& p,
119  const DimensionedField<Type, volMesh>& iF,
120  const fvPatchFieldMapper& mapper
121 )
122 :
123  cyclicAMILduInterfaceField(),
124  coupledFvPatchField<Type>(ptf, p, iF, mapper),
125  cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p)),
126  patchNeighbourFieldPtr_(nullptr)
127 {
128  //if (ptf.patchNeighbourFieldPtr_ && cacheNeighbourField())
129  //{
130  // patchNeighbourFieldPtr_.reset
131  // (
132  // new Field<Type>(ptf.patchNeighbourFieldPtr_(), mapper)
133  // );
134  //}
135 
136  if (!isA<cyclicAMIFvPatch>(this->patch()))
137  {
139  << "\n patch type '" << p.type()
140  << "' not constraint type '" << typeName << "'"
141  << "\n for patch " << p.name()
142  << " of field " << this->internalField().name()
143  << " in file " << this->internalField().objectPath()
144  << exit(FatalError);
145  }
146  if (debug && !ptf.all_ready())
147  {
149  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
151  }
152 }
153 
154 
155 template<class Type>
157 (
158  const cyclicAMIFvPatchField<Type>& ptf
159 )
160 :
161  cyclicAMILduInterfaceField(),
162  coupledFvPatchField<Type>(ptf),
163  cyclicAMIPatch_(ptf.cyclicAMIPatch_),
164  patchNeighbourFieldPtr_(nullptr)
165 {
166  if (debug && !ptf.all_ready())
167  {
169  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
171  }
172 }
173 
174 
175 template<class Type>
177 (
178  const cyclicAMIFvPatchField<Type>& ptf,
179  const DimensionedField<Type, volMesh>& iF
180 )
181 :
182  cyclicAMILduInterfaceField(),
183  coupledFvPatchField<Type>(ptf, iF),
184  cyclicAMIPatch_(ptf.cyclicAMIPatch_),
185  patchNeighbourFieldPtr_(nullptr)
186 {
187  if (debug && !ptf.all_ready())
188  {
190  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
191  << abort(FatalError);
192  }
193 }
194 
195 
196 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
197 
198 template<class Type>
200 {
201  int done = 0;
202 
203  if
204  (
205  UPstream::finishedRequests
206  (
207  recvRequests_.start(),
208  recvRequests_.size()
209  )
210  )
211  {
212  recvRequests_.clear();
213  ++done;
214  }
215 
216  if
217  (
218  UPstream::finishedRequests
219  (
220  sendRequests_.start(),
221  sendRequests_.size()
222  )
223  )
224  {
225  sendRequests_.clear();
226  ++done;
227  }
228 
229  return (done == 2);
230 }
231 
232 
233 template<class Type>
235 {
236  if
237  (
238  UPstream::finishedRequests
239  (
240  recvRequests_.start(),
241  recvRequests_.size()
242  )
243  )
244  {
245  recvRequests_.clear();
246 
247  if
248  (
249  UPstream::finishedRequests
250  (
251  sendRequests_.start(),
252  sendRequests_.size()
253  )
254  )
255  {
256  sendRequests_.clear();
257  }
258 
259  return true;
260  }
261 
262  return false;
263 }
264 
265 
266 
267 template<class Type>
269 (
270  const fvPatchFieldMapper& mapper
271 )
272 {
274  patchNeighbourFieldPtr_.reset(nullptr);
275 }
276 
277 
278 template<class Type>
280 (
281  const fvPatchField<Type>& ptf,
282  const labelList& addr
283 )
284 {
286  patchNeighbourFieldPtr_.reset(nullptr);
287 }
288 
289 
290 template<class Type>
293 (
294  const UList<Type>& internalData
295 ) const
296 {
297  // By pass polyPatch to get nbrId. Instead use cyclicAMIFvPatch virtual
298  // neighbPatch()
299  const auto& neighbPatch = cyclicAMIPatch_.neighbPatch();
300  const labelUList& nbrFaceCells = neighbPatch.faceCells();
301 
302  Field<Type> pnf(internalData, nbrFaceCells);
303  Field<Type> defaultValues;
304 
305  if (cyclicAMIPatch_.applyLowWeightCorrection())
306  {
307  defaultValues = Field<Type>(internalData, cyclicAMIPatch_.faceCells());
308  }
309 
310  tmp<Field<Type>> tpnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
311 
312  if (doTransform())
313  {
314  transform(tpnf.ref(), forwardT(), tpnf());
315  }
316 
317  return tpnf;
318 }
319 
320 
321 template<class Type>
323 {
324  return (FieldBase::localBoundaryConsistency() != 0);
325 }
326 
327 
328 template<class Type>
331 (
332  bool checkCommunicator
333 ) const
334 {
335  const auto& AMI = this->ownerAMI();
336 
337  if
338  (
339  AMI.distributed() && cacheNeighbourField()
340  && (!checkCommunicator || AMI.comm() != -1)
341  )
342  {
343  if (!this->ready())
344  {
346  << "Outstanding recv request(s) on patch "
347  << cyclicAMIPatch_.name()
348  << " field " << this->internalField().name()
349  << abort(FatalError);
350  }
351 
352  const auto& fvp = this->patch();
353 
354  if
355  (
356  patchNeighbourFieldPtr_
357  && !fvp.boundaryMesh().mesh().upToDatePoints(this->internalField())
358  )
359  {
360  //DebugPout
361  // << "cyclicAMIFvPatchField::patchNeighbourField() :"
362  // << " field:" << this->internalField().name()
363  // << " patch:" << fvp.name()
364  // << " CLEARING patchNeighbourField"
365  // << endl;
366  patchNeighbourFieldPtr_.reset(nullptr);
367  }
368 
369  // Initialise if not done in construct-from-dictionary
370  if (!patchNeighbourFieldPtr_)
371  {
372  //DebugPout
373  // << "cyclicAMIFvPatchField::patchNeighbourField() :"
374  // << " field:" << this->internalField().name()
375  // << " patch:" << fvp.name()
376  // << " caching patchNeighbourField"
377  // << endl;
378 
379  // Do interpolation and store result
380  patchNeighbourFieldPtr_.reset
381  (
382  getNeighbourField(this->primitiveField()).ptr()
383  );
384  }
385  else
386  {
387  // Have cached value. Check
388  //if (debug)
389  //{
390  // tmp<Field<Type>> tpnf
391  // (
392  // getNeighbourField(this->primitiveField())
393  // );
394  // if (tpnf() != patchNeighbourFieldPtr_())
395  // {
396  // FatalErrorInFunction
397  // << "On field " << this->internalField().name()
398  // << " patch " << fvp.name() << endl
399  // << "Cached patchNeighbourField :"
400  // << flatOutput(patchNeighbourFieldPtr_()) << endl
401  // << "Calculated patchNeighbourField:"
402  // << flatOutput(tpnf()) << exit(FatalError);
403  // }
404  //}
405  }
406 
407  return patchNeighbourFieldPtr_();
408  }
409  else
410  {
411  // Do interpolation
412  return getNeighbourField(this->primitiveField());
413  }
414 }
415 
416 
417 template<class Type>
420 {
421  return this->getPatchNeighbourField(true); // checkCommunicator = true
422 }
423 
424 
425 template<class Type>
427 (
428  UList<Type>& pnf
429 ) const
430 {
431  // checkCommunicator = false
432  auto tpnf = this->getPatchNeighbourField(false);
433  pnf.deepCopy(tpnf());
434 }
435 
436 
437 template<class Type>
440 {
441  const auto& fld =
443  (
444  this->primitiveField()
445  );
446 
447  return refCast<const cyclicAMIFvPatchField<Type>>
448  (
449  fld.boundaryField()[cyclicAMIPatch_.neighbPatchID()]
450  );
451 }
452 
453 
454 template<class Type>
456 (
457  const Pstream::commsTypes commsType
458 )
459 {
460  if (!this->updated())
461  {
462  this->updateCoeffs();
463  }
464 
465  const auto& AMI = this->ownerAMI();
466 
467  if (AMI.distributed() && cacheNeighbourField() && AMI.comm() != -1)
468  {
469  //DebugPout
470  // << "*** cyclicAMIFvPatchField::initEvaluate() :"
471  // << " field:" << this->internalField().name()
472  // << " patch:" << this->patch().name()
473  // << " sending patchNeighbourField"
474  // << endl;
475 
476  if (commsType != UPstream::commsTypes::nonBlocking)
477  {
478  // Invalidate old field - or flag as fatal?
479  patchNeighbourFieldPtr_.reset(nullptr);
480  return;
481  }
482 
483  // Start sending
484 
485  // Bypass polyPatch to get nbrId.
486  // - use cyclicACMIFvPatch::neighbPatch() virtual instead
487  const cyclicAMIFvPatch& neighbPatch = cyclicAMIPatch_.neighbPatch();
488  const labelUList& nbrFaceCells = neighbPatch.faceCells();
489  const Field<Type> pnf(this->primitiveField(), nbrFaceCells);
490 
491  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
492 
493  // Assert that all receives are known to have finished
494  if (!recvRequests_.empty())
495  {
497  << "Outstanding recv request(s) on patch "
498  << cyclicAMIPatch_.name()
499  << " field " << this->internalField().name()
500  << abort(FatalError);
501  }
502 
503  // Assume that sends are also OK
504  sendRequests_.clear();
505 
506  cpp.initInterpolate
507  (
508  pnf,
509  sendRequests_,
510  sendBufs_,
511  recvRequests_,
512  recvBufs_
513  );
514  }
515 }
516 
517 
518 template<class Type>
520 (
521  const Pstream::commsTypes commsType
522 )
523 {
524  if (!this->updated())
525  {
526  this->updateCoeffs();
527  }
528 
529  const auto& AMI = this->ownerAMI();
530 
531  if (AMI.distributed() && cacheNeighbourField() && AMI.comm() != -1)
532  {
533  // Calculate patchNeighbourField
534  if (commsType != UPstream::commsTypes::nonBlocking)
535  {
537  << "Can only evaluate distributed AMI with nonBlocking"
538  << exit(FatalError);
539  }
540 
541  patchNeighbourFieldPtr_.reset(nullptr);
542 
543  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
544 
545  Field<Type> defaultValues;
546  if (AMI.applyLowWeightCorrection())
547  {
548  defaultValues = this->patchInternalField();
549  }
550 
551  //DebugPout
552  // << "*** cyclicAMIFvPatchField::evaluate() :"
553  // << " field:" << this->internalField().name()
554  // << " patch:" << this->patch().name()
555  // << " receiving&caching patchNeighbourField"
556  // << endl;
557 
558  patchNeighbourFieldPtr_.reset
559  (
560  cpp.interpolate
561  (
562  Field<Type>::null(), // Not used for distributed
563  recvRequests_,
564  recvBufs_,
565  defaultValues
566  ).ptr()
567  );
568 
569  // Receive requests all handled by last function call
570  recvRequests_.clear();
571 
572  if (doTransform())
573  {
574  // In-place transform
575  auto& pnf = *patchNeighbourFieldPtr_;
576  transform(pnf, forwardT(), pnf);
577  }
578  }
579 
580  // Use patchNeighbourField() and patchInternalField() to obtain face value
582 }
583 
584 
585 template<class Type>
587 (
588  solveScalarField& result,
589  const bool add,
590  const lduAddressing& lduAddr,
591  const label patchId,
592  const solveScalarField& psiInternal,
593  const scalarField& coeffs,
594  const direction cmpt,
595  const Pstream::commsTypes commsType
596 ) const
597 {
598  const auto& AMI = this->ownerAMI();
599 
600  if (AMI.distributed() && AMI.comm() != -1)
601  {
602  // Start sending
603  if (commsType != UPstream::commsTypes::nonBlocking)
604  {
606  << "Can only evaluate distributed AMI with nonBlocking"
607  << exit(FatalError);
608  }
609 
610  const labelUList& nbrFaceCells =
611  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
612 
613  solveScalarField pnf(psiInternal, nbrFaceCells);
614 
615  // Transform according to the transformation tensors
616  transformCoupleField(pnf, cmpt);
617 
618  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
619 
620  // Assert that all receives are known to have finished
621  if (!recvRequests_.empty())
622  {
624  << "Outstanding recv request(s) on patch "
625  << cyclicAMIPatch_.name()
626  << " field " << this->internalField().name()
627  << abort(FatalError);
628  }
629 
630  // Assume that sends are also OK
631  sendRequests_.clear();
632 
633  cpp.initInterpolate
634  (
635  pnf,
636  sendRequests_,
637  scalarSendBufs_,
638  recvRequests_,
639  scalarRecvBufs_
640  );
641  }
643  this->updatedMatrix(false);
644 }
645 
646 
647 template<class Type>
649 (
650  solveScalarField& result,
651  const bool add,
652  const lduAddressing& lduAddr,
653  const label patchId,
654  const solveScalarField& psiInternal,
655  const scalarField& coeffs,
656  const direction cmpt,
657  const Pstream::commsTypes commsType
658 ) const
659 {
660  //DebugPout<< "cyclicAMIFvPatchField::updateInterfaceMatrix() :"
661  // << " field:" << this->internalField().name()
662  // << " patch:" << this->patch().name()
663  // << endl;
664 
665  const labelUList& faceCells = lduAddr.patchAddr(patchId);
666 
667  const auto& AMI = this->ownerAMI();
668 
669  solveScalarField pnf;
670 
671  if (AMI.distributed() && AMI.comm() != -1)
672  {
673  if (commsType != UPstream::commsTypes::nonBlocking)
674  {
676  << "Can only evaluate distributed AMI with nonBlocking"
677  << exit(FatalError);
678  }
679 
680  solveScalarField defaultValues;
681  if (AMI.applyLowWeightCorrection())
682  {
683  defaultValues = solveScalarField(psiInternal, faceCells);
684  }
685 
686  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
687 
688  pnf =
689  cpp.interpolate
690  (
691  solveScalarField::null(), // Not used for distributed
692  recvRequests_,
693  scalarRecvBufs_,
694  defaultValues
695  );
696 
697  // Receive requests all handled by last function call
698  recvRequests_.clear();
699  }
700  else
701  {
702  solveScalarField defaultValues;
703  if (cyclicAMIPatch_.applyLowWeightCorrection())
704  {
705  defaultValues = solveScalarField(psiInternal, faceCells);
706  }
707 
708  const labelUList& nbrFaceCells =
709  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
710 
711  pnf = solveScalarField(psiInternal, nbrFaceCells);
712 
713  // Transform according to the transformation tensors
714  transformCoupleField(pnf, cmpt);
715 
716  pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
717  }
718 
719  // Multiply the field by coefficients and add into the result
720  this->addToInternalField(result, !add, faceCells, coeffs, pnf);
722  this->updatedMatrix(true);
723 }
724 
725 
726 template<class Type>
728 (
729  Field<Type>& result,
730  const bool add,
731  const lduAddressing& lduAddr,
732  const label patchId,
733  const Field<Type>& psiInternal,
734  const scalarField& coeffs,
735  const Pstream::commsTypes commsType
736 ) const
737 {
738  const auto& AMI = this->ownerAMI();
739 
740  if (AMI.distributed() && AMI.comm() != -1)
741  {
742  if (commsType != UPstream::commsTypes::nonBlocking)
743  {
745  << "Can only evaluate distributed AMI with nonBlocking"
746  << exit(FatalError);
747  }
748 
749  const labelUList& nbrFaceCells =
750  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
751 
752  Field<Type> pnf(psiInternal, nbrFaceCells);
753 
754  // Transform according to the transformation tensors
755  transformCoupleField(pnf);
756 
757  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
758 
759  // Assert that all receives are known to have finished
760  if (!recvRequests_.empty())
761  {
763  << "Outstanding recv request(s) on patch "
764  << cyclicAMIPatch_.name()
765  << " field " << this->internalField().name()
766  << abort(FatalError);
767  }
768 
769  // Assume that sends are also OK
770  sendRequests_.clear();
771 
772  cpp.initInterpolate
773  (
774  pnf,
775  sendRequests_,
776  sendBufs_,
777  recvRequests_,
778  recvBufs_
779  );
780  }
782  this->updatedMatrix(false);
783 }
784 
785 
786 template<class Type>
788 (
789  Field<Type>& result,
790  const bool add,
791  const lduAddressing& lduAddr,
792  const label patchId,
793  const Field<Type>& psiInternal,
794  const scalarField& coeffs,
795  const Pstream::commsTypes commsType
796 ) const
797 {
798  //DebugPout<< "cyclicAMIFvPatchField::updateInterfaceMatrix() :"
799  // << " field:" << this->internalField().name()
800  // << " patch:" << this->patch().name()
801  // << endl;
802 
803  const labelUList& faceCells = lduAddr.patchAddr(patchId);
804 
805  const auto& AMI = this->ownerAMI();
806 
807  Field<Type> pnf;
808 
809  if (AMI.distributed() && AMI.comm() != -1)
810  {
811  if (commsType != UPstream::commsTypes::nonBlocking)
812  {
814  << "Can only evaluate distributed AMI with nonBlocking"
815  << exit(FatalError);
816  }
817 
818  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
819 
820  Field<Type> defaultValues;
821  if (AMI.applyLowWeightCorrection())
822  {
823  defaultValues = Field<Type>(psiInternal, faceCells);
824  }
825 
826  pnf =
827  cpp.interpolate
828  (
829  Field<Type>::null(), // Not used for distributed
830  recvRequests_,
831  recvBufs_,
832  defaultValues
833  );
834 
835  // Receive requests all handled by last function call
836  recvRequests_.clear();
837  }
838  else
839  {
840  const labelUList& nbrFaceCells =
841  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
842 
843  pnf = Field<Type>(psiInternal, nbrFaceCells);
844 
845  // Transform according to the transformation tensors
846  transformCoupleField(pnf);
847 
848  Field<Type> defaultValues;
849  if (cyclicAMIPatch_.applyLowWeightCorrection())
850  {
851  defaultValues = Field<Type>(psiInternal, faceCells);
852  }
853 
854  pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
855  }
856 
857  // Multiply the field by coefficients and add into the result
858  this->addToInternalField(result, !add, faceCells, coeffs, pnf);
860  this->updatedMatrix(true);
861 }
862 
863 
864 template<class Type>
866 (
867  fvMatrix<Type>& matrix,
868  const label mat,
869  const direction cmpt
870 )
871 {
872  if (this->cyclicAMIPatch().owner())
873  {
874  const label index = this->patch().index();
875 
876  const label globalPatchID =
877  matrix.lduMeshAssembly().patchLocalToGlobalMap()[mat][index];
878 
879  const Field<scalar> intCoeffsCmpt
880  (
881  matrix.internalCoeffs()[globalPatchID].component(cmpt)
882  );
883 
884  const Field<scalar> boundCoeffsCmpt
885  (
886  matrix.boundaryCoeffs()[globalPatchID].component(cmpt)
887  );
888 
889  tmp<Field<scalar>> tintCoeffs(coeffs(matrix, intCoeffsCmpt, mat));
890  tmp<Field<scalar>> tbndCoeffs(coeffs(matrix, boundCoeffsCmpt, mat));
891  const Field<scalar>& intCoeffs = tintCoeffs.ref();
892  const Field<scalar>& bndCoeffs = tbndCoeffs.ref();
893 
894  const labelUList& u = matrix.lduAddr().upperAddr();
895  const labelUList& l = matrix.lduAddr().lowerAddr();
896 
897  label subFaceI = 0;
898 
899  const labelList& faceMap =
900  matrix.lduMeshAssembly().faceBoundMap()[mat][index];
901 
902  forAll (faceMap, j)
903  {
904  label globalFaceI = faceMap[j];
905 
906  const scalar boundCorr = -bndCoeffs[subFaceI];
907  const scalar intCorr = -intCoeffs[subFaceI];
908 
909  matrix.upper()[globalFaceI] += boundCorr;
910  matrix.diag()[u[globalFaceI]] -= intCorr;
911  matrix.diag()[l[globalFaceI]] -= boundCorr;
912 
913  if (matrix.asymmetric())
914  {
915  matrix.lower()[globalFaceI] += intCorr;
916  }
917  subFaceI++;
918  }
919 
920  // Set internalCoeffs and boundaryCoeffs in the assembly matrix
921  // on clyclicAMI patches to be used in the individual matrix by
922  // matrix.flux()
923  if (matrix.psi(mat).mesh().fluxRequired(this->internalField().name()))
924  {
925  matrix.internalCoeffs().set
926  (
927  globalPatchID, intCoeffs*pTraits<Type>::one
928  );
929  matrix.boundaryCoeffs().set
930  (
931  globalPatchID, bndCoeffs*pTraits<Type>::one
932  );
933 
934  const label nbrPathID =
935  cyclicAMIPatch_.cyclicAMIPatch().neighbPatchID();
936 
937  const label nbrGlobalPatchID =
938  matrix.lduMeshAssembly().patchLocalToGlobalMap()
939  [mat][nbrPathID];
940 
941  matrix.internalCoeffs().set
942  (
943  nbrGlobalPatchID, intCoeffs*pTraits<Type>::one
944  );
945  matrix.boundaryCoeffs().set
946  (
947  nbrGlobalPatchID, bndCoeffs*pTraits<Type>::one
948  );
949  }
950  }
951 }
952 
953 
954 template<class Type>
957 (
958  fvMatrix<Type>& matrix,
959  const Field<scalar>& coeffs,
960  const label mat
961 ) const
962 {
963  const label index(this->patch().index());
964 
965  const label nSubFaces
966  (
967  matrix.lduMeshAssembly().cellBoundMap()[mat][index].size()
968  );
969 
970  auto tmapCoeffs = tmp<Field<scalar>>::New(nSubFaces, Zero);
971  auto& mapCoeffs = tmapCoeffs.ref();
972 
973  const scalarListList& srcWeight =
974  cyclicAMIPatch_.cyclicAMIPatch().AMI().srcWeights();
975 
976  label subFaceI = 0;
977  forAll(*this, faceI)
978  {
979  const scalarList& w = srcWeight[faceI];
980  for(label i=0; i<w.size(); i++)
981  {
982  const label localFaceId =
983  matrix.lduMeshAssembly().facePatchFaceMap()[mat][index][subFaceI];
984  mapCoeffs[subFaceI] = w[i]*coeffs[localFaceId];
985  subFaceI++;
986  }
987  }
988 
989  return tmapCoeffs;
990 }
991 
992 
993 template<class Type>
994 template<class Type2>
996 (
997  const refPtr<mapDistribute>& mapPtr,
998  const labelListList& stencil,
999  const Type2& data,
1000  List<Type2>& expandedData
1001 )
1002 {
1003  expandedData.resize_nocopy(stencil.size());
1004  if (mapPtr)
1005  {
1006  Type2 work(data);
1007  mapPtr().distribute(work);
1008 
1009  forAll(stencil, facei)
1010  {
1011  const auto& slots = stencil[facei];
1012  expandedData[facei].push_back
1013  (
1014  UIndirectList<typename Type2::value_type>(work, slots)
1015  );
1016  }
1017  }
1018  else
1019  {
1020  forAll(stencil, facei)
1021  {
1022  const auto& slots = stencil[facei];
1023  expandedData[facei].push_back
1024  (
1025  UIndirectList<typename Type2::value_type>(data, slots)
1026  );
1027  }
1028  }
1029 }
1030 
1031 
1032 template<class Type>
1033 void Foam::cyclicAMIFvPatchField<Type>::write(Ostream& os) const
1034 {
1036  fvPatchField<Type>::writeValueEntry(os);
1037 
1038  if (patchNeighbourFieldPtr_)
1039  {
1040  patchNeighbourFieldPtr_->writeEntry("neighbourValue", os);
1041  }
1043 
1044 
1045 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1046 
1047 template<class Type>
1049 (
1050  const fvPatchField<Type>& ptf
1051 )
1052 {
1054 
1055  //Pout<< "cyclicAMIFvPatchField::operator= :"
1056  // << " field:" << this->internalField().name()
1057  // << " patch:" << this->patch().name()
1058  // << " copying from field:" << ptf.internalField().name()
1059  // << endl;
1060 
1061  const auto* cycPtr = isA<cyclicAMIFvPatchField<Type>>(ptf);
1062 
1063  if
1064  (
1065  cycPtr
1066  && cycPtr->patchNeighbourFieldPtr_
1067  && cycPtr->patchNeighbourFieldPtr_->size() == this->size()
1068  )
1069  {
1070  if (!patchNeighbourFieldPtr_)
1071  {
1072  patchNeighbourFieldPtr_ = autoPtr<Field<Type>>::New();
1073  }
1074 
1075  // Copy values
1076  *patchNeighbourFieldPtr_ = *(cycPtr->patchNeighbourFieldPtr_);
1077  }
1078  else
1079  {
1080  patchNeighbourFieldPtr_.reset(nullptr);
1081  }
1082 }
1083 
1084 
1085 template<class Type>
1087 (
1088  const fvPatchField<Type>& ptf
1089 )
1090 {
1092 
1093  //Pout<< "cyclicAMIFvPatchField::operator== :"
1094  // << " field:" << this->internalField().name()
1095  // << " patch:" << this->patch().name()
1096  // << " copying from field:" << ptf.internalField().name()
1097  // << endl;
1098 
1099  const auto* cycPtr = isA<cyclicAMIFvPatchField<Type>>(ptf);
1100 
1101  if
1102  (
1103  cycPtr
1104  && cycPtr->patchNeighbourFieldPtr_
1105  && cycPtr->patchNeighbourFieldPtr_->size() == this->size()
1106  )
1107  {
1108  if (!patchNeighbourFieldPtr_)
1109  {
1110  patchNeighbourFieldPtr_ = autoPtr<Field<Type>>::New();
1111  }
1112 
1113  // Copy values
1114  *patchNeighbourFieldPtr_ = *(cycPtr->patchNeighbourFieldPtr_);
1115  }
1116  else
1117  {
1118  patchNeighbourFieldPtr_.reset(nullptr);
1119  }
1120 }
1121 
1122 
1123 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
label patchId(-1)
const scalarField & diag() const
Definition: lduMatrix.C:195
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:77
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
void checkCommunicator(int comm, int rank)
Fatal if communicator is outside the allocated range.
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:600
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) to Type reference.
Definition: typeInfo.H:172
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:168
Generic GeometricField class.
Smooth ATC in cells next to a set of patches supplied by type.
Definition: faceCells.H:52
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:76
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:286
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:130
List< scalarList > scalarListList
List of scalarList.
Definition: scalarList.H:35
virtual void write(Ostream &os) const
Write.
virtual void evaluate(const Pstream::commsTypes commsType)
Evaluate the patch field.
A FieldMapper for finite-volume patch fields.
virtual const labelUList & patchAddr(const label patchNo) const =0
Return patch to internal addressing given patch number.
const scalarField & lower() const
Definition: lduMatrix.C:306
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
Matrix is asymmetric (ie, full)
Definition: lduMatrix.H:850
void add(FieldField< Field1, typename typeOfSum< Type1, Type2 >::type > &f, const FieldField< Field1, Type1 > &f1, const FieldField< Field2, Type2 > &f2)
refinementData transform(const tensor &, const refinementData val)
No-op rotational transform for base types.
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))
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.
const scalarField & upper() const
Definition: lduMatrix.C:235
const lduAddressing & lduAddr() const
Return the LDU addressing.
Definition: lduMatrix.H:769
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:629
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...
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
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
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.
void deepCopy(const UList< T > &list)
Copy elements of the given UList. Sizes must match!
Definition: UList.C:97
virtual void rmap(const fvPatchField< Type > &, const labelList &)
Reverse map the given fvPatchField onto this fvPatchField.
volScalarField & p
A class for managing temporary objects.
Definition: HashPtrTable.H:50
tmp< faMatrix< Type > > operator==(const faMatrix< Type > &, const faMatrix< Type > &)
bool coupled
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