AMIInterpolation.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) 2015-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 "meshTools.H"
31 #include "mapDistribute.H"
32 #include "flipOp.H"
33 #include "profiling.H"
34 #include "triangle.H"
35 #include "OFstream.H"
36 #include "registerSwitch.H"
37 #include "ListOps.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43  defineTypeNameAndDebug(AMIInterpolation, 0);
44  defineRunTimeSelectionTable(AMIInterpolation, dict);
45  defineRunTimeSelectionTable(AMIInterpolation, component);
46 }
47 
49 
51 (
52  debug::optimisationSwitch("localAMIComm", 1)
53 );
55 (
56  "localAMIComm",
57  int,
59 );
60 
61 
62 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
63 
66 (
67  const primitivePatch& patch
68 ) const
69 {
70  treeBoundBox bb(patch.points(), patch.meshPoints());
71  bb.inflate(0.01);
72 
74  (
75  treeType
76  (
77  false,
78  patch,
80  ),
81  bb, // overall search domain
82  8, // maxLevel
83  10, // leaf size
84  3.0 // duplicity
85  );
86 }
87 
88 
90 (
91  const primitivePatch& srcPatch,
92  const primitivePatch& tgtPatch,
93  const label comm,
95 ) const
96 {
97  // Either not parallel or no faces on any processor
98  label proci = 0;
99 
100  if (UPstream::parRun())
101  {
102  // Involved in communication pattern?
103  bool inCommGroup = (srcPatch.size() > 0 || tgtPatch.size() > 0);
104 
105  // Track which procs are involved
106  const List<bool> hasFaces
107  (
108  UPstream::allGatherValues<bool>(inCommGroup, comm)
109  );
110 
111  // Always include master (0) in comm-group?
112  // - so messages come from master
113  if (useLocalComm_ > 1 && UPstream::master(comm))
114  {
115  inCommGroup = true;
116  }
117 
118  // Number of communicating procs (ie, they have local faces)
119  label nCommProcs(0);
120 
121  // First proc with local faces (when nCommProcs == 1)
122  label whichProci(-1);
123 
124  // Could use UPstream::splitCommunicator(), but that also incurs
125  // global communication to determine who belongs to the same set.
126  // Instead, an Allgather of the members and compare with the
127  // existing communicator to decide if a new communicator is
128  // required.
129 
130  DynamicList<label> subProcs(hasFaces.size());
131  forAll(hasFaces, i)
132  {
133  if (hasFaces.test(i))
134  {
135  whichProci = i;
136  ++nCommProcs;
137  subProcs.push_back(i);
138  }
139  else if
140  (
141  inCommGroup
142  && (useLocalComm_ > 1) && (i == UPstream::masterNo())
143  )
144  {
145  // Also include master (0) in comm-group?
146  // - so messages come from master
147  subProcs.push_back(UPstream::masterNo());
148  }
149  }
150 
151  //
152  // Define the AMI communication style
153  //
154 
155  if (nCommProcs == 0)
156  {
157  // Probably does not happen. No AMI faces? => no communicator
158  geomComm.reset();
159  }
160  else if (nCommProcs == 1)
161  {
162  proci = whichProci;
163 
164  // No local communicator needed
165  geomComm.reset();
166 
168  << "AMI local to processor" << proci << endl;
169  }
170  else // (nCommProcs > 1)
171  {
172  proci = -1;
173 
174  const label currComm = (geomComm.good() ? geomComm().comm() : -1);
175 
176  if (useLocalComm_ == 0)
177  {
178  // Backwards compatible : no local communicator
179  geomComm.reset();
180  }
181  else if (nCommProcs == subProcs.size())
182  {
183  // Everyone is involved : no local communicator
184  geomComm.reset();
185  }
186  else if (inCommGroup)
187  {
188  if
189  (
190  currComm >= 0
191  && ListOps::equal(subProcs, UPstream::procID(currComm))
192  )
193  {
194  // Keep geomComm
195  if (debug)
196  {
197  Pout<< "Retained geomComm:" << currComm
198  << " with " << subProcs.size()
199  << " processors out of " << UPstream::nProcs(comm)
200  << endl;
201  }
202  }
203  else
204  {
205  geomComm.reset(new UPstream::communicator(comm, subProcs));
206  if (debug)
207  {
208  Pout<< "Allocated geomComm:" << geomComm().comm()
209  << " from " << subProcs.size()
210  << " processors out of " << UPstream::nProcs(comm)
211  << endl;
212  }
213  }
214  }
215  else
216  {
217  // Not inCommGroup, but with local communicator elsewhere
218  geomComm.reset(new UPstream::communicator());
219  if (debug & 2)
220  {
221  Pout<< "Allocated dummy geomComm:" << geomComm().comm()
222  << " src-size:" << srcPatch.size()
223  << " tgt-size:" << tgtPatch.size() << endl;
224  }
225  }
226  }
227 
229  << "AMI split across multiple processors "
230  << flatOutput(subProcs) << endl;
231  }
232 
233  return proci;
234 }
235 
236 
238 (
239  const searchableSurface& surf,
240  pointField& pts
241 ) const
242 {
243  addProfiling(ami, "AMIInterpolation::projectPointsToSurface");
244 
245  DebugInfo<< "AMI: projecting points to surface" << endl;
246 
247  List<pointIndexHit> nearInfo;
248 
249  surf.findNearest(pts, scalarField(pts.size(), GREAT), nearInfo);
250 
251  label nMiss = 0;
252  forAll(nearInfo, i)
253  {
254  const pointIndexHit& pi = nearInfo[i];
255 
256  if (pi.hit())
257  {
258  pts[i] = pi.point();
259  }
260  else
261  {
262  // Point remains unchanged
263  ++nMiss;
264  }
265  }
266 
267  if (nMiss > 0)
268  {
270  << "Error projecting points to surface: "
271  << nMiss << " faces could not be determined"
272  << abort(FatalError);
273  }
274 }
275 
276 
278 (
279  const scalarList& patchAreas,
280  const word& patchName,
281  const labelListList& addr,
282  scalarListList& wght,
283  scalarField& wghtSum,
284  const bool conformal,
285  const bool output,
286  const scalar lowWeightTol,
287  const label comm
288 )
289 {
290  addProfiling(ami, "AMIInterpolation::normaliseWeights");
291 
292  // Normalise the weights
293  wghtSum.resize_nocopy(wght.size());
294  label nLowWeight = 0;
295 
296  forAll(wght, facei)
297  {
298  scalarList& w = wght[facei];
299 
300  if (w.size())
301  {
302  scalar denom = patchAreas[facei];
303 
304  scalar s = sum(w);
305  scalar t = s/denom;
306  if (conformal)
307  {
308  denom = s;
309  }
310 
311  forAll(w, i)
312  {
313  w[i] /= denom;
314  }
315 
316  wghtSum[facei] = t;
317  if (t < lowWeightTol)
318  {
319  ++nLowWeight;
320  }
321  }
322  else
323  {
324  wghtSum[facei] = 0;
325  }
326  }
327 
328  if (output && comm != -1 && returnReduceOr(wght.size(), comm))
329  {
330  auto limits = gMinMax(wghtSum, comm);
331  auto avg = gAverage(wghtSum, comm);
332 
333  label nLow =
334  returnReduce(nLowWeight, sumOp<label>(), UPstream::msgType(), comm);
335 
336  Info.masterStream(comm)
337  << indent
338  << "AMI: Patch " << patchName
339  << " sum(weights)"
340  << " min:" << limits.min()
341  << " max:" << limits.max()
342  << " average:" << avg << nl;
343 
344  if (nLow)
345  {
346  Info.masterStream(comm)
347  << indent
348  << "AMI: Patch " << patchName
349  << " identified " << nLow
350  << " faces with weights less than " << lowWeightTol
351  << endl;
352  }
353  }
354 }
355 
356 
358 (
359  const autoPtr<mapDistribute>& targetMapPtr,
360  const scalarList& fineSrcMagSf,
361  const labelListList& fineSrcAddress,
362  const scalarListList& fineSrcWeights,
363 
364  const labelList& sourceRestrictAddressing,
365  const labelList& targetRestrictAddressing,
366 
367  scalarList& srcMagSf,
368  labelListList& srcAddress,
369  scalarListList& srcWeights,
370  scalarField& srcWeightsSum,
371  autoPtr<mapDistribute>& tgtMap,
372  const label comm
373 )
374 {
375  addProfiling(ami, "AMIInterpolation::agglomerate");
376 
377  const label sourceCoarseSize =
378  (
379  sourceRestrictAddressing.size()
380  ? max(sourceRestrictAddressing)+1
381  : 0
382  );
383 
384  const label targetCoarseSize =
385  (
386  targetRestrictAddressing.size()
387  ? max(targetRestrictAddressing)+1
388  : 0
389  );
390 
391  // Agglomerate face areas
392  {
393  //srcMagSf.setSize(sourceRestrictAddressing.size(), 0.0);
394  srcMagSf.setSize(sourceCoarseSize, 0.0);
395 
396  forAll(sourceRestrictAddressing, facei)
397  {
398  label coarseFacei = sourceRestrictAddressing[facei];
399  srcMagSf[coarseFacei] += fineSrcMagSf[facei];
400  }
401  }
402 
403  // Agglomerate weights and indices
404  if (targetMapPtr)
405  {
406  // We are involved in the communicator but our maps are still empty.
407  // Fix 'm up so they are the same size as the communicator.
408  const mapDistribute& map = *targetMapPtr;
409 
410  if (map.constructMap().empty())
411  {
412  auto& cMap = const_cast<labelListList&>(map.constructMap());
413  cMap.resize_nocopy(UPstream::nProcs(map.comm()));
414  }
415  if (map.subMap().empty())
416  {
417  auto& cMap = const_cast<labelListList&>(map.subMap());
418  cMap.resize_nocopy(UPstream::nProcs(map.comm()));
419  }
420 
421 
422  // Get all restriction addressing.
423  labelList allRestrict(targetRestrictAddressing);
424  map.distribute(allRestrict);
425 
426  // So now we have agglomeration of the target side in
427  // allRestrict:
428  // 0..size-1 : local agglomeration (= targetRestrictAddressing
429  // (but potentially permutated))
430  // size.. : agglomeration data from other processors
431 
432 
433  // The trickiness in this algorithm is finding out the compaction
434  // of the remote data (i.e. allocation of the coarse 'slots'). We could
435  // either send across the slot compaction maps or just make sure
436  // that we allocate the slots in exactly the same order on both sending
437  // and receiving side (e.g. if the submap is set up to send 4 items,
438  // the constructMap is also set up to receive 4 items.
439 
440 
441  // Short note about the various types of indices:
442  // - face indices : indices into the geometry.
443  // - coarse face indices : how the faces get agglomerated
444  // - transferred data : how mapDistribute sends/receives data,
445  // - slots : indices into data after distribution (e.g. stencil,
446  // srcAddress/tgtAddress). Note: for fully local addressing
447  // the slots are equal to face indices.
448  // A mapDistribute has:
449  // - a subMap : these are face indices
450  // - a constructMap : these are from 'transferred-data' to slots
451 
452  labelListList tgtSubMap(Pstream::nProcs(comm));
453 
454  // Local subMap is just identity
455  {
456  tgtSubMap[Pstream::myProcNo(comm)] = identity(targetCoarseSize);
457  }
458 
459  forAll(map.subMap(), proci)
460  {
461  if (proci != Pstream::myProcNo(comm))
462  {
463  // Combine entries that point to the same coarse element.
464  // The important bit is to loop over the data (and hand out
465  // compact indices ) in 'transferred data' order. This
466  // guarantees that we're doing exactly the
467  // same on sending and receiving side - e.g. the fourth element
468  // in the subMap is the fourth element received in the
469  // constructMap
470 
471  const labelList& elems = map.subMap()[proci];
472  const labelList& elemsMap =
473  map.constructMap()[Pstream::myProcNo(comm)];
474  labelList& newSubMap = tgtSubMap[proci];
475  newSubMap.resize_nocopy(elems.size());
476 
477  labelList oldToNew(targetCoarseSize, -1);
478  label newi = 0;
479 
480  for (const label elemi : elems)
481  {
482  label fineElem = elemsMap[elemi];
483  label coarseElem = allRestrict[fineElem];
484  if (oldToNew[coarseElem] == -1)
485  {
486  oldToNew[coarseElem] = newi;
487  newSubMap[newi] = coarseElem;
488  ++newi;
489  }
490  }
491  newSubMap.resize(newi);
492  }
493  }
494 
495  // Reconstruct constructMap by combining entries. Note that order
496  // of handing out indices should be the same as loop above to compact
497  // the sending map
498 
499  labelListList tgtConstructMap(Pstream::nProcs(comm));
500 
501  // Local constructMap is just identity
502  {
503  tgtConstructMap[Pstream::myProcNo(comm)] =
504  identity(targetCoarseSize);
505  }
506 
507  labelList tgtCompactMap(map.constructSize());
508 
509  {
510  // Note that in special cases (e.g. 'appending' two AMIs) the
511  // local size after distributing can be longer than the number
512  // of faces. I.e. it duplicates elements.
513  // Since we don't know this size instead we loop over all
514  // reachable elements (using the local constructMap)
515 
516  const labelList& elemsMap =
517  map.constructMap()[Pstream::myProcNo(comm)];
518  for (const label fineElem : elemsMap)
519  {
520  label coarseElem = allRestrict[fineElem];
521  tgtCompactMap[fineElem] = coarseElem;
522  }
523  }
524 
525  label compacti = targetCoarseSize;
526 
527  // Compact data from other processors
528  forAll(map.constructMap(), proci)
529  {
530  if (proci != Pstream::myProcNo(comm))
531  {
532  // Combine entries that point to the same coarse element. All
533  // elements now are remote data so we cannot use any local
534  // data here - use allRestrict instead.
535  const labelList& elems = map.constructMap()[proci];
536 
537  labelList& newConstructMap = tgtConstructMap[proci];
538  newConstructMap.resize_nocopy(elems.size());
539 
540  if (elems.size())
541  {
542  // Get the maximum target coarse size for this set of
543  // received data.
544  label remoteTargetCoarseSize = labelMin;
545  for (const label elemi : elems)
546  {
547  remoteTargetCoarseSize = max
548  (
549  remoteTargetCoarseSize,
550  allRestrict[elemi]
551  );
552  }
553  remoteTargetCoarseSize += 1;
554 
555  // Combine locally data coming from proci
556  labelList oldToNew(remoteTargetCoarseSize, -1);
557  label newi = 0;
558 
559  for (const label fineElem : elems)
560  {
561  // fineElem now points to section from proci
562  label coarseElem = allRestrict[fineElem];
563  if (oldToNew[coarseElem] == -1)
564  {
565  oldToNew[coarseElem] = newi;
566  tgtCompactMap[fineElem] = compacti;
567  newConstructMap[newi] = compacti++;
568  ++newi;
569  }
570  else
571  {
572  // Get compact index
573  label compacti = oldToNew[coarseElem];
574  tgtCompactMap[fineElem] = newConstructMap[compacti];
575  }
576  }
577  newConstructMap.resize(newi);
578  }
579  }
580  }
581 
582  srcAddress.setSize(sourceCoarseSize);
583  srcWeights.setSize(sourceCoarseSize);
584 
585  forAll(fineSrcAddress, facei)
586  {
587  // All the elements contributing to facei. Are slots in
588  // mapDistribute'd data.
589  const labelList& elems = fineSrcAddress[facei];
590  const scalarList& weights = fineSrcWeights[facei];
591  const scalar fineArea = fineSrcMagSf[facei];
592 
593  label coarseFacei = sourceRestrictAddressing[facei];
594 
595  labelList& newElems = srcAddress[coarseFacei];
596  scalarList& newWeights = srcWeights[coarseFacei];
597 
598  forAll(elems, i)
599  {
600  label elemi = elems[i];
601  label coarseElemi = tgtCompactMap[elemi];
602 
603  label index = newElems.find(coarseElemi);
604  if (index == -1)
605  {
606  newElems.append(coarseElemi);
607  newWeights.append(fineArea*weights[i]);
608  }
609  else
610  {
611  newWeights[index] += fineArea*weights[i];
612  }
613  }
614  }
615 
616  tgtMap.reset
617  (
618  new mapDistribute
619  (
620  compacti,
621  std::move(tgtSubMap),
622  std::move(tgtConstructMap),
623  false, //subHasFlip
624  false, //constructHasFlip
625  comm
626  )
627  );
628  }
629  else
630  {
631  srcAddress.setSize(sourceCoarseSize);
632  srcWeights.setSize(sourceCoarseSize);
633 
634  forAll(fineSrcAddress, facei)
635  {
636  // All the elements contributing to facei. Are slots in
637  // mapDistribute'd data.
638  const labelList& elems = fineSrcAddress[facei];
639  const scalarList& weights = fineSrcWeights[facei];
640  const scalar fineArea = fineSrcMagSf[facei];
641 
642  label coarseFacei = sourceRestrictAddressing[facei];
643 
644  labelList& newElems = srcAddress[coarseFacei];
645  scalarList& newWeights = srcWeights[coarseFacei];
646 
647  forAll(elems, i)
648  {
649  const label elemi = elems[i];
650  const label coarseElemi = targetRestrictAddressing[elemi];
651 
652  const label index = newElems.find(coarseElemi);
653  if (index == -1)
654  {
655  newElems.append(coarseElemi);
656  newWeights.append(fineArea*weights[i]);
657  }
658  else
659  {
660  newWeights[index] += fineArea*weights[i];
661  }
662  }
663  }
664  }
665 
666  // Weights normalisation
667  normaliseWeights
668  (
669  srcMagSf,
670  "source",
671  srcAddress,
672  srcWeights,
673  srcWeightsSum,
674  true,
675  false,
676  -1,
677  comm
678  );
679 }
680 
681 
682 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
683 
685 (
686  const dictionary& dict,
687  const bool reverseTarget
688 )
689 :
690  requireMatch_(dict.getOrDefault("requireMatch", true)),
691  reverseTarget_(dict.getOrDefault("reverseTarget", reverseTarget)),
692  lowWeightCorrection_(dict.getOrDefault<scalar>("lowWeightCorrection", -1)),
693  singlePatchProc_(-999),
694  comm_(UPstream::worldComm),
695  srcMagSf_(),
696  srcAddress_(),
697  srcWeights_(),
698  srcWeightsSum_(),
699  srcCentroids_(),
700  srcMapPtr_(nullptr),
701  tgtMagSf_(),
702  tgtAddress_(),
703  tgtWeights_(),
704  tgtWeightsSum_(),
705  tgtCentroids_(),
706  tgtMapPtr_(nullptr),
707  upToDate_(false)
708 {}
709 
710 
712 (
713  const bool requireMatch,
714  const bool reverseTarget,
715  const scalar lowWeightCorrection
716 )
717 :
718  requireMatch_(requireMatch),
719  reverseTarget_(reverseTarget),
720  lowWeightCorrection_(lowWeightCorrection),
721  singlePatchProc_(-999),
722  comm_(UPstream::worldComm),
723  srcMagSf_(),
724  srcAddress_(),
725  srcWeights_(),
726  srcWeightsSum_(),
727  srcCentroids_(),
728  srcPatchPts_(),
729  srcMapPtr_(nullptr),
730  tgtMagSf_(),
731  tgtAddress_(),
732  tgtWeights_(),
733  tgtWeightsSum_(),
734  tgtCentroids_(),
735  tgtPatchPts_(),
736  tgtMapPtr_(nullptr),
737  upToDate_(false)
738 {}
739 
740 
742 (
743  const AMIInterpolation& fineAMI,
744  const labelList& sourceRestrictAddressing,
745  const labelList& targetRestrictAddressing
746 )
747 :
748  requireMatch_(fineAMI.requireMatch_),
749  reverseTarget_(fineAMI.reverseTarget_),
750  lowWeightCorrection_(-1.0),
751  singlePatchProc_(fineAMI.singlePatchProc_),
752  comm_(fineAMI.comm()), // use fineAMI geomComm if present, comm otherwise
753  geomComm_(),
754  srcMagSf_(),
755  srcAddress_(),
756  srcWeights_(),
757  srcWeightsSum_(),
758  srcPatchPts_(),
759  srcMapPtr_(nullptr),
760  tgtMagSf_(),
761  tgtAddress_(),
762  tgtWeights_(),
763  tgtWeightsSum_(),
764  tgtPatchPts_(),
765  tgtMapPtr_(nullptr),
766  upToDate_(false)
767 {
768  label sourceCoarseSize =
769  (
770  sourceRestrictAddressing.size()
771  ? max(sourceRestrictAddressing)+1
772  : 0
773  );
774 
775  label neighbourCoarseSize =
776  (
777  targetRestrictAddressing.size()
778  ? max(targetRestrictAddressing)+1
779  : 0
780  );
781 
782  if (debug & 2)
783  {
784  Pout<< "AMI: Creating addressing and weights as agglomeration of AMI :"
785  << " source:" << fineAMI.srcAddress().size()
786  << " target:" << fineAMI.tgtAddress().size()
787  << " fineComm:" << fineAMI.comm()
788  << " coarse source size:" << sourceCoarseSize
789  << " neighbour source size:" << neighbourCoarseSize
790  << endl;
791  }
792 
793  if
794  (
795  fineAMI.srcAddress().size() != sourceRestrictAddressing.size()
796  || fineAMI.tgtAddress().size() != targetRestrictAddressing.size()
797  )
798  {
800  << "Size mismatch." << nl
801  << "Source patch size:" << fineAMI.srcAddress().size() << nl
802  << "Source agglomeration size:"
803  << sourceRestrictAddressing.size() << nl
804  << "Target patch size:" << fineAMI.tgtAddress().size() << nl
805  << "Target agglomeration size:"
806  << targetRestrictAddressing.size()
807  << exit(FatalError);
808  }
809 
810 
811  // Agglomerate addresses and weights
812 
813  if (comm() != -1)
814  {
815  //Pout<< "** agglomerating srcAddress, tgtMap" << endl;
816  //if (fineAMI.tgtMapPtr_.valid())
817  //{
818  // const auto& fineTgtMap = fineAMI.tgtMapPtr_();
819  // Pout<< " fineAMI.tgtMapPtr_ comm:" << fineTgtMap.comm()
820  // << " procs:"
821  // << (
822  // fineTgtMap.comm() != -1
823  // ? UPstream::procID(fineTgtMap.comm())
824  // : labelList::null()
825  // )
826  // << endl;
827  //}
828  //else
829  //{
830  // Pout<< " NO fineAMI.tgtMapPtr_" << endl;
831  //}
832  //
834  (
835  fineAMI.tgtMapPtr_,
836  fineAMI.srcMagSf(),
837  fineAMI.srcAddress(),
838  fineAMI.srcWeights(),
839 
840  sourceRestrictAddressing,
841  targetRestrictAddressing,
842 
843  srcMagSf_,
844  srcAddress_,
845  srcWeights_,
847  tgtMapPtr_,
848  comm()
849  );
850 
851  //Pout<< "** agglomerating tgtAddress, srcMap" << endl;
852  //if (fineAMI.srcMapPtr_.valid())
853  //{
854  // const auto& fineSrcMap = fineAMI.srcMapPtr_();
855  // Pout<< " fineAMI.srcMapPtr_ comm:" << fineSrcMap.comm()
856  // << " procs:"
857  // << (
858  // fineSrcMap.comm() != -1
859  // ? UPstream::procID(fineSrcMap.comm())
860  // : labelList::null()
861  // )
862  // << endl;
863  //}
864  //else
865  //{
866  // Pout<< " NO fineAMI.srcMapPtr_" << endl;
867  //}
869  (
870  fineAMI.srcMapPtr_,
871  fineAMI.tgtMagSf(),
872  fineAMI.tgtAddress(),
873  fineAMI.tgtWeights(),
874 
875  targetRestrictAddressing,
876  sourceRestrictAddressing,
877 
878  tgtMagSf_,
879  tgtAddress_,
880  tgtWeights_,
883  comm()
884  );
885  }
886 }
887 
888 
889 Foam::AMIInterpolation::AMIInterpolation(const AMIInterpolation& ami)
890 :
891  requireMatch_(ami.requireMatch_),
892  reverseTarget_(ami.reverseTarget_),
893  lowWeightCorrection_(ami.lowWeightCorrection_),
894  singlePatchProc_(ami.singlePatchProc_),
895  comm_(ami.comm_),
896  geomComm_(ami.geomComm_), // ? steals communicator
897  srcMagSf_(ami.srcMagSf_),
898  srcAddress_(ami.srcAddress_),
899  srcWeights_(ami.srcWeights_),
900  srcWeightsSum_(ami.srcWeightsSum_),
901  srcCentroids_(ami.srcCentroids_),
902  srcMapPtr_(nullptr),
903  tgtMagSf_(ami.tgtMagSf_),
904  tgtAddress_(ami.tgtAddress_),
905  tgtWeights_(ami.tgtWeights_),
906  tgtWeightsSum_(ami.tgtWeightsSum_),
907  tgtCentroids_(ami.tgtCentroids_),
908  tgtMapPtr_(nullptr),
909  upToDate_(false)
910 {}
911 
912 
914 :
915  requireMatch_(readBool(is)),
916  reverseTarget_(readBool(is)),
917  lowWeightCorrection_(readScalar(is)),
918  singlePatchProc_(readLabel(is)),
919  comm_(readLabel(is)), // either geomComm_ or comm_ from sending side
920 
921  srcMagSf_(is),
922  srcAddress_(is),
923  srcWeights_(is),
924  srcWeightsSum_(is),
925  srcCentroids_(is),
926  //srcPatchPts_(is),
927  srcMapPtr_(nullptr),
928 
929  tgtMagSf_(is),
930  tgtAddress_(is),
931  tgtWeights_(is),
932  tgtWeightsSum_(is),
933  tgtCentroids_(is),
934  //tgtPatchPts_(is),
935  tgtMapPtr_(nullptr),
936 
937  upToDate_(readBool(is))
938 {
939  // Hopefully no need to stream geomComm_ since only used in processor
940  // agglomeration?
941 
942  if (singlePatchProc_ == -1 && comm_ != -1)
943  {
944  srcMapPtr_.reset(new mapDistribute(is));
945  tgtMapPtr_.reset(new mapDistribute(is));
946  }
947 }
948 
949 
950 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
951 
953 (
954  const primitivePatch& srcPatch,
955  const primitivePatch& tgtPatch,
956  const autoPtr<searchableSurface>& surfPtr
957 )
958 {
959  if (upToDate_)
960  {
961  return false;
962  }
963 
964  addProfiling(ami, "AMIInterpolation::calculate");
965 
966 
967  // Clear storage (only needed if src/tgt become zero size)
968  {
969  if (srcMagSf_.size())
970  {
971  srcMagSf_.resize_nocopy(srcPatch.size());
972  }
973  srcAddress_.resize_nocopy(srcPatch.size());
974  srcWeights_.resize_nocopy(srcPatch.size());
975  srcWeightsSum_.resize_nocopy(srcPatch.size());
976  if (srcCentroids_.size())
977  {
978  srcCentroids_.resize_nocopy(srcPatch.size());
979  }
980 
981  if (tgtMagSf_.size())
982  {
983  tgtMagSf_.resize_nocopy(tgtPatch.size());
984  }
985  tgtAddress_.resize_nocopy(tgtPatch.size());
986  tgtWeights_.resize_nocopy(tgtPatch.size());
987  tgtWeightsSum_.resize_nocopy(tgtPatch.size());
988 
989  if (tgtCentroids_.size())
990  {
991  tgtCentroids_.resize_nocopy(tgtPatch.size());
992  }
993  }
994 
995 
996  if (surfPtr)
997  {
998  srcPatchPts_ = srcPatch.points();
999  projectPointsToSurface(surfPtr(), srcPatchPts_);
1000  tsrcPatch0_ = refPtr<primitivePatch>::New
1001  (
1002  SubList<face>(srcPatch),
1003  srcPatchPts_
1004  );
1005 
1006  tgtPatchPts_ = tgtPatch.points();
1007  projectPointsToSurface(surfPtr(), tgtPatchPts_);
1008  ttgtPatch0_ = refPtr<primitivePatch>::New
1009  (
1010  SubList<face>(tgtPatch),
1011  tgtPatchPts_
1012  );
1013  }
1014  else
1015  {
1016  tsrcPatch0_.cref(srcPatch);
1017  ttgtPatch0_.cref(tgtPatch);
1018  }
1019 
1020  // Note: use original communicator for statistics
1021  const label srcTotalSize = returnReduce
1022  (
1023  srcPatch.size(),
1024  sumOp<label>(),
1026  comm_
1027  );
1028 
1029  if (srcTotalSize == 0)
1030  {
1031  DebugInfo
1032  << "AMI: no source faces present - no addressing constructed"
1033  << endl;
1034 
1035  singlePatchProc_ = UPstream::myProcNo(comm_);
1036 
1037  return false;
1038  }
1039 
1040  const label tgtTotalSize = returnReduce
1041  (
1042  tgtPatch.size(),
1043  sumOp<label>(),
1045  comm_
1046  );
1047 
1048  // Calculate:
1049  // - which processors have faces
1050  // - allocates a communicator (geomComm_) for those
1051  // - if it is only one processor that holds all faces
1052  singlePatchProc_ = calcDistribution(srcPatch, tgtPatch, comm_, geomComm_);
1053 
1054  Info<< indent << "AMI: Patch source faces: " << srcTotalSize << nl
1055  << indent << "AMI: Patch target faces: " << tgtTotalSize << nl;
1056 
1057  if (distributed())
1058  {
1059  Info<< indent << "AMI: distributed" << endl;
1060  }
1061 
1062  DebugInfo
1063  << "AMI: patch proc:" << singlePatchProc_
1064  << endl;
1065 
1066  return true;
1067 }
1068 
1069 
1071 (
1072  autoPtr<mapDistribute>&& srcToTgtMap,
1073  autoPtr<mapDistribute>&& tgtToSrcMap,
1074  labelListList&& srcAddress,
1075  scalarListList&& srcWeights,
1076  labelListList&& tgtAddress,
1077  scalarListList&& tgtWeights,
1078  const label singlePatchProc
1079 )
1080 {
1082 
1083  srcAddress_.transfer(srcAddress);
1084  srcWeights_.transfer(srcWeights);
1085  tgtAddress_.transfer(tgtAddress);
1086  tgtWeights_.transfer(tgtWeights);
1087 
1088  // Reset the sums of the weights
1089  srcWeightsSum_.resize_nocopy(srcWeights_.size());
1090  forAll(srcWeights_, facei)
1091  {
1092  srcWeightsSum_[facei] = sum(srcWeights_[facei]);
1093  }
1094 
1095  tgtWeightsSum_.resize_nocopy(tgtWeights_.size());
1096  forAll(tgtWeights_, facei)
1097  {
1098  tgtWeightsSum_[facei] = sum(tgtWeights_[facei]);
1099  }
1100 
1101  srcMapPtr_ = std::move(srcToTgtMap);
1102  tgtMapPtr_ = std::move(tgtToSrcMap);
1103 
1104  singlePatchProc_ = singlePatchProc;
1105 
1106  upToDate_ = true;
1107 }
1108 
1109 
1111 (
1112  const primitivePatch& srcPatch,
1113  const primitivePatch& tgtPatch
1114 )
1115 {
1116  addProfiling(ami, "AMIInterpolation::append");
1117 
1118  // Create a new interpolation
1119  auto newPtr = clone();
1120  newPtr->calculate(srcPatch, tgtPatch);
1121 
1122  // If parallel then combine the mapDistribution and re-index
1123  if (distributed() && comm() != -1)
1124  {
1125  labelListList& srcSubMap = srcMapPtr_->subMap();
1126  labelListList& srcConstructMap = srcMapPtr_->constructMap();
1127 
1128  labelListList& tgtSubMap = tgtMapPtr_->subMap();
1129  labelListList& tgtConstructMap = tgtMapPtr_->constructMap();
1130 
1131  labelListList& newSrcSubMap = newPtr->srcMapPtr_->subMap();
1132  labelListList& newSrcConstructMap = newPtr->srcMapPtr_->constructMap();
1133 
1134  labelListList& newTgtSubMap = newPtr->tgtMapPtr_->subMap();
1135  labelListList& newTgtConstructMap = newPtr->tgtMapPtr_->constructMap();
1136 
1137  // Re-mapping/re-indexing - use max sizing
1138  labelList oldMapMap
1139  (
1140  max
1141  (
1142  srcMapPtr_->constructMapTotalSize(),
1143  tgtMapPtr_->constructMapTotalSize()
1144  )
1145  );
1146  labelList newMapMap
1147  (
1148  max
1149  (
1150  newPtr->srcMapPtr_->constructMapTotalSize(),
1151  newPtr->tgtMapPtr_->constructMapTotalSize()
1152  )
1153  );
1154 
1155  // Re-calculate the source indices
1156  {
1157  label total = 0;
1158  auto iter1 = oldMapMap.begin();
1159  auto iter2 = newMapMap.begin();
1160 
1161  forAll(srcSubMap, proci)
1162  {
1163  const label len1 = srcConstructMap[proci].size();
1164  const label len2 = newSrcConstructMap[proci].size();
1165 
1166  std::iota(iter1, (iter1 + len1), total);
1167  iter1 += len1;
1168  total += len1;
1169 
1170  std::iota(iter2, (iter2 + len2), total);
1171  iter2 += len2;
1172  total += len2;
1173  }
1174  }
1175 
1176  // Renumber the source indices
1177  {
1178  for (labelList& list : srcConstructMap)
1179  {
1180  for (label& value : list)
1181  {
1182  value = oldMapMap[value];
1183  }
1184  }
1185 
1186  for (labelList& list : newSrcConstructMap)
1187  {
1188  for (label& value : list)
1189  {
1190  value = newMapMap[value];
1191  }
1192  }
1193 
1194  for (labelList& list : tgtAddress_)
1195  {
1196  for (label& value : list)
1197  {
1198  value = oldMapMap[value];
1199  }
1200  }
1201 
1202  for (labelList& list : newPtr->tgtAddress_)
1203  {
1204  for (label& value : list)
1205  {
1206  value = newMapMap[value];
1207  }
1208  }
1209  }
1210 
1211 
1212  // Re-calculate the target indices
1213  {
1214  label total = 0;
1215  auto iter1 = oldMapMap.begin();
1216  auto iter2 = newMapMap.begin();
1217 
1218  forAll(srcSubMap, proci)
1219  {
1220  const label len1 = tgtConstructMap[proci].size();
1221  const label len2 = newTgtConstructMap[proci].size();
1222 
1223  std::iota(iter1, (iter1 + len1), total);
1224  iter1 += len1;
1225  total += len1;
1226 
1227  std::iota(iter2, (iter2 + len2), total);
1228  iter2 += len2;
1229  total += len2;
1230  }
1231  }
1232 
1233  // Renumber the target indices
1234  {
1235  for (labelList& list : tgtConstructMap)
1236  {
1237  for (label& value : list)
1238  {
1239  value = oldMapMap[value];
1240  }
1241  }
1242 
1243  for (labelList& list : newTgtConstructMap)
1244  {
1245  for (label& value : list)
1246  {
1247  value = newMapMap[value];
1248  }
1249  }
1250 
1251  for (labelList& list : srcAddress_)
1252  {
1253  for (label& value : list)
1254  {
1255  value = oldMapMap[value];
1256  }
1257  }
1258 
1259  for (labelList& list : newPtr->srcAddress_)
1260  {
1261  for (label& value : list)
1262  {
1263  value = newMapMap[value];
1264  }
1265  }
1266  }
1267 
1268  // Sum the construction sizes
1269  srcMapPtr_->constructSize() += newPtr->srcMapPtr_->constructSize();
1270  tgtMapPtr_->constructSize() += newPtr->tgtMapPtr_->constructSize();
1271 
1272  // Combine the maps
1273  forAll(srcSubMap, proci)
1274  {
1275  srcSubMap[proci].push_back(newSrcSubMap[proci]);
1276  srcConstructMap[proci].push_back(newSrcConstructMap[proci]);
1277 
1278  tgtSubMap[proci].push_back(newTgtSubMap[proci]);
1279  tgtConstructMap[proci].push_back(newTgtConstructMap[proci]);
1280  }
1281  }
1282 
1283  // Combine new and current source data
1284  forAll(srcMagSf_, srcFacei)
1285  {
1286  srcAddress_[srcFacei].push_back(newPtr->srcAddress()[srcFacei]);
1287  srcWeights_[srcFacei].push_back(newPtr->srcWeights()[srcFacei]);
1288  srcWeightsSum_[srcFacei] += newPtr->srcWeightsSum()[srcFacei];
1289  }
1290 
1291  // Combine new and current target data
1292  forAll(tgtMagSf_, tgtFacei)
1293  {
1294  tgtAddress_[tgtFacei].push_back(newPtr->tgtAddress()[tgtFacei]);
1295  tgtWeights_[tgtFacei].push_back(newPtr->tgtWeights()[tgtFacei]);
1296  tgtWeightsSum_[tgtFacei] += newPtr->tgtWeightsSum()[tgtFacei];
1297  }
1298 }
1299 
1300 
1302 (
1303  const bool conformal,
1304  const bool output
1305 )
1306 {
1307  normaliseWeights
1308  (
1309  srcMagSf_,
1310  "source",
1311  srcAddress_,
1312  srcWeights_,
1313  srcWeightsSum_,
1314  conformal,
1315  output,
1316  lowWeightCorrection_,
1317  comm()
1318  );
1319 
1320  normaliseWeights
1321  (
1322  tgtMagSf_,
1323  "target",
1324  tgtAddress_,
1325  tgtWeights_,
1326  tgtWeightsSum_,
1327  conformal,
1328  output,
1329  lowWeightCorrection_,
1330  comm()
1331  );
1332 }
1333 
1334 
1336 (
1337  const primitivePatch& srcPatch,
1338  const primitivePatch& tgtPatch,
1339  const vector& n,
1340  const label tgtFacei,
1341  point& tgtPoint
1342 )
1343 const
1344 {
1345  const pointField& srcPoints = srcPatch.points();
1346 
1347  // Source face addresses that intersect target face tgtFacei
1348  const labelList& addr = tgtAddress_[tgtFacei];
1349 
1350  pointHit nearest;
1351  nearest.setDistance(GREAT);
1352  label nearestFacei = -1;
1353 
1354  for (const label srcFacei : addr)
1355  {
1356  const face& f = srcPatch[srcFacei];
1357 
1358  pointHit ray =
1359  f.ray(tgtPoint, n, srcPoints, intersection::algorithm::VISIBLE);
1360 
1361  if (ray.hit())
1362  {
1363  tgtPoint = ray.point();
1364  return srcFacei;
1365  }
1366  else if (ray.distance() < nearest.distance())
1367  {
1368 
1369  nearest = ray;
1370  nearestFacei = srcFacei;
1371  }
1372  }
1373 
1374  if (nearest.hit() || nearest.eligibleMiss())
1375  {
1376  tgtPoint = nearest.point();
1377  return nearestFacei;
1378  }
1379 
1380  return -1;
1381 }
1382 
1383 
1385 (
1386  const primitivePatch& srcPatch,
1387  const primitivePatch& tgtPatch,
1388  const vector& n,
1389  const label srcFacei,
1390  point& srcPoint
1391 )
1392 const
1393 {
1394  const pointField& tgtPoints = tgtPatch.points();
1395 
1396  pointHit nearest;
1397  nearest.setDistance(GREAT);
1398  label nearestFacei = -1;
1399 
1400  // Target face addresses that intersect source face srcFacei
1401  const labelList& addr = srcAddress_[srcFacei];
1402 
1403  for (const label tgtFacei : addr)
1404  {
1405  const face& f = tgtPatch[tgtFacei];
1406 
1407  pointHit ray =
1408  f.ray(srcPoint, n, tgtPoints, intersection::algorithm::VISIBLE);
1409 
1410  if (ray.hit())
1411  {
1412  srcPoint = ray.point();
1413  return tgtFacei;
1414  }
1415  const pointHit near = f.nearestPoint(srcPoint, tgtPoints);
1416 
1417  if (near.distance() < nearest.distance())
1418  {
1419  nearest = near;
1420  nearestFacei = tgtFacei;
1421  }
1422  }
1423  if (nearest.hit() || nearest.eligibleMiss())
1424  {
1425  srcPoint = nearest.point();
1426  return nearestFacei;
1427  }
1428 
1429  return -1;
1430 }
1431 
1432 
1434 {
1435  if (UPstream::parRun() && this->distributed())
1436  {
1437  Log << "Checks only valid for serial running (currently)" << endl;
1438 
1439  return true;
1440  }
1441 
1442  bool symmetricSrc = true;
1443 
1444  Log << " Checking for missing src face in tgt lists" << nl;
1445 
1446  forAll(srcAddress_, srcFacei)
1447  {
1448  const labelList& tgtIds = srcAddress_[srcFacei];
1449  for (const label tgtFacei : tgtIds)
1450  {
1451  if (!tgtAddress_[tgtFacei].found(srcFacei))
1452  {
1453  symmetricSrc = false;
1454 
1455  Log << " srcFacei:" << srcFacei
1456  << " not found in tgtToSrc list for tgtFacei:"
1457  << tgtFacei << nl;
1458  }
1459  }
1460  }
1461 
1462  if (symmetricSrc)
1463  {
1464  Log << " - symmetric" << endl;
1465  }
1466 
1467  bool symmetricTgt = true;
1468 
1469  Log << " Checking for missing tgt face in src lists" << nl;
1470 
1471  forAll(tgtAddress_, tgtFacei)
1472  {
1473  const labelList& srcIds = tgtAddress_[tgtFacei];
1474  for (const label srcFacei : srcIds)
1475  {
1476  if (!srcAddress_[srcFacei].found(tgtFacei))
1477  {
1478  symmetricTgt = false;
1479 
1480  Log << " tgtFacei:" << tgtFacei
1481  << " not found in srcToTgt list for srcFacei:"
1482  << srcFacei << nl;
1483  }
1484  }
1485  }
1486 
1487  if (symmetricTgt)
1488  {
1489  Log << " - symmetric" << endl;
1490  }
1491 
1492  return symmetricSrc && symmetricTgt;
1493 }
1494 
1495 
1497 (
1498  const primitivePatch& srcPatch,
1499  const primitivePatch& tgtPatch,
1500  const labelListList& srcAddress
1501 )
1502 const
1503 {
1504  OFstream os("faceConnectivity" + Foam::name(Pstream::myProcNo()) + ".obj");
1505 
1506  label pti = 1;
1507 
1508  forAll(srcAddress, i)
1509  {
1510  const labelList& addr = srcAddress[i];
1511  const point& srcPt = srcPatch.faceCentres()[i];
1512 
1513  for (const label tgtPti : addr)
1514  {
1515  const point& tgtPt = tgtPatch.faceCentres()[tgtPti];
1516 
1517  meshTools::writeOBJ(os, srcPt);
1518  meshTools::writeOBJ(os, tgtPt);
1519 
1520  os << "l " << pti << " " << pti + 1 << endl;
1522  pti += 2;
1523  }
1524  }
1525 }
1526 
1527 
1528 void Foam::AMIInterpolation::write(Ostream& os) const
1529 {
1530  os.writeEntry("AMIMethod", type());
1531 
1532  if (!requireMatch_)
1533  {
1534  os.writeEntry("requireMatch", requireMatch_);
1535  }
1536 
1537  if (reverseTarget_)
1538  {
1539  os.writeEntry("reverseTarget", reverseTarget_);
1540  }
1541 
1542  if (lowWeightCorrection_ > 0)
1543  {
1544  os.writeEntry("lowWeightCorrection", lowWeightCorrection_);
1545  }
1546 }
1547 
1548 
1549 bool Foam::AMIInterpolation::writeData(Ostream& os) const
1550 {
1551  os << requireMatch()
1552  << token::SPACE<< reverseTarget()
1553  << token::SPACE<< lowWeightCorrection()
1554  << token::SPACE<< singlePatchProc()
1555  << token::SPACE<< comm() // either geomComm_ or comm_
1556 
1557  << token::SPACE<< srcMagSf()
1558  << token::SPACE<< srcAddress()
1559  << token::SPACE<< srcWeights()
1560  << token::SPACE<< srcWeightsSum()
1561  << token::SPACE<< srcCentroids()
1562 
1563  << token::SPACE<< tgtMagSf()
1564  << token::SPACE<< tgtAddress()
1565  << token::SPACE<< tgtWeights()
1566  << token::SPACE<< tgtWeightsSum()
1567  << token::SPACE<< tgtCentroids_
1568 
1569  << token::SPACE<< upToDate();
1570 
1571  if (distributed() && comm() != -1)
1572  {
1573  os << token::SPACE<< srcMap()
1574  << token::SPACE<< tgtMap();
1575  }
1576 
1577  return os.good();
1578 }
1579 
1580 
1581 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
label singlePatchProc_
Index of processor that holds all of both sides. The value is -1 for distributed cases.
dictionary dict
void append(const primitivePatch &srcPatch, const primitivePatch &tgtPatch)
Append additional addressing and weights.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label comm() const noexcept
Communicator (local or otherwise) for parallel operations.
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:491
labelListList tgtAddress_
Addresses of source faces per target face.
dimensionedScalar log(const dimensionedScalar &ds)
label tgtPointFace(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const vector &n, const label srcFacei, point &srcPoint) const
Return target patch face index of point on source patch face.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
const scalarListList & tgtWeights() const
Return const access to target patch weights.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
autoPtr< mapDistribute > tgtMapPtr_
Target map pointer - parallel running only.
void inflate(const scalar factor)
Expand box by factor*mag(span) in all dimensions.
Definition: boundBoxI.H:381
void writeFaceConnectivity(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const labelListList &srcAddress) const
Write face connectivity as OBJ file.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static refPtr< T > New(Args &&... args)
Construct refPtr with forwarding arguments.
Definition: refPtr.H:187
label srcPointFace(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const vector &n, const label tgtFacei, point &tgtPoint) const
Return source patch face index of point on target patch face.
void projectPointsToSurface(const searchableSurface &surf, pointField &pts) const
Project points to surface.
autoPtr< indexedOctree< treeType > > createTree(const primitivePatch &patch) const
Reset the octree for the patch face search.
An Istream is an abstract base class for all input systems (streams, files, token lists etc)...
Definition: Istream.H:57
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
virtual bool writeData(Ostream &os) const
Write AMI raw.
const labelListList & tgtAddress() const
Return const access to target patch addressing.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
PointIndexHit< point > pointIndexHit
A PointIndexHit with a 3D point.
Definition: pointIndexHit.H:58
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
label readLabel(const char *buf)
Parse entire buffer as a label, skipping leading/trailing whitespace.
Definition: label.H:63
#define addProfiling(Name,...)
Define profiling trigger with specified name and description string. The description is generated by ...
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:168
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:321
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1787
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:196
constexpr label labelMin
Definition: label.H:54
registerOptSwitch("localAMIComm", int, Foam::AMIInterpolation::useLocalComm_)
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
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:220
static bool cacheIntersections_
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
autoPtr< mapDistribute > srcMapPtr_
Source map pointer - parallel running only.
label comm_
Communicator to use for parallel operations.
Various functions to operate on Lists.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
AMIInterpolation(const dictionary &dict, const bool reverseTarget=false)
Construct from dictionary.
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
bool hit() const noexcept
Is there a hit.
Definition: pointHit.H:145
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:801
auto limits
Definition: setRDeltaT.H:186
A list of faces which address into the list of points.
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
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
virtual bool calculate(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const autoPtr< searchableSurface > &surfPtr=nullptr)
Update addressing, weights and (optional) centroids.
const List< scalar > & tgtMagSf() const
Return const access to target patch face areas.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
bool good() const noexcept
True if the managed pointer is non-null.
Definition: autoPtr.H:206
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
static void agglomerate(const autoPtr< mapDistribute > &targetMap, const scalarList &fineSrcMagSf, const labelListList &fineSrcAddress, const scalarListList &fineSrcWeights, const labelList &sourceRestrictAddressing, const labelList &targetRestrictAddressing, scalarList &srcMagSf, labelListList &srcAddress, scalarListList &srcWeights, scalarField &srcWeightsSum, autoPtr< mapDistribute > &tgtMap, const label comm)
List< scalarList > scalarListList
List of scalarList.
Definition: scalarList.H:35
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
static int useLocalComm_
Control use of local communicator for AMI communication.
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1596
Space [isspace].
Definition: token.H:131
Encapsulation of data needed to search on PrimitivePatches.
label calcDistribution(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const label comm, autoPtr< UPstream::communicator > &geomComm) const
Calculate if patches are on multiple processors. Allocates local communicator and returns -1 or proce...
void setDistance(const scalar d) noexcept
Set the distance.
Definition: pointHit.H:243
constexpr scalar pi(M_PI)
MinMax< Type > gMinMax(const FieldField< Field, Type > &f)
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Vector< scalar > vector
Definition: vector.H:57
Describes the interaction of a object and a (templated) point. It carries the info of a successful hi...
Definition: pointHit.H:43
const Field< point_type > & points() const noexcept
Return reference to global points.
bool checkSymmetricWeights(const bool log) const
Check if src addresses are present in tgt addresses and viceversa.
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
scalarListList srcWeights_
Weights of target faces per source face.
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:385
#define DebugInfo
Report an information message using Foam::Info.
int optimisationSwitch(const char *name, const int deflt=0)
Lookup optimisation switch or add default value.
Definition: debug.C:234
scalarField srcWeightsSum_
Sum of weights of target faces per source face.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
const scalarListList & srcWeights() const
Return const access to source patch weights.
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
int debug
Static debugging option.
Type gAverage(const FieldField< Field, Type > &f, const label comm)
The global arithmetic average of a FieldField.
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
const List< scalar > & srcMagSf() const
Return const access to source patch face areas.
scalarList tgtMagSf_
Target face areas.
scalarField tgtWeightsSum_
Sum of weights of source faces per target face.
labelListList srcAddress_
Addresses of target faces per source face.
static void normaliseWeights(const scalarList &patchAreas, const word &patchName, const labelListList &addr, scalarListList &wght, scalarField &wghtSum, const bool conformal, const bool output, const scalar lowWeightTol, const label comm)
Normalise the (area) weights - suppresses numerical error in weights calculation. ...
Class containing processor-to-processor mapping information.
vector point
Point is a vector.
Definition: point.H:37
Non-pointer based hierarchical recursive searching.
OSstream & masterStream(int communicator)
Return OSstream for output operations on the master process only, Snull on other processes.
scalarListList tgtWeights_
Weights of source faces per target face.
bool good() const noexcept
True if next operation might succeed.
Definition: IOstream.H:281
scalar distance() const noexcept
Return distance to hit.
Definition: pointHit.H:169
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
#define Log
Definition: PDRblock.C:28
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
const std::string patch
OpenFOAM patch number as a std::string.
const point_type & point() const noexcept
Return the point, no checks.
Definition: pointHit.H:161
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:90
messageStream Info
Information stream (stdout output on master, null elsewhere)
static List< int > & procID(int communicator)
The list of ranks within a given communicator.
Definition: UPstream.H:1672
static Ostream & output(Ostream &os, const IntRange< T > &range)
Definition: IntRanges.C:44
label n
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
static autoPtr< AMIInterpolation > New(const word &modelName, const dictionary &dict, const bool reverseTarget=false)
Selector for dictionary.
bool eligibleMiss() const noexcept
Is this an eligible miss.
Definition: pointHit.H:153
List< label > labelList
A List of labels.
Definition: List.H:61
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;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
void component(FieldField< Field, typename FieldField< Field, Type >::cmptType > &sf, const FieldField< Field, Type > &f, const direction d)
const labelListList & srcAddress() const
Return const access to source patch addressing.
scalarList srcMagSf_
Source face areas.
bool found
bool equal(const UList< Type1 > &a, const UList< Type2 > &b)
Test for list equality with different but compatible data types. Eg, int32 and int64.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Inter-processor communications stream.
Definition: UPstream.H:65
void reset(autoPtr< mapDistribute > &&srcToTgtMap, autoPtr< mapDistribute > &&tgtToSrcMap, labelListList &&srcAddress, scalarListList &&srcWeights, labelListList &&tgtAddress, scalarListList &&tgtWeights, const label singlePatchProc)
Set the maps, addresses and weights from an external source.
bool readBool(Istream &is)
Read bool from stream using Foam::Switch(Istream&)
Definition: bool.C:62
PointHit< point > pointHit
A PointHit with a 3D point.
Definition: pointHit.H:43
Namespace for OpenFOAM.
virtual void write(Ostream &os) const
Write AMI as a dictionary.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225
const pointField & pts