patchInjectionBase.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) 2013-2017 OpenFOAM Foundation
9  Copyright (C) 2024 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 
29 #include "patchInjectionBase.H"
30 #include "polyMesh.H"
31 #include "SubField.H"
32 #include "Random.H"
33 #include "triangle.H"
34 #include "volFields.H"
36 
37 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
38 
40 (
41  const polyMesh& mesh,
42  const word& patchName
43 )
44 :
45  patchName_(patchName),
46  patchId_(mesh.boundaryMesh().findPatchID(patchName_)),
47  patchArea_(0),
48  patchNormal_(),
49  cellOwners_(),
50  triFace_(),
51  triCumulativeMagSf_(),
52  sumTriMagSf_()
53 {
54  if (patchId_ < 0)
55  {
57  << "Requested patch " << patchName_ << " not found" << nl
58  << "Available patches are: " << mesh.boundaryMesh().names() << nl
60  }
61 
63 }
64 
65 
66 Foam::patchInjectionBase::patchInjectionBase(const patchInjectionBase& pib)
67 :
68  patchName_(pib.patchName_),
69  patchId_(pib.patchId_),
70  patchArea_(pib.patchArea_),
71  patchNormal_(pib.patchNormal_),
72  cellOwners_(pib.cellOwners_),
73  triFace_(pib.triFace_),
74  triCumulativeMagSf_(pib.triCumulativeMagSf_),
75  sumTriMagSf_(pib.sumTriMagSf_)
76 {}
77 
78 
79 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
80 
82 {
83  // Set/cache the injector cells
84  const polyPatch& patch = mesh.boundaryMesh()[patchId_];
85  const pointField& points = patch.points();
86 
87  cellOwners_ = patch.faceCells();
88 
89  // Triangulate the patch faces and create addressing
90  {
91  label nTris = 0;
92  for (const face& f : patch)
93  {
94  nTris += f.nTriangles();
95  }
96 
97  DynamicList<labelledTri> dynTriFace(nTris);
98  DynamicList<face> tris(8); // work array
99 
100  forAll(patch, facei)
101  {
102  const face& f = patch[facei];
103 
104  tris.clear();
105  f.triangles(points, tris);
106 
107  for (const auto& t : tris)
108  {
109  dynTriFace.emplace_back(t[0], t[1], t[2], facei);
110  }
111  }
112 
113  // Transfer to persistent storage
114  triFace_.transfer(dynTriFace);
115  }
116 
117 
118  const label myProci = UPstream::myProcNo();
119  const label numProc = UPstream::nProcs();
120 
121  // Calculate the cumulative triangle weights
122  {
123  triCumulativeMagSf_.resize_nocopy(triFace_.size()+1);
124 
125  auto iter = triCumulativeMagSf_.begin();
126 
127  // Set zero value at the start of the tri area/weight list
128  scalar patchArea = 0;
129  *iter++ = patchArea;
130 
131  // Calculate cumulative and total area
132  for (const auto& t : triFace_)
133  {
134  patchArea += t.mag(points);
135  *iter++ = patchArea;
136  }
137 
138  sumTriMagSf_.resize_nocopy(numProc+1);
139  sumTriMagSf_[0] = 0;
140 
141  {
142  scalarList::subList slice(sumTriMagSf_, numProc, 1);
143  slice[myProci] = patchArea;
144  Pstream::allGatherList(slice);
145  }
146 
147  // Convert to cumulative
148  for (label i = 1; i < sumTriMagSf_.size(); ++i)
149  {
150  sumTriMagSf_[i] += sumTriMagSf_[i-1];
151  }
152  }
153 
154  const scalarField magSf(mag(patch.faceAreas()));
155  patchArea_ = sum(magSf);
156  patchNormal_ = patch.faceAreas()/magSf;
157  reduce(patchArea_, sumOp<scalar>());
158 }
159 
160 
162 (
163  const fvMesh& mesh,
164  const scalar fraction01,
165  Random& rnd,
166  vector& position,
167  label& cellOwner,
168  label& tetFacei,
169  label& tetPti
170 )
171 {
172  label facei = -1;
173 
174  if (!cellOwners_.empty())
175  {
176  // Determine which processor to inject from
177  const label proci = whichProc(fraction01);
178 
179  if (UPstream::myProcNo() == proci)
180  {
181  const scalar areaFraction = fraction01*patchArea_;
182 
183  // Find corresponding decomposed face triangle
184  label trii = 0;
185  scalar offset = sumTriMagSf_[proci];
186  forAllReverse(triCumulativeMagSf_, i)
187  {
188  if (areaFraction > triCumulativeMagSf_[i] + offset)
189  {
190  trii = i;
191  break;
192  }
193  }
194 
195  // Set cellOwner
196  facei = triFace_[trii].index();
197  cellOwner = cellOwners_[facei];
198 
199  // Find random point in triangle
200  const polyPatch& patch = mesh.boundaryMesh()[patchId_];
201  const pointField& points = patch.points();
202  const point pf = triFace_[trii].tri(points).randomPoint(rnd);
203 
204  // Position perturbed away from face (into domain)
205  const scalar a = rnd.position(scalar(0.1), scalar(0.5));
206  const vector& pc = mesh.cellCentres()[cellOwner];
207  const vector d =
208  mag((pf - pc) & patchNormal_[facei])*patchNormal_[facei];
209 
210  position = pf - a*d;
211 
212  // Try to find tetFacei and tetPti in the current position
213  mesh.findTetFacePt(cellOwner, position, tetFacei, tetPti);
214 
215  // tetFacei and tetPti not found, check if the cell has changed
216  if (tetFacei == -1 ||tetPti == -1)
217  {
218  mesh.findCellFacePt(position, cellOwner, tetFacei, tetPti);
219  }
220 
221  // Both searches failed, choose a random position within
222  // the original cell
223  if (tetFacei == -1 ||tetPti == -1)
224  {
225  // Reset cellOwner
226  cellOwner = cellOwners_[facei];
227  const scalarField& V = mesh.V();
228 
229  // Construct cell tet indices
230  const List<tetIndices> cellTetIs =
232 
233  // Construct cell tet volume fractions
234  scalarList cTetVFrac(cellTetIs.size(), Zero);
235  for (label teti=1; teti<cellTetIs.size()-1; teti++)
236  {
237  cTetVFrac[teti] =
238  cTetVFrac[teti-1]
239  + cellTetIs[teti].tet(mesh).mag()/V[cellOwner];
240  }
241  cTetVFrac.last() = 1;
242 
243  // Set new particle position
244  const scalar volFrac = rnd.sample01<scalar>();
245  label teti = 0;
246  forAll(cTetVFrac, vfI)
247  {
248  if (cTetVFrac[vfI] > volFrac)
249  {
250  teti = vfI;
251  break;
252  }
253  }
254  position = cellTetIs[teti].tet(mesh).randomPoint(rnd);
255  tetFacei = cellTetIs[teti].face();
256  tetPti = cellTetIs[teti].tetPt();
257  }
258  }
259  }
260 
261  if (facei == -1)
262  {
263  cellOwner = -1;
264  tetFacei = -1;
265  tetPti = -1;
266 
267  // Dummy position
268  position = pTraits<vector>::max;
269  }
270 
271  return facei;
272 }
273 
274 
276 (
277  const fvMesh& mesh,
278  Random& rnd,
279  vector& position,
280  label& cellOwner,
281  label& tetFacei,
282  label& tetPti
283 )
284 {
285  scalar fraction01 = rnd.globalSample01<scalar>();
286 
287  return setPositionAndCell
288  (
289  mesh,
290  fraction01,
291  rnd,
292  position,
293  cellOwner,
294  tetFacei,
295  tetPti
296  );
297 }
298 
299 
300 Foam::label Foam::patchInjectionBase::whichProc(const scalar fraction01) const
301 {
302  const scalar areaFraction = fraction01*patchArea_;
303 
304  // Determine which processor to inject from
305  forAllReverse(sumTriMagSf_, i)
306  {
307  if (areaFraction >= sumTriMagSf_[i])
308  {
309  return i;
310  }
311  }
312 
313  return 0;
314 }
315 
316 
317 // ************************************************************************* //
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
const word patchName_
Patch name.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
label whichProc(const scalar fraction01) const
Return the processor that has the location specified by the fraction.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
SubList< scalar > subList
Declare type of subList.
Definition: List.H:144
patchInjectionBase(const polyMesh &mesh, const word &patchName)
Construct from mesh and patch name.
virtual void updateMesh(const polyMesh &mesh)
Update patch geometry and derived info for injection locations.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
const DimensionedField< scalar, volMesh > & V() const
Return cell volumes.
static List< tetIndices > cellTetIndices(const polyMesh &mesh, label cI)
Return the tet decomposition of the given cell, see.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1077
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
Type sample01()
Return a sample whose components lie in the range [0,1].
dynamicFvMesh & mesh
const pointField & points
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void findCellFacePt(const point &p, label &celli, label &tetFacei, label &tetPti) const
Find the cell, tetFacei and tetPti for point p.
Definition: polyMesh.C:1360
const label patchId_
Patch ID.
Vector< scalar > vector
Definition: vector.H:57
const vectorField & cellCentres() const
Random number generator.
Definition: Random.H:55
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
labelList f(nPoints)
T & last()
Access last element of the list, position [size()-1].
Definition: UList.H:876
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
Definition: ListI.H:205
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual linear/tree communicat...
vector point
Point is a vector.
Definition: point.H:37
label setPositionAndCell(const fvMesh &mesh, const scalar fraction01, Random &rnd, vector &position, label &cellOwner, label &tetFacei, label &tetPti)
Set the injection position and owner cell, tetFace and tetPt.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
const std::string patch
OpenFOAM patch number as a std::string.
void findTetFacePt(const label celli, const point &p, label &tetFacei, label &tetPti) const
Find the tetFacei and tetPti for point p in celli.
Definition: polyMesh.C:1385
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:437
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
Type position(const Type &start, const Type &end)
Return a sample on the interval [start,end].
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127