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 | Copyright (C) 2011-2016 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "wallBoundedParticle.H"
27 
28 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
29 
30 template<class TrackData>
32 (
33  TrackData& td,
34  const scalar trackFraction
35 )
36 {
37 // typedef TrackData::CloudType cloudType;
38  typedef typename TrackData::cloudType::particleType particleType;
39 
40  particleType& p = static_cast<particleType&>(*this);
41  p.hitFace(td);
42 
43  if (!internalFace(facei_))
44  {
45  label origFacei = facei_;
46  label patchi = patch(facei_);
47 
48  // No action taken for tetPtI_ for tetFacei_ here, handled by
49  // patch interaction call or later during processor transfer.
50 
51 
52  // Dummy tet indices. What to do here?
53  tetIndices faceHitTetIs;
54 
55  if
56  (
57  !p.hitPatch
58  (
59  mesh_.boundaryMesh()[patchi],
60  td,
61  patchi,
62  trackFraction,
63  faceHitTetIs
64  )
65  )
66  {
67  // Did patch interaction model switch patches?
68  // Note: recalculate meshEdgeStart_, diagEdge_!
69  if (facei_ != origFacei)
70  {
71  patchi = patch(facei_);
72  }
73 
74  const polyPatch& patch = mesh_.boundaryMesh()[patchi];
75 
76  if (isA<wedgePolyPatch>(patch))
77  {
78  p.hitWedgePatch
79  (
80  static_cast<const wedgePolyPatch&>(patch), td
81  );
82  }
83  else if (isA<symmetryPlanePolyPatch>(patch))
84  {
85  p.hitSymmetryPlanePatch
86  (
87  static_cast<const symmetryPlanePolyPatch&>(patch), td
88  );
89  }
90  else if (isA<symmetryPolyPatch>(patch))
91  {
92  p.hitSymmetryPatch
93  (
94  static_cast<const symmetryPolyPatch&>(patch), td
95  );
96  }
97  else if (isA<cyclicPolyPatch>(patch))
98  {
99  p.hitCyclicPatch
100  (
101  static_cast<const cyclicPolyPatch&>(patch), td
102  );
103  }
104  else if (isA<processorPolyPatch>(patch))
105  {
106  p.hitProcessorPatch
107  (
108  static_cast<const processorPolyPatch&>(patch), td
109  );
110  }
111  else if (isA<wallPolyPatch>(patch))
112  {
113  p.hitWallPatch
114  (
115  static_cast<const wallPolyPatch&>(patch), td, faceHitTetIs
116  );
117  }
118  else
119  {
120  p.hitPatch(patch, td);
121  }
122  }
123  }
124 }
125 
126 
127 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
128 
129 template<class TrackData>
131 (
132  TrackData& td,
133  const vector& endPosition
134 )
135 {
136  // Track particle to a given position and returns 1.0 if the
137  // trajectory is completed without hitting a face otherwise
138  // stops at the face and returns the fraction of the trajectory
139  // completed.
140  // on entry 'stepFraction()' should be set to the fraction of the
141  // time-step at which the tracking starts.
142 
143  // Are we on a track face? If not we do a topological walk.
144 
145  // Particle:
146  // - cell_ always set
147  // - tetFace_, tetPt_ always set (these identify tet particle is in)
148  // - optionally meshEdgeStart_ or diagEdge_ set (edge particle is on)
149 
150  //checkInside();
151  //checkOnTriangle(position());
152  //if (meshEdgeStart_ != -1 || diagEdge_ != -1)
153  //{
154  // checkOnEdge();
155  //}
156 
157  scalar trackFraction = 0.0;
158 
159  if (!td.isWallPatch_[tetFace()])
160  {
161  // Don't track across face. Just walk in cell. Particle is on
162  // mesh edge (as indicated by meshEdgeStart_).
163  const edge meshEdge(currentEdge());
164 
165  // If internal face check whether to go to neighbour cell or just
166  // check to the other internal tet on the edge.
167  if (mesh_.isInternalFace(tetFace()))
168  {
169  label nbrCelli =
170  (
171  celli_ == mesh_.faceOwner()[facei_]
172  ? mesh_.faceNeighbour()[facei_]
173  : mesh_.faceOwner()[facei_]
174  );
175  // Check angle to nbrCell tet. Is it in the direction of the
176  // endposition? I.e. since volume of nbr tet is positive the
177  // tracking direction should be into the tet.
178  tetIndices nbrTi(nbrCelli, tetFacei_, tetPtI_, mesh_);
179  if ((nbrTi.faceTri(mesh_).normal() & (endPosition-position())) < 0)
180  {
181  // Change into nbrCell. No need to change tetFace, tetPt.
182  //Pout<< " crossed from cell:" << celli_
183  // << " into " << nbrCelli << endl;
184  celli_ = nbrCelli;
185  patchInteraction(td, trackFraction);
186  }
187  else
188  {
189  // Walk to other face on edge. Changes tetFace, tetPt but not
190  // cell.
191  crossEdgeConnectedFace(meshEdge);
192  patchInteraction(td, trackFraction);
193  }
194  }
195  else
196  {
197  // Walk to other face on edge. This might give loop since
198  // particle should have been removed?
199  crossEdgeConnectedFace(meshEdge);
200  patchInteraction(td, trackFraction);
201  }
202  }
203  else
204  {
205  // We're inside a tet on the wall. Check if the current tet is
206  // the one to cross. If not we cross into the neighbouring triangle.
207 
208  if (mesh_.isInternalFace(tetFace()))
209  {
211  << "Can only track on boundary faces."
212  << " Face:" << tetFace()
213  << " at:" << mesh_.faceCentres()[tetFace()]
214  << abort(FatalError);
215  }
216 
217  point projectedEndPosition = endPosition;
218  // Remove normal component
219  {
220  const triFace tri(currentTetIndices().faceTriIs(mesh_));
221  vector n = tri.normal(mesh_.points());
222  n /= mag(n);
223  const point& basePt = mesh_.points()[tri[0]];
224  projectedEndPosition -= ((projectedEndPosition-basePt)&n)*n;
225  }
226 
227 
228  bool doTrack = false;
229  if (meshEdgeStart_ == -1 && diagEdge_ == -1)
230  {
231  // We're starting and not yet on an edge.
232  doTrack = true;
233  }
234  else
235  {
236  // See if the current triangle has got a point on the
237  // correct side of the edge.
238  doTrack = isTriAlongTrack(projectedEndPosition);
239  }
240 
241 
242  if (doTrack)
243  {
244  // Track across triangle. Return triangle edge crossed.
245  label triEdgeI = -1;
246  trackFraction = trackFaceTri(projectedEndPosition, triEdgeI);
247 
248  if (triEdgeI == -1)
249  {
250  // Reached endpoint
251  //checkInside();
252  diagEdge_ = -1;
253  meshEdgeStart_ = -1;
254  return trackFraction;
255  }
256 
257  const tetIndices ti(currentTetIndices());
258 
259  // Triangle (faceTriIs) gets constructed from
260  // f[faceBasePtI_],
261  // f[facePtAI_],
262  // f[facePtBI_]
263  //
264  // So edge indices are:
265  // 0 : edge between faceBasePtI_ and facePtAI_
266  // 1 : edge between facePtAI_ and facePtBI_ (is always a real edge)
267  // 2 : edge between facePtBI_ and faceBasePtI_
268 
269  const Foam::face& f = mesh_.faces()[ti.face()];
270  const label fp0 = ti.faceBasePt();
271 
272  if (triEdgeI == 0)
273  {
274  if (ti.facePtA() == f.fcIndex(fp0))
275  {
276  //Pout<< "Real edge." << endl;
277  diagEdge_ = -1;
278  meshEdgeStart_ = fp0;
279  //checkOnEdge();
280  crossEdgeConnectedFace(currentEdge());
281  patchInteraction(td, trackFraction);
282  }
283  else if (ti.facePtA() == f.rcIndex(fp0))
284  {
285  //Note: should not happen since boundary face so owner
286  //Pout<< "Real edge." << endl;
288  << abort(FatalError);
289 
290  diagEdge_ = -1;
291  meshEdgeStart_ = f.rcIndex(fp0);
292  //checkOnEdge();
293  crossEdgeConnectedFace(currentEdge());
294  patchInteraction(td, trackFraction);
295  }
296  else
297  {
298  // Get index of triangle on other side of edge.
299  diagEdge_ = ti.facePtA()-fp0;
300  if (diagEdge_ < 0)
301  {
302  diagEdge_ += f.size();
303  }
304  meshEdgeStart_ = -1;
305  //checkOnEdge();
306  crossDiagonalEdge();
307  }
308  }
309  else if (triEdgeI == 1)
310  {
311  //Pout<< "Real edge." << endl;
312  diagEdge_ = -1;
313  meshEdgeStart_ = ti.facePtA();
314  //checkOnEdge();
315  crossEdgeConnectedFace(currentEdge());
316  patchInteraction(td, trackFraction);
317  }
318  else // if (triEdgeI == 2)
319  {
320  if (ti.facePtB() == f.rcIndex(fp0))
321  {
322  //Pout<< "Real edge." << endl;
323  diagEdge_ = -1;
324  meshEdgeStart_ = ti.facePtB();
325  //checkOnEdge();
326  crossEdgeConnectedFace(currentEdge());
327  patchInteraction(td, trackFraction);
328  }
329  else if (ti.facePtB() == f.fcIndex(fp0))
330  {
331  //Note: should not happen since boundary face so owner
332  //Pout<< "Real edge." << endl;
334  << abort(FatalError);
335 
336  diagEdge_ = -1;
337  meshEdgeStart_ = fp0;
338  //checkOnEdge();
339  crossEdgeConnectedFace(currentEdge());
340  patchInteraction(td, trackFraction);
341  }
342  else
343  {
344  //Pout<< "Triangle edge." << endl;
345  // Get index of triangle on other side of edge.
346  diagEdge_ = ti.facePtB()-fp0;
347  if (diagEdge_ < 0)
348  {
349  diagEdge_ += f.size();
350  }
351  meshEdgeStart_ = -1;
352  //checkOnEdge();
353  crossDiagonalEdge();
354  }
355  }
356  }
357  else
358  {
359  // Current tet is not the right one. Check the neighbour tet.
360 
361  if (meshEdgeStart_ != -1)
362  {
363  // Particle is on mesh edge so change into other face on cell
364  crossEdgeConnectedFace(currentEdge());
365  //checkOnEdge();
366  patchInteraction(td, trackFraction);
367  }
368  else
369  {
370  // Particle is on diagonal edge so change into the other
371  // triangle.
372  crossDiagonalEdge();
373  //checkOnEdge();
374  }
375  }
376  }
377 
378  //checkInside();
379 
380  return trackFraction;
381 }
382 
383 
384 template<class TrackData>
386 (
387  const polyPatch&,
388  TrackData& td,
389  const label patchi,
390  const scalar trackFraction,
391  const tetIndices& tetIs
392 )
393 {
394  // Disable generic patch interaction
395  return false;
396 }
397 
398 
399 template<class TrackData>
401 (
402  const wedgePolyPatch& pp,
403  TrackData& td
404 )
405 {
406  // Remove particle
407  td.keepParticle = false;
408 }
409 
410 
411 template<class TrackData>
413 (
414  const symmetryPlanePolyPatch& pp,
415  TrackData& td
416 )
417 {
418  // Remove particle
419  td.keepParticle = false;
420 }
421 
422 
423 template<class TrackData>
425 (
426  const symmetryPolyPatch& pp,
427  TrackData& td
428 )
429 {
430  // Remove particle
431  td.keepParticle = false;
432 }
433 
434 
435 template<class TrackData>
437 (
438  const cyclicPolyPatch& pp,
439  TrackData& td
440 )
441 {
442  // Remove particle
443  td.keepParticle = false;
444 }
445 
446 
447 template<class TrackData>
449 (
450  const processorPolyPatch& pp,
451  TrackData& td
452 )
453 {
454  // Switch particle
455  td.switchProcessor = true;
456 
457  // Adapt edgeStart_ for other side.
458  // E.g. if edgeStart_ is 1 then the edge is between vertex 1 and 2 so
459  // on the other side between 2 and 3 so edgeStart_ should be
460  // f.size()-edgeStart_-1.
461 
462  const Foam::face& f = mesh_.faces()[face()];
463 
464  if (meshEdgeStart_ != -1)
465  {
466  meshEdgeStart_ = f.size()-meshEdgeStart_-1;
467  }
468  else
469  {
470  // diagEdge_ is relative to faceBasePt
471  diagEdge_ = f.size()-diagEdge_;
472  }
473 }
474 
475 
476 template<class TrackData>
478 (
479  const wallPolyPatch& wpp,
480  TrackData& td,
481  const tetIndices&
482 )
483 {}
484 
485 
486 template<class TrackData>
488 (
489  const polyPatch& wpp,
490  TrackData& td
491 )
492 {
493  // Remove particle
494  td.keepParticle = false;
495 }
496 
497 
498 template<class CloudType>
500 {
501  if (!c.size())
502  {
503  return;
504  }
505 
507 
509  (
510  c.fieldIOobject("meshEdgeStart", IOobject::MUST_READ)
511  );
512 
514  (
515  c.fieldIOobject("diagEdge_", IOobject::MUST_READ)
516  );
518 
519  label i = 0;
520  forAllIter(typename CloudType, c, iter)
521  {
522  iter().meshEdgeStart_ = meshEdgeStart[i];
523  iter().diagEdge_ = diagEdge[i];
524  i++;
525  }
526 }
527 
528 
529 template<class CloudType>
531 {
533 
534  label np = c.size();
535 
537  (
538  c.fieldIOobject("meshEdgeStart", IOobject::NO_READ),
539  np
540  );
542  (
543  c.fieldIOobject("diagEdge", IOobject::NO_READ),
544  np
545  );
546 
547  label i = 0;
548  forAllConstIter(typename CloudType, c, iter)
549  {
550  meshEdgeStart[i] = iter().meshEdgeStart_;
551  diagEdge[i] = iter().diagEdge_;
552  i++;
553  }
554 
555  meshEdgeStart.write();
556  diagEdge.write();
557 }
558 
559 
560 // ************************************************************************* //
Symmetry patch for non-planar or multi-plane patches.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
label facePtA() const
Return face point A.
Definition: tetIndicesI.H:48
void checkFieldIOobject(const Cloud< ParticleType > &c, const IOField< DataType > &data) const
Check lagrangian data field.
Definition: CloudIO.C:215
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
void hitSymmetryPatch(const symmetryPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
triPointRef faceTri(const polyMesh &mesh) const
Return the geometry corresponding to the tri on the.
Definition: tetIndicesI.H:109
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:453
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
bool hitPatch(const polyPatch &, TrackData &td, const label patchi, const scalar trackFraction, const tetIndices &tetIs)
Overridable function to handle the particle hitting a patch.
void hitWedgePatch(const wedgePolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a wedge.
static void readFields(CloudType &c)
Read the fields associated with the owner cloud.
Neighbour processor patch.
label faceBasePt() const
Return the face base point.
Definition: tetIndicesI.H:42
vector normal(const pointField &) const
Vector normal; magnitude is equal to area of face.
Definition: triFaceI.H:181
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
void hitProcessorPatch(const processorPolyPatch &, TrackData &td)
label facePtB() const
Return face point B.
Definition: tetIndicesI.H:54
static void writeFields(const CloudType &c)
Write the fields associated with the owner cloud.
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:68
Cyclic plane patch.
Foam::wallPolyPatch.
Definition: wallPolyPatch.H:48
Wedge front and back plane patch.
Storage and named access for the indices of a tet which is part of the decomposition of a cell...
Definition: tetIndices.H:81
label face() const
Return the face.
Definition: tetIndicesI.H:36
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
static void readFields(CloudType &)
Read.
labelList f(nPoints)
label size() const
Definition: Cloud.H:175
void hitWallPatch(const wallPolyPatch &, TrackData &td, const tetIndices &)
Overridable function to handle the particle hitting a wallPatch.
label rcIndex(const label i) const
Return the reverse circular index, i.e. the previous index.
Definition: UListI.H:65
label meshEdgeStart() const
-1 or label of mesh edge
static void writeFields(const CloudType &)
Write.
void hitCyclicPatch(const cyclicPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a cyclic.
label patchi
void patchInteraction(TrackData &td, const scalar trackFraction)
Do all patch interaction.
scalar trackToEdge(TrackData &td, const vector &endPosition)
Equivalent of trackToFace.
const dimensionedScalar c
Speed of light in a vacuum.
dimensioned< scalar > mag(const dimensioned< Type > &)
label n
IOobject fieldIOobject(const word &fieldName, const IOobject::readOption r) const
Helper to construct IOobject for field and current time.
Definition: CloudIO.C:195
label diagEdge() const
-1 or diagonal edge
volScalarField & p
void hitSymmetryPlanePatch(const symmetryPlanePolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:68
const polyBoundaryMesh & boundaryMesh() const
Return boundaryMesh reference.
Definition: polyPatch.C:278
A primitive field of type <T> with automated input and output.
Definition: IOField.H:50
vector normal() const
Return vector normal.
Definition: triangleI.H:103