cellCuts.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 | Copyright (C) 2011-2017 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 "cellCuts.H"
27 #include "polyMesh.H"
28 #include "Time.H"
29 #include "ListOps.H"
30 #include "cellLooper.H"
31 #include "refineCell.H"
32 #include "meshTools.H"
33 #include "geomCellLooper.H"
34 #include "OFstream.H"
35 #include "plane.H"
36 #include "syncTools.H"
37 #include "dummyTransform.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43  defineTypeNameAndDebug(cellCuts, 0);
44 
45  //- Template specialization for pTraits<edge> so we can use syncTools
46  // functionality
47  template<>
48  class pTraits<edge>
49  {
50  public:
51 
52  //- Component type
53  typedef edge cmptType;
54  };
55 }
56 
57 
58 // * * * * * * * * * * * * * Private Static Functions * * * * * * * * * * * //
59 
60 Foam::label Foam::cellCuts::findPartIndex
61 (
62  const labelList& elems,
63  const label nElems,
64  const label val
65 )
66 {
67  for (label i = 0; i < nElems; i++)
68  {
69  if (elems[i] == val)
70  {
71  return i;
72  }
73  }
74  return -1;
75 }
76 
77 
78 Foam::boolList Foam::cellCuts::expand
79 (
80  const label size,
81  const labelList& labels
82 )
83 {
84  boolList result(size, false);
85 
86  forAll(labels, labelI)
87  {
88  result[labels[labelI]] = true;
89  }
90  return result;
91 }
92 
93 
94 Foam::scalarField Foam::cellCuts::expand
95 (
96  const label size,
97  const labelList& labels,
98  const scalarField& weights
99 )
100 {
101  scalarField result(size, -GREAT);
102 
103  forAll(labels, labelI)
104  {
105  result[labels[labelI]] = weights[labelI];
106  }
107  return result;
108 }
109 
110 
111 Foam::label Foam::cellCuts::firstUnique
112 (
113  const labelList& lst,
114  const Map<label>& map
115 )
116 {
117  forAll(lst, i)
118  {
119  if (!map.found(lst[i]))
120  {
121  return i;
122  }
123  }
124  return -1;
125 }
126 
127 
128 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
129 
130 void Foam::cellCuts::syncProc()
131 {
132  if (!Pstream::parRun())
133  {
134  return;
135  }
136 
137  syncTools::syncPointList(mesh(), pointIsCut_, orEqOp<bool>(), false);
138  syncTools::syncEdgeList(mesh(), edgeIsCut_, orEqOp<bool>(), false);
139  syncTools::syncEdgeList(mesh(), edgeWeight_, maxEqOp<scalar>(), -GREAT);
140 
141  {
142  const label nBnd = mesh().nFaces()-mesh().nInternalFaces();
143 
144  // Convert faceSplitCut into face-local data: vertex and edge w.r.t.
145  // vertex 0: (since this is same on both sides)
146  //
147  // Sending-side vertex Receiving-side vertex
148  // 0 0
149  // 1 3
150  // 2 2
151  // 3 1
152  //
153  // Sending-side edge Receiving side edge
154  // 0-1 3-0
155  // 1-2 2-3
156  // 2-3 1-2
157  // 3-0 0-1
158  //
159  // Encoding is as index:
160  // 0 : not set
161  // >0 : vertex, vertex is index-1
162  // <0 : edge, edge is -index-1
163 
164  edgeList relCuts(nBnd, edge(0, 0));
165 
166  const polyBoundaryMesh& pbm = mesh().boundaryMesh();
167 
168  forAll(pbm, patchi)
169  {
170  const polyPatch& pp = pbm[patchi];
171 
172  if (pp.coupled())
173  {
174  forAll(pp, i)
175  {
176  label facei = pp.start()+i;
177  label bFacei = facei-mesh().nInternalFaces();
178 
179  const Map<edge>::const_iterator iter =
180  faceSplitCut_.find(facei);
181  if (iter != faceSplitCut_.end())
182  {
183  const face& f = mesh().faces()[facei];
184  const labelList& fEdges = mesh().faceEdges()[facei];
185  const edge& cuts = iter();
186 
187  forAll(cuts, i)
188  {
189  if (isEdge(cuts[i]))
190  {
191  label edgei = getEdge(cuts[i]);
192  label index = findIndex(fEdges, edgei);
193  relCuts[bFacei][i] = -index-1;
194  }
195  else
196  {
197  label index = findIndex(f, getVertex(cuts[i]));
198  relCuts[bFacei][i] = index+1;
199  }
200  }
201  }
202  }
203  }
204  }
205 
206  // Exchange
208  (
209  mesh(),
210  relCuts,
211  eqOp<edge>(),
213  );
214 
215  // Convert relCuts back into mesh based data
216  forAll(pbm, patchi)
217  {
218  const polyPatch& pp = pbm[patchi];
219 
220  if (pp.coupled())
221  {
222  forAll(pp, i)
223  {
224  label facei = pp.start()+i;
225  label bFacei = facei-mesh().nInternalFaces();
226 
227  const edge& relCut = relCuts[bFacei];
228  if (relCut != edge(0, 0))
229  {
230  const face& f = mesh().faces()[facei];
231  const labelList& fEdges = mesh().faceEdges()[facei];
232 
233  edge absoluteCut(0, 0);
234  forAll(relCut, i)
235  {
236  if (relCut[i] < 0)
237  {
238  label oppFp = -relCut[i]-1;
239  label fp = f.size()-1-oppFp;
240  absoluteCut[i] = edgeToEVert(fEdges[fp]);
241  }
242  else
243  {
244  label oppFp = relCut[i]-1;
245  label fp = f.size()-1-oppFp;
246  absoluteCut[i] = vertToEVert(f[fp]);
247  }
248  }
249 
250  if
251  (
252  !faceSplitCut_.insert(facei, absoluteCut)
253  && faceSplitCut_[facei] != absoluteCut
254  )
255  {
257  << "Cut " << faceSplitCut_[facei]
258  << " on face " << mesh().faceCentres()[facei]
259  << " of coupled patch " << pp.name()
260  << " is not consistent with coupled cut "
261  << absoluteCut
262  << exit(FatalError);
263  }
264  }
265  }
266  }
267  }
268  }
269 }
270 
271 
272 void Foam::cellCuts::writeUncutOBJ
273 (
274  const fileName& dir,
275  const label celli
276 ) const
277 {
278  // Cell edges
279  OFstream cutsStream(dir / "cell_" + name(celli) + ".obj");
280 
281  Pout<< "Writing cell for time " << mesh().time().timeName()
282  << " to " << cutsStream.name() << nl;
283 
285  (
286  cutsStream,
287  mesh().cells(),
288  mesh().faces(),
289  mesh().points(),
290  labelList(1, celli)
291  );
292 
293  // Loop cutting cell in two
294  OFstream cutStream(dir / "cellCuts_" + name(celli) + ".obj");
295 
296  Pout<< "Writing raw cuts on cell for time " << mesh().time().timeName()
297  << " to " << cutStream.name() << nl;
298 
299  const labelList& cPoints = mesh().cellPoints()[celli];
300 
301  forAll(cPoints, i)
302  {
303  label pointi = cPoints[i];
304  if (pointIsCut_[pointi])
305  {
306  meshTools::writeOBJ(cutStream, mesh().points()[pointi]);
307  }
308  }
309 
310  const pointField& pts = mesh().points();
311 
312  const labelList& cEdges = mesh().cellEdges()[celli];
313 
314  forAll(cEdges, i)
315  {
316  label edgeI = cEdges[i];
317 
318  if (edgeIsCut_[edgeI])
319  {
320  const edge& e = mesh().edges()[edgeI];
321 
322  const scalar w = edgeWeight_[edgeI];
323 
324  meshTools::writeOBJ(cutStream, w*pts[e[1]] + (1-w)*pts[e[0]]);
325  }
326  }
327 }
328 
329 
330 void Foam::cellCuts::writeOBJ
331 (
332  const fileName& dir,
333  const label celli,
334  const pointField& loopPoints,
335  const labelList& anchors
336 ) const
337 {
338  // Cell edges
339  OFstream cutsStream(dir / "cell_" + name(celli) + ".obj");
340 
341  Pout<< "Writing cell for time " << mesh().time().timeName()
342  << " to " << cutsStream.name() << nl;
343 
345  (
346  cutsStream,
347  mesh().cells(),
348  mesh().faces(),
349  mesh().points(),
350  labelList(1, celli)
351  );
352 
353 
354  // Loop cutting cell in two
355  OFstream loopStream(dir / "cellLoop_" + name(celli) + ".obj");
356 
357  Pout<< "Writing loop for time " << mesh().time().timeName()
358  << " to " << loopStream.name() << nl;
359 
360  label vertI = 0;
361 
362  writeOBJ(loopStream, loopPoints, vertI);
363 
364 
365  // Anchors for cell
366  OFstream anchorStream(dir / "anchors_" + name(celli) + ".obj");
367 
368  Pout<< "Writing anchors for time " << mesh().time().timeName()
369  << " to " << anchorStream.name() << endl;
370 
371  forAll(anchors, i)
372  {
373  meshTools::writeOBJ(anchorStream, mesh().points()[anchors[i]]);
374  }
375 }
376 
377 
378 Foam::label Foam::cellCuts::edgeEdgeToFace
379 (
380  const label celli,
381  const label edgeA,
382  const label edgeB
383 ) const
384 {
385  const labelList& cFaces = mesh().cells()[celli];
386 
387  forAll(cFaces, cFacei)
388  {
389  label facei = cFaces[cFacei];
390 
391  const labelList& fEdges = mesh().faceEdges()[facei];
392 
393  if
394  (
395  findIndex(fEdges, edgeA) != -1
396  && findIndex(fEdges, edgeB) != -1
397  )
398  {
399  return facei;
400  }
401  }
402 
403  // Coming here means the loop is illegal since the two edges
404  // are not shared by a face. We just mark loop as invalid and continue.
405 
407  << "cellCuts : Cannot find face on cell "
408  << celli << " that has both edges " << edgeA << ' ' << edgeB << endl
409  << "faces : " << cFaces << endl
410  << "edgeA : " << mesh().edges()[edgeA] << endl
411  << "edgeB : " << mesh().edges()[edgeB] << endl
412  << "Marking the loop across this cell as invalid" << endl;
413 
414  return -1;
415 }
416 
417 
418 Foam::label Foam::cellCuts::edgeVertexToFace
419 (
420  const label celli,
421  const label edgeI,
422  const label vertI
423 ) const
424 {
425  const labelList& cFaces = mesh().cells()[celli];
426 
427  forAll(cFaces, cFacei)
428  {
429  label facei = cFaces[cFacei];
430 
431  const face& f = mesh().faces()[facei];
432 
433  const labelList& fEdges = mesh().faceEdges()[facei];
434 
435  if
436  (
437  findIndex(fEdges, edgeI) != -1
438  && findIndex(f, vertI) != -1
439  )
440  {
441  return facei;
442  }
443  }
444 
446  << "cellCuts : Cannot find face on cell "
447  << celli << " that has both edge " << edgeI << " and vertex "
448  << vertI << endl
449  << "faces : " << cFaces << endl
450  << "edge : " << mesh().edges()[edgeI] << endl
451  << "Marking the loop across this cell as invalid" << endl;
452 
453  return -1;
454 }
455 
456 
457 Foam::label Foam::cellCuts::vertexVertexToFace
458 (
459  const label celli,
460  const label vertA,
461  const label vertB
462 ) const
463 {
464  const labelList& cFaces = mesh().cells()[celli];
465 
466  forAll(cFaces, cFacei)
467  {
468  label facei = cFaces[cFacei];
469 
470  const face& f = mesh().faces()[facei];
471 
472  if
473  (
474  findIndex(f, vertA) != -1
475  && findIndex(f, vertB) != -1
476  )
477  {
478  return facei;
479  }
480  }
481 
483  << "cellCuts : Cannot find face on cell "
484  << celli << " that has vertex " << vertA << " and vertex "
485  << vertB << endl
486  << "faces : " << cFaces << endl
487  << "Marking the loop across this cell as invalid" << endl;
488 
489  return -1;
490 }
491 
492 
493 void Foam::cellCuts::calcFaceCuts() const
494 {
495  if (faceCutsPtr_.valid())
496  {
498  << "faceCuts already calculated" << abort(FatalError);
499  }
500 
501  const faceList& faces = mesh().faces();
502 
503  faceCutsPtr_.reset(new labelListList(mesh().nFaces()));
504  labelListList& faceCuts = faceCutsPtr_();
505 
506  for (label facei = 0; facei < mesh().nFaces(); facei++)
507  {
508  const face& f = faces[facei];
509 
510  // Big enough storage (possibly all points and all edges cut). Shrink
511  // later on.
512  labelList& cuts = faceCuts[facei];
513 
514  cuts.setSize(2*f.size());
515 
516  label cutI = 0;
517 
518  // Do point-edge-point walk over face and collect all cuts.
519  // Problem is that we want to start from one of the endpoints of a
520  // string of connected cuts; we don't want to start somewhere in the
521  // middle.
522 
523  // Pass1: find first point cut not preceeded by a cut.
524  label startFp = -1;
525 
526  forAll(f, fp)
527  {
528  label v0 = f[fp];
529 
530  if (pointIsCut_[v0])
531  {
532  label vMin1 = f[f.rcIndex(fp)];
533 
534  if
535  (
536  !pointIsCut_[vMin1]
537  && !edgeIsCut_[findEdge(facei, v0, vMin1)]
538  )
539  {
540  cuts[cutI++] = vertToEVert(v0);
541  startFp = f.fcIndex(fp);
542  break;
543  }
544  }
545  }
546 
547  // Pass2: first edge cut not preceeded by point cut
548  if (startFp == -1)
549  {
550  forAll(f, fp)
551  {
552  label fp1 = f.fcIndex(fp);
553 
554  label v0 = f[fp];
555  label v1 = f[fp1];
556 
557  label edgeI = findEdge(facei, v0, v1);
558 
559  if (edgeIsCut_[edgeI] && !pointIsCut_[v0])
560  {
561  cuts[cutI++] = edgeToEVert(edgeI);
562  startFp = fp1;
563  break;
564  }
565  }
566  }
567 
568  // Pass3: nothing found so far. Either face is not cut at all or all
569  // vertices are cut. Start from 0.
570  if (startFp == -1)
571  {
572  startFp = 0;
573  }
574 
575  // Store all cuts starting from startFp;
576  label fp = startFp;
577 
578  bool allVerticesCut = true;
579 
580  forAll(f, i)
581  {
582  label fp1 = f.fcIndex(fp);
583 
584  // Get the three items: current vertex, next vertex and edge
585  // inbetween
586  label v0 = f[fp];
587  label v1 = f[fp1];
588  label edgeI = findEdge(facei, v0, v1);
589 
590  if (pointIsCut_[v0])
591  {
592  cuts[cutI++] = vertToEVert(v0);
593  }
594  else
595  {
596  // For check if all vertices have been cut (= illegal)
597  allVerticesCut = false;
598  }
599 
600  if (edgeIsCut_[edgeI])
601  {
602  cuts[cutI++] = edgeToEVert(edgeI);
603  }
604 
605  fp = fp1;
606  }
607 
608 
609  if (allVerticesCut)
610  {
612  << "Face " << facei << " vertices " << f
613  << " has all its vertices cut. Not cutting face." << endl;
614 
615  cutI = 0;
616  }
617 
618  // Remove duplicate starting point
619  if (cutI > 1 && cuts[cutI-1] == cuts[0])
620  {
621  cutI--;
622  }
623  cuts.setSize(cutI);
624  }
625 }
626 
627 
628 Foam::label Foam::cellCuts::findEdge
629 (
630  const label facei,
631  const label v0,
632  const label v1
633 ) const
634 {
635  const edgeList& edges = mesh().edges();
636 
637  const labelList& fEdges = mesh().faceEdges()[facei];
638 
639  forAll(fEdges, i)
640  {
641  const edge& e = edges[fEdges[i]];
642 
643  if
644  (
645  (e[0] == v0 && e[1] == v1)
646  || (e[0] == v1 && e[1] == v0)
647  )
648  {
649  return fEdges[i];
650  }
651  }
652 
653  return -1;
654 }
655 
656 
657 Foam::label Foam::cellCuts::loopFace
658 (
659  const label celli,
660  const labelList& loop
661 ) const
662 {
663  const cell& cFaces = mesh().cells()[celli];
664 
665  forAll(cFaces, cFacei)
666  {
667  label facei = cFaces[cFacei];
668 
669  const labelList& fEdges = mesh().faceEdges()[facei];
670  const face& f = mesh().faces()[facei];
671 
672  bool allOnFace = true;
673 
674  forAll(loop, i)
675  {
676  label cut = loop[i];
677 
678  if (isEdge(cut))
679  {
680  if (findIndex(fEdges, getEdge(cut)) == -1)
681  {
682  // Edge not on face. Skip face.
683  allOnFace = false;
684  break;
685  }
686  }
687  else
688  {
689  if (findIndex(f, getVertex(cut)) == -1)
690  {
691  // Vertex not on face. Skip face.
692  allOnFace = false;
693  break;
694  }
695  }
696  }
697 
698  if (allOnFace)
699  {
700  // Found face where all elements of loop are on the face.
701  return facei;
702  }
703  }
704  return -1;
705 }
706 
707 
708 bool Foam::cellCuts::walkPoint
709 (
710  const label celli,
711  const label startCut,
712 
713  const label exclude0,
714  const label exclude1,
715 
716  const label otherCut,
717 
718  label& nVisited,
719  labelList& visited
720 ) const
721 {
722  label vertI = getVertex(otherCut);
723 
724  const labelList& pFaces = mesh().pointFaces()[vertI];
725 
726  forAll(pFaces, pFacei)
727  {
728  label otherFacei = pFaces[pFacei];
729 
730  if
731  (
732  otherFacei != exclude0
733  && otherFacei != exclude1
734  && meshTools::faceOnCell(mesh(), celli, otherFacei)
735  )
736  {
737  label oldNVisited = nVisited;
738 
739  bool foundLoop =
740  walkCell
741  (
742  celli,
743  startCut,
744  otherFacei,
745  otherCut,
746  nVisited,
747  visited
748  );
749 
750  if (foundLoop)
751  {
752  return true;
753  }
754 
755  // No success. Restore state and continue
756  nVisited = oldNVisited;
757  }
758  }
759  return false;
760 }
761 
762 
763 bool Foam::cellCuts::crossEdge
764 (
765  const label celli,
766  const label startCut,
767  const label facei,
768  const label otherCut,
769 
770  label& nVisited,
771  labelList& visited
772 ) const
773 {
774  // Cross edge to other face
775  label edgeI = getEdge(otherCut);
776 
777  label otherFacei = meshTools::otherFace(mesh(), celli, facei, edgeI);
778 
779  // Store old state
780  label oldNVisited = nVisited;
781 
782  // Recurse to otherCut
783  bool foundLoop =
784  walkCell
785  (
786  celli,
787  startCut,
788  otherFacei,
789  otherCut,
790  nVisited,
791  visited
792  );
793 
794  if (foundLoop)
795  {
796  return true;
797  }
798  else
799  {
800  // No success. Restore state (i.e. backtrack)
801  nVisited = oldNVisited;
802 
803  return false;
804  }
805 }
806 
807 
808 bool Foam::cellCuts::addCut
809 (
810  const label celli,
811  const label cut,
812  label& nVisited,
813  labelList& visited
814 ) const
815 {
816  // Check for duplicate cuts.
817  if (findPartIndex(visited, nVisited, cut) != -1)
818  {
819  // Truncate (copy of) visited for ease of printing.
820  labelList truncVisited(visited);
821  truncVisited.setSize(nVisited);
822 
823  Pout<< "For cell " << celli << " : trying to add duplicate cut " << cut;
824  labelList cuts(1, cut);
825  writeCuts(Pout, cuts, loopWeights(cuts));
826 
827  Pout<< " to path:";
828  writeCuts(Pout, truncVisited, loopWeights(truncVisited));
829  Pout<< endl;
830 
831  return false;
832  }
833  else
834  {
835  visited[nVisited++] = cut;
836 
837  return true;
838  }
839 }
840 
841 
842 bool Foam::cellCuts::walkFace
843 (
844  const label celli,
845  const label startCut,
846  const label facei,
847  const label cut,
848 
849  label& lastCut,
850  label& beforeLastCut,
851  label& nVisited,
852  labelList& visited
853 ) const
854 {
855  const labelList& fCuts = faceCuts()[facei];
856 
857  if (fCuts.size() < 2)
858  {
859  return false;
860  }
861 
862  // Easy case : two cuts.
863  if (fCuts.size() == 2)
864  {
865  if (fCuts[0] == cut)
866  {
867  if (!addCut(celli, cut, nVisited, visited))
868  {
869  return false;
870  }
871 
872  beforeLastCut = cut;
873  lastCut = fCuts[1];
874 
875  return true;
876  }
877  else
878  {
879  if (!addCut(celli, cut, nVisited, visited))
880  {
881  return false;
882  }
883 
884  beforeLastCut = cut;
885  lastCut = fCuts[0];
886 
887  return true;
888  }
889  }
890 
891  // Harder case: more than 2 cuts on face.
892  // Should be start or end of string of cuts. Store all but last cut.
893  if (fCuts[0] == cut)
894  {
895  // Walk forward
896  for (label i = 0; i < fCuts.size()-1; i++)
897  {
898  if (!addCut(celli, fCuts[i], nVisited, visited))
899  {
900  return false;
901  }
902  }
903  beforeLastCut = fCuts[fCuts.size()-2];
904  lastCut = fCuts[fCuts.size()-1];
905  }
906  else if (fCuts[fCuts.size()-1] == cut)
907  {
908  for (label i = fCuts.size()-1; i >= 1; --i)
909  {
910  if (!addCut(celli, fCuts[i], nVisited, visited))
911  {
912  return false;
913  }
914  }
915  beforeLastCut = fCuts[1];
916  lastCut = fCuts[0];
917  }
918  else
919  {
921  << "In middle of cut. cell:" << celli << " face:" << facei
922  << " cuts:" << fCuts << " current cut:" << cut << endl;
923 
924  return false;
925  }
926 
927  return true;
928 }
929 
930 
931 
932 bool Foam::cellCuts::walkCell
933 (
934  const label celli,
935  const label startCut,
936  const label facei,
937  const label cut,
938 
939  label& nVisited,
940  labelList& visited
941 ) const
942 {
943  // Walk across face, storing cuts. Return last two cuts visited.
944  label lastCut = -1;
945  label beforeLastCut = -1;
946 
947 
948  if (debug & 2)
949  {
950  Pout<< "For cell:" << celli << " walked across face " << facei
951  << " from cut ";
952  labelList cuts(1, cut);
953  writeCuts(Pout, cuts, loopWeights(cuts));
954  Pout<< endl;
955  }
956 
957  bool validWalk = walkFace
958  (
959  celli,
960  startCut,
961  facei,
962  cut,
963 
964  lastCut,
965  beforeLastCut,
966  nVisited,
967  visited
968  );
969 
970  if (!validWalk)
971  {
972  return false;
973  }
974 
975  if (debug & 2)
976  {
977  Pout<< " to last cut ";
978  labelList cuts(1, lastCut);
979  writeCuts(Pout, cuts, loopWeights(cuts));
980  Pout<< endl;
981  }
982 
983  // Check if starting point reached.
984  if (lastCut == startCut)
985  {
986  if (nVisited >= 3)
987  {
988  if (debug & 2)
989  {
990  // Truncate (copy of) visited for ease of printing.
991  labelList truncVisited(visited);
992  truncVisited.setSize(nVisited);
993 
994  Pout<< "For cell " << celli << " : found closed path:";
995  writeCuts(Pout, truncVisited, loopWeights(truncVisited));
996  Pout<< " closed by " << lastCut << endl;
997  }
998 
999  return true;
1000  }
1001  else
1002  {
1003  // Loop but too short. Probably folded back on itself.
1004  return false;
1005  }
1006  }
1007 
1008 
1009  // Check last cut and one before that to determine type.
1010 
1011  // From beforeLastCut to lastCut:
1012  // - from edge to edge
1013  // (- always not along existing edge)
1014  // - from edge to vertex
1015  // - not along existing edge
1016  // - along existing edge: not allowed?
1017  // - from vertex to edge
1018  // - not along existing edge
1019  // - along existing edge. Not allowed. See above.
1020  // - from vertex to vertex
1021  // - not along existing edge
1022  // - along existing edge
1023 
1024  if (isEdge(beforeLastCut))
1025  {
1026  if (isEdge(lastCut))
1027  {
1028  // beforeLastCut=edge, lastCut=edge.
1029 
1030  // Cross lastCut (=edge) into face not facei
1031  return crossEdge
1032  (
1033  celli,
1034  startCut,
1035  facei,
1036  lastCut,
1037  nVisited,
1038  visited
1039  );
1040  }
1041  else
1042  {
1043  // beforeLastCut=edge, lastCut=vertex.
1044 
1045  // Go from lastCut to all connected faces (except facei)
1046  return walkPoint
1047  (
1048  celli,
1049  startCut,
1050  facei, // exclude0: don't cross back on current face
1051  -1, // exclude1
1052  lastCut,
1053  nVisited,
1054  visited
1055  );
1056  }
1057  }
1058  else
1059  {
1060  if (isEdge(lastCut))
1061  {
1062  // beforeLastCut=vertex, lastCut=edge.
1063  return crossEdge
1064  (
1065  celli,
1066  startCut,
1067  facei,
1068  lastCut,
1069  nVisited,
1070  visited
1071  );
1072  }
1073  else
1074  {
1075  // beforeLastCut=vertex, lastCut=vertex. Check if along existing
1076  // edge.
1077  label edgeI =
1078  findEdge
1079  (
1080  facei,
1081  getVertex(beforeLastCut),
1082  getVertex(lastCut)
1083  );
1084 
1085  if (edgeI != -1)
1086  {
1087  // Cut along existing edge. So is in fact on two faces.
1088  // Get faces on both sides of the edge to make
1089  // sure we dont fold back on to those.
1090 
1091  label f0, f1;
1092  meshTools::getEdgeFaces(mesh(), celli, edgeI, f0, f1);
1093 
1094  return walkPoint
1095  (
1096  celli,
1097  startCut,
1098  f0,
1099  f1,
1100  lastCut,
1101  nVisited,
1102  visited
1103  );
1104 
1105  }
1106  else
1107  {
1108  // Cross cut across face.
1109  return walkPoint
1110  (
1111  celli,
1112  startCut,
1113  facei, // face to exclude
1114  -1, // face to exclude
1115  lastCut,
1116  nVisited,
1117  visited
1118  );
1119  }
1120  }
1121  }
1122 }
1123 
1124 
1125 void Foam::cellCuts::calcCellLoops(const labelList& cutCells)
1126 {
1127  // Determine for every cut cell the loop (= face) it is cut by. Done by
1128  // starting from a cut edge or cut vertex and walking across faces, from
1129  // cut to cut, until starting cut hit.
1130  // If multiple loops are possible across a cell circumference takes the
1131  // first one found.
1132 
1133  // Calculate cuts per face.
1134  const labelListList& allFaceCuts = faceCuts();
1135 
1136  // Per cell the number of faces with valid cuts. Is used as quick
1137  // rejection to see if cell can be cut.
1138  labelList nCutFaces(mesh().nCells(), 0);
1139 
1140  forAll(allFaceCuts, facei)
1141  {
1142  const labelList& fCuts = allFaceCuts[facei];
1143 
1144  if (fCuts.size() == mesh().faces()[facei].size())
1145  {
1146  // Too many cuts on face. WalkCell would get very upset so disable.
1147  nCutFaces[mesh().faceOwner()[facei]] = labelMin;
1148 
1149  if (mesh().isInternalFace(facei))
1150  {
1151  nCutFaces[mesh().faceNeighbour()[facei]] = labelMin;
1152  }
1153  }
1154  else if (fCuts.size() >= 2)
1155  {
1156  // Could be valid cut. Update count for owner and neighbour.
1157  nCutFaces[mesh().faceOwner()[facei]]++;
1158 
1159  if (mesh().isInternalFace(facei))
1160  {
1161  nCutFaces[mesh().faceNeighbour()[facei]]++;
1162  }
1163  }
1164  }
1165 
1166 
1167  // Stack of visited cuts (nVisited used as stack pointer)
1168  // Size big enough.
1169  labelList visited(mesh().nPoints());
1170 
1171  forAll(cutCells, i)
1172  {
1173  label celli = cutCells[i];
1174 
1175  bool validLoop = false;
1176 
1177  // Quick rejection: has enough faces that are cut?
1178  if (nCutFaces[celli] >= 3)
1179  {
1180  const labelList& cFaces = mesh().cells()[celli];
1181 
1182  if (debug & 2)
1183  {
1184  Pout<< "cell:" << celli << " cut faces:" << endl;
1185  forAll(cFaces, i)
1186  {
1187  label facei = cFaces[i];
1188  const labelList& fCuts = allFaceCuts[facei];
1189 
1190  Pout<< " face:" << facei << " cuts:";
1191  writeCuts(Pout, fCuts, loopWeights(fCuts));
1192  Pout<< endl;
1193  }
1194  }
1195 
1196  label nVisited = 0;
1197 
1198  // Determine the first cut face to start walking from.
1199  forAll(cFaces, cFacei)
1200  {
1201  label facei = cFaces[cFacei];
1202 
1203  const labelList& fCuts = allFaceCuts[facei];
1204 
1205  // Take first or last cut of multiple on face.
1206  // Note that in calcFaceCuts
1207  // we have already made sure this is the start or end of a
1208  // string of cuts.
1209  if (fCuts.size() >= 2)
1210  {
1211  // Try walking from start of fCuts.
1212  nVisited = 0;
1213 
1214  if (debug & 2)
1215  {
1216  Pout<< "cell:" << celli
1217  << " start walk at face:" << facei
1218  << " cut:";
1219  labelList cuts(1, fCuts[0]);
1220  writeCuts(Pout, cuts, loopWeights(cuts));
1221  Pout<< endl;
1222  }
1223 
1224  validLoop =
1225  walkCell
1226  (
1227  celli,
1228  fCuts[0],
1229  facei,
1230  fCuts[0],
1231 
1232  nVisited,
1233  visited
1234  );
1235 
1236  if (validLoop)
1237  {
1238  break;
1239  }
1240 
1241  // No need to try and walk from end of cuts since
1242  // all paths already tried by walkCell.
1243  }
1244  }
1245 
1246  if (validLoop)
1247  {
1248  // Copy nVisited elements out of visited (since visited is
1249  // never truncated for efficiency reasons)
1250 
1251  labelList& loop = cellLoops_[celli];
1252 
1253  loop.setSize(nVisited);
1254 
1255  for (label i = 0; i < nVisited; i++)
1256  {
1257  loop[i] = visited[i];
1258  }
1259  }
1260  else
1261  {
1262  // Invalid loop. Leave cellLoops_[celli] zero size which
1263  // flags this.
1264  Pout<< "calcCellLoops(const labelList&) : did not find valid"
1265  << " loop for cell " << celli << endl;
1266  // Dump cell and cuts on cell.
1267  writeUncutOBJ(".", celli);
1268 
1269  cellLoops_[celli].setSize(0);
1270  }
1271  }
1272  else
1273  {
1274  //Pout<< "calcCellLoops(const labelList&) : did not find valid"
1275  // << " loop for cell " << celli << " since not enough cut faces"
1276  // << endl;
1277  cellLoops_[celli].setSize(0);
1278  }
1279  }
1280 }
1281 
1282 
1283 void Foam::cellCuts::walkEdges
1284 (
1285  const label celli,
1286  const label pointi,
1287  const label status,
1288 
1289  Map<label>& edgeStatus,
1290  Map<label>& pointStatus
1291 ) const
1292 {
1293  if (pointStatus.insert(pointi, status))
1294  {
1295  // First visit to pointi
1296 
1297  const labelList& pEdges = mesh().pointEdges()[pointi];
1298 
1299  forAll(pEdges, pEdgeI)
1300  {
1301  label edgeI = pEdges[pEdgeI];
1302 
1303  if
1304  (
1305  meshTools::edgeOnCell(mesh(), celli, edgeI)
1306  && edgeStatus.insert(edgeI, status)
1307  )
1308  {
1309  // First visit to edgeI so recurse.
1310 
1311  label v2 = mesh().edges()[edgeI].otherVertex(pointi);
1312 
1313  walkEdges(celli, v2, status, edgeStatus, pointStatus);
1314  }
1315  }
1316  }
1317 }
1318 
1319 
1322  const labelList& cellPoints,
1323  const labelList& anchorPoints,
1324  const labelList& loop
1325 ) const
1326 {
1327  labelList newElems(cellPoints.size());
1328  label newElemI = 0;
1329 
1330  forAll(cellPoints, i)
1331  {
1332  label pointi = cellPoints[i];
1333 
1334  if
1335  (
1336  findIndex(anchorPoints, pointi) == -1
1337  && findIndex(loop, vertToEVert(pointi)) == -1
1338  )
1339  {
1340  newElems[newElemI++] = pointi;
1341  }
1342  }
1343 
1344  newElems.setSize(newElemI);
1345 
1346  return newElems;
1347 }
1348 
1349 
1350 bool Foam::cellCuts::loopAnchorConsistent
1351 (
1352  const label celli,
1353  const pointField& loopPts,
1354  const labelList& anchorPoints
1355 ) const
1356 {
1357  // Create identity face for ease of calculation of normal etc.
1358  face f(identity(loopPts.size()));
1359 
1360  vector normal = f.normal(loopPts);
1361  point ctr = f.centre(loopPts);
1362 
1363 
1364  // Get average position of anchor points.
1365  vector avg(Zero);
1366 
1367  forAll(anchorPoints, ptI)
1368  {
1369  avg += mesh().points()[anchorPoints[ptI]];
1370  }
1371  avg /= anchorPoints.size();
1372 
1373 
1374  if (((avg - ctr) & normal) > 0)
1375  {
1376  return true;
1377  }
1378  else
1379  {
1380  return false;
1381  }
1382 }
1383 
1384 
1385 bool Foam::cellCuts::calcAnchors
1386 (
1387  const label celli,
1388  const labelList& loop,
1389  const pointField& loopPts,
1390 
1391  labelList& anchorPoints
1392 ) const
1393 {
1394  const edgeList& edges = mesh().edges();
1395 
1396  const labelList& cPoints = mesh().cellPoints()[celli];
1397  const labelList& cEdges = mesh().cellEdges()[celli];
1398  const cell& cFaces = mesh().cells()[celli];
1399 
1400  // Points on loop
1401 
1402  // Status of point:
1403  // 0 - on loop
1404  // 1 - point set 1
1405  // 2 - point set 2
1406  Map<label> pointStatus(2*cPoints.size());
1407  Map<label> edgeStatus(2*cEdges.size());
1408 
1409  // Mark loop vertices
1410  forAll(loop, i)
1411  {
1412  label cut = loop[i];
1413 
1414  if (isEdge(cut))
1415  {
1416  edgeStatus.insert(getEdge(cut), 0);
1417  }
1418  else
1419  {
1420  pointStatus.insert(getVertex(cut), 0);
1421  }
1422  }
1423  // Since edges between two cut vertices have not been marked, mark them
1424  // explicitly
1425  forAll(cEdges, i)
1426  {
1427  label edgeI = cEdges[i];
1428  const edge& e = edges[edgeI];
1429 
1430  if (pointStatus.found(e[0]) && pointStatus.found(e[1]))
1431  {
1432  edgeStatus.insert(edgeI, 0);
1433  }
1434  }
1435 
1436 
1437  // Find uncut starting vertex
1438  label uncutIndex = firstUnique(cPoints, pointStatus);
1439 
1440  if (uncutIndex == -1)
1441  {
1443  << "Invalid loop " << loop << " for cell " << celli << endl
1444  << "Can not find point on cell which is not cut by loop."
1445  << endl;
1446 
1447  writeOBJ(".", celli, loopPts, labelList(0));
1448 
1449  return false;
1450  }
1451 
1452  // Walk unset vertices and edges and mark with 1 in pointStatus, edgeStatus
1453  walkEdges(celli, cPoints[uncutIndex], 1, edgeStatus, pointStatus);
1454 
1455  // Find new uncut starting vertex
1456  uncutIndex = firstUnique(cPoints, pointStatus);
1457 
1458  if (uncutIndex == -1)
1459  {
1460  // All vertices either in loop or in anchor. So split is along single
1461  // face.
1463  << "Invalid loop " << loop << " for cell " << celli << endl
1464  << "All vertices of cell are either in loop or in anchor set"
1465  << endl;
1466 
1467  writeOBJ(".", celli, loopPts, labelList(0));
1468 
1469  return false;
1470  }
1471 
1472  // Walk unset vertices and edges and mark with 2. These are the
1473  // pointset 2.
1474  walkEdges(celli, cPoints[uncutIndex], 2, edgeStatus, pointStatus);
1475 
1476  // Collect both sets in lists.
1477  DynamicList<label> connectedPoints(cPoints.size());
1478  DynamicList<label> otherPoints(cPoints.size());
1479 
1480  forAllConstIter(Map<label>, pointStatus, iter)
1481  {
1482  if (iter() == 1)
1483  {
1484  connectedPoints.append(iter.key());
1485  }
1486  else if (iter() == 2)
1487  {
1488  otherPoints.append(iter.key());
1489  }
1490  }
1491  connectedPoints.shrink();
1492  otherPoints.shrink();
1493 
1494  // Check that all points have been used.
1495  uncutIndex = firstUnique(cPoints, pointStatus);
1496 
1497  if (uncutIndex != -1)
1498  {
1500  << "Invalid loop " << loop << " for cell " << celli
1501  << " since it splits the cell into more than two cells" << endl;
1502 
1503  writeOBJ(".", celli, loopPts, connectedPoints);
1504 
1505  return false;
1506  }
1507 
1508 
1509  // Check that both parts (connectedPoints, otherPoints) have enough faces.
1510  labelHashSet connectedFaces(2*cFaces.size());
1511  labelHashSet otherFaces(2*cFaces.size());
1512 
1513  forAllConstIter(Map<label>, pointStatus, iter)
1514  {
1515  label pointi = iter.key();
1516 
1517  const labelList& pFaces = mesh().pointFaces()[pointi];
1518 
1519  if (iter() == 1)
1520  {
1521  forAll(pFaces, pFacei)
1522  {
1523  if (meshTools::faceOnCell(mesh(), celli, pFaces[pFacei]))
1524  {
1525  connectedFaces.insert(pFaces[pFacei]);
1526  }
1527  }
1528  }
1529  else if (iter() == 2)
1530  {
1531  forAll(pFaces, pFacei)
1532  {
1533  if (meshTools::faceOnCell(mesh(), celli, pFaces[pFacei]))
1534  {
1535  otherFaces.insert(pFaces[pFacei]);
1536  }
1537  }
1538  }
1539  }
1540 
1541  if (connectedFaces.size() < 3)
1542  {
1544  << "Invalid loop " << loop << " for cell " << celli
1545  << " since would have too few faces on one side." << nl
1546  << "All faces:" << cFaces << endl;
1547 
1548  writeOBJ(".", celli, loopPts, connectedPoints);
1549 
1550  return false;
1551  }
1552 
1553  if (otherFaces.size() < 3)
1554  {
1556  << "Invalid loop " << loop << " for cell " << celli
1557  << " since would have too few faces on one side." << nl
1558  << "All faces:" << cFaces << endl;
1559 
1560  writeOBJ(".", celli, loopPts, otherPoints);
1561 
1562  return false;
1563  }
1564 
1565 
1566  // Check that faces are split into two regions and not more.
1567  // When walking across the face the only transition of pointStatus is
1568  // from set1 to loop to set2 or back. Not allowed is from set1 to loop to
1569  // set1.
1570  {
1571  forAll(cFaces, i)
1572  {
1573  label facei = cFaces[i];
1574 
1575  const face& f = mesh().faces()[facei];
1576 
1577  bool hasSet1 = false;
1578  bool hasSet2 = false;
1579 
1580  label prevStat = pointStatus[f[0]];
1581 
1582  forAll(f, fp)
1583  {
1584  label v0 = f[fp];
1585  label pStat = pointStatus[v0];
1586 
1587  if (pStat == prevStat)
1588  {
1589  }
1590  else if (pStat == 0)
1591  {
1592  // Loop.
1593  }
1594  else if (pStat == 1)
1595  {
1596  if (hasSet1)
1597  {
1598  // Second occurence of set1.
1600  << "Invalid loop " << loop << " for cell " << celli
1601  << " since face " << f << " would be split into"
1602  << " more than two faces" << endl;
1603 
1604  writeOBJ(".", celli, loopPts, otherPoints);
1605 
1606  return false;
1607  }
1608 
1609  hasSet1 = true;
1610  }
1611  else if (pStat == 2)
1612  {
1613  if (hasSet2)
1614  {
1615  // Second occurence of set1.
1617  << "Invalid loop " << loop << " for cell " << celli
1618  << " since face " << f << " would be split into"
1619  << " more than two faces" << endl;
1620 
1621  writeOBJ(".", celli, loopPts, otherPoints);
1622 
1623  return false;
1624  }
1625 
1626  hasSet2 = true;
1627  }
1628  else
1629  {
1631  << abort(FatalError);
1632  }
1633 
1634  prevStat = pStat;
1635 
1636 
1637  label v1 = f.nextLabel(fp);
1638  label edgeI = findEdge(facei, v0, v1);
1639 
1640  label eStat = edgeStatus[edgeI];
1641 
1642  if (eStat == prevStat)
1643  {
1644  }
1645  else if (eStat == 0)
1646  {
1647  // Loop.
1648  }
1649  else if (eStat == 1)
1650  {
1651  if (hasSet1)
1652  {
1653  // Second occurence of set1.
1655  << "Invalid loop " << loop << " for cell " << celli
1656  << " since face " << f << " would be split into"
1657  << " more than two faces" << endl;
1658 
1659  writeOBJ(".", celli, loopPts, otherPoints);
1660 
1661  return false;
1662  }
1663 
1664  hasSet1 = true;
1665  }
1666  else if (eStat == 2)
1667  {
1668  if (hasSet2)
1669  {
1670  // Second occurence of set1.
1672  << "Invalid loop " << loop << " for cell " << celli
1673  << " since face " << f << " would be split into"
1674  << " more than two faces" << endl;
1675 
1676  writeOBJ(".", celli, loopPts, otherPoints);
1677 
1678  return false;
1679  }
1680 
1681  hasSet2 = true;
1682  }
1683  prevStat = eStat;
1684  }
1685  }
1686  }
1687 
1688 
1689 
1690 
1691  // Check which one of point sets to use.
1692  bool loopOk = loopAnchorConsistent(celli, loopPts, connectedPoints);
1693 
1694  //if (debug)
1695  {
1696  // Additional check: are non-anchor points on other side?
1697  bool otherLoopOk = loopAnchorConsistent(celli, loopPts, otherPoints);
1698 
1699  if (loopOk == otherLoopOk)
1700  {
1701  // Both sets of points are supposedly on the same side as the
1702  // loop normal. Oops.
1703 
1705  << " For cell:" << celli
1706  << " achorpoints and nonanchorpoints are geometrically"
1707  << " on same side!" << endl
1708  << "cellPoints:" << cPoints << endl
1709  << "loop:" << loop << endl
1710  << "anchors:" << connectedPoints << endl
1711  << "otherPoints:" << otherPoints << endl;
1712 
1713  writeOBJ(".", celli, loopPts, connectedPoints);
1714  }
1715  }
1716 
1717  if (loopOk)
1718  {
1719  // connectedPoints on 'outside' of loop so these are anchor points
1720  anchorPoints.transfer(connectedPoints);
1721  connectedPoints.clear();
1722  }
1723  else
1724  {
1725  anchorPoints.transfer(otherPoints);
1726  otherPoints.clear();
1727  }
1728  return true;
1729 }
1730 
1731 
1732 Foam::pointField Foam::cellCuts::loopPoints
1733 (
1734  const labelList& loop,
1735  const scalarField& loopWeights
1736 ) const
1737 {
1738  pointField loopPts(loop.size());
1739 
1740  forAll(loop, fp)
1741  {
1742  loopPts[fp] = coord(loop[fp], loopWeights[fp]);
1743  }
1744  return loopPts;
1745 }
1746 
1747 
1748 Foam::scalarField Foam::cellCuts::loopWeights(const labelList& loop) const
1749 {
1750  scalarField weights(loop.size());
1751 
1752  forAll(loop, fp)
1753  {
1754  label cut = loop[fp];
1755 
1756  if (isEdge(cut))
1757  {
1758  label edgeI = getEdge(cut);
1759 
1760  weights[fp] = edgeWeight_[edgeI];
1761  }
1762  else
1763  {
1764  weights[fp] = -GREAT;
1765  }
1766  }
1767  return weights;
1768 }
1769 
1770 
1771 bool Foam::cellCuts::validEdgeLoop
1772 (
1773  const labelList& loop,
1774  const scalarField& loopWeights
1775 ) const
1776 {
1777  forAll(loop, fp)
1778  {
1779  label cut = loop[fp];
1780 
1781  if (isEdge(cut))
1782  {
1783  label edgeI = getEdge(cut);
1784 
1785  // Check: cut compatible only if can be snapped to existing one.
1786  if (edgeIsCut_[edgeI])
1787  {
1788  scalar edgeLen = mesh().edges()[edgeI].mag(mesh().points());
1789 
1790  if
1791  (
1792  mag(loopWeights[fp] - edgeWeight_[edgeI])
1793  > geomCellLooper::snapTol()*edgeLen
1794  )
1795  {
1796  // Positions differ too much->would create two cuts.
1797  return false;
1798  }
1799  }
1800  }
1801  }
1802  return true;
1803 }
1804 
1805 
1806 Foam::label Foam::cellCuts::countFaceCuts
1807 (
1808  const label facei,
1809  const labelList& loop
1810 ) const
1811 {
1812  // Includes cuts through vertices and through edges.
1813  // Assumes that if edge is cut both in edgeIsCut and in loop that the
1814  // position of the cut is the same.
1815 
1816  label nCuts = 0;
1817 
1818  // Count cut vertices
1819  const face& f = mesh().faces()[facei];
1820 
1821  forAll(f, fp)
1822  {
1823  label vertI = f[fp];
1824 
1825  // Vertex already cut or mentioned in current loop.
1826  if
1827  (
1828  pointIsCut_[vertI]
1829  || (findIndex(loop, vertToEVert(vertI)) != -1)
1830  )
1831  {
1832  nCuts++;
1833  }
1834  }
1835 
1836  // Count cut edges.
1837  const labelList& fEdges = mesh().faceEdges()[facei];
1838 
1839  forAll(fEdges, fEdgeI)
1840  {
1841  label edgeI = fEdges[fEdgeI];
1842 
1843  // Edge already cut or mentioned in current loop.
1844  if
1845  (
1846  edgeIsCut_[edgeI]
1847  || (findIndex(loop, edgeToEVert(edgeI)) != -1)
1848  )
1849  {
1850  nCuts++;
1851  }
1852  }
1853 
1854  return nCuts;
1855 }
1856 
1857 
1858 bool Foam::cellCuts::conservativeValidLoop
1859 (
1860  const label celli,
1861  const labelList& loop
1862 ) const
1863 {
1864 
1865  if (loop.size() < 2)
1866  {
1867  return false;
1868  }
1869 
1870  forAll(loop, cutI)
1871  {
1872  if (isEdge(loop[cutI]))
1873  {
1874  label edgeI = getEdge(loop[cutI]);
1875 
1876  if (edgeIsCut_[edgeI])
1877  {
1878  // edge compatibility already checked.
1879  }
1880  else
1881  {
1882  // Quick rejection: vertices of edge itself cannot be cut.
1883  const edge& e = mesh().edges()[edgeI];
1884 
1885  if (pointIsCut_[e.start()] || pointIsCut_[e.end()])
1886  {
1887  return false;
1888  }
1889 
1890 
1891  // Check faces using this edge
1892  const labelList& eFaces = mesh().edgeFaces()[edgeI];
1893 
1894  forAll(eFaces, eFacei)
1895  {
1896  label nCuts = countFaceCuts(eFaces[eFacei], loop);
1897 
1898  if (nCuts > 2)
1899  {
1900  return false;
1901  }
1902  }
1903  }
1904  }
1905  else
1906  {
1907  // Vertex cut
1908 
1909  label vertI = getVertex(loop[cutI]);
1910 
1911  if (!pointIsCut_[vertI])
1912  {
1913  // New cut through vertex.
1914 
1915  // Check edges using vertex.
1916  const labelList& pEdges = mesh().pointEdges()[vertI];
1917 
1918  forAll(pEdges, pEdgeI)
1919  {
1920  label edgeI = pEdges[pEdgeI];
1921 
1922  if (edgeIsCut_[edgeI])
1923  {
1924  return false;
1925  }
1926  }
1927 
1928  // Check faces using vertex.
1929  const labelList& pFaces = mesh().pointFaces()[vertI];
1930 
1931  forAll(pFaces, pFacei)
1932  {
1933  label nCuts = countFaceCuts(pFaces[pFacei], loop);
1934 
1935  if (nCuts > 2)
1936  {
1937  return false;
1938  }
1939  }
1940  }
1941  }
1942  }
1943 
1944  // All ok.
1945  return true;
1946 }
1947 
1948 
1949 bool Foam::cellCuts::validLoop
1950 (
1951  const label celli,
1952  const labelList& loop,
1953  const scalarField& loopWeights,
1954 
1955  Map<edge>& newFaceSplitCut,
1956  labelList& anchorPoints
1957 ) const
1958 {
1959  // Determine compatibility of loop with existing cut pattern. Does not use
1960  // derived cut-addressing (faceCuts), only pointIsCut, edgeIsCut.
1961  // Adds any cross-cuts found to newFaceSplitCut and sets cell points on
1962  // one side of the loop in anchorPoints.
1963 
1964  if (loop.size() < 2)
1965  {
1966  return false;
1967  }
1968 
1969  if (debug & 4)
1970  {
1971  // Allow as fallback the 'old' loop checking where only a single
1972  // cut per face is allowed.
1973  if (!conservativeValidLoop(celli, loop))
1974  {
1975  Info << "Invalid conservative loop: " << loop << endl;
1976  return false;
1977  }
1978  }
1979 
1980  forAll(loop, fp)
1981  {
1982  label cut = loop[fp];
1983  label nextCut = loop[(fp+1) % loop.size()];
1984 
1985  // Label (if any) of face cut (so cut not along existing edge)
1986  label meshFacei = -1;
1987 
1988  if (isEdge(cut))
1989  {
1990  label edgeI = getEdge(cut);
1991 
1992  // Look one cut ahead to find if it is along existing edge.
1993 
1994  if (isEdge(nextCut))
1995  {
1996  // From edge to edge -> cross cut
1997  label nextEdgeI = getEdge(nextCut);
1998 
1999  // Find face and mark as to be split.
2000  meshFacei = edgeEdgeToFace(celli, edgeI, nextEdgeI);
2001 
2002  if (meshFacei == -1)
2003  {
2004  // Can't find face using both cut edges.
2005  return false;
2006  }
2007  }
2008  else
2009  {
2010  // From edge to vertex -> cross cut only if no existing edge.
2011 
2012  label nextVertI = getVertex(nextCut);
2013  const edge& e = mesh().edges()[edgeI];
2014 
2015  if (e.start() != nextVertI && e.end() != nextVertI)
2016  {
2017  // New edge. Find face and mark as to be split.
2018  meshFacei = edgeVertexToFace(celli, edgeI, nextVertI);
2019 
2020  if (meshFacei == -1)
2021  {
2022  // Can't find face. Ilegal.
2023  return false;
2024  }
2025  }
2026  }
2027  }
2028  else
2029  {
2030  // Cut is vertex.
2031  label vertI = getVertex(cut);
2032 
2033  if (isEdge(nextCut))
2034  {
2035  // From vertex to edge -> cross cut only if no existing edge.
2036  label nextEdgeI = getEdge(nextCut);
2037 
2038  const edge& nextE = mesh().edges()[nextEdgeI];
2039 
2040  if (nextE.start() != vertI && nextE.end() != vertI)
2041  {
2042  // Should be cross cut. Find face.
2043  meshFacei = edgeVertexToFace(celli, nextEdgeI, vertI);
2044 
2045  if (meshFacei == -1)
2046  {
2047  return false;
2048  }
2049  }
2050  }
2051  else
2052  {
2053  // From vertex to vertex -> cross cut only if no existing edge.
2054  label nextVertI = getVertex(nextCut);
2055 
2056  if (meshTools::findEdge(mesh(), vertI, nextVertI) == -1)
2057  {
2058  // New edge. Find face.
2059  meshFacei = vertexVertexToFace(celli, vertI, nextVertI);
2060 
2061  if (meshFacei == -1)
2062  {
2063  return false;
2064  }
2065  }
2066  }
2067  }
2068 
2069  if (meshFacei != -1)
2070  {
2071  // meshFacei is cut across along cut-nextCut (so not along existing
2072  // edge). Check if this is compatible with existing pattern.
2073  edge cutEdge(cut, nextCut);
2074 
2075  Map<edge>::const_iterator iter = faceSplitCut_.find(meshFacei);
2076 
2077  if (iter == faceSplitCut_.end())
2078  {
2079  // Face not yet cut so insert.
2080  newFaceSplitCut.insert(meshFacei, cutEdge);
2081  }
2082  else
2083  {
2084  // Face already cut. Ok if same edge.
2085  if (iter() != cutEdge)
2086  {
2087  return false;
2088  }
2089  }
2090  }
2091  }
2092 
2093  // Is there a face on which all cuts are?
2094  label faceContainingLoop = loopFace(celli, loop);
2095 
2096  if (faceContainingLoop != -1)
2097  {
2099  << "Found loop on cell " << celli << " with all points"
2100  << " on face " << faceContainingLoop << endl;
2101 
2102  //writeOBJ(".", celli, loopPoints(loop, loopWeights), labelList(0));
2103 
2104  return false;
2105  }
2106 
2107  // Calculate anchor points
2108  // Final success is determined by whether anchor points can be determined.
2109  return calcAnchors
2110  (
2111  celli,
2112  loop,
2113  loopPoints(loop, loopWeights),
2114  anchorPoints
2115  );
2116 }
2117 
2118 
2119 void Foam::cellCuts::setFromCellLoops()
2120 {
2121  // 'Uncut' edges/vertices that are not used in loops.
2122  pointIsCut_ = false;
2123 
2124  edgeIsCut_ = false;
2125 
2126  faceSplitCut_.clear();
2127 
2128  forAll(cellLoops_, celli)
2129  {
2130  const labelList& loop = cellLoops_[celli];
2131 
2132  if (loop.size())
2133  {
2134  // Storage for cross-face cuts
2135  Map<edge> faceSplitCuts(loop.size());
2136  // Storage for points on one side of cell.
2137  labelList anchorPoints;
2138 
2139  if
2140  (
2141  !validLoop
2142  (
2143  celli,
2144  loop,
2145  loopWeights(loop),
2146  faceSplitCuts,
2147  anchorPoints
2148  )
2149  )
2150  {
2151  //writeOBJ(".", celli, loopPoints(celli), anchorPoints);
2152 
2154  << "Illegal loop " << loop
2155  << " when recreating cut-addressing"
2156  << " from existing cellLoops for cell " << celli
2157  << endl;
2158 
2159  cellLoops_[celli].setSize(0);
2160  cellAnchorPoints_[celli].setSize(0);
2161  }
2162  else
2163  {
2164  // Copy anchor points.
2165  cellAnchorPoints_[celli].transfer(anchorPoints);
2166 
2167  // Copy faceSplitCuts into overall faceSplit info.
2168  forAllConstIter(Map<edge>, faceSplitCuts, iter)
2169  {
2170  faceSplitCut_.insert(iter.key(), iter());
2171  }
2172 
2173  // Update edgeIsCut, pointIsCut information
2174  forAll(loop, cutI)
2175  {
2176  label cut = loop[cutI];
2177 
2178  if (isEdge(cut))
2179  {
2180  edgeIsCut_[getEdge(cut)] = true;
2181  }
2182  else
2183  {
2184  pointIsCut_[getVertex(cut)] = true;
2185  }
2186  }
2187  }
2188  }
2189  }
2190 
2191  // Reset edge weights
2192  forAll(edgeIsCut_, edgeI)
2193  {
2194  if (!edgeIsCut_[edgeI])
2195  {
2196  // Weight not used. Set to illegal value to make any use fall over.
2197  edgeWeight_[edgeI] = -GREAT;
2198  }
2199  }
2200 }
2201 
2202 
2203 bool Foam::cellCuts::setFromCellLoop
2204 (
2205  const label celli,
2206  const labelList& loop,
2207  const scalarField& loopWeights
2208 )
2209 {
2210  // Update basic cut information from single cellLoop. Returns true if loop
2211  // was valid.
2212 
2213  // Dump loop for debugging.
2214  if (debug)
2215  {
2216  OFstream str("last_cell.obj");
2217 
2218  str<< "# edges of cell " << celli << nl;
2219 
2221  (
2222  str,
2223  mesh().cells(),
2224  mesh().faces(),
2225  mesh().points(),
2226  labelList(1, celli)
2227  );
2228 
2229 
2230  OFstream loopStr("last_loop.obj");
2231 
2232  loopStr<< "# looppoints for cell " << celli << nl;
2233 
2234  pointField pointsOfLoop = loopPoints(loop, loopWeights);
2235 
2236  forAll(pointsOfLoop, i)
2237  {
2238  meshTools::writeOBJ(loopStr, pointsOfLoop[i]);
2239  }
2240 
2241  str << 'l';
2242 
2243  forAll(pointsOfLoop, i)
2244  {
2245  str << ' ' << i + 1;
2246  }
2247  str << ' ' << 1 << nl;
2248  }
2249 
2250  bool okLoop = false;
2251 
2252  if (validEdgeLoop(loop, loopWeights))
2253  {
2254  // Storage for cuts across face
2255  Map<edge> faceSplitCuts(loop.size());
2256  // Storage for points on one side of cell
2257  labelList anchorPoints;
2258 
2259  okLoop =
2260  validLoop(celli, loop, loopWeights, faceSplitCuts, anchorPoints);
2261 
2262  if (okLoop)
2263  {
2264  // Valid loop. Copy cellLoops and anchorPoints
2265  cellLoops_[celli] = loop;
2266  cellAnchorPoints_[celli].transfer(anchorPoints);
2267 
2268  // Copy split cuts
2269  forAllConstIter(Map<edge>, faceSplitCuts, iter)
2270  {
2271  faceSplitCut_.insert(iter.key(), iter());
2272  }
2273 
2274 
2275  // Update edgeIsCut, pointIsCut information
2276  forAll(loop, cutI)
2277  {
2278  label cut = loop[cutI];
2279 
2280  if (isEdge(cut))
2281  {
2282  label edgeI = getEdge(cut);
2283 
2284  edgeIsCut_[edgeI] = true;
2285 
2286  edgeWeight_[edgeI] = loopWeights[cutI];
2287  }
2288  else
2289  {
2290  label vertI = getVertex(cut);
2291 
2292  pointIsCut_[vertI] = true;
2293  }
2294  }
2295  }
2296  }
2297 
2298  return okLoop;
2299 }
2300 
2301 
2302 void Foam::cellCuts::setFromCellLoops
2303 (
2304  const labelList& cellLabels,
2305  const labelListList& cellLoops,
2306  const List<scalarField>& cellLoopWeights
2307 )
2308 {
2309  // 'Uncut' edges/vertices that are not used in loops.
2310  pointIsCut_ = false;
2311 
2312  edgeIsCut_ = false;
2313 
2314  forAll(cellLabels, cellLabelI)
2315  {
2316  label celli = cellLabels[cellLabelI];
2317 
2318  const labelList& loop = cellLoops[cellLabelI];
2319 
2320  if (loop.size())
2321  {
2322  const scalarField& loopWeights = cellLoopWeights[cellLabelI];
2323 
2324  if (setFromCellLoop(celli, loop, loopWeights))
2325  {
2326  // Valid loop. Call above will have upated all already.
2327  }
2328  else
2329  {
2330  // Clear cellLoops
2331  cellLoops_[celli].setSize(0);
2332  }
2333  }
2334  }
2335 }
2336 
2337 
2338 void Foam::cellCuts::setFromCellCutter
2339 (
2340  const cellLooper& cellCutter,
2341  const List<refineCell>& refCells
2342 )
2343 {
2344  // 'Uncut' edges/vertices that are not used in loops.
2345  pointIsCut_ = false;
2346 
2347  edgeIsCut_ = false;
2348 
2349  // storage for loop of cuts (cut vertices and/or cut edges)
2350  labelList cellLoop;
2351  scalarField cellLoopWeights;
2352 
2353  // For debugging purposes
2354  DynamicList<label> invalidCutCells(2);
2355  DynamicList<labelList> invalidCutLoops(2);
2356  DynamicList<scalarField> invalidCutLoopWeights(2);
2357 
2358 
2359  forAll(refCells, refCelli)
2360  {
2361  const refineCell& refCell = refCells[refCelli];
2362 
2363  label celli = refCell.cellNo();
2364 
2365  const vector& refDir = refCell.direction();
2366 
2367 
2368  // Cut cell. Determines cellLoop and cellLoopWeights
2369  bool goodCut =
2370  cellCutter.cut
2371  (
2372  refDir,
2373  celli,
2374 
2375  pointIsCut_,
2376  edgeIsCut_,
2377  edgeWeight_,
2378 
2379  cellLoop,
2380  cellLoopWeights
2381  );
2382 
2383  // Check whether edge refinement is on a per face basis compatible with
2384  // current pattern.
2385  if (goodCut)
2386  {
2387  if (setFromCellLoop(celli, cellLoop, cellLoopWeights))
2388  {
2389  // Valid loop. Will have updated all info already.
2390  }
2391  else
2392  {
2393  cellLoops_[celli].setSize(0);
2394 
2396  << "Found loop on cell " << celli
2397  << " that resulted in an unexpected bad cut." << nl
2398  << " Suggestions:" << nl
2399  << " - Turn on the debug switch for 'cellCuts' to get"
2400  << " geometry files that identify this cell." << nl
2401  << " - Also keep in mind to check the defined"
2402  << " reference directions, as these are most likely the"
2403  << " origin of the problem."
2404  << nl << endl;
2405 
2406  // Discarded by validLoop
2407  if (debug)
2408  {
2409  invalidCutCells.append(celli);
2410  invalidCutLoops.append(cellLoop);
2411  invalidCutLoopWeights.append(cellLoopWeights);
2412  }
2413  }
2414  }
2415  else
2416  {
2417  // Clear cellLoops
2418  cellLoops_[celli].setSize(0);
2419  }
2420  }
2421 
2422  if (debug && invalidCutCells.size())
2423  {
2424  invalidCutCells.shrink();
2425  invalidCutLoops.shrink();
2426  invalidCutLoopWeights.shrink();
2427 
2428  fileName cutsFile("invalidLoopCells.obj");
2429 
2430  Pout<< "cellCuts : writing inValidLoops cells to " << cutsFile << endl;
2431 
2432  OFstream cutsStream(cutsFile);
2433 
2435  (
2436  cutsStream,
2437  mesh().cells(),
2438  mesh().faces(),
2439  mesh().points(),
2440  invalidCutCells
2441  );
2442 
2443  fileName loopsFile("invalidLoops.obj");
2444 
2445  Pout<< "cellCuts : writing inValidLoops loops to " << loopsFile << endl;
2446 
2447  OFstream loopsStream(loopsFile);
2448 
2449  label vertI = 0;
2450 
2451  forAll(invalidCutLoops, i)
2452  {
2453  writeOBJ
2454  (
2455  loopsStream,
2456  loopPoints(invalidCutLoops[i], invalidCutLoopWeights[i]),
2457  vertI
2458  );
2459  }
2460  }
2461 }
2462 
2463 
2464 void Foam::cellCuts::setFromCellCutter
2465 (
2466  const cellLooper& cellCutter,
2467  const labelList& cellLabels,
2468  const List<plane>& cellCutPlanes
2469 )
2470 {
2471  // 'Uncut' edges/vertices that are not used in loops.
2472  pointIsCut_ = false;
2473 
2474  edgeIsCut_ = false;
2475 
2476  // storage for loop of cuts (cut vertices and/or cut edges)
2477  labelList cellLoop;
2478  scalarField cellLoopWeights;
2479 
2480  // For debugging purposes
2481  DynamicList<label> invalidCutCells(2);
2482  DynamicList<labelList> invalidCutLoops(2);
2483  DynamicList<scalarField> invalidCutLoopWeights(2);
2484 
2485 
2486  forAll(cellLabels, i)
2487  {
2488  label celli = cellLabels[i];
2489 
2490  // Cut cell. Determines cellLoop and cellLoopWeights
2491  bool goodCut =
2492  cellCutter.cut
2493  (
2494  cellCutPlanes[i],
2495  celli,
2496 
2497  pointIsCut_,
2498  edgeIsCut_,
2499  edgeWeight_,
2500 
2501  cellLoop,
2502  cellLoopWeights
2503  );
2504 
2505  // Check whether edge refinement is on a per face basis compatible with
2506  // current pattern.
2507  if (goodCut)
2508  {
2509  if (setFromCellLoop(celli, cellLoop, cellLoopWeights))
2510  {
2511  // Valid loop. Will have updated all info already.
2512  }
2513  else
2514  {
2515  cellLoops_[celli].setSize(0);
2516 
2517  // Discarded by validLoop
2518  if (debug)
2519  {
2520  invalidCutCells.append(celli);
2521  invalidCutLoops.append(cellLoop);
2522  invalidCutLoopWeights.append(cellLoopWeights);
2523  }
2524  }
2525  }
2526  else
2527  {
2528  // Clear cellLoops
2529  cellLoops_[celli].setSize(0);
2530  }
2531  }
2532 
2533  if (debug && invalidCutCells.size())
2534  {
2535  invalidCutCells.shrink();
2536  invalidCutLoops.shrink();
2537  invalidCutLoopWeights.shrink();
2538 
2539  fileName cutsFile("invalidLoopCells.obj");
2540 
2541  Pout<< "cellCuts : writing inValidLoops cells to " << cutsFile << endl;
2542 
2543  OFstream cutsStream(cutsFile);
2544 
2546  (
2547  cutsStream,
2548  mesh().cells(),
2549  mesh().faces(),
2550  mesh().points(),
2551  invalidCutCells
2552  );
2553 
2554  fileName loopsFile("invalidLoops.obj");
2555 
2556  Pout<< "cellCuts : writing inValidLoops loops to " << loopsFile << endl;
2557 
2558  OFstream loopsStream(loopsFile);
2559 
2560  label vertI = 0;
2561 
2562  forAll(invalidCutLoops, i)
2563  {
2564  writeOBJ
2565  (
2566  loopsStream,
2567  loopPoints(invalidCutLoops[i], invalidCutLoopWeights[i]),
2568  vertI
2569  );
2570  }
2571  }
2572 }
2573 
2574 
2575 void Foam::cellCuts::orientPlanesAndLoops()
2576 {
2577  // Determine anchorPoints if not yet done by validLoop.
2578  forAll(cellLoops_, celli)
2579  {
2580  const labelList& loop = cellLoops_[celli];
2581 
2582  if (loop.size() && cellAnchorPoints_[celli].empty())
2583  {
2584  // Leave anchor points empty if illegal loop.
2585  calcAnchors
2586  (
2587  celli,
2588  loop,
2589  loopPoints(celli),
2590  cellAnchorPoints_[celli]
2591  );
2592  }
2593  }
2594 
2595  if (debug & 2)
2596  {
2597  Pout<< "cellAnchorPoints:" << endl;
2598  }
2599  forAll(cellAnchorPoints_, celli)
2600  {
2601  if (cellLoops_[celli].size())
2602  {
2603  if (cellAnchorPoints_[celli].empty())
2604  {
2606  << "No anchor points for cut cell " << celli << endl
2607  << "cellLoop:" << cellLoops_[celli] << abort(FatalError);
2608  }
2609 
2610  if (debug & 2)
2611  {
2612  Pout<< " cell:" << celli << " anchored at "
2613  << cellAnchorPoints_[celli] << endl;
2614  }
2615  }
2616  }
2617 
2618  // Calculate number of valid cellLoops
2619  nLoops_ = 0;
2620 
2621  forAll(cellLoops_, celli)
2622  {
2623  if (cellLoops_[celli].size())
2624  {
2625  nLoops_++;
2626  }
2627  }
2628 }
2629 
2630 
2631 void Foam::cellCuts::calcLoopsAndAddressing(const labelList& cutCells)
2632 {
2633  // Sanity check on weights
2634  forAll(edgeIsCut_, edgeI)
2635  {
2636  if (edgeIsCut_[edgeI])
2637  {
2638  scalar weight = edgeWeight_[edgeI];
2639 
2640  if (weight < 0 || weight > 1)
2641  {
2643  << "Weight out of range [0,1]. Edge " << edgeI
2644  << " verts:" << mesh().edges()[edgeI]
2645  << " weight:" << weight << abort(FatalError);
2646  }
2647  }
2648  else
2649  {
2650  // Weight not used. Set to illegal value to make any use fall over.
2651  edgeWeight_[edgeI] = -GREAT;
2652  }
2653  }
2654 
2655 
2656  // Calculate faces that split cells in two
2657  calcCellLoops(cutCells);
2658 
2659  if (debug & 2)
2660  {
2661  Pout<< "-- cellLoops --" << endl;
2662  forAll(cellLoops_, celli)
2663  {
2664  const labelList& loop = cellLoops_[celli];
2665 
2666  if (loop.size())
2667  {
2668  Pout<< "cell:" << celli << " ";
2669  writeCuts(Pout, loop, loopWeights(loop));
2670  Pout<< endl;
2671  }
2672  }
2673  }
2674 
2675  // Redo basic cut information (pointIsCut, edgeIsCut, faceSplitCut)
2676  // using cellLoop only.
2677  setFromCellLoops();
2678 }
2679 
2680 
2681 void Foam::cellCuts::check() const
2682 {
2683  // Check weights for unsnapped values
2684  forAll(edgeIsCut_, edgeI)
2685  {
2686  if (edgeIsCut_[edgeI])
2687  {
2688  if
2689  (
2690  edgeWeight_[edgeI] < geomCellLooper::snapTol()
2691  || edgeWeight_[edgeI] > (1 - geomCellLooper::snapTol())
2692  )
2693  {
2694  // Should have been snapped.
2696  << "edge:" << edgeI << " vertices:"
2697  << mesh().edges()[edgeI]
2698  << " weight:" << edgeWeight_[edgeI] << " should have been"
2699  << " snapped to one of its endpoints"
2700  << endl;
2701  }
2702  }
2703  else
2704  {
2705  if (edgeWeight_[edgeI] > - 1)
2706  {
2708  << "edge:" << edgeI << " vertices:"
2709  << mesh().edges()[edgeI]
2710  << " weight:" << edgeWeight_[edgeI] << " is not cut but"
2711  << " its weight is not marked invalid"
2712  << abort(FatalError);
2713  }
2714  }
2715  }
2716 
2717  // Check that all elements of cellloop are registered
2718  forAll(cellLoops_, celli)
2719  {
2720  const labelList& loop = cellLoops_[celli];
2721 
2722  forAll(loop, i)
2723  {
2724  label cut = loop[i];
2725 
2726  if
2727  (
2728  (isEdge(cut) && !edgeIsCut_[getEdge(cut)])
2729  || (!isEdge(cut) && !pointIsCut_[getVertex(cut)])
2730  )
2731  {
2732  labelList cuts(1, cut);
2733  writeCuts(Pout, cuts, loopWeights(cuts));
2734 
2736  << "cell:" << celli << " loop:"
2737  << loop
2738  << " cut:" << cut << " is not marked as cut"
2739  << abort(FatalError);
2740  }
2741  }
2742  }
2743 
2744  // Check that no elements of cell loop are anchor point.
2745  forAll(cellLoops_, celli)
2746  {
2747  const labelList& anchors = cellAnchorPoints_[celli];
2748 
2749  const labelList& loop = cellLoops_[celli];
2750 
2751  if (loop.size() && anchors.empty())
2752  {
2754  << "cell:" << celli << " loop:" << loop
2755  << " has no anchor points"
2756  << abort(FatalError);
2757  }
2758 
2759 
2760  forAll(loop, i)
2761  {
2762  label cut = loop[i];
2763 
2764  if
2765  (
2766  !isEdge(cut)
2767  && findIndex(anchors, getVertex(cut)) != -1
2768  )
2769  {
2771  << "cell:" << celli << " loop:" << loop
2772  << " anchor points:" << anchors
2773  << " anchor:" << getVertex(cut) << " is part of loop"
2774  << abort(FatalError);
2775  }
2776  }
2777  }
2778 
2779 
2780  // Check that cut faces have a neighbour that is cut.
2781  boolList nbrCellIsCut;
2782  {
2783  boolList cellIsCut(mesh().nCells(), false);
2784  forAll(cellLoops_, celli)
2785  {
2786  cellIsCut[celli] = cellLoops_[celli].size();
2787  }
2788  syncTools::swapBoundaryCellList(mesh(), cellIsCut, nbrCellIsCut);
2789  }
2790 
2791  forAllConstIter(Map<edge>, faceSplitCut_, iter)
2792  {
2793  label facei = iter.key();
2794 
2795  if (mesh().isInternalFace(facei))
2796  {
2797  label own = mesh().faceOwner()[facei];
2798  label nei = mesh().faceNeighbour()[facei];
2799 
2800  if (cellLoops_[own].empty() && cellLoops_[nei].empty())
2801  {
2803  << "Internal face:" << facei << " cut by " << iter()
2804  << " has owner:" << own
2805  << " and neighbour:" << nei
2806  << " that are both uncut"
2807  << abort(FatalError);
2808  }
2809  }
2810  else
2811  {
2812  label bFacei = facei - mesh().nInternalFaces();
2813 
2814  label own = mesh().faceOwner()[facei];
2815 
2816  if (cellLoops_[own].empty() && !nbrCellIsCut[bFacei])
2817  {
2819  << "Boundary face:" << facei << " cut by " << iter()
2820  << " has owner:" << own
2821  << " that is uncut"
2822  << abort(FatalError);
2823  }
2824  }
2825  }
2826 }
2827 
2828 
2829 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
2830 
2831 Foam::cellCuts::cellCuts
2833  const polyMesh& mesh,
2834  const labelList& cutCells,
2835  const labelList& meshVerts,
2836  const labelList& meshEdges,
2837  const scalarField& meshEdgeWeights
2838 )
2839 :
2840  edgeVertex(mesh),
2841  pointIsCut_(expand(mesh.nPoints(), meshVerts)),
2842  edgeIsCut_(expand(mesh.nEdges(), meshEdges)),
2843  edgeWeight_(expand(mesh.nEdges(), meshEdges, meshEdgeWeights)),
2844  faceSplitCut_(cutCells.size()),
2845  cellLoops_(mesh.nCells()),
2846  nLoops_(-1),
2847  cellAnchorPoints_(mesh.nCells())
2848 {
2849  if (debug)
2850  {
2851  Pout<< "cellCuts : constructor from cut verts and edges" << endl;
2852  }
2853 
2854  calcLoopsAndAddressing(cutCells);
2855 
2856  // Calculate planes and flip cellLoops if necessary
2857  orientPlanesAndLoops();
2858 
2859  if (debug)
2860  {
2861  check();
2862  }
2863 
2864  clearOut();
2865 
2866  if (debug)
2867  {
2868  Pout<< "cellCuts : leaving constructor from cut verts and edges"
2869  << endl;
2870  }
2871 }
2872 
2873 
2874 Foam::cellCuts::cellCuts
2876  const polyMesh& mesh,
2877  const labelList& meshVerts,
2878  const labelList& meshEdges,
2879  const scalarField& meshEdgeWeights
2880 )
2881 :
2882  edgeVertex(mesh),
2883  pointIsCut_(expand(mesh.nPoints(), meshVerts)),
2884  edgeIsCut_(expand(mesh.nEdges(), meshEdges)),
2885  edgeWeight_(expand(mesh.nEdges(), meshEdges, meshEdgeWeights)),
2886  faceSplitCut_(mesh.nFaces()/10 + 1),
2887  cellLoops_(mesh.nCells()),
2888  nLoops_(-1),
2889  cellAnchorPoints_(mesh.nCells())
2890 {
2891  // Construct from pattern of cuts. Finds out itself which cells are cut.
2892  // (can go wrong if e.g. all neighbours of cell are refined)
2893 
2894  if (debug)
2895  {
2896  Pout<< "cellCuts : constructor from cellLoops" << endl;
2897  }
2898 
2899  calcLoopsAndAddressing(identity(mesh.nCells()));
2900 
2901  // Adds cuts on other side of coupled boundaries
2902  syncProc();
2903 
2904  // Calculate planes and flip cellLoops if necessary
2905  orientPlanesAndLoops();
2906 
2907  if (debug)
2908  {
2909  check();
2910  }
2911 
2912  clearOut();
2913 
2914  if (debug)
2915  {
2916  Pout<< "cellCuts : leaving constructor from cellLoops" << endl;
2917  }
2918 }
2919 
2920 
2921 Foam::cellCuts::cellCuts
2923  const polyMesh& mesh,
2924  const labelList& cellLabels,
2925  const labelListList& cellLoops,
2926  const List<scalarField>& cellEdgeWeights
2927 )
2928 :
2929  edgeVertex(mesh),
2930  pointIsCut_(mesh.nPoints(), false),
2931  edgeIsCut_(mesh.nEdges(), false),
2932  edgeWeight_(mesh.nEdges(), -GREAT),
2933  faceSplitCut_(cellLabels.size()),
2934  cellLoops_(mesh.nCells()),
2935  nLoops_(-1),
2936  cellAnchorPoints_(mesh.nCells())
2937 {
2938  if (debug)
2939  {
2940  Pout<< "cellCuts : constructor from cellLoops" << endl;
2941  }
2942 
2943  // Update pointIsCut, edgeIsCut, faceSplitCut from cell loops.
2944  // Makes sure cuts are consistent
2945  setFromCellLoops(cellLabels, cellLoops, cellEdgeWeights);
2946 
2947  // Adds cuts on other side of coupled boundaries
2948  syncProc();
2949 
2950  // Calculate planes and flip cellLoops if necessary
2951  orientPlanesAndLoops();
2952 
2953  if (debug)
2954  {
2955  check();
2956  }
2957 
2958  clearOut();
2959 
2960  if (debug)
2961  {
2962  Pout<< "cellCuts : leaving constructor from cellLoops" << endl;
2963  }
2964 }
2965 
2966 
2967 Foam::cellCuts::cellCuts
2969  const polyMesh& mesh,
2970  const cellLooper& cellCutter,
2971  const List<refineCell>& refCells
2972 )
2973 :
2974  edgeVertex(mesh),
2975  pointIsCut_(mesh.nPoints(), false),
2976  edgeIsCut_(mesh.nEdges(), false),
2977  edgeWeight_(mesh.nEdges(), -GREAT),
2978  faceSplitCut_(refCells.size()),
2979  cellLoops_(mesh.nCells()),
2980  nLoops_(-1),
2981  cellAnchorPoints_(mesh.nCells())
2982 {
2983  if (debug)
2984  {
2985  Pout<< "cellCuts : constructor from cellCutter" << endl;
2986  }
2987 
2988  // Update pointIsCut, edgeIsCut, faceSplitCut from cell loops.
2989  // Makes sure cuts are consistent
2990  setFromCellCutter(cellCutter, refCells);
2991 
2992  // Adds cuts on other side of coupled boundaries
2993  syncProc();
2994 
2995  // Calculate planes and flip cellLoops if necessary
2996  orientPlanesAndLoops();
2997 
2998  if (debug)
2999  {
3000  check();
3001  }
3002 
3003  clearOut();
3004 
3005  if (debug)
3006  {
3007  Pout<< "cellCuts : leaving constructor from cellCutter" << endl;
3008  }
3009 }
3010 
3011 
3012 Foam::cellCuts::cellCuts
3014  const polyMesh& mesh,
3015  const cellLooper& cellCutter,
3016  const labelList& cellLabels,
3017  const List<plane>& cutPlanes
3018 )
3019 :
3020  edgeVertex(mesh),
3021  pointIsCut_(mesh.nPoints(), false),
3022  edgeIsCut_(mesh.nEdges(), false),
3023  edgeWeight_(mesh.nEdges(), -GREAT),
3024  faceSplitCut_(cellLabels.size()),
3025  cellLoops_(mesh.nCells()),
3026  nLoops_(-1),
3027  cellAnchorPoints_(mesh.nCells())
3028 {
3029  if (debug)
3030  {
3031  Pout<< "cellCuts : constructor from cellCutter with prescribed plane"
3032  << endl;
3033  }
3034 
3035  // Update pointIsCut, edgeIsCut, faceSplitCut from cell loops.
3036  // Makes sure cuts are consistent
3037  setFromCellCutter(cellCutter, cellLabels, cutPlanes);
3038 
3039  // Adds cuts on other side of coupled boundaries
3040  syncProc();
3041 
3042  // Calculate planes and flip cellLoops if necessary
3043  orientPlanesAndLoops();
3044 
3045  if (debug)
3046  {
3047  check();
3048  }
3049 
3050  clearOut();
3051 
3052  if (debug)
3053  {
3054  Pout<< "cellCuts : leaving constructor from cellCutter with prescribed"
3055  << " plane" << endl;
3056  }
3057 }
3058 
3059 
3060 Foam::cellCuts::cellCuts
3062  const polyMesh& mesh,
3063  const boolList& pointIsCut,
3064  const boolList& edgeIsCut,
3065  const scalarField& edgeWeight,
3066  const Map<edge>& faceSplitCut,
3067  const labelListList& cellLoops,
3068  const label nLoops,
3069  const labelListList& cellAnchorPoints
3070 )
3071 :
3072  edgeVertex(mesh),
3073  pointIsCut_(pointIsCut),
3074  edgeIsCut_(edgeIsCut),
3075  edgeWeight_(edgeWeight),
3076  faceSplitCut_(faceSplitCut),
3077  cellLoops_(cellLoops),
3078  nLoops_(nLoops),
3079  cellAnchorPoints_(cellAnchorPoints)
3080 {
3081  if (debug)
3082  {
3083  Pout<< "cellCuts : constructor from components" << endl;
3084  Pout<< "cellCuts : leaving constructor from components" << endl;
3085  }
3086 }
3087 
3088 
3089 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
3090 
3092 {
3093  clearOut();
3094 }
3095 
3096 
3098 {
3099  faceCutsPtr_.clear();
3100 }
3101 
3102 
3103 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
3104 
3105 Foam::pointField Foam::cellCuts::loopPoints(const label celli) const
3106 {
3107  const labelList& loop = cellLoops_[celli];
3108 
3109  pointField loopPts(loop.size());
3110 
3111  forAll(loop, fp)
3112  {
3113  label cut = loop[fp];
3114 
3115  if (isEdge(cut))
3116  {
3117  label edgeI = getEdge(cut);
3118 
3119  loopPts[fp] = coord(cut, edgeWeight_[edgeI]);
3120  }
3121  else
3122  {
3123  loopPts[fp] = coord(cut, -GREAT);
3124  }
3125  }
3126  return loopPts;
3127 }
3128 
3129 
3130 void Foam::cellCuts::flip(const label celli)
3131 {
3132  labelList& loop = cellLoops_[celli];
3133 
3134  reverse(loop);
3135 
3136  // Reverse anchor point set.
3137  cellAnchorPoints_[celli] =
3138  nonAnchorPoints
3139  (
3140  mesh().cellPoints()[celli],
3141  cellAnchorPoints_[celli],
3142  loop
3143  );
3144 }
3145 
3146 
3148 {
3149  labelList& loop = cellLoops_[celli];
3150 
3151  reverse(loop);
3152 }
3153 
3154 
3155 void Foam::cellCuts::writeOBJ
3157  Ostream& os,
3158  const pointField& loopPts,
3159  label& vertI
3160 ) const
3161 {
3162  label startVertI = vertI;
3163 
3164  forAll(loopPts, fp)
3165  {
3166  const point& pt = loopPts[fp];
3167 
3168  os << "v " << pt.x() << ' ' << pt.y() << ' ' << pt.z() << endl;
3169 
3170  vertI++;
3171  }
3172 
3173  os << 'f';
3174  forAll(loopPts, fp)
3175  {
3176  os << ' ' << startVertI + fp + 1;
3177  }
3178  os << endl;
3179 }
3180 
3181 
3182 void Foam::cellCuts::writeOBJ(Ostream& os) const
3183 {
3184  label vertI = 0;
3185 
3186  forAll(cellLoops_, celli)
3187  {
3188  writeOBJ(os, loopPoints(celli), vertI);
3189  }
3190 }
3191 
3192 
3193 void Foam::cellCuts::writeCellOBJ(const fileName& dir, const label celli) const
3194 {
3195  const labelList& anchors = cellAnchorPoints_[celli];
3196 
3197  writeOBJ(dir, celli, loopPoints(celli), anchors);
3198 }
3199 
3200 
3201 // ************************************************************************* //
static void syncBoundaryFaceList(const polyMesh &, UList< T > &, const CombineOp &cop, const TransformOp &top, const bool parRun=Pstream::parRun())
Synchronize values on boundary faces only.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:313
string expand(const string &, const HashTable< string, word, string::hash > &mapping, const char sigil='$')
Expand occurences of variables according to the mapping.
Definition: stringOps.C:75
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
const word & name() const
Return name.
A class for handling file names.
Definition: fileName.H:69
An STL-conforming const_iterator.
Definition: HashTable.H:481
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
const double e
Elementary charge.
Definition: doubleFloat.H:78
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
label rcIndex(const label i) const
Return the reverse circular index, i.e. the previous index.
Definition: UListI.H:65
bool edgeOnCell(const primitiveMesh &, const label celli, const label edgeI)
Is edge used by cell.
Definition: meshTools.C:285
label nFaces() const
Output to file stream.
Definition: OFstream.H:82
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
label nCells() const
void flip(const label celli)
Flip loop for celli. Updates anchor points as well.
Definition: cellCuts.C:3130
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
Abstract base class. Concrete implementations know how to cut a cell (i.e. determine a loop around th...
Definition: cellLooper.H:69
Traits class for primitives.
Definition: pTraits.H:50
point centre(const pointField &) const
Centre point of face.
Definition: face.C:488
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
label findEdge(const edgeList &edges, const labelList &candidates, const label v0, const label v1)
Return edge among candidates that uses the two vertices.
Definition: meshTools.C:337
const Cmpt & z() const
Definition: VectorI.H:87
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:120
bool faceOnCell(const primitiveMesh &, const label celli, const label facei)
Is face used by cell.
Definition: meshTools.C:308
scalar f1
Definition: createFields.H:28
const Cmpt & y() const
Definition: VectorI.H:81
Various functions to operate on Lists.
const vector & direction() const
Definition: refineCell.H:87
Dummy transform to be used with syncTools.
vector normal(const pointField &) const
Vector normal; magnitude is equal to area of face.
Definition: face.C:552
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
static const labelSphericalTensor labelI(1)
Identity labelTensor.
dynamicFvMesh & mesh
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:310
Definition: ops.H:70
const cellShapeList & cells
const pointField & points
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:113
static void syncEdgeList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh edges.
label nPoints
void clearOut()
Clear out demand driven storage.
Definition: cellCuts.C:3097
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=*(cellModeller::lookup("hex"));labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells]=cellShape(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:292
Combines edge or vertex in single label. Used to specify cuts across cell circumference.
Definition: edgeVertex.H:52
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const zero Zero
Definition: zero.H:91
Container with cells to refine. Refinement given as single direction.
Definition: refineCell.H:56
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
~cellCuts()
Destructor.
Definition: cellCuts.C:3091
const Cmpt & x() const
Definition: VectorI.H:75
Foam::polyBoundaryMesh.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:53
void reverse(UList< T > &, const label n)
Definition: UListI.H:322
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:240
static const char nl
Definition: Ostream.H:262
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
label cellNo() const
Definition: refineCell.H:82
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
A normal distribution model.
label nEdges() const
static void swapBoundaryCellList(const polyMesh &mesh, const UList< T > &cellData, List< T > &neighbourCellData)
Swap to obtain neighbour cell values for all boundary faces.
void setSize(const label)
Reset size of List.
Definition: List.C:281
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:394
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
virtual bool cut(const vector &refDir, const label celli, const boolList &vertIsCut, const boolList &edgeIsCut, const scalarField &edgeWeight, labelList &loop, scalarField &loopWeights) const =0
Create cut along circumference of celli. Gets current mesh cuts.
label end() const
Return end vertex label.
Definition: edgeI.H:92
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:56
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:300
edge cmptType
Component type.
Definition: cellCuts.C:53
static void syncPointList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
label nPoints() const
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
label walkFace(const primitiveMesh &, const label facei, const label startEdgeI, const label startVertI, const label nEdges)
Returns label of edge nEdges away from startEdge (in the direction.
Definition: meshTools.C:587
void writeCellOBJ(const fileName &dir, const label celli) const
debugging:Write edges of cell and loop
Definition: cellCuts.C:3193
static scalar snapTol()
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
void getEdgeFaces(const primitiveMesh &, const label celli, const label edgeI, label &face0, label &face1)
Get faces on cell using edgeI. Throws error if no two found.
Definition: meshTools.C:458
static const label labelMin
Definition: label.H:61
label start() const
Return start vertex label.
Definition: edgeI.H:81
label otherFace(const primitiveMesh &, const label celli, const label facei, const label edgeI)
Return face on cell using edgeI but not facei. Throws error.
Definition: meshTools.C:536
labelList nonAnchorPoints(const labelList &cellPoints, const labelList &anchorPoints, const labelList &loop) const
Invert anchor point selection.
Definition: cellCuts.C:1321
Namespace for OpenFOAM.
void flipLoopOnly(const label celli)
Flip loop for celli. Does not update anchors. Use with care.
Definition: cellCuts.C:3147