Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
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
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),
50 triFace_(),
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
66Foam::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_),
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;
137
138 sumTriMagSf_.resize_nocopy(numProc+1);
139 sumTriMagSf_[0] = 0;
140
141 {
142 scalarList::subList slice(sumTriMagSf_, numProc, 1);
143 slice[myProci] = patchArea;
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;
158}
159
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];
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
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
300Foam::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// ************************************************************************* //
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
SubList< scalar > subList
Definition List.H:129
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual communication.
Random number generator.
Definition Random.H:56
Type position(const Type &start, const Type &end)
Return a sample on the interval [start,end].
Type sample01()
Return a sample whose components lie in the range [0,1].
Type globalSample01()
Return a sample whose components lie in the range [0,1].
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
T & last()
Access last element of the list, position [size()-1].
Definition UList.H:971
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
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:1697
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
Mesh data needed to do the Finite Volume discretisation.
Definition fvMesh.H:85
A traits class, which is primarily used for primitives and vector-space.
Definition pTraits.H:64
const word patchName_
Patch name.
const label patchId_
Patch ID.
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.
scalarList triCumulativeMagSf_
Cumulative triangle area per triangle face (processor-local).
label whichProc(const scalar fraction01) const
Return the processor that has the location specified by the fraction.
scalar patchArea_
Patch area - total across all processors.
vectorList patchNormal_
Patch face normal directions.
scalarList sumTriMagSf_
Cumulative area fractions per processor.
labelList cellOwners_
List of cell labels corresponding to injector positions.
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.
List< labelledTri > triFace_
The polyPatch faces as triangles, the index of each corresponds to the undecomposed patch face index.
static List< tetIndices > cellTetIndices(const polyMesh &mesh, label cI)
Return the tet decomposition of the given cell, see.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition word.H:66
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const pointField & points
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
vector point
Point is a vector.
Definition point.H:37
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
List< scalar > scalarList
List of scalar.
Definition scalarList.H:32
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
labelList f(nPoints)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition stdFoam.H:315