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-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "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  int& consistency =
101  GeometricField<Type, fvPatchField, volMesh>::
102  Boundary::localConsistency;
103 
104  const int oldConsistency = consistency;
105  consistency = 0;
106 
107  this->evaluate(UPstream::commsTypes::nonBlocking);
108 
109  consistency = oldConsistency;
110  }
111  else
112  {
113  this->extrapolateInternal(); // Zero-gradient patch values
114  }
115  }
116 }
117 
118 
119 template<class Type>
121 (
122  const cyclicAMIFvPatchField<Type>& ptf,
123  const fvPatch& p,
124  const DimensionedField<Type, volMesh>& iF,
125  const fvPatchFieldMapper& mapper
126 )
127 :
128  cyclicAMILduInterfaceField(),
129  coupledFvPatchField<Type>(ptf, p, iF, mapper),
130  cyclicAMIPatch_(refCast<const cyclicAMIFvPatch>(p)),
131  patchNeighbourFieldPtr_(nullptr)
132 {
133  //if (ptf.patchNeighbourFieldPtr_ && cacheNeighbourField())
134  //{
135  // patchNeighbourFieldPtr_.reset
136  // (
137  // new Field<Type>(ptf.patchNeighbourFieldPtr_(), mapper)
138  // );
139  //}
140 
141  if (!isA<cyclicAMIFvPatch>(this->patch()))
142  {
144  << "\n patch type '" << p.type()
145  << "' not constraint type '" << typeName << "'"
146  << "\n for patch " << p.name()
147  << " of field " << this->internalField().name()
148  << " in file " << this->internalField().objectPath()
149  << exit(FatalError);
150  }
151  if (debug && !ptf.all_ready())
152  {
154  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
156  }
157 }
158 
159 
160 template<class Type>
162 (
163  const cyclicAMIFvPatchField<Type>& ptf
164 )
165 :
166  cyclicAMILduInterfaceField(),
167  coupledFvPatchField<Type>(ptf),
168  cyclicAMIPatch_(ptf.cyclicAMIPatch_),
169  patchNeighbourFieldPtr_(nullptr)
170 {
171  if (debug && !ptf.all_ready())
172  {
174  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
176  }
177 }
178 
179 
180 template<class Type>
182 (
183  const cyclicAMIFvPatchField<Type>& ptf,
184  const DimensionedField<Type, volMesh>& iF
185 )
186 :
187  cyclicAMILduInterfaceField(),
188  coupledFvPatchField<Type>(ptf, iF),
189  cyclicAMIPatch_(ptf.cyclicAMIPatch_),
190  patchNeighbourFieldPtr_(nullptr)
191 {
192  if (debug && !ptf.all_ready())
193  {
195  << "Outstanding request(s) on patch " << cyclicAMIPatch_.name()
196  << abort(FatalError);
197  }
198 }
199 
200 
201 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
202 
203 template<class Type>
205 {
206  int done = 0;
207 
208  if
209  (
210  UPstream::finishedRequests
211  (
212  recvRequests_.start(),
213  recvRequests_.size()
214  )
215  )
216  {
217  recvRequests_.clear();
218  ++done;
219  }
220 
221  if
222  (
223  UPstream::finishedRequests
224  (
225  sendRequests_.start(),
226  sendRequests_.size()
227  )
228  )
229  {
230  sendRequests_.clear();
231  ++done;
232  }
233 
234  return (done == 2);
235 }
236 
237 
238 template<class Type>
240 {
241  if
242  (
243  UPstream::finishedRequests
244  (
245  recvRequests_.start(),
246  recvRequests_.size()
247  )
248  )
249  {
250  recvRequests_.clear();
251 
252  if
253  (
254  UPstream::finishedRequests
255  (
256  sendRequests_.start(),
257  sendRequests_.size()
258  )
259  )
260  {
261  sendRequests_.clear();
262  }
263 
264  return true;
265  }
266 
267  return false;
268 }
269 
270 
271 
272 template<class Type>
274 (
275  const fvPatchFieldMapper& mapper
276 )
277 {
279  patchNeighbourFieldPtr_.reset(nullptr);
280 }
281 
282 
283 template<class Type>
285 (
286  const fvPatchField<Type>& ptf,
287  const labelList& addr
288 )
289 {
291  patchNeighbourFieldPtr_.reset(nullptr);
292 }
293 
294 
295 template<class Type>
298 (
299  const Field<Type>& iField
300 ) const
301 {
302  // By pass polyPatch to get nbrId. Instead use cyclicAMIFvPatch virtual
303  // neighbPatch()
304  const cyclicAMIFvPatch& neighbPatch = cyclicAMIPatch_.neighbPatch();
305  const labelUList& nbrFaceCells = neighbPatch.faceCells();
306 
307  Field<Type> pnf(iField, nbrFaceCells);
308  Field<Type> defaultValues;
309 
310  if (cyclicAMIPatch_.applyLowWeightCorrection())
311  {
312  defaultValues = Field<Type>(iField, cyclicAMIPatch_.faceCells());
313  }
314 
315  tmp<Field<Type>> tpnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
316 
317  if (doTransform())
318  {
319  transform(tpnf.ref(), forwardT(), tpnf());
320  }
321 
322  return tpnf;
323 }
324 
325 
326 template<class Type>
328 {
329  return
330  (
331  GeometricField<Type, fvPatchField, volMesh>::Boundary::localConsistency
332  != 0
333  );
334 }
335 
336 
337 template<class Type>
340 {
341  if (this->ownerAMI().distributed() && cacheNeighbourField())
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  patchNeighbourField(this->primitiveField()).ptr()
383  );
384  }
385  else
386  {
387  // Have cached value. Check
388  //if (debug)
389  //{
390  // tmp<Field<Type>> tpnf
391  // (
392  // patchNeighbourField(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 patchNeighbourField(this->primitiveField());
413  }
414 }
415 
416 
417 template<class Type>
420 {
421  const GeometricField<Type, fvPatchField, volMesh>& fld =
422  static_cast<const GeometricField<Type, fvPatchField, volMesh>&>
423  (
424  this->primitiveField()
425  );
426 
427  return refCast<const cyclicAMIFvPatchField<Type>>
428  (
429  fld.boundaryField()[cyclicAMIPatch_.neighbPatchID()]
430  );
431 }
432 
433 
434 template<class Type>
436 (
437  const Pstream::commsTypes commsType
438 )
439 {
440  if (!this->updated())
441  {
442  this->updateCoeffs();
443  }
444 
445  if (this->ownerAMI().distributed() && cacheNeighbourField())
446  {
447  //DebugPout
448  // << "*** cyclicAMIFvPatchField::initEvaluate() :"
449  // << " field:" << this->internalField().name()
450  // << " patch:" << this->patch().name()
451  // << " sending patchNeighbourField"
452  // << endl;
453 
454  if (commsType != UPstream::commsTypes::nonBlocking)
455  {
456  // Invalidate old field - or flag as fatal?
457  patchNeighbourFieldPtr_.reset(nullptr);
458  return;
459  }
460 
461  // Start sending
462 
463  // Bypass polyPatch to get nbrId.
464  // - use cyclicACMIFvPatch::neighbPatch() virtual instead
465  const cyclicAMIFvPatch& neighbPatch = cyclicAMIPatch_.neighbPatch();
466  const labelUList& nbrFaceCells = neighbPatch.faceCells();
467  const Field<Type> pnf(this->primitiveField(), nbrFaceCells);
468 
469  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
470 
471  // Assert that all receives are known to have finished
472  if (!recvRequests_.empty())
473  {
475  << "Outstanding recv request(s) on patch "
476  << cyclicAMIPatch_.name()
477  << " field " << this->internalField().name()
478  << abort(FatalError);
479  }
480 
481  // Assume that sends are also OK
482  sendRequests_.clear();
483 
484  cpp.initInterpolate
485  (
486  pnf,
487  sendRequests_,
488  sendBufs_,
489  recvRequests_,
490  recvBufs_
491  );
492  }
493 }
494 
495 
496 template<class Type>
498 (
499  const Pstream::commsTypes commsType
500 )
501 {
502  if (!this->updated())
503  {
504  this->updateCoeffs();
505  }
506 
507  const auto& AMI = this->ownerAMI();
508 
509  if (AMI.distributed() && cacheNeighbourField())
510  {
511  // Calculate patchNeighbourField
512  if (commsType != UPstream::commsTypes::nonBlocking)
513  {
515  << "Can only evaluate distributed AMI with nonBlocking"
516  << exit(FatalError);
517  }
518 
519  patchNeighbourFieldPtr_.reset(nullptr);
520 
521  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
522 
523  Field<Type> defaultValues;
524  if (AMI.applyLowWeightCorrection())
525  {
526  defaultValues = this->patchInternalField();
527  }
528 
529  //DebugPout
530  // << "*** cyclicAMIFvPatchField::evaluate() :"
531  // << " field:" << this->internalField().name()
532  // << " patch:" << this->patch().name()
533  // << " receiving&caching patchNeighbourField"
534  // << endl;
535 
536  patchNeighbourFieldPtr_.reset
537  (
538  cpp.interpolate
539  (
540  Field<Type>::null(), // Not used for distributed
541  recvRequests_,
542  recvBufs_,
543  defaultValues
544  ).ptr()
545  );
546 
547  // Receive requests all handled by last function call
548  recvRequests_.clear();
549 
550  auto& patchNeighbourField = patchNeighbourFieldPtr_.ref();
551 
552  if (doTransform())
553  {
554  // In-place transform
555  transform(patchNeighbourField, forwardT(), patchNeighbourField);
556  }
557  }
558 
559  // Use patchNeighbourField() and patchInternalField() to obtain face value
561 }
562 
563 
564 template<class Type>
566 (
567  solveScalarField& result,
568  const bool add,
569  const lduAddressing& lduAddr,
570  const label patchId,
571  const solveScalarField& psiInternal,
572  const scalarField& coeffs,
573  const direction cmpt,
574  const Pstream::commsTypes commsType
575 ) const
576 {
577  if (this->ownerAMI().distributed())
578  {
579  // Start sending
580  if (commsType != UPstream::commsTypes::nonBlocking)
581  {
583  << "Can only evaluate distributed AMI with nonBlocking"
584  << exit(FatalError);
585  }
586 
587  const labelUList& nbrFaceCells =
588  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
589 
590  solveScalarField pnf(psiInternal, nbrFaceCells);
591 
592  // Transform according to the transformation tensors
593  transformCoupleField(pnf, cmpt);
594 
595  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
596 
597  // Assert that all receives are known to have finished
598  if (!recvRequests_.empty())
599  {
601  << "Outstanding recv request(s) on patch "
602  << cyclicAMIPatch_.name()
603  << " field " << this->internalField().name()
604  << abort(FatalError);
605  }
606 
607  // Assume that sends are also OK
608  sendRequests_.clear();
609 
610  cpp.initInterpolate
611  (
612  pnf,
613  sendRequests_,
614  scalarSendBufs_,
615  recvRequests_,
616  scalarRecvBufs_
617  );
618  }
619 }
620 
621 
622 template<class Type>
624 (
625  solveScalarField& result,
626  const bool add,
627  const lduAddressing& lduAddr,
628  const label patchId,
629  const solveScalarField& psiInternal,
630  const scalarField& coeffs,
631  const direction cmpt,
632  const Pstream::commsTypes commsType
633 ) const
634 {
635  //DebugPout<< "cyclicAMIFvPatchField::updateInterfaceMatrix() :"
636  // << " field:" << this->internalField().name()
637  // << " patch:" << this->patch().name()
638  // << endl;
639 
640  const labelUList& faceCells = lduAddr.patchAddr(patchId);
641 
642  const auto& AMI = this->ownerAMI();
643 
644  solveScalarField pnf;
645 
646  if (AMI.distributed())
647  {
648  if (commsType != UPstream::commsTypes::nonBlocking)
649  {
651  << "Can only evaluate distributed AMI with nonBlocking"
652  << exit(FatalError);
653  }
654 
655  solveScalarField defaultValues;
656  if (AMI.applyLowWeightCorrection())
657  {
658  defaultValues = solveScalarField(psiInternal, faceCells);
659  }
660 
661  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
662 
663  pnf =
664  cpp.interpolate
665  (
666  solveScalarField::null(), // Not used for distributed
667  recvRequests_,
668  scalarRecvBufs_,
669  defaultValues
670  );
671 
672  // Receive requests all handled by last function call
673  recvRequests_.clear();
674  }
675  else
676  {
677  solveScalarField defaultValues;
678  if (cyclicAMIPatch_.applyLowWeightCorrection())
679  {
680  defaultValues = solveScalarField(psiInternal, faceCells);
681  }
682 
683  const labelUList& nbrFaceCells =
684  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
685 
686  pnf = solveScalarField(psiInternal, nbrFaceCells);
687 
688  // Transform according to the transformation tensors
689  transformCoupleField(pnf, cmpt);
690 
691  pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
692  }
693 
694  // Multiply the field by coefficients and add into the result
695  this->addToInternalField(result, !add, faceCells, coeffs, pnf);
696 }
697 
698 
699 template<class Type>
701 (
702  Field<Type>& result,
703  const bool add,
704  const lduAddressing& lduAddr,
705  const label patchId,
706  const Field<Type>& psiInternal,
707  const scalarField& coeffs,
708  const Pstream::commsTypes commsType
709 ) const
710 {
711  const auto& AMI = this->ownerAMI();
712 
713  if (AMI.distributed())
714  {
715  if (commsType != UPstream::commsTypes::nonBlocking)
716  {
718  << "Can only evaluate distributed AMI with nonBlocking"
719  << exit(FatalError);
720  }
721 
722  const labelUList& nbrFaceCells =
723  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
724 
725  Field<Type> pnf(psiInternal, nbrFaceCells);
726 
727  // Transform according to the transformation tensors
728  transformCoupleField(pnf);
729 
730  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
731 
732  // Assert that all receives are known to have finished
733  if (!recvRequests_.empty())
734  {
736  << "Outstanding recv request(s) on patch "
737  << cyclicAMIPatch_.name()
738  << " field " << this->internalField().name()
739  << abort(FatalError);
740  }
741 
742  // Assume that sends are also OK
743  sendRequests_.clear();
744 
745  cpp.initInterpolate
746  (
747  pnf,
748  sendRequests_,
749  sendBufs_,
750  recvRequests_,
751  recvBufs_
752  );
753  }
754 }
755 
756 
757 template<class Type>
759 (
760  Field<Type>& result,
761  const bool add,
762  const lduAddressing& lduAddr,
763  const label patchId,
764  const Field<Type>& psiInternal,
765  const scalarField& coeffs,
766  const Pstream::commsTypes commsType
767 ) const
768 {
769  //DebugPout<< "cyclicAMIFvPatchField::updateInterfaceMatrix() :"
770  // << " field:" << this->internalField().name()
771  // << " patch:" << this->patch().name()
772  // << endl;
773 
774  const labelUList& faceCells = lduAddr.patchAddr(patchId);
775 
776  const auto& AMI = this->ownerAMI();
777 
778  Field<Type> pnf;
779 
780  if (AMI.distributed())
781  {
782  if (commsType != UPstream::commsTypes::nonBlocking)
783  {
785  << "Can only evaluate distributed AMI with nonBlocking"
786  << exit(FatalError);
787  }
788 
789  const cyclicAMIPolyPatch& cpp = cyclicAMIPatch_.cyclicAMIPatch();
790 
791  Field<Type> defaultValues;
792  if (AMI.applyLowWeightCorrection())
793  {
794  defaultValues = Field<Type>(psiInternal, faceCells);
795  }
796 
797  pnf =
798  cpp.interpolate
799  (
800  Field<Type>::null(), // Not used for distributed
801  recvRequests_,
802  recvBufs_,
803  defaultValues
804  );
805 
806  // Receive requests all handled by last function call
807  recvRequests_.clear();
808  }
809  else
810  {
811  const labelUList& nbrFaceCells =
812  lduAddr.patchAddr(cyclicAMIPatch_.neighbPatchID());
813 
814  pnf = Field<Type>(psiInternal, nbrFaceCells);
815 
816  // Transform according to the transformation tensors
817  transformCoupleField(pnf);
818 
819  Field<Type> defaultValues;
820  if (cyclicAMIPatch_.applyLowWeightCorrection())
821  {
822  defaultValues = Field<Type>(psiInternal, faceCells);
823  }
824 
825  pnf = cyclicAMIPatch_.interpolate(pnf, defaultValues);
826  }
827 
828  // Multiply the field by coefficients and add into the result
829  this->addToInternalField(result, !add, faceCells, coeffs, pnf);
830 }
831 
832 
833 template<class Type>
835 (
836  fvMatrix<Type>& matrix,
837  const label mat,
838  const direction cmpt
839 )
840 {
841  if (this->cyclicAMIPatch().owner())
842  {
843  const label index = this->patch().index();
844 
845  const label globalPatchID =
846  matrix.lduMeshAssembly().patchLocalToGlobalMap()[mat][index];
847 
848  const Field<scalar> intCoeffsCmpt
849  (
850  matrix.internalCoeffs()[globalPatchID].component(cmpt)
851  );
852 
853  const Field<scalar> boundCoeffsCmpt
854  (
855  matrix.boundaryCoeffs()[globalPatchID].component(cmpt)
856  );
857 
858  tmp<Field<scalar>> tintCoeffs(coeffs(matrix, intCoeffsCmpt, mat));
859  tmp<Field<scalar>> tbndCoeffs(coeffs(matrix, boundCoeffsCmpt, mat));
860  const Field<scalar>& intCoeffs = tintCoeffs.ref();
861  const Field<scalar>& bndCoeffs = tbndCoeffs.ref();
862 
863  const labelUList& u = matrix.lduAddr().upperAddr();
864  const labelUList& l = matrix.lduAddr().lowerAddr();
865 
866  label subFaceI = 0;
867 
868  const labelList& faceMap =
869  matrix.lduMeshAssembly().faceBoundMap()[mat][index];
870 
871  forAll (faceMap, j)
872  {
873  label globalFaceI = faceMap[j];
874 
875  const scalar boundCorr = -bndCoeffs[subFaceI];
876  const scalar intCorr = -intCoeffs[subFaceI];
877 
878  matrix.upper()[globalFaceI] += boundCorr;
879  matrix.diag()[u[globalFaceI]] -= intCorr;
880  matrix.diag()[l[globalFaceI]] -= boundCorr;
881 
882  if (matrix.asymmetric())
883  {
884  matrix.lower()[globalFaceI] += intCorr;
885  }
886  subFaceI++;
887  }
888 
889  // Set internalCoeffs and boundaryCoeffs in the assembly matrix
890  // on clyclicAMI patches to be used in the individual matrix by
891  // matrix.flux()
892  if (matrix.psi(mat).mesh().fluxRequired(this->internalField().name()))
893  {
894  matrix.internalCoeffs().set
895  (
896  globalPatchID, intCoeffs*pTraits<Type>::one
897  );
898  matrix.boundaryCoeffs().set
899  (
900  globalPatchID, bndCoeffs*pTraits<Type>::one
901  );
902 
903  const label nbrPathID =
904  cyclicAMIPatch_.cyclicAMIPatch().neighbPatchID();
905 
906  const label nbrGlobalPatchID =
907  matrix.lduMeshAssembly().patchLocalToGlobalMap()
908  [mat][nbrPathID];
909 
910  matrix.internalCoeffs().set
911  (
912  nbrGlobalPatchID, intCoeffs*pTraits<Type>::one
913  );
914  matrix.boundaryCoeffs().set
915  (
916  nbrGlobalPatchID, bndCoeffs*pTraits<Type>::one
917  );
918  }
919  }
920 }
921 
922 
923 template<class Type>
926 (
927  fvMatrix<Type>& matrix,
928  const Field<scalar>& coeffs,
929  const label mat
930 ) const
931 {
932  const label index(this->patch().index());
933 
934  const label nSubFaces
935  (
936  matrix.lduMeshAssembly().cellBoundMap()[mat][index].size()
937  );
938 
939  auto tmapCoeffs = tmp<Field<scalar>>::New(nSubFaces, Zero);
940  auto& mapCoeffs = tmapCoeffs.ref();
941 
942  const scalarListList& srcWeight =
943  cyclicAMIPatch_.cyclicAMIPatch().AMI().srcWeights();
944 
945  label subFaceI = 0;
946  forAll(*this, faceI)
947  {
948  const scalarList& w = srcWeight[faceI];
949  for(label i=0; i<w.size(); i++)
950  {
951  const label localFaceId =
952  matrix.lduMeshAssembly().facePatchFaceMap()[mat][index][subFaceI];
953  mapCoeffs[subFaceI] = w[i]*coeffs[localFaceId];
954  subFaceI++;
955  }
956  }
957 
958  return tmapCoeffs;
959 }
960 
961 
962 template<class Type>
963 template<class Type2>
965 (
966  const refPtr<mapDistribute>& mapPtr,
967  const labelListList& stencil,
968  const Type2& data,
969  List<Type2>& expandedData
970 )
971 {
972  expandedData.resize_nocopy(stencil.size());
973  if (mapPtr)
974  {
975  Type2 work(data);
976  mapPtr().distribute(work);
977 
978  forAll(stencil, facei)
979  {
980  const labelList& slots = stencil[facei];
981  expandedData[facei].push_back
982  (
983  UIndirectList<typename Type2::value_type>(work, slots)
984  );
985  }
986  }
987  else
988  {
989  forAll(stencil, facei)
990  {
991  const labelList& slots = stencil[facei];
992  expandedData[facei].push_back
993  (
994  UIndirectList<typename Type2::value_type>(data, slots)
995  );
996  }
997  }
998 }
999 
1000 
1001 template<class Type>
1002 void Foam::cyclicAMIFvPatchField<Type>::write(Ostream& os) const
1003 {
1005  fvPatchField<Type>::writeValueEntry(os);
1006 
1007  if (patchNeighbourFieldPtr_)
1008  {
1009  patchNeighbourFieldPtr_->writeEntry("neighbourValue", os);
1010  }
1012 
1013 
1014 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
1015 
1016 template<class Type>
1018 (
1019  const fvPatchField<Type>& ptf
1020 )
1021 {
1023 
1024  //Pout<< "cyclicAMIFvPatchField::operator= :"
1025  // << " field:" << this->internalField().name()
1026  // << " patch:" << this->patch().name()
1027  // << " copying from field:" << ptf.internalField().name()
1028  // << endl;
1029 
1030  const auto* cycPtr = isA<cyclicAMIFvPatchField<Type>>(ptf);
1031  if (cycPtr)
1032  {
1033  const auto& cyc = *cycPtr;
1034  if
1035  (
1036  cyc.patchNeighbourFieldPtr_
1037  && cyc.patchNeighbourFieldPtr_->size() == this->size()
1038  )
1039  {
1040  const auto& cycPnf = cyc.patchNeighbourFieldPtr_();
1041  if (patchNeighbourFieldPtr_)
1042  {
1043  // Copy values
1044  patchNeighbourFieldPtr_() = cycPnf;
1045  }
1046  else
1047  {
1048  // Copy values
1049  patchNeighbourFieldPtr_.reset(new Field<Type>(cycPnf));
1050  }
1051  }
1052  else
1053  {
1054  patchNeighbourFieldPtr_.reset(nullptr);
1055  }
1056  }
1057  else
1058  {
1059  patchNeighbourFieldPtr_.reset(nullptr);
1060  }
1061 }
1062 
1063 
1064 template<class Type>
1066 (
1067  const fvPatchField<Type>& ptf
1068 )
1069 {
1071 
1072  //Pout<< "cyclicAMIFvPatchField::operator== :"
1073  // << " field:" << this->internalField().name()
1074  // << " patch:" << this->patch().name()
1075  // << " copying from field:" << ptf.internalField().name()
1076  // << endl;
1077 
1078  const auto* cycPtr = isA<cyclicAMIFvPatchField<Type>>(ptf);
1079  if (cycPtr)
1080  {
1081  const auto& cyc = *cycPtr;
1082  if
1083  (
1084  cyc.patchNeighbourFieldPtr_
1085  && cyc.patchNeighbourFieldPtr_->size() == this->size()
1086  )
1087  {
1088  const auto& cycPnf = cyc.patchNeighbourFieldPtr_();
1089  if (patchNeighbourFieldPtr_)
1090  {
1091  // Copy values
1092  patchNeighbourFieldPtr_() = cycPnf;
1093  }
1094  else
1095  {
1096  // Copy values
1097  patchNeighbourFieldPtr_.reset(new Field<Type>(cycPnf));
1098  }
1099  }
1100  else
1101  {
1102  patchNeighbourFieldPtr_.reset(nullptr);
1103  }
1104  }
1105  else
1106  {
1107  patchNeighbourFieldPtr_.reset(nullptr);
1108  }
1109 }
1110 
1111 
1112 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
label patchId(-1)
const scalarField & diag() const
Definition: lduMatrix.C:163
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
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:608
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
Smooth ATC in cells next to a set of patches supplied by type.
Definition: faceCells.H:52
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:220
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:130
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.
const scalarField & lower() const
Definition: lduMatrix.C:268
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:817
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 scalarField & upper() const
Definition: lduMatrix.C:203
const lduAddressing & lduAddr() const
Return the LDU addressing.
Definition: lduMatrix.H:755
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:637
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
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 > &)
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