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-2013 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 //- Track particle to a given position and returns 1.0 if the
130 // trajectory is completed without hitting a face otherwise
131 // stops at the face and returns the fraction of the trajectory
132 // completed.
133 // on entry 'stepFraction()' should be set to the fraction of the
134 // time-step at which the tracking starts.
135 template<class TrackData>
137 (
138  TrackData& td,
139  const vector& endPosition
140 )
141 {
142  // Are we on a track face? If not we do a topological walk.
143 
144  // Particle:
145  // - cell_ always set
146  // - tetFace_, tetPt_ always set (these identify tet particle is in)
147  // - optionally meshEdgeStart_ or diagEdge_ set (edge particle is on)
148 
149  //checkInside();
150  //checkOnTriangle(position());
151  //if (meshEdgeStart_ != -1 || diagEdge_ != -1)
152  //{
153  // checkOnEdge();
154  //}
155 
156  scalar trackFraction = 0.0;
157 
158  if (!td.isWallPatch_[tetFace()])
159  {
160  // Don't track across face. Just walk in cell. Particle is on
161  // mesh edge (as indicated by meshEdgeStart_).
162  const edge meshEdge(currentEdge());
163 
164  // If internal face check whether to go to neighbour cell or just
165  // check to the other internal tet on the edge.
166  if (mesh_.isInternalFace(tetFace()))
167  {
168  label nbrCellI =
169  (
170  cellI_ == mesh_.faceOwner()[faceI_]
171  ? mesh_.faceNeighbour()[faceI_]
172  : mesh_.faceOwner()[faceI_]
173  );
174  // Check angle to nbrCell tet. Is it in the direction of the
175  // endposition? I.e. since volume of nbr tet is positive the
176  // tracking direction should be into the tet.
177  tetIndices nbrTi(nbrCellI, tetFaceI_, tetPtI_, mesh_);
178  if ((nbrTi.faceTri(mesh_).normal() & (endPosition-position())) < 0)
179  {
180  // Change into nbrCell. No need to change tetFace, tetPt.
181  //Pout<< " crossed from cell:" << cellI_
182  // << " into " << nbrCellI << endl;
183  cellI_ = nbrCellI;
184  patchInteraction(td, trackFraction);
185  }
186  else
187  {
188  // Walk to other face on edge. Changes tetFace, tetPt but not
189  // cell.
190  crossEdgeConnectedFace(meshEdge);
191  patchInteraction(td, trackFraction);
192  }
193  }
194  else
195  {
196  // Walk to other face on edge. This might give loop since
197  // particle should have been removed?
198  crossEdgeConnectedFace(meshEdge);
199  patchInteraction(td, trackFraction);
200  }
201  }
202  else
203  {
204  // We're inside a tet on the wall. Check if the current tet is
205  // the one to cross. If not we cross into the neighbouring triangle.
206 
207  if (mesh_.isInternalFace(tetFace()))
208  {
210  (
211  "wallBoundedParticle::trackToEdge"
212  "(TrackData&, const vector&)"
213  ) << "Can only track on boundary faces."
214  << " Face:" << tetFace()
215  << " at:" << mesh_.faceCentres()[tetFace()]
216  << abort(FatalError);
217  }
218 
219  point projectedEndPosition = endPosition;
220  // Remove normal component
221  {
222  const triFace tri(currentTetIndices().faceTriIs(mesh_));
223  vector n = tri.normal(mesh_.points());
224  n /= mag(n);
225  const point& basePt = mesh_.points()[tri[0]];
226  projectedEndPosition -= ((projectedEndPosition-basePt)&n)*n;
227  }
228 
229 
230  bool doTrack = false;
231  if (meshEdgeStart_ == -1 && diagEdge_ == -1)
232  {
233  // We're starting and not yet on an edge.
234  doTrack = true;
235  }
236  else
237  {
238  // See if the current triangle has got a point on the
239  // correct side of the edge.
240  doTrack = isTriAlongTrack(projectedEndPosition);
241  }
242 
243 
244  if (doTrack)
245  {
246  // Track across triangle. Return triangle edge crossed.
247  label triEdgeI = -1;
248  trackFraction = trackFaceTri(projectedEndPosition, triEdgeI);
249 
250  if (triEdgeI == -1)
251  {
252  // Reached endpoint
253  //checkInside();
254  diagEdge_ = -1;
255  meshEdgeStart_ = -1;
256  return trackFraction;
257  }
258 
259  const tetIndices ti(currentTetIndices());
260 
261  // Triangle (faceTriIs) gets constructed from
262  // f[faceBasePtI_],
263  // f[facePtAI_],
264  // f[facePtBI_]
265  //
266  // So edge indices are:
267  // 0 : edge between faceBasePtI_ and facePtAI_
268  // 1 : edge between facePtAI_ and facePtBI_ (is always a real edge)
269  // 2 : edge between facePtBI_ and faceBasePtI_
270 
271  const Foam::face& f = mesh_.faces()[ti.face()];
272  const label fp0 = ti.faceBasePt();
273 
274  if (triEdgeI == 0)
275  {
276  if (ti.facePtA() == f.fcIndex(fp0))
277  {
278  //Pout<< "Real edge." << endl;
279  diagEdge_ = -1;
280  meshEdgeStart_ = fp0;
281  //checkOnEdge();
282  crossEdgeConnectedFace(currentEdge());
283  patchInteraction(td, trackFraction);
284  }
285  else if (ti.facePtA() == f.rcIndex(fp0))
286  {
287  //Note: should not happen since boundary face so owner
288  //Pout<< "Real edge." << endl;
289  FatalErrorIn("shold not happend") << info()
290  << abort(FatalError);
291 
292  diagEdge_ = -1;
293  meshEdgeStart_ = f.rcIndex(fp0);
294  //checkOnEdge();
295  crossEdgeConnectedFace(currentEdge());
296  patchInteraction(td, trackFraction);
297  }
298  else
299  {
300  // Get index of triangle on other side of edge.
301  diagEdge_ = ti.facePtA()-fp0;
302  if (diagEdge_ < 0)
303  {
304  diagEdge_ += f.size();
305  }
306  meshEdgeStart_ = -1;
307  //checkOnEdge();
308  crossDiagonalEdge();
309  }
310  }
311  else if (triEdgeI == 1)
312  {
313  //Pout<< "Real edge." << endl;
314  diagEdge_ = -1;
315  meshEdgeStart_ = ti.facePtA();
316  //checkOnEdge();
317  crossEdgeConnectedFace(currentEdge());
318  patchInteraction(td, trackFraction);
319  }
320  else // if (triEdgeI == 2)
321  {
322  if (ti.facePtB() == f.rcIndex(fp0))
323  {
324  //Pout<< "Real edge." << endl;
325  diagEdge_ = -1;
326  meshEdgeStart_ = ti.facePtB();
327  //checkOnEdge();
328  crossEdgeConnectedFace(currentEdge());
329  patchInteraction(td, trackFraction);
330  }
331  else if (ti.facePtB() == f.fcIndex(fp0))
332  {
333  //Note: should not happen since boundary face so owner
334  //Pout<< "Real edge." << endl;
335  FatalErrorIn("shold not happend") << info()
336  << abort(FatalError);
337 
338  diagEdge_ = -1;
339  meshEdgeStart_ = fp0;
340  //checkOnEdge();
341  crossEdgeConnectedFace(currentEdge());
342  patchInteraction(td, trackFraction);
343  }
344  else
345  {
346  //Pout<< "Triangle edge." << endl;
347  // Get index of triangle on other side of edge.
348  diagEdge_ = ti.facePtB()-fp0;
349  if (diagEdge_ < 0)
350  {
351  diagEdge_ += f.size();
352  }
353  meshEdgeStart_ = -1;
354  //checkOnEdge();
355  crossDiagonalEdge();
356  }
357  }
358  }
359  else
360  {
361  // Current tet is not the right one. Check the neighbour tet.
362 
363  if (meshEdgeStart_ != -1)
364  {
365  // Particle is on mesh edge so change into other face on cell
366  crossEdgeConnectedFace(currentEdge());
367  //checkOnEdge();
368  patchInteraction(td, trackFraction);
369  }
370  else
371  {
372  // Particle is on diagonal edge so change into the other
373  // triangle.
374  crossDiagonalEdge();
375  //checkOnEdge();
376  }
377  }
378  }
379 
380  //checkInside();
381 
382  return trackFraction;
383 }
384 
385 
386 template<class TrackData>
388 (
389  const polyPatch&,
390  TrackData& td,
391  const label patchI,
392  const scalar trackFraction,
393  const tetIndices& tetIs
394 )
395 {
396  // Disable generic patch interaction
397  return false;
398 }
399 
400 
401 template<class TrackData>
403 (
404  const wedgePolyPatch& pp,
405  TrackData& td
406 )
407 {
408  // Remove particle
409  td.keepParticle = false;
410 }
411 
412 
413 template<class TrackData>
415 (
416  const symmetryPlanePolyPatch& pp,
417  TrackData& td
418 )
419 {
420  // Remove particle
421  td.keepParticle = false;
422 }
423 
424 
425 template<class TrackData>
427 (
428  const symmetryPolyPatch& pp,
429  TrackData& td
430 )
431 {
432  // Remove particle
433  td.keepParticle = false;
434 }
435 
436 
437 template<class TrackData>
439 (
440  const cyclicPolyPatch& pp,
441  TrackData& td
442 )
443 {
444  // Remove particle
445  td.keepParticle = false;
446 }
447 
448 
449 template<class TrackData>
451 (
452  const processorPolyPatch& pp,
453  TrackData& td
454 )
455 {
456  // Switch particle
457  td.switchProcessor = true;
458 
459  // Adapt edgeStart_ for other side.
460  // E.g. if edgeStart_ is 1 then the edge is between vertex 1 and 2 so
461  // on the other side between 2 and 3 so edgeStart_ should be
462  // f.size()-edgeStart_-1.
463 
464  const Foam::face& f = mesh_.faces()[face()];
465 
466  if (meshEdgeStart_ != -1)
467  {
468  meshEdgeStart_ = f.size()-meshEdgeStart_-1;
469  }
470  else
471  {
472  // diagEdge_ is relative to faceBasePt
473  diagEdge_ = f.size()-diagEdge_;
474  }
475 }
476 
477 
478 template<class TrackData>
480 (
481  const wallPolyPatch& wpp,
482  TrackData& td,
483  const tetIndices&
484 )
485 {}
486 
487 
488 template<class TrackData>
490 (
491  const polyPatch& wpp,
492  TrackData& td
493 )
494 {
495  // Remove particle
496  td.keepParticle = false;
497 }
498 
499 
500 template<class CloudType>
502 {
503  if (!c.size())
504  {
505  return;
506  }
507 
509 
511  (
512  c.fieldIOobject("meshEdgeStart", IOobject::MUST_READ)
513  );
514 
516  (
517  c.fieldIOobject("diagEdge_", IOobject::MUST_READ)
518  );
520 
521  label i = 0;
522  forAllIter(typename CloudType, c, iter)
523  {
524  iter().meshEdgeStart_ = meshEdgeStart[i];
525  iter().diagEdge_ = diagEdge[i];
526  i++;
527  }
528 }
529 
530 
531 template<class CloudType>
533 {
535 
536  label np = c.size();
537 
539  (
540  c.fieldIOobject("meshEdgeStart", IOobject::NO_READ),
541  np
542  );
544  (
545  c.fieldIOobject("diagEdge", IOobject::NO_READ),
546  np
547  );
548 
549  label i = 0;
550  forAllConstIter(typename CloudType, c, iter)
551  {
552  meshEdgeStart[i] = iter().meshEdgeStart_;
553  diagEdge[i] = iter().diagEdge_;
554  i++;
555  }
556 
557  meshEdgeStart.write();
558  diagEdge.write();
559 }
560 
561 
562 // ************************************************************************* //
label meshEdgeStart() const
-1 or label of mesh edge
void hitWedgePatch(const wedgePolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a wedge.
label diagEdge() const
-1 or diagonal edge
dimensioned< scalar > mag(const dimensioned< Type > &)
Wedge front and back plane patch.
labelList f(nPoints)
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
Symmetry patch for non-planar or multi-plane patches.
#define forAllIter(Container, container, iter)
Definition: UList.H:440
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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
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)
const polyBoundaryMesh & boundaryMesh() const
Return boundaryMesh reference.
Definition: polyPatch.C:278
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
void patchInteraction(TrackData &td, const scalar trackFraction)
Do all patch interaction.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
label n
static void writeFields(const CloudType &)
Write.
static void readFields(CloudType &c)
Read the fields associated with the owner cloud.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
Neighbour processor patch.
static void writeFields(const CloudType &c)
Write the fields associated with the owner cloud.
vector normal() const
Return vector normal.
Definition: triangleI.H:103
volScalarField & p
Definition: createFields.H:51
scalar trackToEdge(TrackData &td, const vector &endPosition)
Equivalent of trackToFace.
Cyclic plane patch.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
static void readFields(CloudType &)
Read.
void checkFieldIOobject(const Cloud< ParticleType > &c, const IOField< DataType > &data) const
Check lagrangian data field.
Definition: CloudIO.C:215
Foam::wallPolyPatch.
Definition: wallPolyPatch.H:48
label size() const
Definition: Cloud.H:175
error FatalError
void hitSymmetryPlanePatch(const symmetryPlanePolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
void hitCyclicPatch(const cyclicPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a cyclic.
triPointRef faceTri(const polyMesh &mesh) const
Return the geometry corresponding to the tri on the.
Definition: tetIndicesI.H:109
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:68
const dimensionedScalar c
Speed of light in a vacuum.
label facePtA() const
Return face point A.
Definition: tetIndicesI.H:48
label rcIndex(const label i) const
Return the reverse circular index, i.e. the previous index.
Definition: UListI.H:65
void hitSymmetryPatch(const symmetryPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:68
void hitWallPatch(const wallPolyPatch &, TrackData &td, const tetIndices &)
Overridable function to handle the particle hitting a wallPatch.
bool hitPatch(const polyPatch &, TrackData &td, const label patchI, const scalar trackFraction, const tetIndices &tetIs)
Overridable function to handle the particle hitting a patch.
Storage and named access for the indices of a tet which is part of the decomposition of a cell...
Definition: tetIndices.H:73
IOobject fieldIOobject(const word &fieldName, const IOobject::readOption r) const
Helper to construct IOobject for field and current time.
Definition: CloudIO.C:195
label facePtB() const
Return face point B.
Definition: tetIndicesI.H:54
A primitive field of type <T> with automated input and output.
Definition: IOField.H:50
label face() const
Return the face.
Definition: tetIndicesI.H:36