cellShapeControlMesh.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) 2012-2021 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "cellShapeControlMesh.H"
28 #include "pointFields.H"
29 #include "pointIOField.H"
30 #include "scalarIOField.H"
31 #include "triadIOField.H"
32 #include "tetPointRef.H"
33 #include "plane.H"
34 #include "transform.H"
35 #include "meshTools.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(cellShapeControlMesh, 0);
42 
43  word cellShapeControlMesh::meshSubDir = "cellShapeControlMesh";
44 }
45 
46 
47 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
48 
49 //Foam::tensor Foam::cellShapeControlMesh::requiredAlignment
50 //(
51 // const Foam::point& pt,
52 // const searchableSurfaces& allGeometry,
53 // const conformationSurfaces& geometryToConformTo
54 //) const
55 //{
56 // pointIndexHit surfHit;
57 // label hitSurface;
58 //
59 // geometryToConformTo.findSurfaceNearest
60 // (
61 // pt,
62 // sqr(great),
63 // surfHit,
64 // hitSurface
65 // );
66 //
67 // if (!surfHit.hit())
68 // {
69 // FatalErrorInFunction
70 // << "findSurfaceNearest did not find a hit across the surfaces."
71 // << exit(FatalError) << endl;
72 // }
73 //
74 // // Primary alignment
75 //
76 // vectorField norm(1);
77 //
78 // allGeometry[hitSurface].getNormal
79 // (
80 // List<pointIndexHit>(1, surfHit),
81 // norm
82 // );
83 //
84 // const vector np = norm[0];
85 //
86 // // Generate equally spaced 'spokes' in a circle normal to the
87 // // direction from the vertex to the closest point on the surface
88 // // and look for a secondary intersection.
89 //
90 // const vector d = surfHit.hitPoint() - pt;
91 //
92 // const tensor Rp = rotationTensor(vector(0,0,1), np);
93 //
94 // const label s = 36;//foamyHexMeshControls().alignmentSearchSpokes();
95 //
96 // scalar closestSpokeHitDistance = great;
97 //
98 // pointIndexHit closestSpokeHit;
99 //
100 // label closestSpokeSurface = -1;
101 //
102 // const scalar spanMag = geometryToConformTo.globalBounds().mag();
103 //
104 // for (label i = 0; i < s; i++)
105 // {
106 // vector spoke
107 // (
108 // Foam::cos(i*constant::mathematical::twoPi/s),
109 // Foam::sin(i*constant::mathematical::twoPi/s),
110 // 0
111 // );
112 //
113 // spoke *= spanMag;
114 //
115 // spoke = Rp & spoke;
116 //
117 // pointIndexHit spokeHit;
118 //
119 // label spokeSurface = -1;
120 //
121 // // internal spoke
122 //
123 // geometryToConformTo.findSurfaceNearestIntersection
124 // (
125 // pt,
126 // pt + spoke,
127 // spokeHit,
128 // spokeSurface
129 // );
130 //
131 // if (spokeHit.hit())
132 // {
133 // scalar spokeHitDistance = mag
134 // (
135 // spokeHit.hitPoint() - pt
136 // );
137 //
138 // if (spokeHitDistance < closestSpokeHitDistance)
139 // {
140 // closestSpokeHit = spokeHit;
141 // closestSpokeSurface = spokeSurface;
142 // closestSpokeHitDistance = spokeHitDistance;
143 // }
144 // }
145 //
146 // // external spoke
147 //
148 // Foam::point mirrorPt = pt + 2*d;
149 //
150 // geometryToConformTo.findSurfaceNearestIntersection
151 // (
152 // mirrorPt,
153 // mirrorPt + spoke,
154 // spokeHit,
155 // spokeSurface
156 // );
157 //
158 // if (spokeHit.hit())
159 // {
160 // scalar spokeHitDistance = mag
161 // (
162 // spokeHit.hitPoint() - mirrorPt
163 // );
164 //
165 // if (spokeHitDistance < closestSpokeHitDistance)
166 // {
167 // closestSpokeHit = spokeHit;
168 // closestSpokeSurface = spokeSurface;
169 // closestSpokeHitDistance = spokeHitDistance;
170 // }
171 // }
172 // }
173 //
174 // if (closestSpokeSurface == -1)
175 // {
181 //
182 // return I;
183 // }
184 //
185 // // Auxiliary alignment generated by spoke intersection normal.
186 //
187 // allGeometry[closestSpokeSurface].getNormal
188 // (
189 // List<pointIndexHit>(1, closestSpokeHit),
190 // norm
191 // );
192 //
193 // const vector& na = norm[0];
194 //
195 // // Secondary alignment
196 // vector ns = np ^ na;
197 //
198 // if (mag(ns) < small)
199 // {
200 // FatalErrorInFunction
201 // << "Parallel normals detected in spoke search." << nl
202 // << "point: " << pt << nl
203 // << "closest surface point: " << surfHit.hitPoint() << nl
204 // << "closest spoke hit: " << closestSpokeHit.hitPoint() << nl
205 // << "np: " << surfHit.hitPoint() + np << nl
206 // << "ns: " << closestSpokeHit.hitPoint() + na << nl
207 // << exit(FatalError);
208 // }
209 //
210 // ns /= mag(ns);
211 //
212 // tensor Rs = rotationTensor((Rp & vector(0,1,0)), ns);
213 //
214 // return (Rs & Rp);
215 //}
216 
217 
219 {
220  label nRemoved = 0;
221  for
222  (
223  CellSizeDelaunay::Finite_vertices_iterator vit =
224  finite_vertices_begin();
225  vit != finite_vertices_end();
226  ++vit
227  )
228  {
229  std::list<Vertex_handle> verts;
230  adjacent_vertices(vit, std::back_inserter(verts));
231 
232  bool removePt = true;
233  for
234  (
235  std::list<Vertex_handle>::iterator aVit = verts.begin();
236  aVit != verts.end();
237  ++aVit
238  )
239  {
240  Vertex_handle avh = *aVit;
241 
242  scalar diff =
243  mag(avh->targetCellSize() - vit->targetCellSize())
244  /max(vit->targetCellSize(), 1e-6);
245 
246  if (diff > 0.05)
247  {
248  removePt = false;
249  }
250  }
251 
252  if (removePt)
253  {
254  remove(vit);
255  nRemoved++;
256  }
257  }
258 
259  return nRemoved;
260 }
261 
262 
264 {
265  tmp<pointField> tcellCentres(new pointField(number_of_finite_cells()));
266  pointField& cellCentres = tcellCentres.ref();
267 
268  label count = 0;
269  for
270  (
271  CellSizeDelaunay::Finite_cells_iterator c = finite_cells_begin();
272  c != finite_cells_end();
273  ++c
274  )
275  {
276  if (c->hasFarPoint())
277  {
278  continue;
279  }
280 
281  scalarList bary;
283 
284  const Foam::point centre = topoint
285  (
286  CGAL::centroid<baseK>
287  (
288  c->vertex(0)->point(),
289  c->vertex(1)->point(),
290  c->vertex(2)->point(),
291  c->vertex(3)->point()
292  )
293  );
294 
295  cellCentres[count++] = centre;
296  }
297 
298  cellCentres.resize(count);
299 
300  return tcellCentres;
301 }
302 
303 
305 {
306  OFstream str
307  (
308  "refinementTriangulation_"
310  + ".obj"
311  );
312 
313  label count = 0;
314 
315  Info<< "Write refinementTriangulation" << endl;
316 
317  for
318  (
319  CellSizeDelaunay::Finite_edges_iterator e = finite_edges_begin();
320  e != finite_edges_end();
321  ++e
322  )
323  {
324  Cell_handle c = e->first;
325  Vertex_handle vA = c->vertex(e->second);
326  Vertex_handle vB = c->vertex(e->third);
327 
328  // Don't write far edges
329  if (vA->farPoint() || vB->farPoint())
330  {
331  continue;
332  }
333 
334  // Don't write unowned edges
335  if (vA->referred() && vB->referred())
336  {
337  continue;
338  }
339 
340  pointFromPoint p1 = topoint(vA->point());
341  pointFromPoint p2 = topoint(vB->point());
342 
343  meshTools::writeOBJ(str, p1, p2, count);
344  }
345 
346  if (is_valid())
347  {
348  Info<< " Triangulation is valid" << endl;
349  }
350  else
351  {
353  << "Triangulation is not valid"
354  << abort(FatalError);
355  }
356 }
357 
358 
359 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
360 
362 :
363  DistributedDelaunayMesh<CellSizeDelaunay>
364  (
365  runTime,
366  meshSubDir
367  ),
368  runTime_(runTime)
369 {
370  if (this->vertexCount())
371  {
372  fvMesh mesh
373  (
374  IOobject
375  (
376  meshSubDir,
377  runTime.timeName(),
378  runTime,
381  )
382  );
383 
384  if (mesh.nPoints() == this->vertexCount())
385  {
386  pointScalarField sizes
387  (
388  IOobject
389  (
390  "sizes",
391  runTime.timeName(),
392  meshSubDir,
393  runTime,
396  false
397  ),
398  pointMesh::New(mesh)
399  );
400 
401  triadIOField alignments
402  (
403  IOobject
404  (
405  "alignments",
406  mesh.time().timeName(),
407  meshSubDir,
408  mesh.time(),
411  false
412  )
413  );
414 
415  if
416  (
417  sizes.size() == this->vertexCount()
418  && alignments.size() == this->vertexCount()
419  )
420  {
421  for
422  (
423  Finite_vertices_iterator vit = finite_vertices_begin();
424  vit != finite_vertices_end();
425  ++vit
426  )
427  {
428  vit->targetCellSize() = sizes[vit->index()];
429  vit->alignment() = alignments[vit->index()];
430  }
431  }
432  else
433  {
435  << "Cell size point field is not the same size as the "
436  << "mesh."
437  << abort(FatalError);
438  }
439  }
440  }
441 }
442 
443 
444 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
445 
447 {}
448 
449 
450 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
451 
453 (
454  const Foam::point& pt,
455  barycentric& bary,
456  Cell_handle& ch
457 ) const
458 {
459  // Use the previous cell handle as a hint on where to start searching
460  // Giving a hint causes strange errors...
461  ch = locate(toPoint(pt));
462 
463  if (dimension() > 2 && !is_infinite(ch))
464  {
465  oldCellHandle_ = ch;
466 
467  tetPointRef tet
468  (
469  topoint(ch->vertex(0)->point()),
470  topoint(ch->vertex(1)->point()),
471  topoint(ch->vertex(2)->point()),
472  topoint(ch->vertex(3)->point())
473  );
474 
475  bary = tet.pointToBarycentric(pt);
476  }
477 }
478 
479 
481 {
482  DynamicList<Foam::point> pts(number_of_vertices());
483 
484  for
485  (
486  Finite_vertices_iterator vit = finite_vertices_begin();
487  vit != finite_vertices_end();
488  ++vit
489  )
490  {
491  if (vit->real())
492  {
493  pts.append(topoint(vit->point()));
494  }
495  }
496 
497  boundBox bb(pts);
498 
499  return bb;
500 }
501 
502 
504 (
505  const backgroundMeshDecomposition& decomposition
506 )
507 {
508  DynamicList<Foam::point> points(number_of_vertices());
509  DynamicList<scalar> sizes(number_of_vertices());
510  DynamicList<tensor> alignments(number_of_vertices());
511 
512  DynamicList<Vb> farPts(8);
513 
514  for
515  (
516  Finite_vertices_iterator vit = finite_vertices_begin();
517  vit != finite_vertices_end();
518  ++vit
519  )
520  {
521  if (vit->real())
522  {
523  points.append(topoint(vit->point()));
524  sizes.append(vit->targetCellSize());
525  alignments.append(vit->alignment());
526  }
527  else if (vit->farPoint())
528  {
529  farPts.append
530  (
531  Vb
532  (
533  vit->point(),
534  -1,
535  Vb::vtFar,
537  )
538  );
539 
540  farPts.last().targetCellSize() = vit->targetCellSize();
541  farPts.last().alignment() = vit->alignment();
542  }
543  }
544 
545  autoPtr<mapDistribute> mapDist =
547  (
548  decomposition,
549  points
550  );
551 
552  mapDist().distribute(sizes);
553  mapDist().distribute(alignments);
554 
555  // Reset the entire tessellation
557 
558 
559  // Internal points have to be inserted first
560  DynamicList<Vb> verticesToInsert(points.size());
561 
562 
563  forAll(farPts, ptI)
564  {
565  verticesToInsert.append(farPts[ptI]);
566  }
567 
568 
569  forAll(points, pI)
570  {
571  verticesToInsert.append
572  (
573  Vb
574  (
575  toPoint(points[pI]),
576  -1,
579  )
580  );
581 
582  verticesToInsert.last().targetCellSize() = sizes[pI];
583  verticesToInsert.last().alignment() = alignments[pI];
584  }
585 
586  Info<< nl << " Inserting distributed background tessellation..." << endl;
587 
588  this->rangeInsertWithInfo
589  (
590  verticesToInsert.begin(),
591  verticesToInsert.end(),
592  true
593  );
594 
595  sync(decomposition.procBounds());
596 
597  Info<< " Total number of vertices after redistribution "
598  << returnReduce(label(number_of_vertices()), sumOp<label>()) << endl;
599 }
600 
601 
603 {
604  tensorField alignmentsTmp(number_of_vertices(), Zero);
605 
606  label count = 0;
607  for
608  (
609  Finite_vertices_iterator vit = finite_vertices_begin();
610  vit != finite_vertices_end();
611  ++vit
612  )
613  {
614  alignmentsTmp[count++] = vit->alignment();
615  }
616 
617  return alignmentsTmp;
618 }
619 
620 
622 {
623  Info<< "Writing " << meshSubDir << endl;
624 
625  // Reindex the cells
626  label cellCount = 0;
627  for
628  (
629  Finite_cells_iterator cit = finite_cells_begin();
630  cit != finite_cells_end();
631  ++cit
632  )
633  {
634  if (!cit->hasFarPoint() && !is_infinite(cit))
635  {
636  cit->cellIndex() = cellCount++;
637  }
638  }
639 
641  labelList cellMap;
642 
643  autoPtr<polyMesh> meshPtr = DelaunayMesh<CellSizeDelaunay>::createMesh
644  (
645  meshSubDir,
646  vertexMap,
647  cellMap
648  );
649  const polyMesh& mesh = meshPtr();
650 
651  pointScalarField sizes
652  (
653  IOobject
654  (
655  "sizes",
656  mesh.time().timeName(),
657  meshSubDir,
658  mesh.time(),
661  ),
662  pointMesh::New(mesh),
663  scalar(0)
664  );
665 
666  triadIOField alignments
667  (
668  IOobject
669  (
670  "alignments",
671  mesh.time().timeName(),
672  meshSubDir,
673  mesh.time(),
676  ),
677  sizes.size()
678  );
679 
680  // Write alignments
681 // OFstream str(runTime_.path()/"alignments.obj");
682 
683  for
684  (
685  Finite_vertices_iterator vit = finite_vertices_begin();
686  vit != finite_vertices_end();
687  ++vit
688  )
689  {
690  if (!vit->farPoint())
691  {
692  // Populate sizes
693  sizes[vertexMap[labelPair(vit->index(), vit->procIndex())]] =
694  vit->targetCellSize();
695 
696  alignments[vertexMap[labelPair(vit->index(), vit->procIndex())]] =
697  vit->alignment();
698 
699 // // Write alignments
700 // const tensor& alignment = vit->alignment();
701 // pointFromPoint pt = topoint(vit->point());
702 //
703 // if
704 // (
705 // alignment.x() == triad::unset[0]
706 // || alignment.y() == triad::unset[0]
707 // || alignment.z() == triad::unset[0]
708 // )
709 // {
710 // Info<< "Bad alignment = " << vit->info();
711 //
712 // vit->alignment() = tensor::I;
713 //
714 // Info<< "New alignment = " << vit->info();
715 //
716 // continue;
717 // }
718 //
719 // meshTools::writeOBJ(str, pt, alignment.x() + pt);
720 // meshTools::writeOBJ(str, pt, alignment.y() + pt);
721 // meshTools::writeOBJ(str, pt, alignment.z() + pt);
722  }
723  }
724 
725  mesh.write();
726  sizes.write();
727  alignments.write();
728 }
729 
730 
732 (
733  const autoPtr<backgroundMeshDecomposition>& decomposition
734 ) const
735 {
736  // Loop over all the tets and estimate the cell count in each one
737 
738  scalar cellCount = 0;
739 
740  for
741  (
742  Finite_cells_iterator cit = finite_cells_begin();
743  cit != finite_cells_end();
744  ++cit
745  )
746  {
747  if (!cit->hasFarPoint() && !is_infinite(cit))
748  {
749  // TODO: Check if tet centre is on the processor..
750  CGAL::Tetrahedron_3<baseK> tet
751  (
752  cit->vertex(0)->point(),
753  cit->vertex(1)->point(),
754  cit->vertex(2)->point(),
755  cit->vertex(3)->point()
756  );
757 
758  pointFromPoint centre = topoint(CGAL::centroid(tet));
759 
760  if
761  (
763  && !decomposition().positionOnThisProcessor(centre)
764  )
765  {
766  continue;
767  }
768 
769  scalar volume = CGAL::to_double(tet.volume());
770 
771  scalar averagedPointCellSize = 0;
772  // scalar averagedPointCellSize = 1;
773 
774  // Get an average volume by averaging the cell size of the vertices
775  for (label vI = 0; vI < 4; ++vI)
776  {
777  averagedPointCellSize += cit->vertex(vI)->targetCellSize();
778  // averagedPointCellSize *= cit->vertex(vI)->targetCellSize();
779  }
780 
781  averagedPointCellSize /= 4;
782  // averagedPointCellSize = ::sqrt(averagedPointCellSize);
783 
784 // if (averagedPointCellSize < small)
785 // {
786 // Pout<< "Volume = " << volume << endl;
787 //
788 // for (label vI = 0; vI < 4; ++vI)
789 // {
790 // Pout<< "Point " << vI
791 // << ", point = " << topoint(cit->vertex(vI)->point())
792 // << ", size = " << cit->vertex(vI)->targetCellSize()
793 // << endl;
794 // }
795 // }
796 
797  cellCount += volume/pow(averagedPointCellSize, 3);
798  }
799  }
800 
801  return cellCount;
802 }
803 
804 
805 // ************************************************************************* //
GeometricField< scalar, pointPatchField, pointMesh > pointScalarField
Definition: pointFields.H:49
tetrahedron< point, const point & > tetPointRef
Definition: tetPointRef.H:44
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
~cellShapeControlMesh()
Destructor.
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
pointFromPoint topoint(const Point &P)
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
tmp< pointField > cellCentres() const
Get the centres of all the tets.
static fvMesh * meshPtr
Definition: globalFoam.H:52
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
HashTable< label, labelPair, FixedList< label, 2 >::Hash<> > labelTolabelPairHashTable
Definition: DelaunayMesh.H:90
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool distribute(const boundBox &bb)
void barycentricCoords(const Foam::point &pt, barycentric &bary, Cell_handle &ch) const
Calculate and return the barycentric coordinates for.
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:58
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
Barycentric< scalar > barycentric
A scalar version of the templated Barycentric.
Definition: barycentric.H:45
const dimensionedScalar c
Speed of light in a vacuum.
tensorField dumpAlignments() const
An indexed form of CGAL::Triangulation_vertex_base_3<K> used to keep track of the Delaunay vertices i...
Definition: indexedVertex.H:51
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
dynamicFvMesh & mesh
const pointField & points
3D tensor transformation operations.
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
void reset()
Clear the entire triangulation.
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
PointFrompoint toPoint(const Foam::point &p)
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const zero Zero
Definition: zero.H:97
void distribute(const backgroundMeshDecomposition &decomposition)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
cellShapeControlMesh(const Time &runTime)
static const char nl
Definition: Ostream.H:260
defineTypeNameAndDebug(combustionModel, 0)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
CGAL::Delaunay_triangulation_3< K, Tds, FastLocator > CellSizeDelaunay
static word meshSubDir
Return the mesh sub-directory name (usually "cellShapeControlMesh")
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
CellSizeDelaunay::Cell_handle Cell_handle
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
boundBox bounds() const
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
const doubleScalar e
Elementary charge.
Definition: doubleScalar.H:105
label estimateCellCount(const autoPtr< backgroundMeshDecomposition > &decomposition) const
A class for managing temporary objects.
Definition: PtrList.H:53
IOField< triad > triadIOField
triadField with IO.
Definition: triadIOField.H:42
autoPtr< polyMesh > createMesh(const fileName &name, labelTolabelPairHashTable &vertexMap, labelList &cellMap, const bool writeDelaunayData=true) const
Create an fvMesh from the triangulation.
Namespace for OpenFOAM.