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 -------------------------------------------------------------------------------
11 License
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 
37 void 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 
109 void 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 
202 void 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 
382 Foam::extendedUpwindCellToFaceStencil::extendedUpwindCellToFaceStencil
383 (
384  const cellToFaceStencil& stencil,
385  const bool pureUpwind,
386  const scalar minOpposedness
387 )
388 :
389  extendedCellToFaceStencil(stencil.mesh()),
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 
526 Foam::extendedUpwindCellToFaceStencil::extendedUpwindCellToFaceStencil
527 (
528  const cellToFaceStencil& stencil
529 )
530 :
531  extendedCellToFaceStencil(stencil.mesh()),
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 // ************************************************************************* //
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::cellToFaceStencil::mesh
const polyMesh & mesh() const
Definition: cellToFaceStencil.H:131
Foam::DynamicList< label >
Foam::syncTools::syncBoundaryFaceList
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.
Definition: syncToolsTemplates.C:998
Foam::primitiveMesh::cells
const cellList & cells() const
Definition: primitiveMeshCells.C:138
dummyTransform.H
Dummy transform to be used with syncTools.
Foam::boolList
List< bool > boolList
A List of bools.
Definition: List.H:65
syncTools.H
Foam::polyBoundaryMesh::start
label start() const
The start label of the boundary faces in the polyMesh face list.
Definition: polyBoundaryMesh.C:611
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
n
label n
Definition: TABSMDCalcMethod2.H:31
SortableList.H
extendedUpwindCellToFaceStencil.H
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::mapDistribute
Class containing processor-to-processor mapping information.
Definition: mapDistribute.H:163
Foam::polyMesh::faceOwner
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1107
Foam::cellToFaceStencil::globalNumbering
const globalIndex & globalNumbering() const
Global numbering for cells and boundary faces.
Definition: cellToFaceStencil.H:137
Foam::fvMesh::C
const volVectorField & C() const
Return cell centres as volVectorField.
Definition: fvMeshGeometry.C:341
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::extendedCellToFaceStencil
Calculates/constains the extended cell-to-face stencil.
Definition: extendedCellToFaceStencil.H:67
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:85
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::Vector< scalar >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
cellToFaceStencil.H
Foam::primitiveMesh::faceCentres
const vectorField & faceCentres() const
Definition: primitiveMeshFaceCentresAndAreas.C:77
Foam::cellToFaceStencil
Base class for extended cell-to-face stencils (face values from neighbouring cells)
Definition: cellToFaceStencil.H:56
points
const pointField & points
Definition: gmvOutputHeader.H:1
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::labelHashSet
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
Foam::extendedCellToFaceStencil::mesh_
const polyMesh & mesh_
Definition: extendedCellToFaceStencil.H:73
Foam::primitiveMesh::faceAreas
const vectorField & faceAreas() const
Definition: primitiveMeshFaceCentresAndAreas.C:89