perfectInterface.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 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 Description
25  Best thing is probably to look at attachDetach which does almost exactly
26  the same but for the geometric matching of points and face centres.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "perfectInterface.H"
31 #include "polyMesh.H"
32 #include "polyTopoChange.H"
33 #include "matchPoints.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
41 }
42 
43 const Foam::scalar Foam::perfectInterface::tol_ = 1e-3;
44 
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
48 Foam::pointField Foam::perfectInterface::calcFaceCentres
49 (
50  const indirectPrimitivePatch& pp
51 )
52 {
53  const pointField& points = pp.points();
54 
55  pointField ctrs(pp.size());
56 
57  forAll(ctrs, patchFacei)
58  {
59  ctrs[patchFacei] = pp[patchFacei].centre(points);
60  }
61 
62  return ctrs;
63 }
64 
65 
66 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
67 
69 (
70  const word& name,
71  const polyMesh& mesh,
72  const word& masterPatchName,
73  const word& slavePatchName
74 )
75 :
76  mesh_(mesh),
77  masterPatchIndex_(mesh_.boundaryMesh().findIndex(masterPatchName)),
78  slavePatchIndex_(mesh_.boundaryMesh().findIndex(slavePatchName))
79 {}
80 
81 
82 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
83 
85 {}
86 
87 
88 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
89 
91 (
92  const indirectPrimitivePatch& pp0,
93  const indirectPrimitivePatch& pp1,
95 ) const
96 {
97  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
98 
99  // Some aliases
100  const edgeList& edges0 = pp0.edges();
101  const pointField& pts0 = pp0.localPoints();
102  const pointField& pts1 = pp1.localPoints();
103  const labelList& meshPts0 = pp0.meshPoints();
104  const labelList& meshPts1 = pp1.meshPoints();
105 
106 
107  // Get local dimension as fraction of minimum edge length
108 
109  scalar minLen = great;
110 
111  forAll(edges0, edgeI)
112  {
113  minLen = min(minLen, edges0[edgeI].mag(pts0));
114  }
115  scalar typDim = tol_*minLen;
116 
117  if (debug)
118  {
119  Pout<< "typDim:" << typDim << " edges0:" << edges0.size()
120  << " pts0:" << pts0.size() << " pts1:" << pts1.size()
121  << " pp0:" << pp0.size() << " pp1:" << pp1.size() << endl;
122  }
123 
124 
125  // Determine pointMapping in mesh point labels. Uses geometric
126  // comparison to find correspondence between patch points.
127 
128  labelList renumberPoints(mesh_.points().size());
129  forAll(renumberPoints, i)
130  {
131  renumberPoints[i] = i;
132  }
133  {
134  labelList from1To0Points(pts1.size());
135 
136  const bool matchOk = matchPoints
137  (
138  pts1,
139  pts0,
140  scalarField(pts1.size(), typDim), // tolerance
141  true, // verbose
142  from1To0Points
143  );
144 
145  if (!matchOk)
146  {
148  << "Points on patch sides do not match to within tolerance "
149  << typDim << exit(FatalError);
150  }
151 
152  forAll(pts1, i)
153  {
154  renumberPoints[meshPts1[i]] = meshPts0[from1To0Points[i]];
155  }
156  }
157 
158 
159 
160  // Calculate correspondence between patch faces
161 
162  labelList from0To1Faces(pp1.size());
163 
164  const bool matchOk = matchPoints
165  (
166  calcFaceCentres(pp0),
167  calcFaceCentres(pp1),
168  scalarField(pp0.size(), typDim), // tolerance
169  true, // verbose
170  from0To1Faces
171  );
172 
173  if (!matchOk)
174  {
176  << "Face centres of patch sides do not match to within tolerance "
177  << typDim << exit(FatalError);
178  }
179 
180 
181 
182  // Now
183  // - renumber faces using pts1 (except patch1 faces)
184  // - remove patch1 faces. Remember cell label on owner side.
185  // - modify patch0 faces to be internal.
186 
187  // 1. Get faces to be renumbered
188  labelHashSet affectedFaces(2*pp1.size());
189  forAll(meshPts1, i)
190  {
191  const label meshPointi = meshPts1[i];
192 
193  if (meshPointi != renumberPoints[meshPointi])
194  {
195  const labelList& pFaces = mesh_.pointFaces()[meshPointi];
196 
197  forAll(pFaces, pFacei)
198  {
199  affectedFaces.insert(pFaces[pFacei]);
200  }
201  }
202  }
203  forAll(pp1, i)
204  {
205  affectedFaces.erase(pp1.addressing()[i]);
206  }
207  // Remove patch0 from renumbered faces. Should not be necessary since
208  // patch0 and 1 should not share any point (if created by mergeMeshing)
209  // so affectedFaces should not contain any patch0 faces but you can
210  // never be sure what the user is doing.
211  forAll(pp0, i)
212  {
213  const label facei = pp0.addressing()[i];
214 
215  if (affectedFaces.erase(facei))
216  {
218  << "Found face " << facei << " vertices "
219  << mesh_.faces()[facei] << " whose points are"
220  << " used both by master patch and slave patch" << endl;
221  }
222  }
223 
224 
225  // 2. Renumber (non patch0/1) faces.
226  forAllConstIter(labelHashSet, affectedFaces, iter)
227  {
228  const label facei = iter.key();
229  const face& f = mesh_.faces()[facei];
230 
231  face newFace(f.size());
232 
233  forAll(newFace, fp)
234  {
235  newFace[fp] = renumberPoints[f[fp]];
236  }
237 
238  label nbr = -1;
239 
240  label patchi = -1;
241 
242  if (mesh_.isInternalFace(facei))
243  {
244  nbr = mesh_.faceNeighbour()[facei];
245  }
246  else
247  {
248  patchi = patches.whichPatch(facei);
249  }
250 
251  ref.modifyFace
252  (
253  newFace, // modified face
254  facei, // label of face being modified
255  mesh_.faceOwner()[facei], // owner
256  nbr, // neighbour
257  false, // face flip
258  patchi // patch for face
259  );
260  }
261 
262 
263  // 3. Remove patch1 points
264  forAll(meshPts1, i)
265  {
266  const label meshPointi = meshPts1[i];
267 
268  if (meshPointi != renumberPoints[meshPointi])
269  {
270  ref.removePoint(meshPointi, -1);
271  }
272  }
273 
274 
275  // 4. Remove patch1 faces
276  forAll(pp1, i)
277  {
278  const label facei = pp1.addressing()[i];
279  ref.removeFace(facei, -1);
280  }
281 
282 
283  // 5. Modify patch0 faces for new points (not really necessary; see
284  // comment above about patch1 and patch0 never sharing points) and
285  // becoming internal.
286  forAll(pp0, i)
287  {
288  const label facei = pp0.addressing()[i];
289  const face& f = mesh_.faces()[facei];
290 
291  face newFace(f.size());
292 
293  forAll(newFace, fp)
294  {
295  newFace[fp] = renumberPoints[f[fp]];
296  }
297 
298  const label own = mesh_.faceOwner()[facei];
299  const label pp1Facei = pp1.addressing()[from0To1Faces[i]];
300  const label nbr = mesh_.faceOwner()[pp1Facei];
301 
302  if (own < nbr)
303  {
304  ref.modifyFace
305  (
306  newFace, // modified face
307  facei, // label of face being modified
308  own, // owner
309  nbr, // neighbour
310  false, // face flip
311  -1 // patch for face
312  );
313  }
314  else
315  {
316  ref.modifyFace
317  (
318  newFace.reverseFace(), // modified face
319  facei, // label of face being modified
320  nbr, // owner
321  own, // neighbour
322  true, // face flip
323  -1 // patch for face
324  );
325  }
326  }
327 }
328 
329 
331 {
332  if (debug)
333  {
334  Pout<< "bool perfectInterface::setRefinement(polyTopoChange&) const : "
335  << "masterPatchIndex_:" << masterPatchIndex_
336  << " slavePatchIndex_:" << slavePatchIndex_ << endl;
337  }
338 
339  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
340  const polyPatch& patch0 = patches[masterPatchIndex_];
341  const polyPatch& patch1 = patches[slavePatchIndex_];
342 
343  labelList pp0Labels(identityMap(patch0.size())+patch0.start());
345  (
346  IndirectList<face>(mesh_.faces(), pp0Labels),
347  mesh_.points()
348  );
349 
350  labelList pp1Labels(identityMap(patch1.size())+patch1.start());
352  (
353  IndirectList<face>(mesh_.faces(), pp1Labels),
354  mesh_.points()
355  );
356 
357  setRefinement(pp0, pp1, ref);
358 }
359 
360 
361 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
Macros for easy insertion into run-time selection tables.
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
bool erase(const iterator &)
Erase a hashedEntry specified by given iterator.
Definition: HashTable.C:445
A List with indirect addressing.
Definition: IndirectList.H:105
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const labelList & meshPoints() const
Return labelList of mesh points in patch. They are constructed.
const Field< PointType > & localPoints() const
Return pointField of points in patch.
label size() const
Return the number of elements in the list.
const List< label > & addressing() const
Return the list addressing.
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
face reverseFace() const
Return face with reverse direction.
Definition: face.C:256
Hack of attachDetach to couple patches when they perfectly align. Does not decouple....
perfectInterface(const word &name, const polyMesh &mesh, const word &masterPatchName, const word &slavePatchName)
Construct from components.
virtual ~perfectInterface()
Destructor.
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:280
Direct mesh changes based on v1.3 polyTopoChange syntax.
A class for handling words, derived from string.
Definition: word.H:62
trAU ref().rename("rAU")
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
const pointField & points
const fvPatchList & patches
Determine correspondence between points. See below.
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar e
Elementary charge.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensioned< scalar > mag(const dimensioned< Type > &)
defineTypeNameAndDebug(combustionModel, 0)
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:33
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
labelList identityMap(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
Foam::indirectPrimitivePatch.
labelList f(nPoints)
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, &mergedCyclicPolyPatch::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:229