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