perfectInterface.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2018-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Description
28  Best thing is probably to look at attachDetach which does almost exactly
29  the same but for the geometric matching of points and face centres.
30 
31 \*---------------------------------------------------------------------------*/
32 
33 #include "perfectInterface.H"
34 #include "polyTopoChanger.H"
35 #include "polyMesh.H"
36 #include "polyTopoChange.H"
38 #include "mapPolyMesh.H"
39 #include "matchPoints.H"
40 #include "polyModifyFace.H"
41 #include "polyRemovePoint.H"
42 #include "polyRemoveFace.H"
43 #include "indirectPrimitivePatch.H"
44 
45 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
46 
47 namespace Foam
48 {
49  defineTypeNameAndDebug(perfectInterface, 0);
51  (
52  polyMeshModifier,
53  perfectInterface,
54  dictionary
55  );
56 }
57 
58 
59 // Tolerance used as fraction of minimum edge length.
60 const Foam::scalar Foam::perfectInterface::tol_ = 1e-3;
61 
62 
63 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
64 
65 Foam::pointField Foam::perfectInterface::calcFaceCentres
66 (
68 )
69 {
70  const pointField& points = pp.points();
71 
72  pointField ctrs(pp.size());
73 
74  forAll(ctrs, patchFacei)
75  {
76  ctrs[patchFacei] = pp[patchFacei].centre(points);
77  }
78 
79  return ctrs;
80 }
81 
82 
83 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
84 
85 Foam::perfectInterface::perfectInterface
86 (
87  const word& name,
88  const label index,
89  const polyTopoChanger& mme,
90  const word& faceZoneName,
91  const word& masterPatchName,
92  const word& slavePatchName
93 )
94 :
95  polyMeshModifier(name, index, mme, true),
96  faceZoneID_(faceZoneName, mme.mesh().faceZones()),
97  masterPatchID_(masterPatchName, mme.mesh().boundaryMesh()),
98  slavePatchID_(slavePatchName, mme.mesh().boundaryMesh())
99 {}
100 
101 
102 Foam::perfectInterface::perfectInterface
103 (
104  const word& name,
105  const dictionary& dict,
106  const label index,
107  const polyTopoChanger& mme
108 )
109 :
110  polyMeshModifier(name, index, mme, dict.get<bool>("active")),
111  faceZoneID_
112  (
113  dict.get<keyType>("faceZoneName"),
114  mme.mesh().faceZones()
115  ),
116  masterPatchID_
117  (
118  dict.get<keyType>("masterPatchName"),
119  mme.mesh().boundaryMesh()
120  ),
121  slavePatchID_
122  (
123  dict.get<keyType>("slavePatchName"),
124  mme.mesh().boundaryMesh()
125  )
126 {}
127 
128 
129 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
130 
132 {
133  // If modifier is inactive, skip change
134  if (!active())
135  {
136  if (debug)
137  {
138  Pout<< "bool perfectInterface::changeTopology() const "
139  << "for object " << name() << " : "
140  << "Inactive" << endl;
141  }
142 
143  return false;
144  }
145  else
146  {
147  // I want topo change every time step.
148  return true;
149  }
150 }
151 
152 
154 (
155  const indirectPrimitivePatch& pp0,
156  const indirectPrimitivePatch& pp1,
157  polyTopoChange& ref
158 ) const
159 {
160  const polyMesh& mesh = topoChanger().mesh();
161 
162  const polyBoundaryMesh& patches = mesh.boundaryMesh();
163 
164  // Some aliases
165  const edgeList& edges0 = pp0.edges();
166  const pointField& pts0 = pp0.localPoints();
167  const pointField& pts1 = pp1.localPoints();
168  const labelList& meshPts0 = pp0.meshPoints();
169  const labelList& meshPts1 = pp1.meshPoints();
170 
171 
172  // Get local dimension as fraction of minimum edge length
173 
174  scalar minLen = GREAT;
175 
176  forAll(edges0, edgeI)
177  {
178  minLen = min(minLen, edges0[edgeI].mag(pts0));
179  }
180  scalar typDim = tol_*minLen;
181 
182  if (debug)
183  {
184  Pout<< "typDim:" << typDim << " edges0:" << edges0.size()
185  << " pts0:" << pts0.size() << " pts1:" << pts1.size()
186  << " pp0:" << pp0.size() << " pp1:" << pp1.size() << endl;
187  }
188 
189 
190  // Determine pointMapping in mesh point labels. Uses geometric
191  // comparison to find correspondence between patch points.
192 
193  labelList renumberPoints(mesh.points().size());
194  forAll(renumberPoints, i)
195  {
196  renumberPoints[i] = i;
197  }
198  {
199  labelList from1To0Points(pts1.size());
200 
201  bool matchOk = matchPoints
202  (
203  pts1,
204  pts0,
205  scalarField(pts1.size(), typDim), // tolerance
206  true, // verbose
207  from1To0Points
208  );
209 
210  if (!matchOk)
211  {
213  << "Points on patch sides do not match to within tolerance "
214  << typDim << exit(FatalError);
215  }
216 
217  forAll(pts1, i)
218  {
219  renumberPoints[meshPts1[i]] = meshPts0[from1To0Points[i]];
220  }
221  }
222 
223 
224 
225  // Calculate correspondence between patch faces
226 
227  labelList from0To1Faces(pp1.size());
228 
229  bool matchOk = matchPoints
230  (
231  calcFaceCentres(pp0),
232  calcFaceCentres(pp1),
233  scalarField(pp0.size(), typDim), // tolerance
234  true, // verbose
235  from0To1Faces
236  );
237 
238  if (!matchOk)
239  {
241  << "Face centres of patch sides do not match to within tolerance "
242  << typDim << exit(FatalError);
243  }
244 
245 
246 
247  // Now
248  // - renumber faces using pts1 (except patch1 faces)
249  // - remove patch1 faces. Remember cell label on owner side.
250  // - modify patch0 faces to be internal.
251 
252  // 1. Get faces to be renumbered
253  labelHashSet affectedFaces(2*pp1.size());
254  forAll(meshPts1, i)
255  {
256  label meshPointi = meshPts1[i];
257 
258  if (meshPointi != renumberPoints[meshPointi])
259  {
260  const labelList& pFaces = mesh.pointFaces()[meshPointi];
261 
262  affectedFaces.insert(pFaces);
263  }
264  }
265  forAll(pp1, i)
266  {
267  affectedFaces.erase(pp1.addressing()[i]);
268  }
269  // Remove patch0 from renumbered faces. Should not be necessary since
270  // patch0 and 1 should not share any point (if created by mergeMeshing)
271  // so affectedFaces should not contain any patch0 faces but you can
272  // never be sure what the user is doing.
273  forAll(pp0, i)
274  {
275  label facei = pp0.addressing()[i];
276 
277  if (affectedFaces.erase(facei))
278  {
280  << "Found face " << facei << " vertices "
281  << mesh.faces()[facei] << " whose points are"
282  << " used both by master patch and slave patch" << endl;
283  }
284  }
285 
286 
287  // 2. Renumber (non patch0/1) faces.
288  for (const label facei : affectedFaces)
289  {
290  const face& f = mesh.faces()[facei];
291 
292  face newFace(f.size());
293 
294  forAll(newFace, fp)
295  {
296  newFace[fp] = renumberPoints[f[fp]];
297  }
298 
299  label nbr = -1;
300 
301  label patchi = -1;
302 
303  if (mesh.isInternalFace(facei))
304  {
305  nbr = mesh.faceNeighbour()[facei];
306  }
307  else
308  {
309  patchi = patches.whichPatch(facei);
310  }
311 
312  label zoneID = mesh.faceZones().whichZone(facei);
313 
314  bool zoneFlip = false;
315 
316  if (zoneID >= 0)
317  {
318  const faceZone& fZone = mesh.faceZones()[zoneID];
319 
320  zoneFlip = fZone.flipMap()[fZone.whichFace(facei)];
321  }
322 
323  ref.setAction
324  (
325  polyModifyFace
326  (
327  newFace, // modified face
328  facei, // label of face being modified
329  mesh.faceOwner()[facei], // owner
330  nbr, // neighbour
331  false, // face flip
332  patchi, // patch for face
333  false, // remove from zone
334  zoneID, // zone for face
335  zoneFlip // face flip in zone
336  )
337  );
338  }
339 
340 
341  // 3. Remove patch1 points
342  forAll(meshPts1, i)
343  {
344  label meshPointi = meshPts1[i];
345 
346  if (meshPointi != renumberPoints[meshPointi])
347  {
348  ref.setAction(polyRemovePoint(meshPointi));
349  }
350  }
351 
352 
353  // 4. Remove patch1 faces
354  forAll(pp1, i)
355  {
356  label facei = pp1.addressing()[i];
357  ref.setAction(polyRemoveFace(facei));
358  }
359 
360 
361  // 5. Modify patch0 faces for new points (not really necessary; see
362  // comment above about patch1 and patch0 never sharing points) and
363  // becoming internal.
364  const boolList& mfFlip =
365  mesh.faceZones()[faceZoneID_.index()].flipMap();
366 
367  forAll(pp0, i)
368  {
369  label facei = pp0.addressing()[i];
370 
371  const face& f = mesh.faces()[facei];
372 
373  face newFace(f.size());
374 
375  forAll(newFace, fp)
376  {
377  newFace[fp] = renumberPoints[f[fp]];
378  }
379 
380  label own = mesh.faceOwner()[facei];
381 
382  label pp1Facei = pp1.addressing()[from0To1Faces[i]];
383 
384  label nbr = mesh.faceOwner()[pp1Facei];
385 
386  if (own < nbr)
387  {
388  ref.setAction
389  (
390  polyModifyFace
391  (
392  newFace, // modified face
393  facei, // label of face being modified
394  own, // owner
395  nbr, // neighbour
396  false, // face flip
397  -1, // patch for face
398  false, // remove from zone
399  faceZoneID_.index(), // zone for face
400  mfFlip[i] // face flip in zone
401  )
402  );
403  }
404  else
405  {
406  ref.setAction
407  (
408  polyModifyFace
409  (
410  newFace.reverseFace(), // modified face
411  facei, // label of face being modified
412  nbr, // owner
413  own, // neighbour
414  true, // face flip
415  -1, // patch for face
416  false, // remove from zone
417  faceZoneID_.index(), // zone for face
418  !mfFlip[i] // face flip in zone
419  )
420  );
421  }
422  }
423 }
424 
425 
426 void Foam::perfectInterface::setRefinement(polyTopoChange& ref) const
427 {
428  if (debug)
429  {
430  Pout<< "bool perfectInterface::setRefinement(polyTopoChange&) const : "
431  << "for object " << name() << " : "
432  << "masterPatchID_:" << masterPatchID_
433  << " slavePatchID_:" << slavePatchID_
434  << " faceZoneID_:" << faceZoneID_ << endl;
435  }
436 
437  if
438  (
439  masterPatchID_.active()
440  && slavePatchID_.active()
441  && faceZoneID_.active()
442  )
443  {
444  const polyMesh& mesh = topoChanger().mesh();
445 
446  const polyBoundaryMesh& patches = mesh.boundaryMesh();
447  const polyPatch& patch0 = patches[masterPatchID_.index()];
448  const polyPatch& patch1 = patches[slavePatchID_.index()];
449 
451  (
452  IndirectList<face>(mesh.faces(), identity(patch0.range())),
453  mesh.points()
454  );
455 
457  (
458  IndirectList<face>(mesh.faces(), identity(patch1.range())),
459  mesh.points()
460  );
462  setRefinement(pp0, pp1, ref);
463  }
464 }
465 
466 
468 {
469  // Update only my points. Nothing to be done here as points already
470  // shared by now.
471 }
472 
473 
475 {
476  // Mesh has changed topologically. Update local topological data
477  const polyMesh& mesh = topoChanger().mesh();
478 
479  faceZoneID_.update(mesh.faceZones());
480  masterPatchID_.update(mesh.boundaryMesh());
481  slavePatchID_.update(mesh.boundaryMesh());
482 }
483 
484 
486 {
487  os << nl << type() << nl
488  << name()<< nl
489  << faceZoneID_.name() << nl
490  << masterPatchID_.name() << nl
491  << slavePatchID_.name() << endl;
492 }
493 
494 
496 {
497  os << nl;
498 
499  os.beginBlock(name());
500  os.writeEntry("type", type());
501  os.writeEntry("active", active());
502  os.writeEntry("faceZoneName", faceZoneID_.name());
503  os.writeEntry("masterPatchName", masterPatchID_.name());
504  os.writeEntry("slavePatchName", slavePatchID_.name());
505  os.endBlock();
506 }
507 
508 
509 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
A class for handling keywords in dictionaries.
Definition: keyType.H:66
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1122
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
virtual void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:321
virtual void modifyMotionPoints(pointField &motionPoints) const
Modify motion points to comply with the topological change.
virtual void write(Ostream &) const
Write.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
Determine correspondence between points. See below.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:157
Macros for easy insertion into run-time selection tables.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
bool matchPoints(const UList< point > &pts0, const UList< point > &pts1, const UList< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:29
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
const pointField & points
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
List of mesh modifiers defining the mesh dynamics.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual Ostream & endBlock()
Write end block group.
Definition: Ostream.C:108
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1116
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1103
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
Virtual base class for mesh modifiers.
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
virtual bool update()=0
Update the mesh for both mesh motion and topology change.
rDeltaT ref()
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:670
defineTypeNameAndDebug(combustionModel, 0)
labelList f(nPoints)
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::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].reset(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
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:346
#define WarningInFunction
Report a warning using Foam::Warning.
const polyBoundaryMesh & patches
virtual void writeDict(Ostream &) const
Write dictionary.
virtual Ostream & beginBlock(const keyType &kw)
Write begin block group with the given name.
Definition: Ostream.C:90
const labelListList & pointFaces() const
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< label > labelList
A List of labels.
Definition: List.H:62
virtual bool changeTopology() const
Check for topology change.
List< bool > boolList
A List of bools.
Definition: List.H:60
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)