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"
44
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
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
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,
158) const
159{
160 const polyMesh& mesh = topoChanger().mesh();
161
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 (
453 mesh.points()
454 );
455
457 (
459 mesh.points()
460 );
461
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// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
bool insert(const Key &key)
Insert a new entry, not overwriting existing entries.
Definition: HashSet.H:191
bool erase(const iterator &iter)
Erase an entry specified by given iterator.
Definition: HashTable.C:440
A List with indirect addressing.
Definition: IndirectList.H:119
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
virtual Ostream & endBlock()
Write end block group.
Definition: Ostream.C:105
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:239
virtual Ostream & beginBlock(const keyType &kw)
Write begin block group with the given name.
Definition: Ostream.C:87
A list of faces which address into the list of points.
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:114
label whichZone(const label objectIndex) const
Given a global object index, return the zone it is in.
Definition: ZoneMesh.C:288
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
Definition: boundaryMesh.H:63
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
virtual bool update()=0
Update the mesh for both mesh motion and topology change.
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:67
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:372
const boolList & flipMap() const noexcept
Return face flip map.
Definition: faceZone.H:272
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
face reverseFace() const
Return face with reverse direction.
Definition: face.C:636
virtual bool write()
Write the output fields.
Foam::dictionary writeDict() const
Write to dictionary.
A class for handling keywords in dictionaries.
Definition: keyType.H:71
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
void updateMesh()
Update for new mesh topology.
Hack of attachDetach to couple patches when they perfectly align. Does not decouple....
virtual bool changeTopology() const
Check for topology change.
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.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Virtual base class for mesh modifiers.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:498
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1127
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
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:75
labelRange range() const
Return start/size range of this patch.
Definition: polyPatch.H:370
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:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
rDeltaT ref()
bool
Definition: EEqn.H:20
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
const pointField & points
const labelIOList & zoneID
Determine correspondence between points. See below.
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
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:36
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
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
labelList f(nPoints)
dictionary dict
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333