cyclicAMIGAMGInterface.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-2016 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 "AMIInterpolation.H"
30 #include "cyclicAMIGAMGInterface.H"
32 #include "Map.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38  defineTypeNameAndDebug(cyclicAMIGAMGInterface, 0);
40  (
41  GAMGInterface,
42  cyclicAMIGAMGInterface,
43  lduInterface
44  );
46  (
47  GAMGInterface,
48  cyclicAMIGAMGInterface,
49  Istream
50  );
51 }
52 
53 
54 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
55 
56 Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface
57 (
58  const label index,
59  const lduInterfacePtrsList& coarseInterfaces,
60  const lduInterface& fineInterface,
61  const labelField& localRestrictAddressing,
62  const labelField& neighbourRestrictAddressing,
63  const label fineLevelIndex,
64  const label coarseComm
65 )
66 :
68  (
69  index,
70  coarseInterfaces
71  ),
72  neighbPatchID_
73  (
74  refCast<const cyclicAMILduInterface>(fineInterface).neighbPatchID()
75  ),
76  owner_
77  (
78  refCast<const cyclicAMILduInterface>(fineInterface).owner()
79  ),
80  forwardT_
81  (
82  refCast<const cyclicAMILduInterface>(fineInterface).forwardT()
83  ),
84  reverseT_
85  (
86  refCast<const cyclicAMILduInterface>(fineInterface).reverseT()
87  ),
88  myProcNo_(-1)
89 {
90  const auto& fineCyclicAMIInterface =
91  refCast<const cyclicAMILduInterface>(fineInterface);
92 
93  // Construct face agglomeration from cell agglomeration
94  {
95  // From coarse face to cell
96  DynamicList<label> dynFaceCells(localRestrictAddressing.size());
97 
98  // From face to coarse face
99  DynamicList<label> dynFaceRestrictAddressing
100  (
101  localRestrictAddressing.size()
102  );
103 
104  Map<label> masterToCoarseFace(localRestrictAddressing.size());
105 
106  for (const label curMaster : localRestrictAddressing)
107  {
108  const auto iter = masterToCoarseFace.cfind(curMaster);
109 
110  if (iter.good())
111  {
112  // Already have coarse face
113  dynFaceRestrictAddressing.append(iter.val());
114  }
115  else
116  {
117  // New coarse face
118  const label coarseI = dynFaceCells.size();
119  dynFaceRestrictAddressing.append(coarseI);
120  dynFaceCells.append(curMaster);
121  masterToCoarseFace.insert(curMaster, coarseI);
122  }
123  }
124 
125  faceCells_.transfer(dynFaceCells);
126  faceRestrictAddressing_.transfer(dynFaceRestrictAddressing);
127  }
128 
129 
130  // On the owner side construct the AMI
131 
132  if (fineCyclicAMIInterface.owner())
133  {
134  // Construct the neighbour side agglomeration (as the neighbour would
135  // do it so it the exact loop above using neighbourRestrictAddressing
136  // instead of localRestrictAddressing)
137 
138  labelList nbrFaceRestrictAddressing;
139  {
140  // From face to coarse face
141  DynamicList<label> dynNbrFaceRestrictAddressing
142  (
143  neighbourRestrictAddressing.size()
144  );
145 
146  Map<label> masterToCoarseFace(neighbourRestrictAddressing.size());
147 
148  for (const label curMaster : neighbourRestrictAddressing)
149  {
150  const auto iter = masterToCoarseFace.cfind(curMaster);
151 
152  if (iter.good())
153  {
154  // Already have coarse face
155  dynNbrFaceRestrictAddressing.append(iter.val());
156  }
157  else
158  {
159  // New coarse face
160  const label coarseI = masterToCoarseFace.size();
161  dynNbrFaceRestrictAddressing.append(coarseI);
162  masterToCoarseFace.insert(curMaster, coarseI);
163  }
164  }
165 
166  nbrFaceRestrictAddressing.transfer(dynNbrFaceRestrictAddressing);
167  }
168 
169 
170  amiPtr_.reset
171  (
173  (
174  fineCyclicAMIInterface.AMI(),
176  nbrFaceRestrictAddressing
177  )
178  );
179 
180 
181  const auto& AMI = amiPtr_();
182 
183  if (debug & 2 && AMI.comm() != -1)
184  {
185  const auto oldWarnComm = UPstream::commWarn(AMI.comm());
186 
187  const label myRank = UPstream::myProcNo(AMI.comm());
188  Pout<< "At level:" << fineLevelIndex
189  << " agglomerating from ownsize:"
190  << fineInterface.faceCells().size()
191  << " nbrSize:" << neighbourRestrictAddressing.size()
192  << " down to ownsize:" << AMI.srcAddress().size()
193  << " nbrsize:" << AMI.tgtAddress().size()
194  << " Patch:" << index << " comm:" << AMI.comm()
195  << " nProcs:" << UPstream::nProcs(AMI.comm())
196  << " myRank:" << myRank << " agglomerated AMI:"
197  << endl;
198 
199  const label nbrSize = AMI.tgtAddress().size();
200  // From from nbr to owner side
201  {
202  Pout<< "From nbr:" << nbrSize << " to owner:" << this->size()
203  << endl;
204 
205  const auto& addresses = AMI.srcAddress();
206  const auto& weights = AMI.srcWeights();
207 
208  labelList globalIDs(identity(nbrSize));
209  if (AMI.distributed() && AMI.comm() != -1)
210  {
211  const auto& map = AMI.tgtMap();
212  forAll(map.subMap(), proci)
213  {
214  Pout<< " TGTMap: sending to rank:" << proci
215  << " elements:" << flatOutput(map.subMap()[proci])
216  << endl;
217  }
218  forAll(map.constructMap(), proci)
219  {
220  Pout<< " TGTMap: receiving from rank:" << proci
221  << " elements:"
222  << flatOutput(map.constructMap()[proci])
223  << endl;
224  }
225  // Fetch remote global IDs
226  const globalIndex globalFaces(nbrSize, AMI.comm());
227  Pout<< " localNbrSize:" << nbrSize
228  << " globalSize:" << globalFaces.totalSize() << endl;
229 
230  //const label myOffset = globalFaces.offsets()[myRank];
231  for (label& id : globalIDs)
232  {
233  id = globalFaces.toGlobal(myRank, id);
234  }
235  map.distribute(globalIDs);
236  }
237 
238  // Renumber my slots so they are now global face numbers
239  forAll(addresses, facei)
240  {
241  Pout<< " source face:" << facei
242  << " have weights:"
243  << flatOutput(weights[facei])
244  << " from slots:" << flatOutput(addresses[facei])
245  << " from global tgt faces:"
246  << UIndirectList<label>(globalIDs, addresses[facei])
247  << endl;
248  }
249  }
250  // From from owner to nbr side
251  {
252  Pout<< "From owner:" << this->size() << " to nbr:" << nbrSize
253  << endl;
254 
255  const auto& addresses = AMI.tgtAddress();
256  const auto& weights = AMI.tgtWeights();
257 
258  labelList globalIDs(identity(this->size()));
259  if (AMI.distributed() && AMI.comm() != -1)
260  {
261  const auto& map = AMI.srcMap();
262  forAll(map.subMap(), proci)
263  {
264  Pout<< " SRCMap: sending to rank:" << proci
265  << " elements:" << flatOutput(map.subMap()[proci])
266  << endl;
267  }
268  forAll(map.constructMap(), proci)
269  {
270  Pout<< " SRCMap: receiving from rank:" << proci
271  << " elements:"
272  << flatOutput(map.constructMap()[proci])
273  << endl;
274  }
275  // Fetch remote global IDs
276  const globalIndex globalFaces(this->size(), AMI.comm());
277  Pout<< " localSize:" << this->size()
278  << " globalSize:" << globalFaces.totalSize() << endl;
279 
280  for (label& id : globalIDs)
281  {
282  id = globalFaces.toGlobal(myRank, id);
283  }
284  map.distribute(globalIDs);
285  }
286 
287  // Renumber my slots so they are now global face numbers
288  forAll(addresses, facei)
289  {
290  Pout<< " target face:" << facei
291  << " have weights:"
292  << flatOutput(weights[facei])
293  << " from slots:" << flatOutput(addresses[facei])
294  << " from global src faces:"
295  << UIndirectList<label>(globalIDs, addresses[facei])
296  << endl;
297  }
298  }
299  Pout<< "DONE agglomerating at level:" << fineLevelIndex << endl;
300 
301  UPstream::commWarn(oldWarnComm);
302  }
303  }
304 }
305 
306 
307 Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface
308 (
309  const label index,
310  const lduInterfacePtrsList& coarseInterfaces,
311  Istream& is
312 )
313 :
314  GAMGInterface(index, coarseInterfaces, is),
315  neighbPatchID_(readLabel(is)),
316  owner_(readBool(is)),
317  forwardT_(is),
318  reverseT_(is),
319  myProcNo_(-1)
320 {
321  const bool hasAMI(readBool(is));
322 
323  if (hasAMI)
324  {
325  amiPtr_.reset(new AMIPatchToPatchInterpolation(is));
326 
327  // Store originating ranks locally - used when processor agglomerating
328  // onto a processor that wasn't in the communicator originally (since
329  // it had no faces)
330  const label comm = AMI().comm();
331 
332  if (comm != -1)
333  {
334  is >> myProcNo_;
335  }
336  }
337 }
338 
339 
340 Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface
341 (
342  const label index,
343  const lduInterfacePtrsList& coarseInterfaces,
344  const lduInterface& fineInterface,
345  const labelList& interfaceMap,
346  const labelUList& faceCells,
347  const labelUList& faceRestrictAddresssing,
348  const labelUList& faceOffsets,
349  const lduInterfacePtrsList& allInterfaces,
350  const label coarseComm,
351  const label myProcNo,
352  const labelList& procAgglomMap
353 )
354 :
355  GAMGInterface
356  (
357  index,
358  coarseInterfaces,
359  faceCells,
360  faceRestrictAddresssing
361  ),
362  neighbPatchID_
363  (
364  interfaceMap.find
365  (
366  refCast
367  <
368  const cyclicAMILduInterface
369  >(fineInterface).neighbPatchID()
370  )
371  ),
372  owner_
373  (
374  refCast<const cyclicAMILduInterface>(fineInterface).owner()
375  ),
376  forwardT_
377  (
378  refCast<const cyclicAMILduInterface>(fineInterface).forwardT()
379  ),
380  reverseT_
381  (
382  refCast<const cyclicAMILduInterface>(fineInterface).reverseT()
383  ),
384  myProcNo_(-1)
385 {
386  if (!owner_)
387  {
388  return;
389  }
390 
391 
392  // Get stats, sizes from the input interfaces. For the global settings
393  // the problem is that the
394  // local processor might not have any valid interfaces so here just
395  // collect and do a global reduction afterwards.
396 
397  // Structure to pack all. First element is used to decide who has the
398  // valid AMI.
399  typedef
400  Tuple2
401  <
402  label,
403  Tuple2
404  <
405  Tuple2
406  <
407  FixedList<bool, 4>,
408  scalar
409  >,
410  label
411  >
412  > AMIType;
413 
414  AMIType globalInfo;
415  FixedList<bool, 4>& bools = globalInfo.second().first().first();
416 
417  // Define aliases to make our life easier
418  label& firstValidAMI = globalInfo.first();
419  bool& requireMatch = bools[0];
420  bool& reverseTarget = bools[1];
421  bool& srcHasFlip = bools[2];
422  bool& tgtHasFlip = bools[3];
423  scalar& lowWeightCorrection = globalInfo.second().first().second();
424  label& singlePatchProc = globalInfo.second().second();
425 
426  // Initialise all global variables
427  firstValidAMI = labelMax;
428  requireMatch = false;
429  reverseTarget = false;
430  srcHasFlip = false;
431  tgtHasFlip = false;
432  lowWeightCorrection = -1;
433  singlePatchProc = -1;
434 
435  // Initialise all local variables
436  bool hasSrcMagSf = false;
437  bool hasSrcCentroids = false;
438  bool hasTgtMagSf = false;
439  label nSrc = 0;
440  label nTgt = 0;
441 
442  forAll(allInterfaces, inti)
443  {
444  if (allInterfaces.set(inti))
445  {
446  const auto& intf =
447  refCast<const cyclicAMIGAMGInterface>(allInterfaces[inti]);
448 
449  if (!intf.amiPtr_)
450  {
451  continue;
452  }
453 
454  if (firstValidAMI == labelMax)
455  {
456  firstValidAMI = inti;
457  }
458 
459  const auto& AMI = intf.AMI();
460 
461  if (AMI.distributed() && AMI.comm() != -1)
462  {
463  singlePatchProc = -1;
464  srcHasFlip =
465  srcHasFlip || AMI.srcMap().constructHasFlip();
466  tgtHasFlip =
467  tgtHasFlip || AMI.tgtMap().constructHasFlip();
468  }
469  requireMatch = AMI.requireMatch();
470  reverseTarget = AMI.reverseTarget();
471  lowWeightCorrection = AMI.lowWeightCorrection();
472 
473  nSrc += AMI.srcAddress().size();
474  nTgt += AMI.tgtAddress().size();
475 
476  if (AMI.srcMagSf().size())
477  {
478  hasSrcMagSf = true;
479  if (AMI.srcMagSf().size() != AMI.srcAddress().size())
480  {
482  << "srcMagSf size:" << AMI.srcMagSf().size()
483  << "srcAddress size:" << AMI.srcAddress().size()
484  << exit(FatalError);
485  }
486  }
487  if (AMI.srcCentroids().size())
488  {
489  hasSrcCentroids = true;
490  if (AMI.srcCentroids().size() != AMI.srcAddress().size())
491  {
493  << "srcCentroids size:" << AMI.srcCentroids().size()
494  << "srcAddress size:" << AMI.srcAddress().size()
495  << exit(FatalError);
496  }
497  }
498  if (AMI.tgtMagSf().size())
499  {
500  hasTgtMagSf = true;
501  if (AMI.tgtMagSf().size() != AMI.tgtAddress().size())
502  {
504  << "tgtMagSf size:" << AMI.tgtMagSf().size()
505  << "tgtAddress size:" << AMI.tgtAddress().size()
506  << exit(FatalError);
507  }
508  }
509  }
510  }
511 
512 
513  // Reduce global information in case one of the coarse ranks does not
514  // have an input AMI to get data from. Could use minFirstEqOp from Tuple2
515  // instead ...
517  (
518  globalInfo,
519  [](AMIType& x, const AMIType& y)
520  {
521  if (y.first() < x.first())
522  {
523  x = y;
524  }
525  },
527  coarseComm
528  );
529 
530  DebugPout
531  << "Input amis :"
532  << " singlePatchProc:" << singlePatchProc
533  << " srcHasFlip:" << srcHasFlip
534  << " tgtHasFlip:" << tgtHasFlip
535  << " requireMatch:" << requireMatch
536  << " reverseTarget:" << reverseTarget
537  << " lowWeightCorrection:" << lowWeightCorrection
538  << " hasSrcMagSf:" << hasSrcMagSf
539  << " hasSrcCentroids:" << hasSrcCentroids
540  << " hasTgtMagSf:" << hasTgtMagSf
541  << " nSrc:" << nSrc
542  << " nTgt:" << nTgt
543  << endl;
544 
545 
546  labelListList srcAddress;
547  scalarListList srcWeights;
548  scalarList srcMagSf;
549  // Needed?
550  pointListList srcCentroids;
551 
552  labelListList tgtAddress;
553  scalarListList tgtWeights;
554  scalarList tgtMagSf;
555 
556 
557  // Map to send src side data to tgt side
558  autoPtr<mapDistribute> srcToTgtMap;
559 
560  // Map to send tgt side data to src side
561  autoPtr<mapDistribute> tgtToSrcMap;
562 
563  if (singlePatchProc == -1)
564  {
565  // Find ranks that agglomerate together
566  const label myAgglom = UPstream::myProcNo(coarseComm);
567 
568  // Per input map either -1 or the index in the maps that is local
569  // data.
570  labelList localRanks(allInterfaces.size(), -1);
571  // From rank in coarse communicator back to rank in original (fine)
572  // communicator.
573  labelListList newToOldRanks;
574  {
575  // Pass 1: count number of valid maps
576  label nOldRanks = 0;
577  forAll(allInterfaces, inti)
578  {
579  if (allInterfaces.set(inti))
580  {
581  const auto& intf = refCast<const cyclicAMIGAMGInterface>
582  (
583  allInterfaces[inti]
584  );
585 
586  if (!intf.amiPtr_ || intf.AMI().comm() == -1)
587  {
588  continue;
589  }
590  nOldRanks++;
591  }
592  }
593 
594  // Pass 2: collect
595  DynamicList<label> oldRanks(nOldRanks);
596  forAll(allInterfaces, inti)
597  {
598  if (allInterfaces.set(inti))
599  {
600  const auto& intf = refCast<const cyclicAMIGAMGInterface>
601  (
602  allInterfaces[inti]
603  );
604 
605  if (!intf.amiPtr_ || intf.AMI().comm() == -1)
606  {
607  continue;
608  }
609 
610  label fineRank = -1;
611  if (intf.myProcNo() == -1)
612  {
613  // The interface was already local so got never
614  // sent across so myProcNo_ is never set ...
615  fineRank = UPstream::myProcNo(intf.AMI().comm());
616  }
617  else
618  {
619  fineRank = intf.myProcNo();
620  }
621 
622  oldRanks.append(fineRank);
623  localRanks[inti] = fineRank;
624  }
625  }
626 
627  // Pull individual parts together - this is the only communication
628  // needed.
629  newToOldRanks = Pstream::listGatherValues
630  (
631  labelList(std::move(oldRanks)),
632  coarseComm
633  );
634  Pstream::broadcast(newToOldRanks, coarseComm);
635  }
636 
637 
638  // Create combined maps
639  UPtrList<const mapDistribute> srcMaps(allInterfaces.size());
640  UPtrList<const mapDistribute> tgtMaps(allInterfaces.size());
641  forAll(allInterfaces, inti)
642  {
643  if (allInterfaces.set(inti))
644  {
645  const auto& intf = refCast<const cyclicAMIGAMGInterface>
646  (
647  allInterfaces[inti]
648  );
649 
650  if (!intf.amiPtr_)
651  {
652  // Should not be in allInterfaces?
653  continue;
654  }
655 
656  const auto& AMI = intf.AMI();
657 
658  if (AMI.comm() != -1)
659  {
660  srcMaps.set(inti, &AMI.srcMap());
661  tgtMaps.set(inti, &AMI.tgtMap());
662  }
663  }
664  }
665 
666 
667  // Offsets for slots into results of srcToTgtMap
668  labelList srcStartOfLocal;
669  List<Map<label>> srcCompactMaps;
670 
671  srcToTgtMap.reset
672  (
673  new mapDistribute
674  (
675  srcMaps,
676  localRanks, // per src map which rank represents local data
677  coarseComm,
678  newToOldRanks, // destination rank to source ranks
679  srcStartOfLocal,
680  srcCompactMaps
681  )
682  );
683 
684 
685  // Assemble tgtAddress
686  tgtAddress.setSize(nTgt);
687  if (tgtAddress.size())
688  {
689  label alli = 0;
690  forAll(allInterfaces, inti)
691  {
692  if (allInterfaces.set(inti))
693  {
694  const auto& intf = refCast<const cyclicAMIGAMGInterface>
695  (
696  allInterfaces[inti]
697  );
698 
699  if (!intf.amiPtr_)
700  {
701  continue;
702  }
703 
704  const auto& AMI = intf.AMI();
705  const auto& tgtSlots = AMI.tgtAddress();
706  const label localSize =
707  srcStartOfLocal[inti+1]
708  - srcStartOfLocal[inti];
709 
710  forAll(tgtSlots, tgti)
711  {
712  // Append old slots: copy old values and adapt
713  auto& newSlots = tgtAddress[alli++];
714  newSlots = tgtSlots[tgti];
715 
716  // Renumber to new indices
718  (
719  newSlots,
720  localSize,
721  srcStartOfLocal[inti],
722  srcCompactMaps[inti],
723  srcHasFlip //hasFlip
724  );
725 
726  for (const label slot : newSlots)
727  {
728  if
729  (
730  slot < 0
731  || slot >= srcToTgtMap().constructSize()
732  )
733  {
734  FatalErrorInFunction << " newSlots:"
735  << newSlots << exit(FatalError);
736  }
737  }
738  }
739  }
740  }
741 
742  if (nTgt != alli)
743  {
744  FatalErrorInFunction << "nTgt:" << nTgt
745  << " alli:" << alli << exit(FatalError);
746  }
747  }
748 
749  // Offsets for slots into results of tgtToSrcMap
750  labelList tgtStartOfLocal;
751  List<Map<label>> tgtCompactMaps;
752 
753  tgtToSrcMap.reset
754  (
755  new mapDistribute
756  (
757  tgtMaps,
758  localRanks,
759  coarseComm,
760  newToOldRanks,
761  tgtStartOfLocal,
762  tgtCompactMaps
763  )
764  );
765 
766 
767  // Assemble srcAddress
768  srcAddress.setSize(nSrc);
769  if (srcAddress.size())
770  {
771  label alli = 0;
772  forAll(allInterfaces, inti)
773  {
774  if (allInterfaces.set(inti))
775  {
776  const auto& intf = refCast<const cyclicAMIGAMGInterface>
777  (
778  allInterfaces[inti]
779  );
780 
781  if (!intf.amiPtr_)
782  {
783  continue;
784  }
785 
786  const auto& AMI = intf.AMI();
787  const auto& srcSlots = AMI.srcAddress();
788  const label localSize =
789  tgtStartOfLocal[inti+1]
790  - tgtStartOfLocal[inti];
791 
792  forAll(srcSlots, srci)
793  {
794  // Append old slots: copy old values and adapt
795  auto& newSlots = srcAddress[alli++];
796  newSlots = srcSlots[srci];
797  // Renumber to new indices
799  (
800  newSlots,
801  localSize,
802  tgtStartOfLocal[inti],
803  tgtCompactMaps[inti],
804  tgtHasFlip
805  );
806 
807  for (const label slot : newSlots)
808  {
809  if
810  (
811  slot < 0
812  || slot >= tgtToSrcMap().constructSize()
813  )
814  {
815  FatalErrorInFunction << " newSlots:"
816  << newSlots << exit(FatalError);
817  }
818  }
819  }
820  }
821  }
822 
823  if (nSrc != alli)
824  {
825  FatalErrorInFunction << "nSrc:" << nSrc
826  << " alli:" << alli << exit(FatalError);
827  }
828  }
829 
830 
831  // Clean up: if no remote elements sent/received mark as
832  // non-distributed. We could do this at the start but this
833  // needs to take all the internal transport into account. Easier
834  // (but less efficient) to do afterwards now all is compacted.
835  {
836  const auto& map = srcToTgtMap().subMap();
837 
838  bool usesRemote = false;
839  forAll(map, proci)
840  {
841  if (proci != myAgglom)
842  {
843  const auto& ss = srcToTgtMap().subMap()[proci];
844  const auto& sc = srcToTgtMap().constructMap()[proci];
845  const auto& ts = tgtToSrcMap().subMap()[proci];
846  const auto& tc = tgtToSrcMap().constructMap()[proci];
847 
848  if (ss.size() || sc.size() || ts.size() || tc.size())
849  {
850  usesRemote = true;
851  break;
852  }
853  }
854  }
855 
856  // We can't have a single rank become fully-local since we
857  // expect singlePatchProc to be synchronised. So make sure all
858  // have become local
859 
860  if (!returnReduceOr(usesRemote, coarseComm))
861  {
862  DebugPout<< "** making fully local on new rank "
863  << myAgglom << " in comm:" << coarseComm << endl;
864  singlePatchProc = myAgglom;
865  srcToTgtMap.clear();
866  tgtToSrcMap.clear();
867  }
868  }
869  }
870  else
871  {
872  // src/tgt address are straight indices
873 
874  srcAddress.setSize(nSrc);
875  tgtAddress.setSize(nTgt);
876 
877  nSrc = 0;
878  nTgt = 0;
879  forAll(allInterfaces, inti)
880  {
881  if (allInterfaces.set(inti))
882  {
883  const auto& intf = refCast<const cyclicAMIGAMGInterface>
884  (
885  allInterfaces[inti]
886  );
887 
888  if (!intf.amiPtr_)
889  {
890  continue;
891  }
892 
893  const auto& AMI = intf.AMI();
894 
895  const auto& srcA = AMI.srcAddress();
896  if (srcAddress.size())
897  {
898  label srci = nSrc;
899  forAll(srcA, i)
900  {
901  srcAddress[srci++] = srcA[i]+nTgt;
902  }
903  }
904 
905  const auto& tgtA = AMI.tgtAddress();
906  if (tgtAddress.size())
907  {
908  label tgti = nTgt;
909  forAll(tgtA, i)
910  {
911  tgtAddress[tgti++] = tgtA[i]+nSrc;
912  }
913  }
914 
915  nSrc += srcA.size();
916  nTgt += tgtA.size();
917  }
918  }
919  }
920 
921  srcWeights.setSize(nSrc);
922  if (hasSrcMagSf)
923  {
924  srcMagSf.setSize(nSrc);
925  }
926  if (hasSrcCentroids)
927  {
928  srcCentroids.setSize(nSrc);
929  }
930  tgtWeights.setSize(nTgt);
931  if (hasTgtMagSf)
932  {
933  tgtMagSf.setSize(nTgt);
934  }
935 
936 
937  // Append individual data
938  nSrc = 0;
939  nTgt = 0;
940  forAll(allInterfaces, inti)
941  {
942  if (allInterfaces.set(inti))
943  {
944  const auto& intf = refCast<const cyclicAMIGAMGInterface>
945  (
946  allInterfaces[inti]
947  );
948 
949  if (!intf.amiPtr_)
950  {
951  continue;
952  }
953 
954  const auto& AMI = intf.AMI();
955 
956  const auto& srcA = AMI.srcAddress();
957  {
958  // weights
959  SubList<scalarList>(srcWeights, srcA.size(), nSrc) =
960  AMI.srcWeights();
961 
962  // magSf
963  if (hasSrcMagSf)
964  {
965  SubList<scalar>(srcMagSf, srcA.size(), nSrc) =
966  AMI.srcMagSf();
967  }
968 
969  // centroids
970  if (hasSrcCentroids)
971  {
972  SubList<pointList>(srcCentroids, srcA.size(), nSrc) =
973  AMI.srcCentroids();
974  }
975  }
976 
977  const auto& tgtA = AMI.tgtAddress();
978  {
979  // weights
980  SubList<scalarList>(tgtWeights, tgtA.size(), nTgt) =
981  AMI.tgtWeights();
982 
983  if (hasTgtMagSf)
984  {
985  SubList<scalar>(tgtMagSf, tgtA.size(), nTgt) =
986  AMI.tgtMagSf();
987  }
988  }
989 
990  nSrc += srcA.size();
991  nTgt += tgtA.size();
992  }
993  }
994 
995 
996  // Construct with same arguments as original
997  amiPtr_.reset
998  (
1000  (
1001  requireMatch,
1002  reverseTarget,
1003  lowWeightCorrection
1004  )
1005  );
1006  amiPtr_().comm(coarseComm),
1007  amiPtr_().reset
1008  (
1009  std::move(srcToTgtMap),
1010  std::move(tgtToSrcMap),
1011  std::move(srcAddress),
1012  std::move(srcWeights),
1013  std::move(tgtAddress),
1014  std::move(tgtWeights),
1015  singlePatchProc
1016  );
1017  amiPtr_().srcMagSf() = std::move(srcMagSf);
1018  amiPtr_().srcCentroids() = std::move(srcCentroids);
1019  amiPtr_().tgtMagSf() = std::move(tgtMagSf);
1020 
1021 
1022  if (debug & 2)
1023  {
1024  const auto& AMI = amiPtr_();
1025 
1026  const auto oldWarnComm = UPstream::commWarn(AMI.comm());
1027 
1028  const label myRank = UPstream::myProcNo(AMI.comm());
1029  Pout<< "PROCAGGLOMERATED :"
1030  << " Patch:" << index << " comm:" << AMI.comm()
1031  << " nProcs:" << UPstream::nProcs(AMI.comm())
1032  << " myRank:" << myRank << " agglomerated AMI:"
1033  << endl;
1034 
1035  const label nbrSize = AMI.tgtAddress().size();
1036  // From from nbr to owner side
1037  {
1038  Pout<< "From nbr:" << nbrSize << " to owner:" << this->size()
1039  << endl;
1040 
1041  const auto& addresses = AMI.srcAddress();
1042  const auto& weights = AMI.srcWeights();
1043 
1044  labelList globalIDs(identity(nbrSize));
1045  if (AMI.distributed() && AMI.comm() != -1)
1046  {
1047  const auto& map = AMI.tgtMap();
1048  forAll(map.subMap(), proci)
1049  {
1050  Pout<< " TGTMap: sending to rank:" << proci
1051  << " elements:" << flatOutput(map.subMap()[proci])
1052  << endl;
1053  }
1054  forAll(map.constructMap(), proci)
1055  {
1056  Pout<< " TGTMap: receiving from rank:" << proci
1057  << " elements:"
1058  << flatOutput(map.constructMap()[proci])
1059  << endl;
1060  }
1061 
1062  // Fetch remote global IDs
1063  const globalIndex globalFaces(nbrSize, AMI.comm());
1064  Pout<< " localNbrSize:" << nbrSize
1065  << " globalSize:" << globalFaces.totalSize() << endl;
1066  for (label& id : globalIDs)
1067  {
1068  id = globalFaces.toGlobal(myRank, id);
1069  }
1070  map.distribute(globalIDs);
1071  }
1072 
1073  // Renumber my slots so they are now global face numbers
1074  forAll(addresses, facei)
1075  {
1076  Pout<< " source face:" << facei
1077  << " have weights:"
1078  << flatOutput(weights[facei])
1079  << " from slots:" << flatOutput(addresses[facei])
1080  << " from global tgt faces:"
1081  << UIndirectList<label>(globalIDs, addresses[facei])
1082  << endl;
1083  }
1084  UPstream::commWarn(oldWarnComm);
1085  }
1086  // From from owner to nbr side
1087  {
1088  Pout<< "From owner:" << this->size() << " to nbr:" << nbrSize
1089  << endl;
1090 
1091  const auto& addresses = AMI.tgtAddress();
1092  const auto& weights = AMI.tgtWeights();
1093 
1094  labelList globalIDs(identity(this->size()));
1095  if (AMI.distributed() && AMI.comm() != -1)
1096  {
1097  const auto& map = AMI.srcMap();
1098  forAll(map.subMap(), proci)
1099  {
1100  Pout<< " SRCMap: sending to rank:" << proci
1101  << " elements:" << flatOutput(map.subMap()[proci])
1102  << endl;
1103  }
1104  forAll(map.constructMap(), proci)
1105  {
1106  Pout<< " SRCMap: receiving from rank:" << proci
1107  << " elements:"
1108  << flatOutput(map.constructMap()[proci])
1109  << endl;
1110  }
1111 
1112  // Fetch remote global IDs
1113  const globalIndex globalFaces(this->size(), AMI.comm());
1114  Pout<< " localSize:" << this->size()
1115  << " globalSize:" << globalFaces.totalSize() << endl;
1116  for (label& id : globalIDs)
1117  {
1118  id = globalFaces.toGlobal(myRank, id);
1119  }
1120  map.distribute(globalIDs);
1121  }
1122 
1123  // Renumber my slots so they are now global face numbers
1124  forAll(addresses, facei)
1125  {
1126  Pout<< " target face:" << facei
1127  << " have weights:"
1128  << flatOutput(weights[facei])
1129  << " from slots:" << flatOutput(addresses[facei])
1130  << " from global src faces:"
1131  << UIndirectList<label>(globalIDs, addresses[facei])
1132  << endl;
1133  }
1134  }
1135  Pout<< "DONE PROCAGGLOMERATED" << endl;
1136  UPstream::commWarn(oldWarnComm);
1137  }
1138 }
1139 
1140 
1141 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1142 
1144 (
1145  const Pstream::commsTypes commsType,
1146  const labelUList& iF
1147 ) const
1148 {
1149  const cyclicAMIGAMGInterface& nbr =
1150  dynamic_cast<const cyclicAMIGAMGInterface&>(neighbPatch());
1151  const labelUList& nbrFaceCells = nbr.faceCells();
1152 
1153  auto tpnf = tmp<labelField>::New(nbrFaceCells.size());
1154  labelField& pnf = tpnf.ref();
1155 
1156  forAll(pnf, facei)
1157  {
1158  pnf[facei] = iF[nbrFaceCells[facei]];
1159  }
1160 
1161  return tpnf;
1162 }
1163 
1164 
1165 void Foam::cyclicAMIGAMGInterface::write(Ostream& os) const
1166 {
1168 
1169  const bool hasAMI = bool(amiPtr_);
1170 
1171  os << token::SPACE << neighbPatchID_
1172  << token::SPACE << owner_
1173  << token::SPACE << forwardT_
1174  << token::SPACE << reverseT_
1175  << token::SPACE << hasAMI;
1176 
1177  if (hasAMI)
1178  {
1179  os << token::SPACE;
1180  AMI().writeData(os);
1181 
1182  // Write processors in communicator
1183  const label comm = AMI().comm();
1184 
1185  if (comm != -1)
1186  {
1187  os << token::SPACE
1188  << UPstream::myProcNo(comm);
1189  }
1190  }
1191 }
1192 
1193 
1194 // ************************************************************************* //
virtual label size() const
Return size.
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
label find(const ListType &input, const UnaryPredicate &pred, const label start=0)
Same as ListOps::find_if.
Definition: ListOps.H:840
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:48
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
const pointListList & srcCentroids() const
Return const access to source patch face centroids.
label comm() const noexcept
Communicator (local or otherwise) for parallel operations.
virtual const labelUList & faceCells() const =0
Return faceCell addressing.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
commsTypes
Communications types.
Definition: UPstream.H:77
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:337
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
const scalarListList & tgtWeights() const
Return const access to target patch weights.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
virtual tmp< labelField > internalFieldTransfer(const Pstream::commsTypes commsType, const labelUList &iF) const
Transfer and return internal field adjacent to the interface.
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:526
AMIInterpolation AMIPatchToPatchInterpolation
Patch-to-patch interpolation == Foam::AMIInterpolation.
virtual label index() const
const mapDistribute & srcMap() const
Source map - valid only if singlePatchProc = -1 This gets source data into a form to be consumed by t...
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition: typeInfo.H:172
const labelListList & tgtAddress() const
Return const access to target patch addressing.
T & first()
Access first element of the list, position [0].
Definition: UList.H:886
bool requireMatch() const noexcept
Return the requireMatch flag.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition: label.H:63
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1787
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
labelList faceRestrictAddressing_
Face restrict addressing.
Definition: GAMGInterface.H:76
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition: UPstream.H:1611
bool distributed() const noexcept
Distributed across processors (singlePatchProc == -1)
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Macros for easy insertion into run-time selection tables.
UList< label > labelUList
A UList of labels.
Definition: UList.H:76
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
static label commWarn(const label communicator) noexcept
Alter communicator debugging setting. Warns for use of any communicator differing from specified...
Definition: UPstream.H:1040
scalar y
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1602
An abstract base class for cyclic AMI coupled interfaces.
void setSize(const label n)
Alias for resize()
Definition: List.H:325
const List< scalar > & tgtMagSf() const
Return const access to target patch face areas.
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:113
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
List< scalarList > scalarListList
List of scalarList.
Definition: scalarList.H:35
Space [isspace].
Definition: token.H:131
UPtrList< const lduInterface > lduInterfacePtrsList
Store lists of lduInterface as a UPtrList.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
virtual void write(Ostream &) const
Write to stream.
List< bool > bools(const labelHashSet &locations)
Transform the on locations to a boolList, with true for each non-negative location and false for all ...
Definition: HashOps.C:72
const scalarListList & srcWeights() const
Return const access to source patch weights.
bool constructHasFlip() const noexcept
Does constructMap include a sign.
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
bool reverseTarget() const noexcept
Access to the reverseTarget flag.
const List< scalar > & srcMagSf() const
Return const access to source patch face areas.
Abstract base class for GAMG agglomerated interfaces.
Definition: GAMGInterface.H:50
virtual const AMIPatchToPatchInterpolation & AMI() const
static void combineReduce(T &value, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) applying cop to inplace combine value from different processors...
virtual void write(Ostream &) const =0
Write to stream.
An abstract base class for implicitly-coupled interfaces e.g. processor and cyclic patches...
Definition: lduInterface.H:53
#define DebugPout
Report an information message using Foam::Pout.
static List< T > listGatherValues(const T &localValue, const int communicator=UPstream::worldComm, const int tag=UPstream::msgType())
Gather individual values into list locations.
constexpr label labelMax
Definition: label.H:55
labelList faceCells_
Face-cell addressing.
Definition: GAMGInterface.H:71
List< label > labelList
A List of labels.
Definition: List.H:61
const mapDistribute & tgtMap() const
Target map - valid only if singlePatchProc=-1. This gets target data into a form to be consumed by sr...
List< pointList > pointListList
List of pointList.
Definition: pointList.H:35
A class for managing temporary objects.
Definition: HashPtrTable.H:50
scalar lowWeightCorrection() const
Threshold weight below which interpolation is deactivated.
const labelListList & srcAddress() const
Return const access to source patch addressing.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
bool readBool(Istream &is)
Read bool from stream using Foam::Switch(Istream&)
Definition: bool.C:62
Namespace for OpenFOAM.
static label renumberMap(labelListList &mapElements, const labelUList &oldToNew, const bool hasFlip)
Helper for renumbering the (compacted) map elements using the supplied old-to-new mapping...
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225