intersectionPatchToPatch.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) 2021-2023 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 
27 #include "triIntersect.H"
28 #include "vtkWritePolyData.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35 namespace patchToPatches
36 {
39 
41  debug::debugSwitch((intersection::typeName + "SrcFace").c_str(), -1);
43  debug::debugSwitch((intersection::typeName + "TgtFace").c_str(), -1);
44 }
45 }
46 
47 
48 // * * * * * * * * * * * Private Static Member Functions * * * * * * * * * * //
49 
50 template<class Type>
52 Foam::patchToPatches::intersection::triPointValues
53 (
54  const triFace& t,
55  const UList<Type>& values
56 )
57 {
58  FixedList<Type, 3> result;
59  forAll(t, i)
60  {
61  result[i] = values[t[i]];
62  }
63  return result;
64 }
65 
66 
67 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
68 
70 (
71  const face& srcFace,
72  const pointField& srcPoints,
73  const vectorField& srcPointNormals
74 )
75 {
76  static DynamicList<point> ps;
77 
78  ps.clear();
79 
80  const scalar l = sqrt(mag(srcFace.area(srcPoints)));
81 
82  forAll(srcFace, srcFacePointi)
83  {
84  const label srcPointi = srcFace[srcFacePointi];
85 
86  const point& p = srcPoints[srcPointi];
87  const vector& n = srcPointNormals[srcPointi];
88 
89  ps.append(p - l/2*n);
90  ps.append(p + l/2*n);
91  }
92 
93  return treeBoundBox(ps);
94 }
95 
96 
97 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
98 
99 Foam::treeBoundBox Foam::patchToPatches::intersection::srcBox
100 (
101  const face& srcFace,
102  const pointField& srcPoints,
103  const vectorField& srcPointNormals
104 ) const
105 {
106  return srcBoxStatic(srcFace, srcPoints, srcPointNormals);
107 }
108 
109 
110 bool Foam::patchToPatches::intersection::intersectFaces
111 (
112  const primitiveOldTimePatch& srcPatch,
113  const vectorField& srcPointNormals,
114  const vectorField& srcPointNormals0,
115  const primitiveOldTimePatch& tgtPatch,
116  const label srcFacei,
117  const label tgtFacei
118 )
119 {
120  // Quick rejection based on bound box
121  const treeBoundBox srcFaceBox =
122  srcBox
123  (
124  srcPatch.localFaces()[srcFacei],
125  srcPatch.localPoints(),
126  srcPointNormals
127  );
128  const treeBoundBox tgtFaceBox(tgtPatch.points(), tgtPatch[tgtFacei]);
129  if (!srcFaceBox.overlaps(tgtFaceBox)) return false;
130 
131  // Construct face triangulations on demand
132  if (srcTriPoints_[srcFacei].empty())
133  {
134  triEngine_.triangulate
135  (
137  (
138  srcPatch.localPoints(),
139  srcPatch.localFaces()[srcFacei]
140  )
141  );
142 
143  srcTriPoints_[srcFacei] =
144  triEngine_.triPoints(srcPatch.localFaces()[srcFacei]);
145  srcTriFaceEdges_[srcFacei] = triEngine_.triEdges();
146  }
147  if (tgtTriPoints_[tgtFacei].empty())
148  {
149  triEngine_.triangulate
150  (
151  UIndirectList<point>
152  (
153  tgtPatch.localPoints(),
154  tgtPatch.localFaces()[tgtFacei]
155  )
156  );
157 
158  tgtTriPoints_[tgtFacei] =
159  triEngine_.triPoints(tgtPatch.localFaces()[tgtFacei]);
160  tgtTriFaceEdges_[tgtFacei] = triEngine_.triEdges();
161  }
162 
163  // Construct and initialise workspace
164  bool srcCouples = false;
165  couple srcCouple;
166  srcFaceEdgePart_.resize(srcPatch[srcFacei].size());
167  forAll(srcFaceEdgePart_, srcFaceEdgei)
168  {
169  const edge e =
170  srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
171  const vector eC = e.centre(srcPatch.localPoints());
172  srcFaceEdgePart_[srcFaceEdgei] = part(Zero, eC);
173  }
174 
175  bool tgtCouples = false;
176  couple tgtCouple;
177  tgtFaceEdgePart_.resize(tgtPatch[tgtFacei].size());
178  forAll(tgtFaceEdgePart_, tgtFaceEdgei)
179  {
180  const edge e =
181  tgtPatch.localFaces()[tgtFacei].faceEdge(tgtFaceEdgei);
182  const vector eC = e.centre(tgtPatch.localPoints());
183  tgtFaceEdgePart_[tgtFaceEdgei] = part(Zero, eC);
184  }
185 
186  part errorPart(Zero, srcPatch.faceCentres()[srcFacei]);
187 
188  // Cache the face area magnitudes
189  const scalar srcMagA = mag(srcPatch.faceAreas()[srcFacei]);
190  const scalar tgtMagA = mag(tgtPatch.faceAreas()[tgtFacei]);
191 
192  // Determine whether or not to debug this tri intersection
193  const bool debugTriIntersect =
194  (debugSrcFacei != -1 || debugTgtFacei != -1)
195  && (debugSrcFacei == -1 || debugSrcFacei == srcFacei)
196  && (debugTgtFacei == -1 || debugTgtFacei == tgtFacei);
197 
198  // Loop the face triangles and compute the intersections
199  bool anyCouples = false;
200  forAll(srcTriPoints_[srcFacei], srcFaceTrii)
201  {
202  const triFace& srcT = srcTriPoints_[srcFacei][srcFaceTrii];
203 
204  const FixedList<point, 3> srcPs =
205  triPointValues(srcT, srcPatch.localPoints());
206  const FixedList<vector, 3> srcNs =
207  triPointValues(srcT, srcPointNormals);
208 
209  forAll(tgtTriPoints_[tgtFacei], tgtFaceTrii)
210  {
211  const triFace tgtT =
212  reverse()
213  ? tgtTriPoints_[tgtFacei][tgtFaceTrii].reverseFace()
214  : tgtTriPoints_[tgtFacei][tgtFaceTrii];
215 
216  const FixedList<point, 3> tgtPs =
217  triPointValues(tgtT, tgtPatch.localPoints());
218 
219  // Do tri-intersection
220  ictSrcPoints_.clear();
221  ictSrcPointNormals_.clear();
222  ictTgtPoints_.clear();
223  ictPointLocations_.clear();
225  (
226  srcPs,
227  srcNs,
228  {false, false, false},
229  {-1, -1, -1},
230  tgtPs,
231  {false, false, false},
232  {-1, -1, -1},
233  ictSrcPoints_,
234  ictSrcPointNormals_,
235  ictTgtPoints_,
236  ictPointLocations_,
237  debugTriIntersect,
238  debugTriIntersect
239  ? word
240  (
241  typeName
242  + "_srcFace=" + Foam::name(srcFacei)
243  + "_tgtFace=" + Foam::name(tgtFacei)
244  + "_intersection=" + Foam::name
245  (srcFaceTrii*tgtTriPoints_[tgtFacei].size() + tgtFaceTrii)
246  )
247  : word::null
248  );
249 
250  // If there is no intersection then continue
251  if (ictPointLocations_.empty())
252  {
253  continue;
254  }
255 
256  // Mark that there has been an intersection
257  anyCouples = true;
258 
259  // Compute the intersection geometry
260  const part ictSrcPart(ictSrcPoints_);
261  const part ictTgtPart(ictTgtPoints_);
262 
263  // If the intersection is below tolerance then continue
264  if
265  (
266  mag(ictSrcPart.area) < small*srcMagA
267  || mag(ictTgtPart.area) < small*tgtMagA
268  )
269  {
270  continue;
271  }
272 
273  // Mark that the source and target faces intersect
274  srcCouples = tgtCouples = true;
275 
276  // Store the intersection geometry
277  srcCouple += ictSrcPart;
278  srcCouple.nbr += ictTgtPart;
279  if (reverse())
280  {
281  tgtCouple += ictTgtPart;
282  tgtCouple.nbr += ictSrcPart;
283  }
284  else
285  {
286  tgtCouple -= ictTgtPart;
287  tgtCouple.nbr -= ictSrcPart;
288  }
289 
290  // Store the intersection polygons for debugging
291  const label debugSrcPoint0 = debugPoints_.size();
292  const label debugTgtPoint0 =
293  debugPoints_.size() + ictSrcPoints_.size();
294  if (debug)
295  {
296  debugPoints_.append(ictSrcPoints_);
297  debugPoints_.append(ictTgtPoints_);
298  debugFaces_.append
299  (
300  debugSrcPoint0 + identityMap(ictSrcPoints_.size())
301  );
302  debugFaceSrcFaces_.append(srcFacei);
303  debugFaceTgtFaces_.append(tgtFacei);
304  debugFaceSides_.append(1);
305  debugFaces_.append
306  (
307  debugTgtPoint0 + identityMap(ictTgtPoints_.size())
308  );
309  debugFaceSrcFaces_.append(srcFacei);
310  debugFaceTgtFaces_.append(tgtFacei);
311  debugFaceSides_.append(-1);
312  }
313 
314  // Store edge and error areas
315  forAll(ictPointLocations_, i0)
316  {
317  const label i1 = ictPointLocations_.fcIndex(i0);
318 
319  // Get the locations on each end of this edge of the
320  // intersection polygon
321  const triIntersect::location l0 = ictPointLocations_[i0];
322  const triIntersect::location l1 = ictPointLocations_[i1];
323 
324  // Get the geometry for the projection of this edge
325  const part ictEdgePart
326  (
327  FixedList<point, 4>
328  ({
329  ictSrcPoints_[i0],
330  ictSrcPoints_[i1],
331  ictTgtPoints_[i1],
332  ictTgtPoints_[i0]
333  })
334  );
335 
336  // Store the "side" of the intersection that this edge
337  // corresponds to
338  label ictEdgeSide = -labelMax;
339 
340  // If this edge corresponds to an edge of the source
341  // triangle
342  if
343  (
344  l0.isSrcNotTgtPoint()
345  || l1.isSrcNotTgtPoint()
346  || (
347  l0.isIntersection()
348  && l1.isIntersection()
349  && l0.srcEdgei() == l1.srcEdgei()
350  )
351  )
352  {
353  const label srcEi =
354  l0.isSrcPoint() ? l0.srcPointi()
355  : l1.isSrcPoint() ? (l1.srcPointi() + 2) % 3
356  : l0.srcEdgei();
357 
358  const label srcFaceEdgei =
359  srcTriFaceEdges_[srcFacei][srcFaceTrii][srcEi];
360 
361  if (srcFaceEdgei < srcPatch[srcFacei].size())
362  {
363  srcFaceEdgePart_[srcFaceEdgei] += ictEdgePart;
364  ictEdgeSide = 1;
365  }
366  else
367  {
368  errorPart += ictEdgePart;
369  ictEdgeSide = 0;
370  }
371  }
372 
373  // If this edge corresponds to an edge of the target
374  // triangle
375  else if
376  (
377  l0.isTgtNotSrcPoint()
378  || l1.isTgtNotSrcPoint()
379  || (
380  l0.isIntersection()
381  && l1.isIntersection()
382  && l0.tgtEdgei() == l1.tgtEdgei()
383  )
384  )
385  {
386  const label tgtEi =
387  l0.isTgtPoint() ? (l0.tgtPointi() + 2) % 3
388  : l1.isTgtPoint() ? l1.tgtPointi()
389  : l0.tgtEdgei();
390 
391  const label tgtFaceEdgei =
392  tgtTriFaceEdges_[tgtFacei][tgtFaceTrii]
393  [reverse() ? 2 - tgtEi : tgtEi];
394 
395  if (tgtFaceEdgei < tgtPatch[tgtFacei].size())
396  {
397  if (reverse())
398  {
399  tgtFaceEdgePart_[tgtFaceEdgei] += ictEdgePart;
400  }
401  else
402  {
403  tgtFaceEdgePart_[tgtFaceEdgei] -= ictEdgePart;
404  }
405  ictEdgeSide = -1;
406  }
407  else
408  {
409  errorPart += ictEdgePart;
410  ictEdgeSide = 0;
411  }
412  }
413 
414  // No other location combinations should be possible for an
415  // intersection without any shared points
416  else
417  {
419  << "Tri-intersection topology not recognised. "
420  << "This is a bug." << exit(FatalError);
421  }
422 
423  // Store the projected edge quadrilateral for debugging
424  if (debug)
425  {
426  debugFaces_.append
427  (
428  labelList
429  ({
430  debugSrcPoint0 + i0,
431  debugSrcPoint0 + i1,
432  debugTgtPoint0 + i1,
433  debugTgtPoint0 + i0
434  })
435  );
436  debugFaceSrcFaces_.append(srcFacei);
437  debugFaceTgtFaces_.append(tgtFacei);
438  debugFaceSides_.append(ictEdgeSide);
439  }
440  }
441  }
442  }
443 
444  // If the source face couples the target, then store the intersection
445  if (srcCouples)
446  {
447  srcLocalTgtFaces_[srcFacei].append(tgtFacei);
448  srcCouples_[srcFacei].append(srcCouple);
449  }
450 
451  // If any intersection has occurred then store the edge and error parts
452  if (anyCouples)
453  {
454  forAll(srcFaceEdgeParts_[srcFacei], srcFaceEdgei)
455  {
456  srcFaceEdgeParts_[srcFacei][srcFaceEdgei] +=
457  srcFaceEdgePart_[srcFaceEdgei];
458  }
459  srcErrorParts_[srcFacei] -= sum(tgtFaceEdgePart_);
460  srcErrorParts_[srcFacei] += errorPart;
461  }
462 
463  // If the target face couples the source, then store in the intersection
464  if (tgtCouples)
465  {
466  tgtLocalSrcFaces_[tgtFacei].append(srcFacei);
467  tgtCouples_[tgtFacei].append(tgtCouple);
468  }
469 
470  return anyCouples;
471 }
472 
473 
474 void Foam::patchToPatches::intersection::initialise
475 (
476  const primitiveOldTimePatch& srcPatch,
477  const vectorField& srcPointNormals,
478  const vectorField& srcPointNormals0,
479  const primitiveOldTimePatch& tgtPatch
480 )
481 {
483  (
484  srcPatch,
485  srcPointNormals,
486  srcPointNormals0,
487  tgtPatch
488  );
489 
490  srcCouples_.resize(srcPatch.size());
491  forAll(srcLocalTgtFaces_, i)
492  {
493  srcCouples_[i].clear();
494  }
495 
496  srcEdgeParts_.resize(srcPatch.nEdges());
497  forAll(srcEdgeParts_, srcEdgei)
498  {
499  const edge& e = srcPatch.edges()[srcEdgei];
500  const point c = e.centre(srcPatch.localPoints());
501  srcEdgeParts_[srcEdgei] = part(Zero, c);
502  }
503 
504  srcErrorParts_.resize(srcPatch.size());
505  forAll(srcErrorParts_, srcFacei)
506  {
507  srcErrorParts_[srcFacei] =
508  part(Zero, srcPatch.faceCentres()[srcFacei]);
509  }
510 
511  tgtCouples_.resize(tgtPatch.size());
512  forAll(tgtLocalSrcFaces_, i)
513  {
514  tgtCouples_[i].clear();
515  }
516 
517  srcTriPoints_ = List<triFaceList>(srcPatch.size());
518  srcTriFaceEdges_ = List<List<FixedList<label, 3>>>(srcPatch.size());
519  tgtTriPoints_ = List<triFaceList>(tgtPatch.size());
520  tgtTriFaceEdges_ = List<List<FixedList<label, 3>>>(tgtPatch.size());
521 
522  srcFaceEdgeParts_.resize(srcPatch.size());
523  forAll(srcFaceEdgeParts_, srcFacei)
524  {
525  srcFaceEdgeParts_[srcFacei].resize(srcPatch[srcFacei].size());
526  forAll(srcFaceEdgeParts_[srcFacei], srcFaceEdgei)
527  {
528  const label srcEdgei =
529  srcPatch.faceEdges()[srcFacei][srcFaceEdgei];
530  srcFaceEdgeParts_[srcFacei][srcFaceEdgei] = srcEdgeParts_[srcEdgei];
531  }
532  }
533 
534  if (debug)
535  {
536  debugPoints_.clear();
537  debugFaces_.clear();
538  debugFaceSrcFaces_.clear();
539  debugFaceTgtFaces_.clear();
540  debugFaceSides_.clear();
541  }
542 }
543 
544 
545 Foam::labelList Foam::patchToPatches::intersection::finaliseLocal
546 (
547  const primitiveOldTimePatch& srcPatch,
548  const vectorField& srcPointNormals,
549  const vectorField& srcPointNormals0,
550  const primitiveOldTimePatch& tgtPatch
551 )
552 {
553  const labelList newToOldLocalTgtFace =
555  (
556  srcPatch,
557  srcPointNormals,
558  srcPointNormals0,
559  tgtPatch
560  );
561 
562  tgtCouples_ = List<DynamicList<couple>>(tgtCouples_, newToOldLocalTgtFace);
563 
564  return newToOldLocalTgtFace;
565 }
566 
567 
568 void Foam::patchToPatches::intersection::rDistributeTgt
569 (
570  const primitiveOldTimePatch& tgtPatch
571 )
572 {
574 
576  (
577  tgtPatch.size(),
578  tgtMapPtr_(),
579  tgtCouples_
580  );
581 }
582 
583 
584 Foam::label Foam::patchToPatches::intersection::finalise
585 (
586  const primitiveOldTimePatch& srcPatch,
587  const vectorField& srcPointNormals,
588  const vectorField& srcPointNormals0,
589  const primitiveOldTimePatch& tgtPatch,
590  const transformer& tgtToSrc
591 )
592 {
593  const label nCouples =
595  (
596  srcPatch,
597  srcPointNormals,
598  srcPointNormals0,
599  tgtPatch,
600  tgtToSrc
601  );
602 
603  // Convert face-edge-parts to edge-parts
604  labelList srcEdgeNParts(srcEdgeParts_.size(), 0);
605  forAll(srcEdgeParts_, srcEdgei)
606  {
607  const edge& e = srcPatch.edges()[srcEdgei];
608 
609  srcEdgeParts_[srcEdgei] = part();
610 
611  forAll(srcPatch.edgeFaces()[srcEdgei], i)
612  {
613  const label srcFacei = srcPatch.edgeFaces()[srcEdgei][i];
614  const label srcFaceEdgei =
615  findIndex(srcPatch.faceEdges()[srcFacei], srcEdgei);
616 
617  const edge fe =
618  srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
619 
620  if (edge::compare(e, fe) > 0)
621  {
622  srcEdgeParts_[srcEdgei] +=
623  srcFaceEdgeParts_[srcFacei][srcFaceEdgei];
624  }
625  else
626  {
627  srcEdgeParts_[srcEdgei] -=
628  srcFaceEdgeParts_[srcFacei][srcFaceEdgei];
629  }
630 
631  srcEdgeNParts[srcEdgei] ++;
632  }
633  }
634  forAll(srcEdgeParts_, srcEdgei)
635  {
636  srcEdgeParts_[srcEdgei].area /= srcEdgeNParts[srcEdgei];
637  }
638 
639  // Add the difference between the face-edge-part and the edge-part into the
640  // face-error-parts
641  forAll(srcEdgeParts_, srcEdgei)
642  {
643  const edge& e = srcPatch.edges()[srcEdgei];
644 
645  forAll(srcPatch.edgeFaces()[srcEdgei], i)
646  {
647  const label srcFacei = srcPatch.edgeFaces()[srcEdgei][i];
648  const label srcFaceEdgei =
649  findIndex(srcPatch.faceEdges()[srcFacei], srcEdgei);
650 
651  const edge fe =
652  srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
653 
654  if (edge::compare(e, fe) > 0)
655  {
656  srcErrorParts_[srcFacei] -= srcEdgeParts_[srcEdgei];
657  }
658  else
659  {
660  srcErrorParts_[srcFacei] += srcEdgeParts_[srcEdgei];
661  }
662 
663  srcErrorParts_[srcFacei] +=
664  srcFaceEdgeParts_[srcFacei][srcFaceEdgei];
665  }
666  }
667 
668  // Transform the target couples back to the target side
669  if (!isNull(tgtToSrc))
670  {
671  forAll(tgtCouples_, tgtFacei)
672  {
673  forAll(tgtCouples_[tgtFacei], i)
674  {
675  couple& c = tgtCouples_[tgtFacei][i];
676 
677  c.area = tgtToSrc.invTransform(c.area);
678  c.centre = tgtToSrc.invTransformPosition(c.centre);
679  c.nbr.area = tgtToSrc.invTransform(c.nbr.area);
680  c.nbr.centre = tgtToSrc.invTransformPosition(c.nbr.centre);
681  }
682  }
683  }
684 
685  // Calculate coverage and total areas on both sides
686  auto coverage = []
687  (
688  const primitivePatch& patch,
689  const List<DynamicList<couple>>& couples,
690  scalar& area,
691  scalar& coupleArea,
692  List<scalar>& coverage
693  )
694  {
695  area = 0;
696  coupleArea = 0;
697  coverage.resize(patch.size());
698 
699  forAll(patch, facei)
700  {
701  const scalar magA = mag(patch.faceAreas()[facei]);
702 
703  vector aCouple = Zero;
704  forAll(couples[facei], i)
705  {
706  aCouple += couples[facei][i].area;
707  }
708  const scalar magACouple = mag(aCouple);
709 
710  area += magA;
711  coupleArea += magACouple;
712  coverage[facei] = magACouple/magA;
713  }
714 
715  reduce(area, sumOp<scalar>());
716  reduce(coupleArea, sumOp<scalar>());
717  };
718  scalar srcArea = 0, srcCoupleArea = 0;
719  scalar tgtArea = 0, tgtCoupleArea = 0;
720  coverage(srcPatch, srcCouples_, srcArea, srcCoupleArea, srcCoverage_);
721  coverage(tgtPatch, tgtCouples_, tgtArea, tgtCoupleArea, tgtCoverage_);
722 
723  // Clear the triangulation workspace
724  srcTriPoints_.clear();
725  srcTriFaceEdges_.clear();
726  tgtTriPoints_.clear();
727  tgtTriFaceEdges_.clear();
728 
729  // Clear face-edge-parts
730  srcFaceEdgePart_.clear();
731  tgtFaceEdgePart_.clear();
732  srcFaceEdgeParts_.clear();
733 
734  // Checking and reporting
735  if (nCouples != 0)
736  {
737  scalarField srcOpenness(srcPatch.size());
738  scalarField srcError(srcPatch.size());
739  scalarField srcDepth(srcPatch.size());
740  scalarField srcAngle(srcPatch.size());
741  forAll(srcPatch, srcFacei)
742  {
743  const vector& a = srcPatch.faceAreas()[srcFacei];
744  const scalar magA = mag(a);
745  const point& c = srcPatch.faceCentres()[srcFacei];
746 
747  couple Cpl(part(Zero, c), part(Zero, c));
748  forAll(srcCouples_[srcFacei], srcTgtFacei)
749  {
750  const couple& cpl = srcCouples_[srcFacei][srcTgtFacei];
751 
752  Cpl += cpl;
753  Cpl.nbr += cpl.nbr;
754  }
755 
756  vector projectionA = Zero;
757  scalar projectionV = 0;
758  forAll(srcCouples_[srcFacei], srcTgtFacei)
759  {
760  const couple& cpl = srcCouples_[srcFacei][srcTgtFacei];
761 
762  projectionA += cpl.nbr.area;
763  projectionV +=
764  - (cpl.area/3 & (cpl.centre - Cpl.centre))
765  + (cpl.nbr.area/3 & (cpl.nbr.centre - Cpl.centre));
766  }
767  forAll(srcPatch.faceEdges()[srcFacei], srcFaceEdgei)
768  {
769  const label srcEdgei =
770  srcPatch.faceEdges()[srcFacei][srcFaceEdgei];
771 
772  const edge& e = srcPatch.edges()[srcEdgei];
773  const edge fe =
774  srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
775 
776  const scalar sign = edge::compare(e, fe);
777 
778  projectionA += sign*srcEdgeParts_[srcEdgei].area;
779  projectionV +=
780  sign*srcEdgeParts_[srcEdgei].area/3
781  & (srcEdgeParts_[srcEdgei].centre - Cpl.centre);
782  }
783  projectionA += srcErrorParts_[srcFacei].area;
784  projectionV +=
785  srcErrorParts_[srcFacei].area/3
786  & (srcErrorParts_[srcFacei].centre - Cpl.centre);
787 
788  const vector aHat = normalised(a);
789  const vector aOppHat = normalised(a - Cpl.area + Cpl.nbr.area);
790  srcAngle[srcFacei] =
791  radToDeg(acos(min(max(aHat & aOppHat, -1), +1)));
792  srcOpenness[srcFacei] = mag(projectionA - Cpl.area)/magA;
793  srcError[srcFacei] = mag(srcErrorParts_[srcFacei].area)/magA;
794  srcDepth[srcFacei] = mag(projectionV)/pow3(sqrt(magA));
795  }
796 
797  reduce(tgtArea, sumOp<scalar>());
798  reduce(tgtCoupleArea, sumOp<scalar>());
799 
800  Info<< indent << "Source min/average/max coverage = "
801  << gMin(srcCoverage_) << '/' << srcCoupleArea/srcArea << '/'
802  << gMax(srcCoverage_) << endl
803  << indent << "Target min/average/max coverage = "
804  << gMin(tgtCoverage_) << '/' << tgtCoupleArea/tgtArea << '/'
805  << gMax(tgtCoverage_) << endl
806  << indent << "Source average openness/error/depth/angle = "
807  << gAverage(srcOpenness) << '/' << gAverage(srcError) << '/'
808  << gAverage(srcDepth) << '/' << gAverage(srcAngle) << endl
809  << indent << "Source max openness/error/depth/angle = "
810  << gMax(srcOpenness) << '/' << gMax(srcError) << '/'
811  << gMax(srcDepth) << '/' << gMax(srcAngle) << endl;
812 
813  if (debug)
814  {
815  word name = patchToPatch::typeName + '_' + typeName;
816 
817  if (Pstream::parRun())
818  {
819  name += "_proc" + Foam::name(Pstream::myProcNo());
820  }
821 
822  Info<< indent << "Writing intersected faces to "
823  << name + ".vtk" << endl;
825  (
826  name + ".vtk",
827  name,
828  false,
829  debugPoints_,
830  labelList(),
831  labelListList(),
832  debugFaces_,
833  "srcFace", false, Field<label>(debugFaceSrcFaces_),
834  "tgtFace", false, Field<label>(debugFaceTgtFaces_),
835  "side", false, Field<label>(debugFaceSides_)
836  );
837 
838  debugPoints_.clear();
839  debugFaces_.clear();
840  debugFaceSrcFaces_.clear();
841  debugFaceTgtFaces_.clear();
842  debugFaceSides_.clear();
843 
844  Info<< indent << "Writing source patch to "
845  << name + "_srcPatch.vtk" << endl;
847  (
848  name + "_srcPatch" + ".vtk",
849  name + "_srcPatch",
850  false,
851  srcPatch.localPoints(),
852  labelList(),
853  labelListList(),
854  srcPatch.localFaces(),
855  "coverage", false, scalarField(srcCoverage_),
856  "openness", false, srcOpenness,
857  "error", false, srcError,
858  "depth", false, srcDepth,
859  "angle", false, srcAngle,
860  "normals", true, srcPointNormals
861  );
862 
863  Info<< indent << "Writing target patch to "
864  << name + "_tgtPatch.vtk" << endl;
866  (
867  name + "_tgtPatch" + ".vtk",
868  name + "_tgtPatch",
869  false,
870  tgtPatch.localPoints(),
871  labelList(),
872  labelListList(),
873  tgtPatch.localFaces(),
874  "coverage", false, scalarField(tgtCoverage_)
875  );
876  }
877  }
878 
879  return nCouples;
880 }
881 
882 
884 Foam::patchToPatches::intersection::srcWeights() const
885 {
886  List<DynamicList<scalar>>* resultPtr
887  (
888  new List<DynamicList<scalar>>(srcCouples_.size())
889  );
890  List<DynamicList<scalar>>& result = *resultPtr;
891 
892  forAll(srcCouples_, srcFacei)
893  {
894  result[srcFacei].resize(srcCouples_[srcFacei].size());
895  scalar aSum = 0;
896 
897  forAll(srcCouples_[srcFacei], i)
898  {
899  const scalar a = mag(srcCouples_[srcFacei][i].area);
900  result[srcFacei][i] = a;
901  aSum += a;
902  }
903 
904  forAll(srcCouples_[srcFacei], i)
905  {
906  result[srcFacei][i] *= srcCoverage_[srcFacei]/aSum;
907  }
908  }
909 
910  return tmpNrc<List<DynamicList<scalar>>>(resultPtr);
911 }
912 
913 
915 Foam::patchToPatches::intersection::tgtWeights() const
916 {
917  List<DynamicList<scalar>>* resultPtr
918  (
919  new List<DynamicList<scalar>>(tgtCouples_.size())
920  );
921  List<DynamicList<scalar>>& result = *resultPtr;
922 
923  forAll(tgtCouples_, tgtFacei)
924  {
925  result[tgtFacei].resize(tgtCouples_[tgtFacei].size());
926  scalar aSum = 0;
927 
928  forAll(tgtCouples_[tgtFacei], i)
929  {
930  const scalar a = mag(tgtCouples_[tgtFacei][i].area);
931  result[tgtFacei][i] = a;
932  aSum += a;
933  }
934 
935  forAll(tgtCouples_[tgtFacei], i)
936  {
937  result[tgtFacei][i] *= tgtCoverage_[tgtFacei]/aSum;
938  }
939  }
940 
941  return tmpNrc<List<DynamicList<scalar>>>(resultPtr);
942 }
943 
944 
945 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
946 
948 :
950 
951  srcCouples_(),
952  srcCoverage_(),
953  srcEdgeParts_(),
954  srcErrorParts_(),
955  tgtCouples_(),
956  tgtCoverage_(),
957 
958  triEngine_(),
959 
960  srcTriPoints_(),
961  srcTriFaceEdges_(),
962  tgtTriPoints_(),
963  tgtTriFaceEdges_(),
964 
965  ictSrcPoints_(),
966  ictSrcPointNormals_(),
967  ictTgtPoints_(),
968  ictPointLocations_(),
969 
970  srcFaceEdgePart_(),
971  tgtFaceEdgePart_(),
972 
973  srcFaceEdgeParts_(),
974 
975  debugPoints_(),
976  debugFaces_(),
977  debugFaceSrcFaces_(),
978  debugFaceTgtFaces_(),
979  debugFaceSides_()
980 {}
981 
982 
983 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
984 
986 {}
987 
988 
989 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Macros for easy insertion into run-time selection tables.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:236
const Field< PointType > & faceAreas() const
Return face areas for patch.
const Field< PointType > & points() const
Return reference to global points.
const List< FaceType > & localFaces() const
Return patch faces addressing into local point list.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
const Field< PointType > & faceCentres() const
Return face centres for patch.
A List with indirect addressing.
Definition: UIndirectList.H:60
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
static int compare(const edge &, const edge &)
Compare edges.
Definition: edgeI.H:36
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
static vector area(const PointField &ps)
Return vector area given face points.
Class to generate coupling geometry between two primitive patches.
Definition: patchToPatch.H:56
virtual void rDistributeTgt(const primitiveOldTimePatch &tgtPatch)
Send data that resulted from an intersection between the source.
Definition: patchToPatch.C:724
virtual labelList finaliseLocal(const primitiveOldTimePatch &srcPatch, const vectorField &srcPointNormals, const vectorField &srcPointNormals0, const primitiveOldTimePatch &tgtPatch)
Finalise the intersection locally. Trims the local target patch.
Definition: patchToPatch.C:662
virtual void initialise(const primitiveOldTimePatch &srcPatch, const vectorField &srcPointNormals, const vectorField &srcPointNormals0, const primitiveOldTimePatch &tgtPatch)
Initialisation.
Definition: patchToPatch.C:640
virtual label finalise(const primitiveOldTimePatch &srcPatch, const vectorField &srcPointNormals, const vectorField &srcPointNormals0, const primitiveOldTimePatch &tgtPatch, const transformer &tgtToSrc)
Finalising.
Definition: patchToPatch.C:737
Class to generate patchToPatch coupling geometry. A full geometric intersection is done between a fac...
static treeBoundBox srcBoxStatic(const face &srcFace, const pointField &srcPoints, const vectorField &srcPointNormals)
Get the bound box for a source face.
static int debugSrcFacei
Extra debugging for intersections between specific faces. Named.
intersection(const bool reverse)
Construct from components.
A class for managing temporary objects without reference counting.
Definition: tmpNrc.H:53
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:90
bool overlaps(const boundBox &) const
Overlaps other bounding box?
Definition: boundBoxI.H:120
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:71
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
const dimensionedScalar c
Speed of light in a vacuum.
int debugSwitch(const char *name, const int defaultValue=0)
Lookup debug switch or add default value.
Definition: debug.C:211
static void rDistributeListList(const label size, const distributionMap &map, List< List< Type >> &data)
Reverse distribute a list-list given the map.
addToRunTimeSelectionTable(patchToPatch, intersection, bool)
defineTypeNameAndDebug(intersection, 0)
void intersectTris(const FixedList< point, 3 > &srcPs, const FixedList< vector, 3 > &srcNs, const FixedList< bool, 3 > &srcOwns, const FixedList< label, 3 > &srcTgtPis, const FixedList< point, 3 > &tgtPs, const FixedList< bool, 3 > &tgtOwns, const FixedList< label, 3 > &tgtSrcPis, DynamicList< point > &srcPoints, DynamicList< vector > &srcPointNormals, DynamicList< point > &tgtPoints, DynamicList< location > &pointLocations, const bool debug, const word &writePrefix=word::null)
Construct the intersection of a source triangle's projected volume and a.
void write(const fileName &file, const word &title, const bool binary, const PointField &points, const VertexList &vertices, const LineList &lines, const FaceList &faces, const wordList &fieldNames, const boolList &fieldIsPointValues, const UPtrList< const Field< label >> &fieldLabelValues #define FieldTypeValuesConstArg(Type, nullArg))
Write VTK polygonal data to a file. Takes a PtrList of fields of labels and.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
const doubleScalar e
Definition: doubleScalar.H:105
List< label > labelList
A List of labels.
Definition: labelList.H:56
dimensionedScalar sign(const dimensionedScalar &ds)
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 & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
dimensionedScalar pow3(const dimensionedScalar &ds)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
scalar radToDeg(const scalar rad)
Conversion from radians to degrees.
messageStream Info
vector point
Point is a vector.
Definition: point.H:41
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void reverse(UList< T > &, const label n)
Definition: UListI.H:334
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
Addressing for a faceList slice.
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
dimensionedScalar sqrt(const dimensionedScalar &ds)
PrimitiveOldTimePatch< SubList< face >, const pointField & > primitiveOldTimePatch
Addressing for a faceList slice.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
dimensioned< scalar > mag(const dimensioned< Type > &)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
Form normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:413
Field< vector > vectorField
Specialisation of Field<T> for vector.
Type gAverage(const FieldField< Field, Type > &f)
bool isNull(const T &t)
Return true if t is a reference to the nullObject of type T.
Definition: nullObjectI.H:52
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
Type gMin(const FieldField< Field, Type > &f)
static const label labelMax
Definition: label.H:62
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:221
Type gMax(const FieldField< Field, Type > &f)
dimensionedScalar acos(const dimensionedScalar &ds)
face triFace(3)
volScalarField & p
Functions with which to perform an intersection of a pair of triangles; the source and target....