createPolyBoundary.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) 2016 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 boundary faces
29 - use pointCells when searching for connectivity
30 - initialize the cell connectivity with '-1'
31 - find both cell faces corresponding to the baffles and mark them
32 to prevent a connection
33 - standard connectivity checks
34
35 - added baffle and monitoring support
36
37\*---------------------------------------------------------------------------*/
38
39#include "meshReader.H"
40#include "Time.H"
41#include "polyPatch.H"
42#include "emptyPolyPatch.H"
43#include "preservePatchTypes.H"
44
45// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
46
47void Foam::meshReader::addPolyBoundaryFace
48(
49 const label cellId,
50 const label cellFaceId,
51 const label nCreatedFaces
52)
53{
54#ifdef DEBUG_BOUNDARY
55 Info<< nCreatedFaces
56 << " add bnd for cell " << cellId
57 << " face " << cellFaceId
58 << " (original cell " << origCellId_[cellId] << ")"
59 << endl;
60#endif
61
62 // standard case: volume cells
63 const face& thisFace = cellFaces_[cellId][cellFaceId];
64
65 // Debugging
66 if (cellPolys_[cellId][cellFaceId] > nInternalFaces_)
67 {
69 << "Problem with face: " << thisFace << endl
70 << "Probably multiple definitions "
71 << "of a single boundary face." << endl
72 << endl;
73 }
74 else if (cellPolys_[cellId][cellFaceId] >= 0)
75 {
77 << "Problem with face: " << thisFace << endl
78 << "Probably trying to define a boundary face "
79 << "on a previously matched internal face." << endl
80 << "Internal face: "
81 << meshFaces_[cellPolys_[cellId][cellFaceId]]
82 << endl;
83 }
84
85 meshFaces_[nCreatedFaces] = thisFace;
86 cellPolys_[cellId][cellFaceId] = nCreatedFaces;
87}
88
89
90void Foam::meshReader::addPolyBoundaryFace
91(
92 const cellFaceIdentifier& identifier,
93 const label nCreatedFaces
94)
95{
96 addPolyBoundaryFace
97 (
98 identifier.cellId(),
99 identifier.faceId(),
100 nCreatedFaces
101 );
102}
103
104
105// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
106
107void Foam::meshReader::createPolyBoundary()
108{
109 label nBoundaryFaces = 0;
110 label nMissingFaces = 0;
111 label nInterfaces = 0;
112
113 const faceListList& cFaces = cellFaces();
114
115 // determine number of non-patched faces:
116 forAll(cellPolys_, celli)
117 {
118 cell& curCell = cellPolys_[celli];
119
120 forAll(curCell, fI)
121 {
122 if (curCell[fI] < 0)
123 {
124 nMissingFaces++;
125 }
126 }
127 }
128
129 forAll(boundaryIds_, patchi)
130 {
131 nBoundaryFaces += boundaryIds_[patchi].size();
132 }
133
134 Info<< nl
135 << "There are " << nMissingFaces
136 << " faces to be patched and " << nBoundaryFaces
137 << " specified - collect missed boundaries to final patch" << endl;
138
139 patchStarts_.setSize(boundaryIds_.size());
140 patchSizes_.setSize(boundaryIds_.size());
141
142 label nCreatedFaces = nInternalFaces_;
143 label baffleOffset = cFaces.size();
144 interfaces_.setSize(baffleIds_.size());
145 nBoundaryFaces = 0;
146
147 forAll(boundaryIds_, patchi)
148 {
149 const List<cellFaceIdentifier>& idList = boundaryIds_[patchi];
150
151 patchStarts_[patchi] = nCreatedFaces;
152
153 // write each baffle side separately
154 if (patchPhysicalTypes_[patchi] == "baffle")
155 {
156 label count = 0;
157
158 for (label side = 0; side < 2; ++side)
159 {
160 label position = nInterfaces;
161
162 forAll(idList, bndI)
163 {
164 label baffleI = idList[bndI].cellId() - baffleOffset;
165
166 if
167 (
168 baffleI >= 0
169 && baffleI < baffleFaces_.size()
170 && baffleIds_[baffleI].size()
171 )
172 {
173 addPolyBoundaryFace
174 (
175 baffleIds_[baffleI][side],
176 nCreatedFaces
177 );
178
179 // remove applied boundaries (2nd pass)
180 if (side == 1)
181 {
182 baffleIds_[baffleI].clear();
183 }
184
185 interfaces_[position][side] = nCreatedFaces;
186
187 nBoundaryFaces++;
188 nCreatedFaces++;
189 position++;
190 count++;
191 }
192 }
193 }
194
195 nInterfaces += (count - (count % 2)) / 2;
196 }
197 else if (patchPhysicalTypes_[patchi] == "monitoring")
198 {
199 // translate the "monitoring" pseudo-boundaries to face sets
200 labelList monitoring(idList.size());
201
202 label monitorI = 0;
203 forAll(idList, bndI)
204 {
205 label cellId = idList[bndI].cellId();
206 label faceId = idList[bndI].faceId();
207
208 // standard case: volume cells
209 if (cellId < baffleOffset)
210 {
211 label faceNr = cellPolys_[cellId][faceId];
212 if (faceNr >= 0)
213 {
214 monitoring[monitorI++] = faceNr;
215 }
216 }
217 }
218
219 monitoringSets_.insert(patchNames_[patchi], monitoring);
220 }
221 else
222 {
223 forAll(idList, bndI)
224 {
225 // standard case: volume cells
226 if (idList[bndI].cellId() < baffleOffset)
227 {
228 addPolyBoundaryFace
229 (
230 idList[bndI],
231 nCreatedFaces
232 );
233
234 nBoundaryFaces++;
235 nCreatedFaces++;
236 }
237 }
238 }
239
240 patchSizes_[patchi] = nCreatedFaces - patchStarts_[patchi];
241 }
242
243 // add in missing faces
244 Info<< "Missing faces added to patch after face "
245 << nCreatedFaces << ":" <<endl;
246 nMissingFaces = 0;
247
248 // look for baffles first - keep them together at the start of the patch
249 for (label side = 0; side < 2; ++side)
250 {
251 label position = nInterfaces;
252
253 forAll(baffleIds_, baffleI)
254 {
255 if (baffleIds_[baffleI].size())
256 {
257 // add each side for each baffle
258 addPolyBoundaryFace
259 (
260 baffleIds_[baffleI][side],
261 nCreatedFaces
262 );
263
264 interfaces_[position][side] = nCreatedFaces;
265
266 // remove applied boundaries (2nd pass)
267 if (side == 1)
268 {
269 baffleIds_[baffleI].clear();
270 }
271
272 nMissingFaces++;
273 nCreatedFaces++;
274 position++;
275 }
276 }
277 }
278
279 nInterfaces += (nMissingFaces - (nMissingFaces % 2)) / 2;
280
281 // scan for any other missing faces
282 forAll(cellPolys_, celli)
283 {
284 const labelList& curFaces = cellPolys_[celli];
285
286 forAll(curFaces, cellFacei)
287 {
288 if (curFaces[cellFacei] < 0)
289 {
290 // just report the first few
291 if (nMissingFaces < 4)
292 {
293 const face& thisFace = cFaces[celli][cellFacei];
294
295 Info<< " cell " << celli << " face " << cellFacei
296 << " (original cell " << origCellId_[celli] << ")"
297 << " face: " << thisFace
298 << endl;
299 }
300 else if (nMissingFaces == 5)
301 {
302 Info<< " ..." << nl << endl;
303 }
304
305 addPolyBoundaryFace(celli, cellFacei, nCreatedFaces);
306 nMissingFaces++;
307 nCreatedFaces++;
308 }
309 }
310 }
311
312 Info<< "Added " << nMissingFaces << " unmatched faces" << endl;
313
314 // Add missing faces to last patch ('Default_Empty' etc.)
315 if (nMissingFaces > 0)
316 {
317 patchSizes_.last() = nMissingFaces;
318 }
319
320
321 // reset the size of the face list
322 meshFaces_.setSize(nCreatedFaces);
323
324 // check the mesh for face mismatch
325 // (faces addressed once or more than twice)
326 labelList markupFaces(meshFaces_.size(), Zero);
327
328 forAll(cellPolys_, celli)
329 {
330 const labelList& curFaces = cellPolys_[celli];
331
332 forAll(curFaces, facei)
333 {
334 markupFaces[curFaces[facei]]++;
335 }
336 }
337
338 for (label i = nInternalFaces_; i < markupFaces.size(); i++)
339 {
340 markupFaces[i]++;
341 }
342
343 label nProblemFaces = 0;
344
345 forAll(markupFaces, facei)
346 {
347 if (markupFaces[facei] != 2)
348 {
349 const face& problemFace = meshFaces_[facei];
350
352 << "Problem with face " << facei << ": addressed "
353 << markupFaces[facei] << " times (should be 2!). Face: "
354 << problemFace << endl;
355
356 nProblemFaces++;
357 }
358 }
359
360 if (nProblemFaces > 0)
361 {
362 Info<< "Number of incorrectly matched faces: "
363 << nProblemFaces << endl;
364 }
365
366 // adjust for missing members
367 if (nInterfaces < interfaces_.size())
368 {
369 interfaces_.setSize(nInterfaces);
370 }
371
372 Info<< "Number of boundary faces: " << nBoundaryFaces << nl
373 << "Total number of faces: " << nCreatedFaces << nl
374 << "Number of interfaces: " << nInterfaces << endl;
375}
376
377
378// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
379
381Foam::meshReader::polyBoundaryPatches(const polyMesh& mesh)
382{
383 label nUsed = 0, nEmpty = 0;
384 label nPatches = patchStarts_.size();
385
386 // avoid empty patches - move to the end of the lists and truncate
387 labelList oldToNew = identity(nPatches);
388 forAll(patchSizes_, patchi)
389 {
390 if (patchSizes_[patchi] > 0)
391 {
392 oldToNew[patchi] = nUsed++;
393 }
394 else
395 {
396 nEmpty++;
397 oldToNew[patchi] = nPatches - nEmpty;
398 }
399 }
400
401 nPatches = nUsed;
402
403 if (nEmpty)
404 {
405 Info<< "Removing " << nEmpty << " empty patches" << endl;
406
407 inplaceReorder(oldToNew, patchTypes_);
408 inplaceReorder(oldToNew, patchNames_);
409 inplaceReorder(oldToNew, patchStarts_);
410 inplaceReorder(oldToNew, patchSizes_);
411 }
412
413 patchTypes_.setSize(nPatches);
414 patchNames_.setSize(nPatches);
415 patchStarts_.setSize(nPatches);
416 patchSizes_.setSize(nPatches);
417
418
419 List<polyPatch*> p(nPatches);
420
421 // All patch dictionaries
422 PtrList<dictionary> patchDicts(patchNames_.size());
423 // Default boundary patch types
425
426 // we could consider dropping this entirely
428 (
429 mesh,
430 mesh.instance(),
431 mesh.meshDir(),
432 patchNames_,
434 "defaultFaces",
436 );
437 forAll(patchDicts, patchi)
438 {
439 if (!patchDicts.set(patchi))
440 {
441 patchDicts.set(patchi, new dictionary());
442 }
443 dictionary& patchDict = patchDicts[patchi];
444
445 // Add but not override 'type'
446 if (!patchDict.found("type"))
447 {
448 patchDict.add("type", patchTypes_[patchi], false);
449 }
450
451 // Add but not override 'physicalType' but only if it differs
452 // from 'type'
453 if
454 (
455 patchi < patchPhysicalTypes_.size()
456 && patchPhysicalTypes_[patchi].size()
457 && patchPhysicalTypes_[patchi] != patchTypes_[patchi]
458 && !patchDict.found("physicalType")
459 )
460 {
461 patchDict.add("physicalType", patchPhysicalTypes_[patchi], false);
462 }
463
464 // Overwrite sizes and start
465 patchDict.add("nFaces", patchSizes_[patchi], true);
466 patchDict.add("startFace", patchStarts_[patchi], true);
467 }
468
469
470 forAll(patchStarts_, patchi)
471 {
472 p[patchi] = polyPatch::New
473 (
474 patchNames_[patchi],
475 patchDicts[patchi],
476 patchi,
478 ).ptr();
479 }
480
481 return p;
482}
483
484
485// ************************************************************************* //
const fileName & instance() const noexcept
Read access to instance path component.
Definition: IOobjectI.H:196
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
faceList meshFaces_
Global face list for polyMesh.
Definition: meshReader.H:242
label nInternalFaces_
Number of internal faces for polyMesh.
Definition: meshReader.H:239
labelList origCellId_
Lookup original Cell number for a given cell.
Definition: meshReader.H:219
faceListList cellFaces_
List of faces for every cell.
Definition: meshReader.H:245
fileName meshDir() const
Return the local mesh directory (dbDir()/meshSubDir)
Definition: polyMesh.C:848
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
volScalarField & p
dynamicFvMesh & mesh
const label nPatches
label cellId
label faceId(-1)
#define InfoInFunction
Report an information message using Foam::Info.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:78
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
List< label > labelList
A List of labels.
Definition: List.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
void preservePatchTypes(const objectRegistry &obr, const word &meshInstance, const fileName &meshDir, const wordList &patchNames, PtrList< dictionary > &patchDicts, const word &defaultFacesName, word &defaultFacesType)
Preserve patch types.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
List< faceList > faceListList
A List of faceList.
Definition: faceListFwd.H:49
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
preservePatchTypes
PtrList< dictionary > patchDicts
Definition: readKivaGrid.H:532
word defaultFacesType
Definition: readKivaGrid.H:456
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
static const char *const typeName
The type name used in ensight case files.