Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
11License
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
27Description
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"
45// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
46
47namespace Foam
48{
51 (
55 );
56}
57
58
59// Tolerance used as fraction of minimum edge length.
60const Foam::scalar Foam::perfectInterface::tol_ = 1e-3;
61
62
63// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
64
65Foam::pointField Foam::perfectInterface::calcFaceCentres
66(
67 const indirectPrimitivePatch& pp
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
85Foam::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
102Foam::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()
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 (
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 (
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 (
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
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
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
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// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition HashSet.H:229
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition HashTable.C:489
label size() const noexcept
The number of elements in the list.
A List with indirect addressing.
const Addr & addressing() const noexcept
The list addressing.
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
const Field< point_type > & localPoints() const
Return pointField of points in patch.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition ZoneMesh.C:410
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
A subset of mesh faces organised as a primitive patch.
Definition faceZone.H:63
label whichFace(const label meshFaceID) const
The local index of the given mesh face, -1 if not in the zone.
Definition faceZone.H:394
const boolList & flipMap() const noexcept
Return face flip map.
Definition faceZone.H:389
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
face reverseFace() const
Return face with reverse direction.
Definition face.C:612
A class for handling keywords in dictionaries.
Definition keyType.H:69
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Hack of attachDetach to couple patches when they perfectly align. Does not decouple....
virtual void write(Ostream &) const
Write.
virtual bool changeTopology() const
Check for topology change.
virtual void writeDict(Ostream &) const
Write dictionary.
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
virtual void modifyMotionPoints(pointField &motionPoints) const
Modify motion points to comply with the topological change.
virtual void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
Virtual base class for mesh modifiers.
label index() const
Return the index of this modifier.
const word & name() const
Return name of this modifier.
Switch active() const
If modifier activate?
const polyTopoChanger & topoChanger() const
Return reference to morph engine.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition polyMesh.H:671
virtual const faceList & faces() const
Return raw faces.
Definition polyMesh.C:1088
virtual const labelList & faceOwner() const
Return face owner.
Definition polyMesh.C:1101
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition polyMesh.C:1107
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
Class describing modification of a face.
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
labelRange range() const
Return start/size range of this patch.
Definition polyPatch.H:454
Class containing data for face removal.
Class containing data for point removal.
Direct mesh changes based on v1.3 polyTopoChange syntax.
List of mesh modifiers defining the mesh dynamics.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
const labelListList & pointFaces() const
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
rDeltaT ref()
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
auto & name
const pointField & points
Determine correspondence between points. See below.
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
List< edge > edgeList
List of edge.
Definition edgeList.H:32
List< label > labelList
A List of labels.
Definition List.H:62
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:801
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
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...
List< bool > boolList
A List of bools.
Definition List.H:60
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
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
vectorField pointField
pointField is a vectorField.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
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];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } 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};constexpr 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< DynamicList< face > > pFaces[nBCs]
labelList f(nPoints)
dictionary dict
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299