wallBoundedParticle.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// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32
34(
35 sizeof(wallBoundedParticle) - sizeof(particle)
36);
37
38
39// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
40
42{
43 if ((meshEdgeStart_ != -1) == (diagEdge_ != -1))
44 {
46 << "Particle:"
47 << info()
48 << "cannot both be on a mesh edge and a face-diagonal edge."
49 << " meshEdgeStart_:" << meshEdgeStart_
50 << " diagEdge_:" << diagEdge_
51 << abort(FatalError);
52 }
53
54 const Foam::face& f = mesh().faces()[tetFace()];
55
56 if (meshEdgeStart_ != -1)
57 {
58 return edge(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
59 }
60 else
61 {
62 label faceBasePti = mesh().tetBasePtIs()[tetFace()];
63 if (faceBasePti == -1)
64 {
65 //FatalErrorInFunction
66 //WarningInFunction
67 // << "No base point for face " << tetFace() << ", " << f
68 // << ", produces a decomposition that has a minimum "
69 // << "volume greater than tolerance."
70 // //<< abort(FatalError);
71 // << endl;
72 faceBasePti = 0;
73 }
74
75 label diagPti = (faceBasePti + diagEdge_)%f.size();
76
77 return edge(f[faceBasePti], f[diagPti]);
78 }
79}
80
81
83(
84 const label& celli,
85 label& tetFacei,
86 label& tetPti,
87 const edge& e
88)
89{
90 const faceList& pFaces = mesh().faces();
91 const cellList& pCells = mesh().cells();
92
93 const Foam::face& f = pFaces[tetFacei];
94
95 const Foam::cell& thisCell = pCells[celli];
96
97 for (const label facei : thisCell)
98 {
99 // Loop over all other faces of this cell and
100 // find the one that shares this edge
101
102 if (tetFacei == facei)
103 {
104 continue;
105 }
106
107 const Foam::face& otherFace = pFaces[facei];
108
109 label edDir = otherFace.edgeDirection(e);
110
111 if (edDir == 0)
112 {
113 continue;
114 }
115 else if (f == pFaces[facei])
116 {
117 // This is a necessary condition if using duplicate baffles
118 // (so coincident faces). We need to make sure we don't cross into
119 // the face with the same vertices since we might enter a tracking
120 // loop where it never exits. This test should be cheap
121 // for most meshes so can be left in for 'normal' meshes.
122 continue;
123 }
124 else
125 {
126 //Found edge on other face
127 tetFacei = facei;
128
129 label eIndex = -1;
130
131 if (edDir == 1)
132 {
133 // Edge is in the forward circulation of this face, so
134 // work with the start point of the edge
135 eIndex = otherFace.find(e.start());
136 }
137 else
138 {
139 // edDir == -1, so the edge is in the reverse
140 // circulation of this face, so work with the end
141 // point of the edge
142 eIndex = otherFace.find(e.end());
143 }
144
145 label tetBasePtI = mesh().tetBasePtIs()[facei];
146
147 if (tetBasePtI == -1)
148 {
149 //FatalErrorInFunction
150 //WarningInFunction
151 // << "No base point for face " << fI << ", " << f
152 // << ", produces a decomposition that has a minimum "
153 // << "volume greater than tolerance."
154 // //<< abort(FatalError);
155 // << endl;
156 tetBasePtI = 0;
157 }
158
159 // Find eIndex relative to the base point on new face
160 eIndex -= tetBasePtI;
161
162 if (neg(eIndex))
163 {
164 eIndex = (eIndex + otherFace.size()) % otherFace.size();
165 }
166
167 if (eIndex == 0)
168 {
169 // The point is the base point, so this is first tet
170 // in the face circulation
171 tetPti = 1;
172 }
173 else if (eIndex == otherFace.size() - 1)
174 {
175 // The point is the last before the base point, so
176 // this is the last tet in the face circulation
177 tetPti = otherFace.size() - 2;
178 }
179 else
180 {
181 tetPti = eIndex;
182 }
183
184 break;
185 }
186 }
187}
188
189
191{
192 // Update tetFace, tetPt
193 crossEdgeConnectedFace(cell(), tetFace(), tetPt(), meshEdge);
194
195 // Update face to be same as tracking one
196 face() = tetFace();
197
198 // And adapt meshEdgeStart_.
199 const Foam::face& f = mesh().faces()[tetFace()];
200 label fp = f.find(meshEdge[0]);
201
202 if (f.nextLabel(fp) == meshEdge[1])
203 {
204 meshEdgeStart_ = fp;
205 }
206 else
207 {
208 label fpMin1 = f.rcIndex(fp);
209
210 if (f[fpMin1] == meshEdge[1])
211 {
212 meshEdgeStart_ = fpMin1;
213 }
214 else
215 {
217 << "Problem :"
218 << " particle:"
219 << info()
220 << "face:" << tetFace()
221 << " verts:" << f
222 << " meshEdge:" << meshEdge
223 << abort(FatalError);
224 }
225 }
226
227 diagEdge_ = -1;
228
229 // Check that still on same mesh edge
230 const edge eNew(f[meshEdgeStart_], f.nextLabel(meshEdgeStart_));
231 if (eNew != meshEdge)
232 {
234 << "Problem" << abort(FatalError);
235 }
236}
237
238
240{
241 if (diagEdge_ == -1)
242 {
244 << "Particle:"
245 << info()
246 << "not on a diagonal edge" << abort(FatalError);
247 }
248 if (meshEdgeStart_ != -1)
249 {
251 << "Particle:"
252 << info()
253 << "meshEdgeStart_:" << meshEdgeStart_ << abort(FatalError);
254 }
255
256 const Foam::face& f = mesh().faces()[tetFace()];
257
258 // tetPti starts from 1, goes up to f.size()-2
259
260 if (tetPt() == diagEdge_)
261 {
262 tetPt() = f.rcIndex(tetPt());
263 }
264 else
265 {
266 label nextTetPt = f.fcIndex(tetPt());
267 if (diagEdge_ == nextTetPt)
268 {
269 tetPt() = nextTetPt;
270 }
271 else
272 {
274 << "Particle:"
275 << info()
276 << "tetPt:" << tetPt()
277 << " diagEdge:" << diagEdge_ << abort(FatalError);
278 }
279 }
280
281 meshEdgeStart_ = -1;
282}
283
284
286(
287 const vector& n,
288 const vector& endPosition,
289 label& minEdgei
290)
291{
292 // Track p from position to endPosition
293 const triFace tri(currentTetIndices().faceTriIs(mesh(), false));
294
295 // Check which edge intersects the trajectory.
296 // Project trajectory onto triangle
297 minEdgei = -1;
298 scalar minS = 1; // end position
299
300 edge currentE(-1, -1);
301 if (meshEdgeStart_ != -1 || diagEdge_ != -1)
302 {
303 currentE = currentEdge();
304 }
305
306 // Determine path along line position+s*d to see where intersections are.
307 forAll(tri, i)
308 {
309 label j = tri.fcIndex(i);
310
311 const point& pt0 = mesh().points()[tri[i]];
312 const point& pt1 = mesh().points()[tri[j]];
313
314 if (edge(tri[i], tri[j]) == currentE)
315 {
316 // Do not check particle is on
317 continue;
318 }
319
320 // Outwards pointing normal
321 vector edgeNormal = (pt1 - pt0)^n;
322 edgeNormal.normalise();
323
324 // Determine whether position and end point on either side of edge.
325 scalar sEnd = (endPosition - pt0)&edgeNormal;
326 if (sEnd >= 0)
327 {
328 // endPos is outside triangle. localPosition_ should always be
329 // inside.
330 scalar sStart = (localPosition_ - pt0)&edgeNormal;
331 if (mag(sEnd - sStart) > VSMALL)
332 {
333 scalar s = sStart/(sStart - sEnd);
334
335 if (s >= 0 && s < minS)
336 {
337 minS = s;
338 minEdgei = i;
339 }
340 }
341 }
342 }
343
344 if (minEdgei != -1)
345 {
346 localPosition_ += minS*(endPosition - localPosition_);
347 }
348 else
349 {
350 // Did not hit any edge so tracked to the end position. Set position
351 // without any calculation to avoid truncation errors.
352 localPosition_ = endPosition;
353 minS = 1.0;
354 }
355
356 // Project localPosition_ back onto plane of triangle
357 const point& triPt = mesh().points()[tri[0]];
358 localPosition_ -= ((localPosition_ - triPt)&n)*n;
359
360 return minS;
361}
362
363
365(
366 const vector& n,
367 const point& endPosition
368) const
369{
370 const triFace triVerts(currentTetIndices().faceTriIs(mesh(), false));
371 const edge currentE = currentEdge();
372
373 if
374 (
375 currentE[0] == currentE[1]
376 || !triVerts.found(currentE[0])
377 || !triVerts.found(currentE[1])
378 )
379 {
381 << "Edge " << currentE << " not on triangle " << triVerts
382 << info()
383 << abort(FatalError);
384 }
385
386
387 const vector dir = endPosition - localPosition_;
388
389 forAll(triVerts, i)
390 {
391 label j = triVerts.fcIndex(i);
392 const point& pt0 = mesh().points()[triVerts[i]];
393 const point& pt1 = mesh().points()[triVerts[j]];
394
395 if (edge(triVerts[i], triVerts[j]) == currentE)
396 {
397 vector edgeNormal = (pt1-pt0)^n;
398 return (dir&edgeNormal) < 0;
399 }
400 }
401
403 << "Problem" << abort(FatalError);
404
405 return false;
406}
407
408
409// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
410
412(
413 const polyMesh& mesh,
414 const point& position,
415 const label celli,
416 const label tetFacei,
417 const label tetPti,
418 const label meshEdgeStart,
419 const label diagEdge
420)
421:
422 particle(mesh, position, celli, tetFacei, tetPti, false),
423 localPosition_(position),
424 meshEdgeStart_(meshEdgeStart),
425 diagEdge_(diagEdge)
426{}
427
428
430(
431 const polyMesh& mesh,
432 Istream& is,
433 bool readFields,
434 bool newFormat
435)
436:
437 particle(mesh, is, readFields, newFormat)
438{
439 if (readFields)
440 {
441 if (is.format() == IOstream::ASCII)
442 {
444 }
445 if (!is.checkLabelSize<>() || !is.checkScalarSize<>())
446 {
447 // Non-native label or scalar size
448
449 is.beginRawRead();
450
451 readRawScalar(is, localPosition_.data(), vector::nComponents);
454
455 is.endRawRead();
456 }
457 else
458 {
459 is.read(reinterpret_cast<char*>(&localPosition_), sizeofFields_);
460 }
461 }
462
464}
465
466
468(
470)
471:
472 particle(p),
473 localPosition_(p.localPosition_),
474 meshEdgeStart_(p.meshEdgeStart_),
475 diagEdge_(p.diagEdge_)
476{}
477
478
479// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
480
481Foam::Ostream& Foam::operator<<
482(
483 Ostream& os,
485)
486{
487 if (os.format() == IOstream::ASCII)
488 {
489 os << static_cast<const particle&>(p)
490 << token::SPACE << p.localPosition_
491 << token::SPACE << p.meshEdgeStart_
492 << token::SPACE << p.diagEdge_;
493 }
494 else
495 {
496 os << static_cast<const particle&>(p);
497 os.write
498 (
499 reinterpret_cast<const char*>(&p.localPosition_),
501 );
502 }
503
504 return os;
505}
506
507
508Foam::Ostream& Foam::operator<<
509(
510 Ostream& os,
512)
513{
514 const wallBoundedParticle& p = ip.t_;
515
516 tetPointRef tpr(p.currentTetIndices().tet(p.mesh()));
517
518 os << " " << static_cast<const particle&>(p) << nl
519 << " tet:" << nl;
520 os << " ";
521 meshTools::writeOBJ(os, tpr.a());
522 os << " ";
523 meshTools::writeOBJ(os, tpr.b());
524 os << " ";
525 meshTools::writeOBJ(os, tpr.c());
526 os << " ";
527 meshTools::writeOBJ(os, tpr.d());
528 os << " l 1 2" << nl
529 << " l 1 3" << nl
530 << " l 1 4" << nl
531 << " l 2 3" << nl
532 << " l 2 4" << nl
533 << " l 3 4" << nl;
534 os << " ";
535 meshTools::writeOBJ(os, p.localPosition_);
536
537 return os;
538}
539
540
541// ************************************************************************* //
label n
const Mesh & mesh() const
Return mesh.
bool found(const T &val, label pos=0) const
True if the value if found in the list.
Definition: FixedListI.H:332
label fcIndex(const label i) const
Definition: FixedListI.H:235
streamFormat format() const noexcept
Get the current stream format.
std::enable_if< std::is_integral< T >::value, bool >::type checkLabelSize() const noexcept
Definition: IOstream.H:300
virtual bool check(const char *operation) const
Check IOstream status for given operation.
Definition: IOstream.C:58
std::enable_if< std::is_floating_point< T >::value, bool >::type checkScalarSize() const noexcept
Definition: IOstream.H:309
A helper class for outputting values to Ostream.
Definition: InfoProxy.H:52
An Istream is an abstract base class for all input systems (streams, files, token lists etc)....
Definition: Istream.H:64
virtual bool endRawRead()=0
End of low-level raw binary read.
virtual bool beginRawRead()=0
Start of low-level raw binary read.
virtual Istream & read(token &)=0
Return next token from stream.
virtual Ostream & write(const char c)
Write character.
Definition: OBJstream.C:78
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition: UListI.H:350
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:212
label rcIndex(const label i) const noexcept
Definition: UListI.H:67
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
label fcIndex(const label i) const noexcept
Definition: UListI.H:60
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Definition: VectorI.H:123
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:57
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:66
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
static constexpr direction nComponents
Number of components in bool is 1.
Definition: bool.H:98
Base particle class.
Definition: particle.H:79
const polyMesh & mesh() const noexcept
Return the mesh database.
Definition: particleI.H:137
label tetFace() const noexcept
Return current tet face particle is in.
Definition: particleI.H:161
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1108
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition: polyMesh.C:906
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
const cellList & cells() const
A tetrahedron primitive.
Definition: tetrahedron.H:87
const Point & a() const
Return vertices.
Definition: tetrahedronI.H:76
const Point & c() const
Definition: tetrahedronI.H:90
const Point & b() const
Definition: tetrahedronI.H:83
const Point & d() const
Definition: tetrahedronI.H:97
@ SPACE
Space [isspace].
Definition: token.H:125
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:72
Particle class that tracks on triangles of boundary faces. Use trackToEdge similar to trackToFace on ...
label meshEdgeStart_
Particle is on mesh edge:
bool isTriAlongTrack(const vector &n, const point &endPosition) const
Is current triangle in the track direction.
edge currentEdge() const
Construct current edge.
InfoProxy< wallBoundedParticle > info() const
Return info proxy.
static const std::size_t sizeofFields_
Size in bytes of the fields.
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.
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.
volScalarField & p
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
#define FUNCTION_NAME
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
void readFields(const typename GeoFieldType::Mesh &mesh, const IOobjectList &objects, const wordHashSet &selectedFields, LIFOStack< regIOobject * > &storedObjects)
Read the selected GeometricFields of the templated type.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
label readRawLabel(Istream &is)
Read raw label from binary stream.
Definition: label.C:46
errorManip< error > abort(error &err)
Definition: errorManip.H:144
dimensionedScalar neg(const dimensionedScalar &ds)
error FatalError
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} label minLabel=min(start, end);pointMap[start]=pointMap[end]=minLabel;} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};const label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< SLList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:235
labelList f(nPoints)
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333