Loading...
Searching...
No Matches
wallBoundedParticleTemplates.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) 2017-2019 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 "wallBoundedParticle.H"
30
31// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32
33template<class TrackCloudType>
35(
36 TrackCloudType& cloud,
38 const scalar trackFraction
39)
40{
41 typename TrackCloudType::particleType& p =
42 static_cast<typename TrackCloudType::particleType&>(*this);
43 typename TrackCloudType::particleType::trackingData& ttd =
44 static_cast<typename TrackCloudType::particleType::trackingData&>(td);
45
46 if (!mesh().isInternalFace(face()))
47 {
48 label origFacei = face();
49 label patchi = patch();
50
51 // Did patch interaction model switch patches?
52 // Note: recalculate meshEdgeStart_, diagEdge_!
53 if (face() != origFacei)
54 {
55 patchi = patch();
56 }
57
58 const polyPatch& patch = mesh().boundaryMesh()[patchi];
59
61 {
62 p.hitProcessorPatch(cloud, ttd);
63 }
64 else if (isA<wallPolyPatch>(patch))
65 {
66 p.hitWallPatch(cloud, ttd);
67 }
68 else
69 {
70 td.keepParticle = false;
71 }
72 }
73}
74
75
76// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
77
78template<class TrackCloudType>
80(
81 TrackCloudType& cloud,
82 trackingData& td,
83 const vector& endPosition
84)
85{
86 // Track particle to a given position and returns 1.0 if the
87 // trajectory is completed without hitting a face otherwise
88 // stops at the face and returns the fraction of the trajectory
89 // completed.
90 // on entry 'stepFraction()' should be set to the fraction of the
91 // time-step at which the tracking starts.
92
93 // Are we on a track face? If not we do a topological walk.
94
95 // Particle:
96 // - cell_ always set
97 // - tetFace_, tetPt_ always set (these identify tet particle is in)
98 // - optionally meshEdgeStart_ or diagEdge_ set (edge particle is on)
99
100 //checkInside();
101 //checkOnTriangle(localPosition_);
102 //if (meshEdgeStart_ != -1 || diagEdge_ != -1)
103 //{
104 // checkOnEdge();
105 //}
106
107 scalar trackFraction = 0.0;
108
109 if (!td.isWallPatch_[tetFace()])
110 {
111 // Don't track across face. Just walk in cell. Particle is on
112 // mesh edge (as indicated by meshEdgeStart_).
113 const edge meshEdge(currentEdge());
114
115 // If internal face check whether to go to neighbour cell or just
116 // check to the other internal tet on the edge.
117 if (mesh().isInternalFace(tetFace()))
118 {
119 label nbrCelli =
120 (
121 this->cell() == mesh().faceOwner()[face()]
122 ? mesh().faceNeighbour()[face()]
123 : mesh().faceOwner()[face()]
124 );
125 // Check angle to nbrCell tet. Is it in the direction of the
126 // endposition? i.e. since volume of nbr tet is positive the
127 // tracking direction should be into the tet.
128 tetIndices nbrTi(nbrCelli, tetFace(), tetPt());
129
130 const bool posVol = (nbrTi.tet(mesh()).mag() > 0);
131 const vector path(endPosition - localPosition_);
132
133 if (posVol == ((nbrTi.faceTri(mesh()).areaNormal() & path) < 0))
134 {
135 // Change into nbrCell. No need to change tetFace, tetPt.
136 //Pout<< " crossed from cell:" << celli_
137 // << " into " << nbrCelli << endl;
138 this->cell() = nbrCelli;
139 patchInteraction(cloud, td, trackFraction);
140 }
141 else
142 {
143 // Walk to other face on edge. Changes tetFace, tetPt but not
144 // cell.
145 crossEdgeConnectedFace(meshEdge);
146 patchInteraction(cloud, td, trackFraction);
147 }
148 }
149 else
150 {
151 // Walk to other face on edge. This might give loop since
152 // particle should have been removed?
153 crossEdgeConnectedFace(meshEdge);
154 patchInteraction(cloud, td, trackFraction);
155 }
156 }
157 else
158 {
159 // We're inside a tet on the wall. Check if the current tet is
160 // the one to cross. If not we cross into the neighbouring triangle.
161
162 if (mesh().isInternalFace(tetFace()))
163 {
165 << "Can only track on boundary faces."
166 << " Face:" << tetFace()
167 << " at:" << mesh().faceCentres()[tetFace()]
168 << abort(FatalError);
169 }
170
171 const triFace tri(currentTetIndices().faceTriIs(mesh(), false));
172 const vector n = tri.unitNormal(mesh().points());
173
174 point projectedEndPosition = endPosition;
175
176 const bool posVol = (currentTetIndices().tet(mesh()).mag() > 0);
177
178 if (!posVol)
179 {
180 // Negative tet volume. Track back by setting the end point
181 projectedEndPosition =
182 localPosition_ - (endPosition - localPosition_);
183
184 // Make sure to use a large enough vector to cross the negative
185 // face. Bit overkill.
186 const vector d(endPosition - localPosition_);
187 const scalar magD(mag(d));
188 if (magD > ROOTVSMALL)
189 {
190 // Get overall mesh bounding box
192 // Extend to make 3D
193 meshBb.inflate(ROOTSMALL);
194
195 // Create vector guaranteed to cross mesh bounds
196 projectedEndPosition = localPosition_ - meshBb.mag()*d/magD;
197
198 // Clip to mesh bounds
199 point intPt;
200 direction intPtBits;
201 bool ok = meshBb.intersects
202 (
203 projectedEndPosition,
204 localPosition_ - projectedEndPosition,
205 projectedEndPosition,
206 localPosition_,
207 intPt,
208 intPtBits
209 );
210 if (ok)
211 {
212 // Should always be the case
213 projectedEndPosition = intPt;
214 }
215 }
216 }
217
218 // Remove normal component
219 {
220 const point& basePt = mesh().points()[tri[0]];
221 projectedEndPosition -= ((projectedEndPosition - basePt)&n)*n;
222 }
223
224
225 bool doTrack = false;
226 if (meshEdgeStart_ == -1 && diagEdge_ == -1)
227 {
228 // We're starting and not yet on an edge.
229 doTrack = true;
230 }
231 else
232 {
233 // See if the current triangle has got a point on the
234 // correct side of the edge.
235 doTrack = isTriAlongTrack(n, projectedEndPosition);
236 }
237
238
239 if (doTrack)
240 {
241 // Track across triangle. Return triangle edge crossed.
242 label triEdgei = -1;
243 trackFraction = trackFaceTri(n, projectedEndPosition, triEdgei);
244
245 if (triEdgei == -1)
246 {
247 // Reached endpoint
248 //checkInside();
249 diagEdge_ = -1;
250 meshEdgeStart_ = -1;
251 return trackFraction;
252 }
253
254 const tetIndices ti(currentTetIndices());
255 const triFace trif(ti.triIs(mesh(), false));
256 // Triangle (faceTriIs) gets constructed from
257 // f[faceBasePtI_],
258 // f[facePtAI_],
259 // f[facePtBI_]
260 //
261 // So edge indices are:
262 // 0 : edge between faceBasePtI_ and facePtAI_
263 // 1 : edge between facePtAI_ and facePtBI_ (is always a real edge)
264 // 2 : edge between facePtBI_ and faceBasePtI_
265
266 const Foam::face& f = mesh().faces()[ti.face()];
267 const label fp0 = trif[0];
268
269 if (triEdgei == 0)
270 {
271 if (trif[1] == f.fcIndex(fp0))
272 {
273 //Pout<< "Real edge." << endl;
274 diagEdge_ = -1;
275 meshEdgeStart_ = fp0;
276 //checkOnEdge();
277 crossEdgeConnectedFace(currentEdge());
278 patchInteraction(cloud, td, trackFraction);
279 }
280 else if (trif[1] == f.rcIndex(fp0))
281 {
282 //Note: should not happen since boundary face so owner
283 //Pout<< "Real edge." << endl;
285 << abort(FatalError);
286
287 diagEdge_ = -1;
288 meshEdgeStart_ = f.rcIndex(fp0);
289 //checkOnEdge();
290 crossEdgeConnectedFace(currentEdge());
291 patchInteraction(cloud, td, trackFraction);
292 }
293 else
294 {
295 // Get index of triangle on other side of edge.
296 diagEdge_ = trif[1] - fp0;
297 if (diagEdge_ < 0)
298 {
299 diagEdge_ += f.size();
300 }
301 meshEdgeStart_ = -1;
302 //checkOnEdge();
303 crossDiagonalEdge();
304 }
305 }
306 else if (triEdgei == 1)
307 {
308 //Pout<< "Real edge." << endl;
309 diagEdge_ = -1;
310 meshEdgeStart_ = trif[1];
311 //checkOnEdge();
312 crossEdgeConnectedFace(currentEdge());
313 patchInteraction(cloud, td, trackFraction);
314 }
315 else // if (triEdgei == 2)
316 {
317 if (trif[2] == f.rcIndex(fp0))
318 {
319 //Pout<< "Real edge." << endl;
320 diagEdge_ = -1;
321 meshEdgeStart_ = trif[2];
322 //checkOnEdge();
323 crossEdgeConnectedFace(currentEdge());
324 patchInteraction(cloud, td, trackFraction);
325 }
326 else if (trif[2] == f.fcIndex(fp0))
327 {
328 //Note: should not happen since boundary face so owner
329 //Pout<< "Real edge." << endl;
331
332 diagEdge_ = -1;
333 meshEdgeStart_ = fp0;
334 //checkOnEdge();
335 crossEdgeConnectedFace(currentEdge());
336 patchInteraction(cloud, td, trackFraction);
337 }
338 else
339 {
340 //Pout<< "Triangle edge." << endl;
341 // Get index of triangle on other side of edge.
342 diagEdge_ = trif[2] - fp0;
343 if (diagEdge_ < 0)
344 {
345 diagEdge_ += f.size();
346 }
347 meshEdgeStart_ = -1;
348 //checkOnEdge();
349 crossDiagonalEdge();
350 }
351 }
352 }
353 else
354 {
355 // Current tet is not the right one. Check the neighbour tet.
356
357 if (meshEdgeStart_ != -1)
358 {
359 // Particle is on mesh edge so change into other face on cell
360 crossEdgeConnectedFace(currentEdge());
361 //checkOnEdge();
362 patchInteraction(cloud, td, trackFraction);
363 }
364 else
365 {
366 // Particle is on diagonal edge so change into the other
367 // triangle.
368 crossDiagonalEdge();
369 //checkOnEdge();
370 }
371 }
372 }
373
374 //checkInside();
375
376 return trackFraction;
377}
378
379
380template<class TrackCloudType>
382(
383 TrackCloudType& cloud,
384 trackingData& td
385)
386{
387 // Switch particle
388 td.switchProcessor = true;
389
390 // Adapt edgeStart_ for other side.
391 // E.g. if edgeStart_ is 1 then the edge is between vertex 1 and 2 so
392 // on the other side between 2 and 3 so edgeStart_ should be
393 // f.size()-edgeStart_-1.
394
395 const Foam::face& f = mesh().faces()[face()];
396
397 if (meshEdgeStart_ != -1)
398 {
399 meshEdgeStart_ = f.size() - meshEdgeStart_-1;
400 }
401 else
402 {
403 // diagEdge_ is relative to faceBasePt
404 diagEdge_ = f.size() - diagEdge_;
405 }
406}
407
408
409template<class TrackCloudType>
411(
412 TrackCloudType& cloud,
414)
415{}
416
417
418template<class TrackCloudType>
419void Foam::wallBoundedParticle::readFields(TrackCloudType& c)
420{
421 if (!c.size())
422 {
423 return;
424 }
425
427
428 IOField<point> localPosition
429 (
430 c.newIOobject("position", IOobject::MUST_READ)
431 );
432 c.checkFieldIOobject(c, localPosition);
433
434 IOField<label> meshEdgeStart
435 (
436 c.newIOobject("meshEdgeStart", IOobject::MUST_READ)
437 );
438 c.checkFieldIOobject(c, meshEdgeStart);
439
440 IOField<label> diagEdge
441 (
442 c.newIOobject("diagEdge", IOobject::MUST_READ)
443 );
444 c.checkFieldIOobject(c, diagEdge);
445
446 label i = 0;
447 for (wallBoundedParticle& p : c)
448 {
449 p.localPosition_ = localPosition[i];
450 p.meshEdgeStart_ = meshEdgeStart[i];
451 p.diagEdge_ = diagEdge[i];
453 ++i;
454 }
455}
456
457
458template<class TrackCloudType>
459void Foam::wallBoundedParticle::writeFields(const TrackCloudType& c)
460{
462
463 const label np = c.size();
464
465 IOField<point> localPosition
466 (
467 c.newIOobject("position", IOobject::NO_READ),
468 np
469 );
470 IOField<label> meshEdgeStart
471 (
472 c.newIOobject("meshEdgeStart", IOobject::NO_READ),
473 np
474 );
475 IOField<label> diagEdge
476 (
477 c.newIOobject("diagEdge", IOobject::NO_READ),
478 np
479 );
480
481 label i = 0;
482 for (const wallBoundedParticle& p : c)
483 {
484 localPosition[i] = p.localPosition_;
485 meshEdgeStart[i] = p.meshEdgeStart_;
486 diagEdge[i] = p.diagEdge_;
487
488 ++i;
489 }
490
491 localPosition.write();
492 meshEdgeStart.write();
493 diagEdge.write();
494}
495
496
497// ************************************************************************* //
label n
A primitive field of type <T> with automated input and output.
Definition IOField.H:53
@ NO_READ
Nothing to be read.
@ MUST_READ
Reading required.
label rcIndex(const label i) const noexcept
The reverse circular index. The previous index in the list which returns to the last at the beginning...
Definition UListI.H:106
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition UListI.H:99
A cloud is a registry collection of lagrangian particles.
Definition cloud.H:56
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
tetIndices currentTetIndices() const noexcept
Return indices of the current tet that the particle occupies.
Definition particleI.H:236
label face() const noexcept
Return current face particle is on otherwise -1.
Definition particleI.H:158
label tetPt() const noexcept
Return current tet face particle is in.
Definition particleI.H:146
static void readFields(TrackCloudType &c)
Read the fields associated with the owner cloud.
const polyMesh & mesh() const noexcept
Return the mesh database.
Definition particleI.H:110
label tetFace() const noexcept
Return current tet face particle is in.
Definition particleI.H:134
label patch() const
Return the index of patch that the particle is on.
Definition particleI.H:277
label cell() const noexcept
Return current cell particle is in.
Definition particleI.H:122
static void writeFields(const TrackCloudType &c)
Write the fields associated with the owner cloud.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
virtual const faceList & faces() const
Return raw faces.
Definition polyMesh.C:1088
virtual const labelList & faceOwner() const
Return face owner.
Definition polyMesh.C:1101
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition polyMesh.C:1107
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
const vectorField & faceCentres() const
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
Storage and named access for the indices of a tet which is part of the decomposition of a cell.
Definition tetIndices.H:79
label face() const noexcept
Return the face index.
Definition tetIndices.H:156
triFace triIs(const polyMesh &mesh, const bool warn=true) const
Local indices corresponding to the tri on the face for this tet. The normal of the tri points out of ...
Definition tetIndicesI.H:89
tetPointRef tet(const polyMesh &mesh) const
The tet geometry for this tet, where point0 is the cell centre.
triPointRef faceTri(const polyMesh &mesh) const
The triangle geometry for the face for this tet. The normal of the tri points out of the cell.
Standard boundBox with extra functionality for use in octree.
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition triFace.H:68
vector unitNormal(const UList< point > &points) const
The unit normal.
Definition triFaceI.H:185
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
Class used to pass tracking data to the trackToFace function.
label meshEdgeStart_
Particle is on mesh edge:
bool isTriAlongTrack(const vector &n, const point &endPosition) const
Is current triangle in the track direction.
wallBoundedParticle(const polyMesh &c, const point &position, const label celli, const label tetFacei, const label tetPti, const label meshEdgeStart, const label diagEdge)
Construct from components.
label meshEdgeStart() const noexcept
The mesh edge label or -1.
void patchInteraction(TrackCloudType &cloud, trackingData &td, const scalar trackFraction)
Do all patch interaction.
edge currentEdge() const
Construct current edge.
static void writeFields(const CloudType &)
Write.
void hitProcessorPatch(TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting a processorPatch.
scalar trackToEdge(TrackCloudType &cloud, trackingData &td, const vector &endPosition)
Equivalent of trackToFace.
label diagEdge_
Particle is on diagonal edge:
scalar trackFaceTri(const vector &n, const vector &endPosition, label &)
Track through single triangle.
void crossEdgeConnectedFace(const label &celli, label &tetFacei, label &tetPti, const edge &e)
Replacement for particle::crossEdgeConnectedFace that avoids bombing.
label diagEdge() const noexcept
The diagonal edge label or -1.
void hitWallPatch(TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting a wallPatch.
point localPosition_
Particle position is updated locally as opposed to via track.
void crossDiagonalEdge()
Cross diagonal edge into different triangle on same face,cell.
static void readFields(CloudType &)
Read.
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
volScalarField & p
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const pointField & points
wallPoints::trackData td(isBlockedFace, regionToBlockSize)
Namespace for bounding specifications. At the moment, mostly for tables.
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
errorManip< error > abort(error &err)
Definition errorManip.H:139
uint8_t direction
Definition direction.H:49
vector point
Point is a vector.
Definition point.H:37
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
Vector< scalar > vector
Definition vector.H:57
labelList f(nPoints)
List< treeBoundBox > meshBb(1, treeBoundBox(coarseMesh.points()).extend(rndGen, 1e-3))