AMIInterpolation.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "AMIInterpolation.H"
27 #include "AMIMethod.H"
28 #include "meshTools.H"
29 #include "mapDistribute.H"
30 #include "flipOp.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36  defineTypeNameAndDebug(AMIInterpolation, 0);
37 }
38 
39 
40 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
41 
43 (
44  const interpolationMethod& im
45 )
46 {
47  word method = "unknown-interpolationMethod";
48 
49  switch (im)
50  {
51  case imDirect:
52  {
53  method = "directAMI";
54  break;
55  }
56  case imMapNearest:
57  {
58  method = "mapNearestAMI";
59  break;
60  }
61  case imFaceAreaWeight:
62  {
63  method = "faceAreaWeightAMI";
64  break;
65  }
66  case imPartialFaceAreaWeight:
67  {
68  method = "partialFaceAreaWeightAMI";
69  break;
70  }
71  case imSweptFaceAreaWeight:
72  {
73  method = "sweptFaceAreaWeightAMI";
74  break;
75  }
76  default:
77  {
79  << "Unhandled interpolationMethod enumeration " << method
80  << abort(FatalError);
81  }
82  }
83 
84  return method;
85 }
86 
87 
90 {
91  interpolationMethod method = imDirect;
92 
93  wordList methods
94  (
96  (
97  "("
98  "directAMI "
99  "mapNearestAMI "
100  "faceAreaWeightAMI "
101  "partialFaceAreaWeightAMI "
102  "sweptFaceAreaWeightAMI"
103  ")"
104  )()
105  );
106 
107  if (im == "directAMI")
108  {
109  method = imDirect;
110  }
111  else if (im == "mapNearestAMI")
112  {
113  method = imMapNearest;
114  }
115  else if (im == "faceAreaWeightAMI")
116  {
117  method = imFaceAreaWeight;
118  }
119  else if (im == "partialFaceAreaWeightAMI")
120  {
121  method = imPartialFaceAreaWeight;
122  }
123  else if (im == "sweptFaceAreaWeightAMI")
124  {
125  method = imSweptFaceAreaWeight;
126  }
127  else
128  {
130  << "Invalid interpolationMethod " << im
131  << ". Valid methods are:" << methods
132  << exit(FatalError);
133  }
134 
135  return method;
136 }
137 
138 
140 (
141  const primitivePatch& patch,
143 )
144 {
145  tmp<scalarField> tResult(new scalarField(patch.size(), Zero));
146  scalarField& result = tResult.ref();
147 
148  const pointField& patchPoints = patch.localPoints();
149 
150  triFaceList patchFaceTris;
151 
152  forAll(result, patchFacei)
153  {
155  (
156  patch.localFaces()[patchFacei],
157  patchPoints,
158  triMode,
159  patchFaceTris
160  );
161 
162  forAll(patchFaceTris, i)
163  {
164  result[patchFacei] +=
165  patchFaceTris[i].tri(patchPoints).mag();
166  }
167  }
168 
169  return tResult;
170 }
171 
172 
173 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
174 
175 void Foam::AMIInterpolation::projectPointsToSurface
176 (
177  const searchableSurface& surf,
178  pointField& pts
179 ) const
180 {
181  if (debug)
182  {
183  Info<< "AMI: projecting points to surface" << endl;
184  }
185 
187 
188  surf.findNearest(pts, scalarField(pts.size(), great), nearInfo);
189 
190  label nMiss = 0;
191  forAll(nearInfo, i)
192  {
193  const pointIndexHit& pi = nearInfo[i];
194 
195  if (pi.hit())
196  {
197  pts[i] = pi.hitPoint();
198  }
199  else
200  {
201  pts[i] = pts[i];
202  nMiss++;
203  }
204  }
205 
206  if (nMiss > 0)
207  {
209  << "Error projecting points to surface: "
210  << nMiss << " faces could not be determined"
211  << abort(FatalError);
212  }
213 }
214 
215 
216 void Foam::AMIInterpolation::sumWeights
217 (
218  const scalarListList& wght,
219  scalarField& wghtSum
220 )
221 {
222  wghtSum.setSize(wght.size());
223  wghtSum = Zero;
224 
225  forAll(wght, facei)
226  {
227  wghtSum[facei] = sum(wght[facei]);
228  }
229 }
230 
231 
232 void Foam::AMIInterpolation::sumWeights
233 (
234  const UPtrList<scalarListList>& wghts,
235  scalarField& wghtSum
236 )
237 {
238  wghtSum.setSize(wghts[0].size());
239  wghtSum = Zero;
240 
241  forAll(wghts[0], facei)
242  {
243  forAll(wghts, wghtsi)
244  {
245  forAll(wghts[wghtsi][facei], i)
246  {
247  wghtSum[facei] += wghts[wghtsi][facei][i];
248  }
249  }
250  }
251 }
252 
253 
254 void Foam::AMIInterpolation::reportSumWeights
255 (
256  const scalarField& patchAreas,
257  const word& patchName,
258  const scalarField& wghtSum,
259  const scalar lowWeightTol
260 )
261 {
262  if (returnReduce(wghtSum.size(), sumOp<label>()) == 0)
263  {
264  return;
265  }
266 
267  label nLowWeight = 0;
268  forAll(wghtSum, facei)
269  {
270  if (wghtSum[facei] < lowWeightTol)
271  {
272  ++ nLowWeight;
273  }
274  }
275  reduce(nLowWeight, sumOp<label>());
276 
277  Info<< indent << "AMI: Patch " << patchName
278  << " sum(weights) min/max/average = " << gMin(wghtSum) << ", "
279  << gMax(wghtSum) << ", "
280  << gSum(wghtSum*patchAreas)/gSum(patchAreas) << endl;
281 
282  if (nLowWeight)
283  {
284  Info<< indent << "AMI: Patch " << patchName << " identified "
285  << nLowWeight << " faces with weights less than "
286  << lowWeightTol << endl;
287  }
288 }
289 
290 
291 void Foam::AMIInterpolation::normaliseWeights
292 (
293  scalarListList& wght,
294  const scalarField& wghtSum
295 )
296 {
297  forAll(wghtSum, facei)
298  {
299  scalarList& w = wght[facei];
300 
301  forAll(w, i)
302  {
303  w[i] /= wghtSum[facei];
304  }
305  }
306 }
307 
308 
309 void Foam::AMIInterpolation::normaliseWeights
310 (
312  const scalarField& wghtSum
313 )
314 {
315  forAll(wghtSum, facei)
316  {
317  forAll(wghts, wghtsi)
318  {
319  scalarList& w = wghts[wghtsi][facei];
320 
321  forAll(w, i)
322  {
323  w[i] /= wghtSum[facei];
324  }
325  }
326  }
327 }
328 
329 
330 void Foam::AMIInterpolation::agglomerate
331 (
332  const autoPtr<mapDistribute>& targetMapPtr,
333  const scalarField& fineSrcMagSf,
334  const labelListList& fineSrcAddress,
335  const scalarListList& fineSrcWeights,
336 
337  const labelList& sourceRestrictAddressing,
338  const labelList& targetRestrictAddressing,
339 
340  scalarField& srcMagSf,
341  labelListList& srcAddress,
342  scalarListList& srcWeights,
343  scalarField& srcWeightsSum,
344  autoPtr<mapDistribute>& tgtMap
345 )
346 {
347  label sourceCoarseSize =
348  (
349  sourceRestrictAddressing.size()
350  ? max(sourceRestrictAddressing)+1
351  : 0
352  );
353 
354  label targetCoarseSize =
355  (
356  targetRestrictAddressing.size()
357  ? max(targetRestrictAddressing)+1
358  : 0
359  );
360 
361  // Agglomerate face areas
362  {
363  srcMagSf.setSize(sourceRestrictAddressing.size(), 0.0);
364  forAll(sourceRestrictAddressing, facei)
365  {
366  label coarseFacei = sourceRestrictAddressing[facei];
367  srcMagSf[coarseFacei] += fineSrcMagSf[facei];
368  }
369  }
370 
371 
372  // Agglomerate weights and indices
373  if (targetMapPtr.valid())
374  {
375  const mapDistribute& map = targetMapPtr();
376 
377  // Get all restriction addressing.
378  labelList allRestrict(targetRestrictAddressing);
379  map.distribute(allRestrict);
380 
381  // So now we have agglomeration of the target side in
382  // allRestrict:
383  // 0..size-1 : local agglomeration (= targetRestrictAddressing)
384  // size.. : agglomeration data from other processors
385 
386  labelListList tgtSubMap(Pstream::nProcs());
387 
388  // Local subMap is just identity
389  {
390  tgtSubMap[Pstream::myProcNo()] = identity(targetCoarseSize);
391  }
392 
393  forAll(map.subMap(), proci)
394  {
395  if (proci != Pstream::myProcNo())
396  {
397  // Combine entries that point to the same coarse element. All
398  // the elements refer to local data so index into
399  // targetRestrictAddressing or allRestrict (since the same
400  // for local data).
401  const labelList& elems = map.subMap()[proci];
402  labelList& newSubMap = tgtSubMap[proci];
403  newSubMap.setSize(elems.size());
404 
405  labelList oldToNew(targetCoarseSize, -1);
406  label newI = 0;
407 
408  forAll(elems, i)
409  {
410  label fineElem = elems[i];
411  label coarseElem = allRestrict[fineElem];
412  if (oldToNew[coarseElem] == -1)
413  {
414  oldToNew[coarseElem] = newI;
415  newSubMap[newI] = coarseElem;
416  newI++;
417  }
418  }
419  newSubMap.setSize(newI);
420  }
421  }
422 
423  // Reconstruct constructMap by combining entries. Note that order
424  // of handing out indices should be the same as loop above to compact
425  // the sending map
426 
427  labelListList tgtConstructMap(Pstream::nProcs());
428  labelList tgtCompactMap;
429 
430  // Local constructMap is just identity
431  {
432  tgtConstructMap[Pstream::myProcNo()] =
433  identity(targetCoarseSize);
434 
435  tgtCompactMap = targetRestrictAddressing;
436  }
437  tgtCompactMap.setSize(map.constructSize());
438  label compactI = targetCoarseSize;
439 
440  // Compact data from other processors
441  forAll(map.constructMap(), proci)
442  {
443  if (proci != Pstream::myProcNo())
444  {
445  // Combine entries that point to the same coarse element. All
446  // elements now are remote data so we cannot use any local
447  // data here - use allRestrict instead.
448  const labelList& elems = map.constructMap()[proci];
449 
450  labelList& newConstructMap = tgtConstructMap[proci];
451  newConstructMap.setSize(elems.size());
452 
453  if (elems.size())
454  {
455  // Get the maximum target coarse size for this set of
456  // received data.
457  label remoteTargetCoarseSize = labelMin;
458  forAll(elems, i)
459  {
460  remoteTargetCoarseSize = max
461  (
462  remoteTargetCoarseSize,
463  allRestrict[elems[i]]
464  );
465  }
466  remoteTargetCoarseSize += 1;
467 
468  // Combine locally data coming from proci
469  labelList oldToNew(remoteTargetCoarseSize, -1);
470  label newI = 0;
471 
472  forAll(elems, i)
473  {
474  label fineElem = elems[i];
475  // fineElem now points to section from proci
476  label coarseElem = allRestrict[fineElem];
477  if (oldToNew[coarseElem] == -1)
478  {
479  oldToNew[coarseElem] = newI;
480  tgtCompactMap[fineElem] = compactI;
481  newConstructMap[newI] = compactI++;
482  newI++;
483  }
484  else
485  {
486  // Get compact index
487  label compactI = oldToNew[coarseElem];
488  tgtCompactMap[fineElem] = newConstructMap[compactI];
489  }
490  }
491  newConstructMap.setSize(newI);
492  }
493  }
494  }
495 
496 
497  srcAddress.setSize(sourceCoarseSize);
498  srcWeights.setSize(sourceCoarseSize);
499 
500  forAll(fineSrcAddress, facei)
501  {
502  // All the elements contributing to facei. Are slots in
503  // mapDistribute'd data.
504  const labelList& elems = fineSrcAddress[facei];
505  const scalarList& weights = fineSrcWeights[facei];
506  const scalar fineArea = fineSrcMagSf[facei];
507 
508  label coarseFacei = sourceRestrictAddressing[facei];
509 
510  const scalar coarseArea = srcMagSf[coarseFacei];
511 
512  labelList& newElems = srcAddress[coarseFacei];
513  scalarList& newWeights = srcWeights[coarseFacei];
514 
515  forAll(elems, i)
516  {
517  label elemI = elems[i];
518  label coarseElemI = tgtCompactMap[elemI];
519 
520  label index = findIndex(newElems, coarseElemI);
521  if (index == -1)
522  {
523  newElems.append(coarseElemI);
524  newWeights.append(fineArea/coarseArea*weights[i]);
525  }
526  else
527  {
528  newWeights[index] += fineArea/coarseArea*weights[i];
529  }
530  }
531  }
532 
533  tgtMap.reset
534  (
535  new mapDistribute
536  (
537  compactI,
538  move(tgtSubMap),
539  move(tgtConstructMap)
540  )
541  );
542  }
543  else
544  {
545  srcAddress.setSize(sourceCoarseSize);
546  srcWeights.setSize(sourceCoarseSize);
547 
548  forAll(fineSrcAddress, facei)
549  {
550  // All the elements contributing to facei. Are slots in
551  // mapDistribute'd data.
552  const labelList& elems = fineSrcAddress[facei];
553  const scalarList& weights = fineSrcWeights[facei];
554  const scalar fineArea = fineSrcMagSf[facei];
555 
556  label coarseFacei = sourceRestrictAddressing[facei];
557 
558  const scalar coarseArea = srcMagSf[coarseFacei];
559 
560  labelList& newElems = srcAddress[coarseFacei];
561  scalarList& newWeights = srcWeights[coarseFacei];
562 
563  forAll(elems, i)
564  {
565  label elemI = elems[i];
566  label coarseElemI = targetRestrictAddressing[elemI];
567 
568  label index = findIndex(newElems, coarseElemI);
569  if (index == -1)
570  {
571  newElems.append(coarseElemI);
572  newWeights.append(fineArea/coarseArea*weights[i]);
573  }
574  else
575  {
576  newWeights[index] += fineArea/coarseArea*weights[i];
577  }
578  }
579  }
580  }
581 }
582 
583 
584 void Foam::AMIInterpolation::constructFromSurface
585 (
586  const primitivePatch& srcPatch,
587  const primitivePatch& tgtPatch,
588  const autoPtr<searchableSurface>& surfPtr,
589  const bool report
590 )
591 {
592  if (surfPtr.valid())
593  {
594  // Create new patches for source and target
595  pointField srcPoints = srcPatch.points();
596  primitivePatch srcPatch0
597  (
599  (
600  srcPatch,
601  srcPatch.size(),
602  0
603  ),
604  srcPoints
605  );
606 
607  if (debug)
608  {
609  OFstream os("amiSrcPoints.obj");
610  forAll(srcPoints, i)
611  {
612  meshTools::writeOBJ(os, srcPoints[i]);
613  }
614  }
615 
616  pointField tgtPoints = tgtPatch.points();
617  primitivePatch tgtPatch0
618  (
620  (
621  tgtPatch,
622  tgtPatch.size(),
623  0
624  ),
625  tgtPoints
626  );
627 
628  if (debug)
629  {
630  OFstream os("amiTgtPoints.obj");
631  forAll(tgtPoints, i)
632  {
633  meshTools::writeOBJ(os, tgtPoints[i]);
634  }
635  }
636 
637 
638  // Map source and target patches onto projection surface
639  projectPointsToSurface(surfPtr(), srcPoints);
640  projectPointsToSurface(surfPtr(), tgtPoints);
641 
642 
643  // Calculate AMI interpolation
644  update(srcPatch0, tgtPatch0, report);
645  }
646  else
647  {
648  update(srcPatch, tgtPatch, report);
649  }
650 }
651 
652 
653 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
654 
656 (
657  const primitivePatch& srcPatch,
658  const primitivePatch& tgtPatch,
660  const bool requireMatch,
661  const interpolationMethod& method,
662  const scalar lowWeightCorrection,
663  const bool reverseTarget,
664  const bool report
665 )
666 :
667  methodName_(interpolationMethodToWord(method)),
668  reverseTarget_(reverseTarget),
669  requireMatch_(requireMatch),
670  singlePatchProc_(-999),
671  lowWeightCorrection_(lowWeightCorrection),
672  srcAddress_(),
673  srcWeights_(),
674  srcWeightsSum_(),
675  tgtAddress_(),
676  tgtWeights_(),
677  tgtWeightsSum_(),
678  triMode_(triMode),
679  srcMapPtr_(nullptr),
680  tgtMapPtr_(nullptr)
681 {
682  update(srcPatch, tgtPatch, report);
683 }
684 
685 
687 (
688  const primitivePatch& srcPatch,
689  const primitivePatch& tgtPatch,
691  const bool requireMatch,
692  const word& methodName,
693  const scalar lowWeightCorrection,
694  const bool reverseTarget,
695  const bool report
696 )
697 :
698  methodName_(methodName),
699  reverseTarget_(reverseTarget),
700  requireMatch_(requireMatch),
701  singlePatchProc_(-999),
702  lowWeightCorrection_(lowWeightCorrection),
703  srcAddress_(),
704  srcWeights_(),
705  srcWeightsSum_(),
706  tgtAddress_(),
707  tgtWeights_(),
708  tgtWeightsSum_(),
709  triMode_(triMode),
710  srcMapPtr_(nullptr),
711  tgtMapPtr_(nullptr)
712 {
713  update(srcPatch, tgtPatch, report);
714 }
715 
716 
718 (
719  const primitivePatch& srcPatch,
720  const primitivePatch& tgtPatch,
721  const autoPtr<searchableSurface>& surfPtr,
723  const bool requireMatch,
724  const interpolationMethod& method,
725  const scalar lowWeightCorrection,
726  const bool reverseTarget,
727  const bool report
728 )
729 :
730  methodName_(interpolationMethodToWord(method)),
731  reverseTarget_(reverseTarget),
732  requireMatch_(requireMatch),
733  singlePatchProc_(-999),
734  lowWeightCorrection_(lowWeightCorrection),
735  srcAddress_(),
736  srcWeights_(),
737  srcWeightsSum_(),
738  tgtAddress_(),
739  tgtWeights_(),
740  tgtWeightsSum_(),
741  triMode_(triMode),
742  srcMapPtr_(nullptr),
743  tgtMapPtr_(nullptr)
744 {
745  constructFromSurface(srcPatch, tgtPatch, surfPtr, report);
746 }
747 
748 
750 (
751  const primitivePatch& srcPatch,
752  const primitivePatch& tgtPatch,
753  const autoPtr<searchableSurface>& surfPtr,
755  const bool requireMatch,
756  const word& methodName,
757  const scalar lowWeightCorrection,
758  const bool reverseTarget,
759  const bool report
760 )
761 :
762  methodName_(methodName),
763  reverseTarget_(reverseTarget),
764  requireMatch_(requireMatch),
765  singlePatchProc_(-999),
766  lowWeightCorrection_(lowWeightCorrection),
767  srcAddress_(),
768  srcWeights_(),
769  srcWeightsSum_(),
770  tgtAddress_(),
771  tgtWeights_(),
772  tgtWeightsSum_(),
773  triMode_(triMode),
774  srcMapPtr_(nullptr),
775  tgtMapPtr_(nullptr)
776 {
777  constructFromSurface(srcPatch, tgtPatch, surfPtr, report);
778 }
779 
780 
782 (
783  const AMIInterpolation& fineAMI,
784  const labelList& sourceRestrictAddressing,
785  const labelList& targetRestrictAddressing,
786  const bool report
787 )
788 :
789  methodName_(fineAMI.methodName_),
790  reverseTarget_(fineAMI.reverseTarget_),
791  requireMatch_(fineAMI.requireMatch_),
792  singlePatchProc_(fineAMI.singlePatchProc_),
793  lowWeightCorrection_(-1.0),
794  srcAddress_(),
795  srcWeights_(),
796  srcWeightsSum_(),
797  tgtAddress_(),
798  tgtWeights_(),
799  tgtWeightsSum_(),
800  triMode_(fineAMI.triMode_),
801  srcMapPtr_(nullptr),
802  tgtMapPtr_(nullptr)
803 {
804  label sourceCoarseSize =
805  (
806  sourceRestrictAddressing.size()
807  ? max(sourceRestrictAddressing)+1
808  : 0
809  );
810 
811  label neighbourCoarseSize =
812  (
813  targetRestrictAddressing.size()
814  ? max(targetRestrictAddressing)+1
815  : 0
816  );
817 
818  if (debug & 2)
819  {
820  Pout<< "AMI: Creating addressing and weights as agglomeration of AMI :"
821  << " source:" << fineAMI.srcAddress().size()
822  << " target:" << fineAMI.tgtAddress().size()
823  << " coarse source size:" << sourceCoarseSize
824  << " neighbour source size:" << neighbourCoarseSize
825  << endl;
826  }
827 
828  if
829  (
830  fineAMI.srcAddress().size() != sourceRestrictAddressing.size()
831  || fineAMI.tgtAddress().size() != targetRestrictAddressing.size()
832  )
833  {
835  << "Size mismatch." << nl
836  << "Source patch size:" << fineAMI.srcAddress().size() << nl
837  << "Source agglomeration size:"
838  << sourceRestrictAddressing.size() << nl
839  << "Target patch size:" << fineAMI.tgtAddress().size() << nl
840  << "Target agglomeration size:"
841  << targetRestrictAddressing.size()
842  << exit(FatalError);
843  }
844 
845  // Agglomerate addresses and weights
846  agglomerate
847  (
848  fineAMI.tgtMapPtr_,
849  fineAMI.srcMagSf(),
850  fineAMI.srcAddress(),
851  fineAMI.srcWeights(),
852 
853  sourceRestrictAddressing,
854  targetRestrictAddressing,
855 
856  srcMagSf_,
857  srcAddress_,
858  srcWeights_,
859  srcWeightsSum_,
860  tgtMapPtr_
861  );
862 
863  agglomerate
864  (
865  fineAMI.srcMapPtr_,
866  fineAMI.tgtMagSf(),
867  fineAMI.tgtAddress(),
868  fineAMI.tgtWeights(),
869 
870  targetRestrictAddressing,
871  sourceRestrictAddressing,
872 
873  tgtMagSf_,
874  tgtAddress_,
875  tgtWeights_,
876  tgtWeightsSum_,
877  srcMapPtr_
878  );
879 
880  // Weight summation and normalisation
881  sumWeights(*this);
882  if (report)
883  {
884  reportSumWeights(*this);
885  }
886  if (requireMatch_)
887  {
888  normaliseWeights(*this);
889  }
890 }
891 
892 
893 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
894 
896 {}
897 
898 
899 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
900 
902 (
903  const primitivePatch& srcPatch,
904  const primitivePatch& tgtPatch,
905  const bool report
906 )
907 {
908  label srcTotalSize = returnReduce(srcPatch.size(), sumOp<label>());
909  label tgtTotalSize = returnReduce(tgtPatch.size(), sumOp<label>());
910 
911  if (srcTotalSize == 0)
912  {
913  if (debug)
914  {
915  Info<< "AMI: no source faces present - no addressing constructed"
916  << endl;
917  }
918 
919  return;
920  }
921 
922  if (report)
923  {
924  Info<< indent
925  << "AMI: Creating addressing and weights between "
926  << srcTotalSize << " source faces and "
927  << tgtTotalSize << " target faces"
928  << endl;
929  }
930 
931  // Calculate face areas
932  srcMagSf_ = patchMagSf(srcPatch, triMode_);
933  tgtMagSf_ = patchMagSf(tgtPatch, triMode_);
934 
935  // Calculate if patches present on multiple processors
936  singlePatchProc_ = calcDistribution(srcPatch, tgtPatch);
937 
938  if (singlePatchProc_ == -1)
939  {
940  // Convert local addressing to global addressing
941  globalIndex globalSrcFaces(srcPatch.size());
942  globalIndex globalTgtFaces(tgtPatch.size());
943 
944  // Create processor map of overlapping faces. This map gets
945  // (possibly remote) faces from the tgtPatch such that they (together)
946  // cover all of the srcPatch
947  autoPtr<mapDistribute> mapPtr = calcProcMap(srcPatch, tgtPatch);
948  const mapDistribute& map = mapPtr();
949 
950  // Create new target patch that fully encompasses source patch
951 
952  // Faces and points
953  faceList newTgtFaces;
954  pointField newTgtPoints;
955 
956  // Original faces from tgtPatch (in globalIndexing since might be
957  // remote)
958  labelList tgtFaceIDs;
959  distributeAndMergePatches
960  (
961  map,
962  tgtPatch,
963  globalTgtFaces,
964  newTgtFaces,
965  newTgtPoints,
966  tgtFaceIDs
967  );
968 
970  newTgtPatch
971  (
973  (
974  newTgtFaces,
975  newTgtFaces.size()
976  ),
977  newTgtPoints
978  );
979  scalarField newTgtMagSf(patchMagSf(newTgtPatch, triMode_));
980 
981  // Calculate AMI interpolation
982  autoPtr<AMIMethod> AMIPtr
983  (
985  (
986  methodName_,
987  srcPatch,
988  newTgtPatch,
989  srcMagSf_,
990  newTgtMagSf,
991  triMode_,
992  reverseTarget_,
993  requireMatch_ && (lowWeightCorrection_ < 0)
994  )
995  );
996 
997  AMIPtr->calculate
998  (
999  srcAddress_,
1000  srcWeights_,
1001  tgtAddress_,
1002  tgtWeights_
1003  );
1004 
1005  // Now
1006  // ~~~
1007  // srcAddress_ : per srcPatch face a list of the newTgtPatch (not
1008  // tgtPatch) faces it overlaps
1009  // tgtAddress_ : per newTgtPatch (not tgtPatch) face a list of the
1010  // srcPatch faces it overlaps
1011 
1012 
1013  // Rework newTgtPatch indices into globalIndices of tgtPatch
1014  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1015 
1016 
1017  forAll(srcAddress_, i)
1018  {
1019  labelList& addressing = srcAddress_[i];
1020  forAll(addressing, addrI)
1021  {
1022  addressing[addrI] = tgtFaceIDs[addressing[addrI]];
1023  }
1024  }
1025 
1026  forAll(tgtAddress_, i)
1027  {
1028  labelList& addressing = tgtAddress_[i];
1029  forAll(addressing, addrI)
1030  {
1031  addressing[addrI] = globalSrcFaces.toGlobal(addressing[addrI]);
1032  }
1033  }
1034 
1035  // Send data back to originating procs. Note that contributions
1036  // from different processors get added (ListAppendEqOp)
1037 
1039  (
1041  List<labelPair>(),
1042  tgtPatch.size(),
1043  map.constructMap(),
1044  false, // has flip
1045  map.subMap(),
1046  false, // has flip
1047  tgtAddress_,
1049  flipOp(), // flip operation
1050  labelList()
1051  );
1052 
1054  (
1056  List<labelPair>(),
1057  tgtPatch.size(),
1058  map.constructMap(),
1059  false,
1060  map.subMap(),
1061  false,
1062  tgtWeights_,
1064  flipOp(),
1065  scalarList()
1066  );
1067 
1068  // Cache maps and reset addresses
1069  List<Map<label>> cMap;
1070  srcMapPtr_.reset(new mapDistribute(globalSrcFaces, tgtAddress_, cMap));
1071  tgtMapPtr_.reset(new mapDistribute(globalTgtFaces, srcAddress_, cMap));
1072 
1073  if (debug)
1074  {
1075  writeFaceConnectivity(srcPatch, newTgtPatch, srcAddress_);
1076  }
1077  }
1078  else
1079  {
1080  // Calculate AMI interpolation
1081  autoPtr<AMIMethod> AMIPtr
1082  (
1084  (
1085  methodName_,
1086  srcPatch,
1087  tgtPatch,
1088  srcMagSf_,
1089  tgtMagSf_,
1090  triMode_,
1091  reverseTarget_,
1092  requireMatch_ && (lowWeightCorrection_ < 0)
1093  )
1094  );
1095 
1096  AMIPtr->calculate
1097  (
1098  srcAddress_,
1099  srcWeights_,
1100  tgtAddress_,
1101  tgtWeights_
1102  );
1103  }
1104 
1105  // Weight summation and normalisation
1106  sumWeights(*this);
1107  if (report)
1108  {
1109  reportSumWeights(*this);
1110  }
1111  if (requireMatch_)
1112  {
1113  normaliseWeights(*this);
1114  }
1115 
1116  if (debug)
1117  {
1118  Info<< "AMIIPatchToPatchnterpolation :"
1119  << "Constructed addressing and weights" << nl
1120  << " triMode :"
1122  << " singlePatchProc:" << singlePatchProc_ << nl
1123  << " srcMagSf :" << gSum(srcMagSf_) << nl
1124  << " tgtMagSf :" << gSum(tgtMagSf_) << nl
1125  << endl;
1126  }
1127 }
1128 
1129 
1130 void Foam::AMIInterpolation::sumWeights(AMIInterpolation& AMI)
1131 {
1132  sumWeights(AMI.srcWeights_, AMI.srcWeightsSum_);
1133  sumWeights(AMI.tgtWeights_, AMI.tgtWeightsSum_);
1134 }
1135 
1136 
1137 void Foam::AMIInterpolation::sumWeights(PtrList<AMIInterpolation>& AMIs)
1138 {
1139  UPtrList<scalarListList> srcWeights(AMIs.size());
1140  forAll(AMIs, i)
1141  {
1142  srcWeights.set(i, &AMIs[i].srcWeights_);
1143  }
1144 
1145  sumWeights(srcWeights, AMIs[0].srcWeightsSum_);
1146 
1147  for (label i = 1; i < AMIs.size(); ++ i)
1148  {
1149  AMIs[i].srcWeightsSum_ = AMIs[0].srcWeightsSum_;
1150  }
1151 
1152  UPtrList<scalarListList> tgtWeights(AMIs.size());
1153  forAll(AMIs, i)
1154  {
1155  tgtWeights.set(i, &AMIs[i].tgtWeights_);
1156  }
1157 
1158  sumWeights(tgtWeights, AMIs[0].tgtWeightsSum_);
1159 
1160  for (label i = 1; i < AMIs.size(); ++ i)
1161  {
1162  AMIs[i].tgtWeightsSum_ = AMIs[0].tgtWeightsSum_;
1163  }
1164 }
1165 
1166 
1167 void Foam::AMIInterpolation::reportSumWeights(AMIInterpolation& AMI)
1168 {
1169  reportSumWeights
1170  (
1171  AMI.srcMagSf_,
1172  "source",
1173  AMI.srcWeightsSum_,
1174  AMI.lowWeightCorrection_
1175  );
1176 
1177  reportSumWeights
1178  (
1179  AMI.tgtMagSf_,
1180  "target",
1181  AMI.tgtWeightsSum_,
1182  AMI.lowWeightCorrection_
1183  );
1184 }
1185 
1186 
1187 void Foam::AMIInterpolation::normaliseWeights(AMIInterpolation& AMI)
1188 {
1189  normaliseWeights(AMI.srcWeights_, AMI.srcWeightsSum_);
1190  normaliseWeights(AMI.tgtWeights_, AMI.tgtWeightsSum_);
1191 }
1192 
1193 
1194 void Foam::AMIInterpolation::normaliseWeights(UPtrList<AMIInterpolation>& AMIs)
1195 {
1196  UPtrList<scalarListList> srcWeights(AMIs.size());
1197  forAll(AMIs, i)
1198  {
1199  srcWeights.set(i, &AMIs[i].srcWeights_);
1200  }
1201 
1202  normaliseWeights(srcWeights, AMIs[0].srcWeightsSum_);
1203 
1204  UPtrList<scalarListList> tgtWeights(AMIs.size());
1205  forAll(AMIs, i)
1206  {
1207  tgtWeights.set(i, &AMIs[i].tgtWeights_);
1208  }
1209 
1210  normaliseWeights(tgtWeights, AMIs[0].tgtWeightsSum_);
1211 }
1212 
1213 
1216  const primitivePatch& srcPatch,
1217  const primitivePatch& tgtPatch,
1218  const vector& n,
1219  const label tgtFacei,
1220  point& tgtPoint
1221 )
1222 const
1223 {
1224  const pointField& srcPoints = srcPatch.points();
1225 
1226  // Source face addresses that intersect target face tgtFacei
1227  const labelList& addr = tgtAddress_[tgtFacei];
1228 
1229  pointHit nearest;
1230  label nearestFacei = -1;
1231 
1232  forAll(addr, i)
1233  {
1234  const label srcFacei = addr[i];
1235  const face& f = srcPatch[srcFacei];
1236 
1237  const pointHit ray =
1238  f.ray(tgtPoint, n, srcPoints, intersection::algorithm::visible);
1239 
1240  if (ray.hit())
1241  {
1242  tgtPoint = ray.rawPoint();
1243  return srcFacei;
1244  }
1245 
1246  const pointHit near = f.nearestPoint(tgtPoint, srcPoints);
1247 
1248  if (near.distance() < nearest.distance())
1249  {
1250  nearest = near;
1251  nearestFacei = srcFacei;
1252  }
1253  }
1254 
1255  if (nearest.hit() || nearest.eligibleMiss())
1256  {
1257  tgtPoint = nearest.rawPoint();
1258  return nearestFacei;
1259  }
1260 
1261  return -1;
1262 }
1263 
1264 
1267  const primitivePatch& srcPatch,
1268  const primitivePatch& tgtPatch,
1269  const vector& n,
1270  const label srcFacei,
1271  point& srcPoint
1272 )
1273 const
1274 {
1275  const pointField& tgtPoints = tgtPatch.points();
1276 
1277  pointHit nearest;
1278  label nearestFacei = -1;
1279 
1280  // Target face addresses that intersect source face srcFacei
1281  const labelList& addr = srcAddress_[srcFacei];
1282 
1283  forAll(addr, i)
1284  {
1285  const label tgtFacei = addr[i];
1286  const face& f = tgtPatch[tgtFacei];
1287 
1288  const pointHit ray =
1289  f.ray(srcPoint, n, tgtPoints, intersection::algorithm::visible);
1290 
1291  if (ray.hit())
1292  {
1293  srcPoint = ray.rawPoint();
1294  return tgtFacei;
1295  }
1296 
1297  const pointHit near = f.nearestPoint(srcPoint, tgtPoints);
1298 
1299  if (near.distance() < nearest.distance())
1300  {
1301  nearest = near;
1302  nearestFacei = tgtFacei;
1303  }
1304  }
1305 
1306  if (nearest.hit() || nearest.eligibleMiss())
1307  {
1308  srcPoint = nearest.rawPoint();
1309  return nearestFacei;
1310  }
1311 
1312  return -1;
1313 }
1314 
1315 
1318  const primitivePatch& srcPatch,
1319  const primitivePatch& tgtPatch,
1320  const labelListList& srcAddress
1321 )
1322 const
1323 {
1324  OFstream os("faceConnectivity" + Foam::name(Pstream::myProcNo()) + ".obj");
1325 
1326  label ptI = 1;
1327 
1328  forAll(srcAddress, i)
1329  {
1330  const labelList& addr = srcAddress[i];
1331  const point& srcPt = srcPatch.faceCentres()[i];
1332 
1333  forAll(addr, j)
1334  {
1335  label tgtPtI = addr[j];
1336  const point& tgtPt = tgtPatch.faceCentres()[tgtPtI];
1337 
1338  meshTools::writeOBJ(os, srcPt);
1339  meshTools::writeOBJ(os, tgtPt);
1340 
1341  os << "l " << ptI << " " << ptI + 1 << endl;
1342 
1343  ptI += 2;
1344  }
1345  }
1346 }
1347 
1348 
1349 // ************************************************************************* //
static word interpolationMethodToWord(const interpolationMethod &method)
Convert interpolationMethod to word representation.
Class containing functor to negate primitives. Dummy for all other types.
Definition: flipOp.H:50
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:221
void update(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const bool report)
Update addressing and weights.
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:124
void reset(T *=nullptr)
If object pointer already set, delete object and set to given.
Definition: autoPtrI.H:114
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
error FatalError
const scalarListList & tgtWeights() const
Return const access to target patch weights.
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
const Field< PointType > & faceCentres() const
Return face centres for patch.
Type gMin(const FieldField< Field, Type > &f)
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
void writeFaceConnectivity(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const labelListList &srcAddress) const
Write face connectivity as OBJ file.
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:181
Output to file stream.
Definition: OFstream.H:82
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 labelListList & subMap() const
From subsetted data back to original data.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const labelListList & tgtAddress() const
Return const access to target patch addressing.
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
pointHit ray(const point &p, const vector &n, const pointField &, const intersection::algorithm alg=intersection::algorithm::fullRay, const intersection::direction dir=intersection::direction::vector) const
Return potential intersection with face with a ray starting.
static tmp< scalarField > patchMagSf(const primitivePatch &patch, const faceAreaIntersect::triangulationMode triMode)
Calculate the patch face magnitudes for the given tri-mode.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Tuple2< scalar, label > nearInfo
Private class for finding nearest.
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:53
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
virtual void calculate(labelListList &srcAddress, scalarListList &srcWeights, labelListList &tgtAddress, scalarListList &tgtWeights, label srcFacei=-1, label tgtFacei=-1)=0
Update addressing and weights.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
static const NamedEnum< triangulationMode, 2 > triangulationModeNames_
static void triangulate(const face &f, const pointField &points, const triangulationMode &triMode, triFaceList &faceTris)
Triangulate a face using the given triangulation mode.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
interpolationMethod
Enumeration specifying interpolation method.
static autoPtr< AMIMethod > New(const word &methodName, const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const scalarField &srcMagSf, const scalarField &tgtMagSf, const faceAreaIntersect::triangulationMode &triMode, const bool reverseTarget, const bool requireMatch)
Selector.
Definition: AMIMethodNew.C:31
const scalarField & srcMagSf() const
Return const access to source patch face areas.
A list of faces which address into the list of points.
const Point & hitPoint() const
Return hit point.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
A List obtained as a section of another List.
Definition: SubList.H:53
Type gSum(const FieldField< Field, Type > &f)
virtual void findNearest(const pointField &sample, const scalarField &nearestDistSqr, List< pointIndexHit > &) const =0
AMIInterpolation(const primitivePatch &srcPatch, const primitivePatch &tgtPatch, const faceAreaIntersect::triangulationMode &triMode, const bool requireMatch=true, const interpolationMethod &method=imFaceAreaWeight, const scalar lowWeightCorrection=-1, const bool reverseTarget=false, const bool report=true)
Construct from components.
A class for handling words, derived from string.
Definition: word.H:59
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
static void distribute(const Pstream::commsTypes commsType, const List< labelPair > &schedule, const label constructSize, const labelListList &subMap, const bool subHasFlip, const labelListList &constructMap, const bool constructHasFlip, List< T > &, const negateOp &negOp, const int tag=UPstream::msgType())
Distribute data. Note:schedule only used for.
bool hit() const
Is there a hit.
const Field< PointType > & points() const
Return reference to global points.
bool hit() const
Is there a hit.
Definition: PointHit.H:120
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const zero Zero
Definition: zero.H:97
virtual ~AMIInterpolation()
Destructor.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: UPtrList.H:54
bool valid() const
Return true if the autoPtr valid (ie, the pointer is set)
Definition: autoPtrI.H:83
errorManip< error > abort(error &err)
Definition: errorManip.H:131
const Point & rawPoint() const
Return point with no checking.
Definition: PointHit.H:158
const scalarListList & srcWeights() const
Return const access to source patch weights.
static const char nl
Definition: Ostream.H:260
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
label constructSize() const
Constructed data size.
void setSize(const label)
Reset size of List.
Definition: List.C:281
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
Class containing processor-to-processor mapping information.
pointHit nearestPoint(const point &p, const pointField &) const
Return nearest point to face.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:70
Input from memory buffer stream.
Definition: IStringStream.H:49
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
Interpolation class dealing with transfer of data between two primitive patches with an arbitrary mes...
messageStream Info
const labelListList & constructMap() const
From subsetted data to new reconstructed data.
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Helper class for list to append y onto the end of x.
Definition: ListOps.H:273
static interpolationMethod wordTointerpolationMethod(const word &method)
Convert word to interpolationMethod.
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
scalar distance() const
Return distance to hit.
Definition: PointHit.H:139
A class for managing temporary objects.
Definition: PtrList.H:53
bool eligibleMiss() const
Is this an eligible miss.
Definition: PointHit.H:164
const labelListList & srcAddress() const
Return const access to source patch addressing.
static const label labelMin
Definition: label.H:61
const scalarField & tgtMagSf() const
Return const access to target patch face areas.
Namespace for OpenFOAM.