extendedUpwindCellToFaceStencil.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 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
27\*---------------------------------------------------------------------------*/
28
30#include "cellToFaceStencil.H"
31#include "syncTools.H"
32#include "SortableList.H"
33#include "dummyTransform.H"
34
35// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
36
37void Foam::extendedUpwindCellToFaceStencil::selectOppositeFaces
38(
39 const boolList& nonEmptyFace,
40 const scalar minOpposedness,
41 const label facei,
42 const label celli,
43 DynamicList<label>& oppositeFaces
44) const
45{
46 const vectorField& areas = mesh_.faceAreas();
47 const labelList& own = mesh_.faceOwner();
48 const cell& cFaces = mesh_.cells()[celli];
49
50 SortableList<scalar> opposedness(cFaces.size(), -GREAT);
51
52 // Pick up all the faces that oppose this one.
53 forAll(cFaces, i)
54 {
55 label otherFacei = cFaces[i];
56
57 if (otherFacei != facei && nonEmptyFace[otherFacei])
58 {
59 if ((own[otherFacei] == celli) == (own[facei] == celli))
60 {
61 opposedness[i] = -(areas[otherFacei] & areas[facei]);
62 }
63 else
64 {
65 opposedness[i] = (areas[otherFacei] & areas[facei]);
66 }
67 }
68 }
69
70 label sz = opposedness.size();
71
72 oppositeFaces.clear();
73
74 scalar myAreaSqr = magSqr(areas[facei]);
75
76 if (myAreaSqr > VSMALL)
77 {
78 forAll(opposedness, i)
79 {
80 opposedness[i] /= myAreaSqr;
81 }
82 // Sort in incrementing order
83 opposedness.sort();
84
85 // Pick largest no matter what
86 oppositeFaces.append(cFaces[opposedness.indices()[sz-1]]);
87
88 for (label i = sz-2; i >= 0; --i)
89 {
90 if (opposedness[i] < minOpposedness)
91 {
92 break;
93 }
94 oppositeFaces.append(cFaces[opposedness.indices()[i]]);
95 }
96 }
97 else
98 {
99 // Sort in incrementing order
100 opposedness.sort();
101
102 // Tiny face. Do what?
103 // Pick largest no matter what
104 oppositeFaces.append(cFaces[opposedness.indices()[sz-1]]);
105 }
106}
107
108
109void Foam::extendedUpwindCellToFaceStencil::transportStencil
110(
111 const boolList& nonEmptyFace,
112 const labelListList& faceStencil,
113 const scalar minOpposedness,
114 const label facei,
115 const label celli,
116 const bool stencilHasNeighbour,
117
118 DynamicList<label>& oppositeFaces,
119 labelHashSet& faceStencilSet,
120 labelList& transportedStencil
121) const
122{
123 label globalOwn = faceStencil[facei][0];
124 label globalNei = -1;
125 if (stencilHasNeighbour && faceStencil[facei].size() >= 2)
126 {
127 globalNei = faceStencil[facei][1];
128 }
129
130
131 selectOppositeFaces
132 (
133 nonEmptyFace,
134 minOpposedness,
135 facei,
136 celli,
137 oppositeFaces
138 );
139
140 // Collect all stencils of oppositefaces
141 faceStencilSet.clear();
142 forAll(oppositeFaces, i)
143 {
144 const labelList& fStencil = faceStencil[oppositeFaces[i]];
145
146 forAll(fStencil, j)
147 {
148 label globalI = fStencil[j];
149
150 if (globalI != globalOwn && globalI != globalNei)
151 {
152 faceStencilSet.insert(globalI);
153 }
154 }
155 }
156
157 // Add my owner and neighbour first.
158 if (stencilHasNeighbour)
159 {
160 transportedStencil.setSize(faceStencilSet.size()+2);
161 label n = 0;
162 transportedStencil[n++] = globalOwn;
163 transportedStencil[n++] = globalNei;
164
165 for (const label stencili : faceStencilSet)
166 {
167 if (stencili != globalOwn && stencili != globalNei)
168 {
169 transportedStencil[n++] = stencili;
170 }
171 }
172 if (n != transportedStencil.size())
173 {
175 << "problem:" << faceStencilSet
176 << abort(FatalError);
177 }
178 }
179 else
180 {
181 transportedStencil.setSize(faceStencilSet.size()+1);
182 label n = 0;
183 transportedStencil[n++] = globalOwn;
184
185 for (const label stencili : faceStencilSet)
186 {
187 if (stencili != globalOwn)
188 {
189 transportedStencil[n++] = stencili;
190 }
191 }
192 if (n != transportedStencil.size())
193 {
195 << "problem:" << faceStencilSet
196 << abort(FatalError);
197 }
198 }
199}
200
201
202void Foam::extendedUpwindCellToFaceStencil::transportStencils
203(
204 const labelListList& faceStencil,
205 const scalar minOpposedness,
206 labelListList& ownStencil,
207 labelListList& neiStencil
208)
209{
210 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
211 const label nBnd = mesh_.nBoundaryFaces();
212 const labelList& own = mesh_.faceOwner();
213 const labelList& nei = mesh_.faceNeighbour();
214
215 // Work arrays
216 DynamicList<label> oppositeFaces;
217 labelHashSet faceStencilSet;
218
219
220 // For quick detection of empty faces
221 boolList nonEmptyFace(mesh_.nFaces(), true);
222 forAll(patches, patchi)
223 {
224 const polyPatch& pp = patches[patchi];
225
226 if (isA<emptyPolyPatch>(pp))
227 {
228 label facei = pp.start();
229 forAll(pp, i)
230 {
231 nonEmptyFace[facei++] = false;
232 }
233 }
234 }
235
236
237 // Do the owner side
238 // ~~~~~~~~~~~~~~~~~
239 // stencil is synchronised at entry so no need to swap.
240
241 ownStencil.setSize(mesh_.nFaces());
242
243 // Internal faces
244 for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
245 {
246 // Get stencil as owner + neighbour + stencil from 'opposite' faces
247 transportStencil
248 (
249 nonEmptyFace,
250 faceStencil,
251 minOpposedness,
252 facei,
253 own[facei],
254 true, //stencilHasNeighbour
255 oppositeFaces,
256 faceStencilSet,
257 ownStencil[facei]
258 );
259 }
260 // Boundary faces
261 forAll(patches, patchi)
262 {
263 const polyPatch& pp = patches[patchi];
264 label facei = pp.start();
265
266 if (pp.coupled())
267 {
268 forAll(pp, i)
269 {
270 transportStencil
271 (
272 nonEmptyFace,
273 faceStencil,
274 minOpposedness,
275 facei,
276 own[facei],
277 true, //stencilHasNeighbour
278
279 oppositeFaces,
280 faceStencilSet,
281 ownStencil[facei]
282 );
283 facei++;
284 }
285 }
286 else if (!isA<emptyPolyPatch>(pp))
287 {
288 forAll(pp, i)
289 {
290 // faceStencil does not contain neighbour
291 transportStencil
292 (
293 nonEmptyFace,
294 faceStencil,
295 minOpposedness,
296 facei,
297 own[facei],
298 false, //stencilHasNeighbour
299
300 oppositeFaces,
301 faceStencilSet,
302 ownStencil[facei]
303 );
304 facei++;
305 }
306 }
307 }
308
309
310 // Swap coupled boundary stencil
311 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
312
313 labelListList neiBndStencil(nBnd);
314 for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); facei++)
315 {
316 neiBndStencil[facei-mesh_.nInternalFaces()] = ownStencil[facei];
317 }
318 //syncTools::swapBoundaryFaceList(mesh_, neiBndStencil);
320 (
321 mesh_,
322 neiBndStencil,
323 eqOp<labelList>(),
324 dummyTransform()
325 );
326
327
328
329 // Do the neighbour side
330 // ~~~~~~~~~~~~~~~~~~~~~
331 // - internal faces : get opposite faces on neighbour side
332 // - boundary faces : empty
333 // - coupled faces : in neiBndStencil
334
335 neiStencil.setSize(mesh_.nFaces());
336
337 // Internal faces
338 for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
339 {
340 transportStencil
341 (
342 nonEmptyFace,
343 faceStencil,
344 minOpposedness,
345 facei,
346 nei[facei],
347 true, //stencilHasNeighbour
348
349 oppositeFaces,
350 faceStencilSet,
351 neiStencil[facei]
352 );
353 }
354
355 // Boundary faces
356 forAll(patches, patchi)
357 {
358 const polyPatch& pp = patches[patchi];
359 label facei = pp.start();
360
361 if (pp.coupled())
362 {
363 forAll(pp, i)
364 {
365 neiStencil[facei].transfer
366 (
367 neiBndStencil[facei-mesh_.nInternalFaces()]
368 );
369 facei++;
370 }
371 }
372 else
373 {
374 // Boundary has empty neighbour stencil
375 }
376 }
377}
378
379
380// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
381
383(
384 const cellToFaceStencil& stencil,
385 const bool pureUpwind,
386 const scalar minOpposedness
387)
388:
390 pureUpwind_(pureUpwind)
391{
392 //forAll(stencil, facei)
393 //{
394 // const labelList& fCells = stencil[facei];
395 //
396 // Pout<< "Face:" << facei << " at:" << mesh_.faceCentres()[facei]
397 // << endl;
398 //
399 // forAll(fCells, i)
400 // {
401 // label globalI = fCells[i];
402 //
403 // if (globalI < mesh_.nCells())
404 // {
405 // Pout<< " cell:" << globalI
406 // << " at:" << mesh_.cellCentres()[globalI] << endl;
407 // }
408 // else
409 // {
410 // label facei = globalI-mesh_.nCells() + mesh_.nInternalFaces();
411 //
412 // Pout<< " boundary:" << facei
413 // << " at:" << mesh_.faceCentres()[facei] << endl;
414 // }
415 // }
416 //}
417 //Pout<< endl << endl;
418
419
420 // Transport centred stencil to upwind/downwind face
421 transportStencils
422 (
423 stencil,
424 minOpposedness,
425 ownStencil_,
426 neiStencil_
427 );
428
429 {
430 List<Map<label>> compactMap(Pstream::nProcs());
431 ownMapPtr_.reset
432 (
433 new mapDistribute
434 (
435 stencil.globalNumbering(),
436 ownStencil_,
437 compactMap
438 )
439 );
440 }
441
442 {
443
444 List<Map<label>> compactMap(Pstream::nProcs());
445 neiMapPtr_.reset
446 (
447 new mapDistribute
448 (
449 stencil.globalNumbering(),
450 neiStencil_,
451 compactMap
452 )
453 );
454 }
455
456 // stencil now in compact form
457 if (pureUpwind_)
458 {
459 const fvMesh& mesh = dynamic_cast<const fvMesh&>(stencil.mesh());
460
461 List<List<point>> stencilPoints(ownStencil_.size());
462
463 // Owner stencil
464 // ~~~~~~~~~~~~~
465
466 collectData(ownMapPtr_(), ownStencil_, mesh.C(), stencilPoints);
467
468 // Mask off all stencil points on wrong side of face
469 forAll(stencilPoints, facei)
470 {
471 const point& fc = mesh.faceCentres()[facei];
472 const vector& fArea = mesh.faceAreas()[facei];
473
474 const List<point>& points = stencilPoints[facei];
475 const labelList& stencil = ownStencil_[facei];
476
477 DynamicList<label> newStencil(stencil.size());
478 forAll(points, i)
479 {
480 if (((points[i]-fc) & fArea) < 0)
481 {
482 newStencil.append(stencil[i]);
483 }
484 }
485 if (newStencil.size() != stencil.size())
486 {
487 ownStencil_[facei].transfer(newStencil);
488 }
489 }
490
491
492 // Neighbour stencil
493 // ~~~~~~~~~~~~~~~~~
494
495 collectData(neiMapPtr_(), neiStencil_, mesh.C(), stencilPoints);
496
497 // Mask off all stencil points on wrong side of face
498 forAll(stencilPoints, facei)
499 {
500 const point& fc = mesh.faceCentres()[facei];
501 const vector& fArea = mesh.faceAreas()[facei];
502
503 const List<point>& points = stencilPoints[facei];
504 const labelList& stencil = neiStencil_[facei];
505
506 DynamicList<label> newStencil(stencil.size());
507 forAll(points, i)
508 {
509 if (((points[i]-fc) & fArea) > 0)
510 {
511 newStencil.append(stencil[i]);
512 }
513 }
514 if (newStencil.size() != stencil.size())
515 {
516 neiStencil_[facei].transfer(newStencil);
517 }
518 }
519
520 // Note: could compact schedule as well. for if cells are not needed
521 // across any boundary anymore. However relatively rare.
522 }
523}
524
525
527(
528 const cellToFaceStencil& stencil
529)
530:
532 pureUpwind_(true)
533{
534 // Calculate stencil points with full stencil
535
536 ownStencil_ = stencil;
537
538 {
539 List<Map<label>> compactMap(Pstream::nProcs());
540 ownMapPtr_.reset
541 (
542 new mapDistribute
543 (
544 stencil.globalNumbering(),
545 ownStencil_,
546 compactMap
547 )
548 );
549 }
550
551 const fvMesh& mesh = dynamic_cast<const fvMesh&>(stencil.mesh());
552
553 List<List<point>> stencilPoints(ownStencil_.size());
554 collectData(ownMapPtr_(), ownStencil_, mesh.C(), stencilPoints);
555
556 // Split stencil into owner and neighbour
557 neiStencil_.setSize(ownStencil_.size());
558
559 forAll(stencilPoints, facei)
560 {
561 const point& fc = mesh.faceCentres()[facei];
562 const vector& fArea = mesh.faceAreas()[facei];
563
564 const List<point>& points = stencilPoints[facei];
565 const labelList& stencil = ownStencil_[facei];
566
567 DynamicList<label> newOwnStencil(stencil.size());
568 DynamicList<label> newNeiStencil(stencil.size());
569 forAll(points, i)
570 {
571 if (((points[i]-fc) & fArea) > 0)
572 {
573 newNeiStencil.append(stencil[i]);
574 }
575 else
576 {
577 newOwnStencil.append(stencil[i]);
578 }
579 }
580 if (newNeiStencil.size() > 0)
581 {
582 ownStencil_[facei].transfer(newOwnStencil);
583 neiStencil_[facei].transfer(newNeiStencil);
584 }
585 }
586
587 // Should compact schedule. Or have both return the same schedule.
588 neiMapPtr_.reset(new mapDistribute(ownMapPtr_()));
589}
590
591
592// ************************************************************************* //
label n
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:503
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
void transfer(List< T > &list)
Definition: List.C:447
void setSize(const label n)
Alias for resize()
Definition: List.H:218
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Base class for extended cell-to-face stencils (face values from neighbouring cells)
const polyMesh & mesh() const
const globalIndex & globalNumbering() const
Global numbering for cells and boundary faces.
Calculates/constains the extended cell-to-face stencil.
static void collectData(const mapDistribute &map, const labelListList &stencil, const GeometricField< T, fvPatchField, volMesh > &fld, List< List< T > > &stencilFld)
Use map to get the data into stencil order.
Creates upwind stencil by shifting a centred stencil to upwind and downwind faces and optionally remo...
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
const volVectorField & C() const
Return cell centres as volVectorField.
Class containing processor-to-processor mapping information.
label start() const noexcept
The start label of boundary faces in the polyMesh face list.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1121
const vectorField & faceCentres() const
const vectorField & faceAreas() const
const cellList & cells() const
static void syncBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const TransformOp &top, const bool parRun=Pstream::parRun())
Synchronize values on boundary faces only.
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
Dummy transform to be used with syncTools.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const pointField & points
List< label > labelList
A List of labels.
Definition: List.H:66
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Field< vector > vectorField
Specialisation of Field<T> for vector.
List< bool > boolList
A List of bools.
Definition: List.H:64
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
error FatalError
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333