particleTemplates.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-2017 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 "IOPosition.H"
27 
28 #include "cyclicPolyPatch.H"
29 #include "cyclicAMIPolyPatch.H"
30 #include "processorPolyPatch.H"
31 #include "symmetryPlanePolyPatch.H"
32 #include "symmetryPolyPatch.H"
33 #include "wallPolyPatch.H"
34 #include "wedgePolyPatch.H"
35 #include "meshTools.H"
36 
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 
39 template<class TrackData>
41 (
42  const label patchi,
43  TrackData& td
44 )
45 {
46  // Convert the face index to be local to the processor patch
47  facei_ = mesh_.boundaryMesh()[patchi].whichFace(facei_);
48 }
49 
50 
51 template<class TrackData>
53 (
54  const label patchi,
55  TrackData& td
56 )
57 {
58  const coupledPolyPatch& ppp =
59  refCast<const coupledPolyPatch>(mesh_.boundaryMesh()[patchi]);
60 
61  if (!ppp.parallel())
62  {
63  const tensor& T =
64  (
65  ppp.forwardT().size() == 1
66  ? ppp.forwardT()[0]
67  : ppp.forwardT()[facei_]
68  );
69  transformProperties(T);
70  }
71  else if (ppp.separated())
72  {
73  const vector& s =
74  (
75  (ppp.separation().size() == 1)
76  ? ppp.separation()[0]
77  : ppp.separation()[facei_]
78  );
79  transformProperties(-s);
80  }
81 
82  // Set the topology
83  celli_ = ppp.faceCells()[facei_];
84  facei_ += ppp.start();
85  tetFacei_ = facei_;
86  // Faces either side of a coupled patch are numbered in opposite directions
87  // as their normals both point away from their connected cells. The tet
88  // point therefore counts in the opposite direction from the base point.
89  tetPti_ = mesh_.faces()[tetFacei_].size() - 1 - tetPti_;
90 
91  // Reflect to account for the change of triangle orientation in the new cell
92  reflect();
93 
94  // Note that the position does not need transforming explicitly. The face-
95  // triangle on the receive patch is the transformation of the one on the
96  // send patch, so whilst the barycentric coordinates remain the same, the
97  // change of triangle implicitly transforms the position.
98 }
99 
100 
101 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
102 
103 template<class CloudType>
105 {
106  bool valid = c.size();
107 
108  IOobject procIO(c.fieldIOobject("origProcId", IOobject::MUST_READ));
109 
110  bool haveFile = procIO.typeHeaderOk<IOField<label>>(true);
111 
112  IOField<label> origProcId(procIO, valid && haveFile);
113  c.checkFieldIOobject(c, origProcId);
115  (
116  c.fieldIOobject("origId", IOobject::MUST_READ),
117  valid && haveFile
118  );
120 
121  label i = 0;
122  forAllIter(typename CloudType, c, iter)
123  {
124  particle& p = iter();
125 
126  p.origProc_ = origProcId[i];
127  p.origId_ = origId[i];
128  i++;
129  }
130 }
131 
132 
133 template<class CloudType>
135 {
136  label np = c.size();
137 
138  IOPosition<CloudType> ioP(c);
139  ioP.write(np > 0);
140 
142  (
143  c.fieldIOobject("origProcId", IOobject::NO_READ),
144  np
145  );
147  (
148  c.fieldIOobject("origId", IOobject::NO_READ),
149  np
150  );
151 
152  label i = 0;
153  forAllConstIter(typename CloudType, c, iter)
154  {
155  origProc[i] = iter().origProc_;
156  origId[i] = iter().origId_;
157  i++;
158  }
159 
160  origProc.write(np > 0);
161  origId.write(np > 0);
162 }
163 
164 
165 template<class TrackData>
167 (
168  const vector& displacement,
169  const scalar fraction,
170  TrackData& td
171 )
172 {
173  // Track
174  trackToFace(displacement, fraction);
175 
176  // If the track is complete, return
177  if (!onFace())
178  {
179  return;
180  }
181 
182  // Hit face/patch processing
183  typedef typename TrackData::cloudType::particleType particleType;
184  particleType& p = static_cast<particleType&>(*this);
185  p.hitFace(td);
186  if (onInternalFace())
187  {
188  changeCell();
189  }
190  else
191  {
192  label origFacei = facei_;
193  label patchi = mesh_.boundaryMesh().whichPatch(facei_);
194 
195  // No action is taken for tetPti_ for tetFacei_ here. These are handled
196  // by the patch interaction call or later during processor transfer.
197 
198  const tetIndices faceHitTetIs(celli_, tetFacei_, tetPti_);
199 
200  if
201  (
202  !p.hitPatch
203  (
204  mesh_.boundaryMesh()[patchi],
205  td,
206  patchi,
207  stepFraction(),
208  faceHitTetIs
209  )
210  )
211  {
212  // Did patch interaction model switch patches?
213  if (facei_ != origFacei)
214  {
215  patchi = mesh_.boundaryMesh().whichPatch(facei_);
216  }
217 
218  const polyPatch& patch = mesh_.boundaryMesh()[patchi];
219 
220  if (isA<wedgePolyPatch>(patch))
221  {
222  p.hitWedgePatch
223  (
224  static_cast<const wedgePolyPatch&>(patch), td
225  );
226  }
227  else if (isA<symmetryPlanePolyPatch>(patch))
228  {
229  p.hitSymmetryPlanePatch
230  (
231  static_cast<const symmetryPlanePolyPatch&>(patch), td
232  );
233  }
234  else if (isA<symmetryPolyPatch>(patch))
235  {
236  p.hitSymmetryPatch
237  (
238  static_cast<const symmetryPolyPatch&>(patch), td
239  );
240  }
241  else if (isA<cyclicPolyPatch>(patch))
242  {
243  p.hitCyclicPatch
244  (
245  static_cast<const cyclicPolyPatch&>(patch), td
246  );
247  }
248  else if (isA<cyclicAMIPolyPatch>(patch))
249  {
250  p.hitCyclicAMIPatch
251  (
252  static_cast<const cyclicAMIPolyPatch&>(patch),
253  td,
254  displacement
255  );
256  }
257  else if (isA<processorPolyPatch>(patch))
258  {
259  p.hitProcessorPatch
260  (
261  static_cast<const processorPolyPatch&>(patch), td
262  );
263  }
264  else if (isA<wallPolyPatch>(patch))
265  {
266  p.hitWallPatch
267  (
268  static_cast<const wallPolyPatch&>(patch), td, faceHitTetIs
269  );
270  }
271  else
272  {
273  p.hitPatch(patch, td);
274  }
275  }
276  }
277 }
278 
279 
280 template<class TrackData>
281 void Foam::particle::hitFace(TrackData&)
282 {}
283 
284 
285 template<class TrackData>
287 (
288  const polyPatch&,
289  TrackData&,
290  const label,
291  const scalar,
292  const tetIndices&
293 )
294 {
295  return false;
296 }
297 
298 
299 template<class TrackData>
301 (
302  const wedgePolyPatch& wpp,
303  TrackData&
304 )
305 {
307  << "Hitting a wedge patch should not be possible."
308  << abort(FatalError);
309 
310  vector nf = normal();
311  nf /= mag(nf);
312 
313  transformProperties(I - 2.0*nf*nf);
314 }
315 
316 
317 template<class TrackData>
319 (
320  const symmetryPlanePolyPatch& spp,
321  TrackData&
322 )
323 {
324  vector nf = normal();
325  nf /= mag(nf);
326 
327  transformProperties(I - 2.0*nf*nf);
328 }
329 
330 
331 template<class TrackData>
333 (
334  const symmetryPolyPatch& spp,
335  TrackData&
336 )
337 {
338  vector nf = normal();
339  nf /= mag(nf);
340 
341  transformProperties(I - 2.0*nf*nf);
342 }
343 
344 
345 template<class TrackData>
347 (
348  const cyclicPolyPatch& cpp,
349  TrackData& td
350 )
351 {
352  const cyclicPolyPatch& receiveCpp = cpp.neighbPatch();
353  const label receiveFacei = receiveCpp.whichFace(facei_);
354 
355  // Set the topology
356  facei_ = tetFacei_ = cpp.transformGlobalFace(facei_);
357  celli_ = mesh_.faceOwner()[facei_];
358  // See note in correctAfterParallelTransfer for tetPti addressing ...
359  tetPti_ = mesh_.faces()[tetFacei_].size() - 1 - tetPti_;
360 
361  // Reflect to account for the change of triangle orientation in the new cell
362  reflect();
363 
364  // Transform the properties
365  if (!receiveCpp.parallel())
366  {
367  const tensor& T =
368  (
369  receiveCpp.forwardT().size() == 1
370  ? receiveCpp.forwardT()[0]
371  : receiveCpp.forwardT()[receiveFacei]
372  );
374  }
375  else if (receiveCpp.separated())
376  {
377  const vector& s =
378  (
379  (receiveCpp.separation().size() == 1)
380  ? receiveCpp.separation()[0]
381  : receiveCpp.separation()[receiveFacei]
382  );
384  }
385 }
386 
387 
388 template<class TrackData>
390 (
391  const cyclicAMIPolyPatch& cpp,
392  TrackData& td,
393  const vector& direction
394 )
395 {
396  vector pos = position();
397 
398  const cyclicAMIPolyPatch& receiveCpp = cpp.neighbPatch();
399  const label sendFacei = cpp.whichFace(facei_);
400  const label receiveFacei = cpp.pointFace(sendFacei, direction, pos);
401 
402  if (receiveFacei < 0)
403  {
404  // If the patch face of the particle is not known assume that the
405  // particle is lost and mark it to be deleted.
406  td.keepParticle = false;
408  << "Particle lost across " << cyclicAMIPolyPatch::typeName
409  << " patches " << cpp.name() << " and " << receiveCpp.name()
410  << " at position " << pos << endl;
411  }
412 
413  // Set the topology
414  facei_ = tetFacei_ = receiveFacei + receiveCpp.start();
415 
416  // Locate the particle on the recieving side
417  vector directionT = direction;
418  cpp.reverseTransformDirection(directionT, sendFacei);
419  locate
420  (
421  pos,
422  &directionT,
423  mesh_.faceOwner()[facei_],
424  false,
425  "Particle crossed between " + cyclicAMIPolyPatch::typeName +
426  " patches " + cpp.name() + " and " + receiveCpp.name() +
427  " to a location outside of the mesh."
428  );
429 
430  // The particle must remain associated with a face for the tracking to
431  // register as incomplete
432  facei_ = tetFacei_;
433 
434  // Transform the properties
435  if (!receiveCpp.parallel())
436  {
437  const tensor& T =
438  (
439  receiveCpp.forwardT().size() == 1
440  ? receiveCpp.forwardT()[0]
441  : receiveCpp.forwardT()[receiveFacei]
442  );
444  }
445  else if (receiveCpp.separated())
446  {
447  const vector& s =
448  (
449  (receiveCpp.separation().size() == 1)
450  ? receiveCpp.separation()[0]
451  : receiveCpp.separation()[receiveFacei]
452  );
454  }
455 }
456 
457 
458 template<class TrackData>
460 {}
461 
462 
463 template<class TrackData>
465 (
466  const wallPolyPatch&,
467  TrackData&,
468  const tetIndices&
469 )
470 {}
471 
472 
473 template<class TrackData>
474 void Foam::particle::hitPatch(const polyPatch&, TrackData&)
475 {}
476 
477 
478 // ************************************************************************* //
Symmetry patch for non-planar or multi-plane patches.
void hitSymmetryPlanePatch(const symmetryPlanePolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:424
label origProc() const
Return the originating processor ID.
Definition: particleI.H:93
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
const word & name() const
Return name.
bool typeHeaderOk(const bool checkType=true)
Read header (uses typeFilePath to find file) and check header.
void prepareForParallelTransfer(const label patchi, TrackData &td)
Convert global addressing to the processor patch.
virtual bool separated() const
Are the planes separated.
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
void hitWallPatch(const wallPolyPatch &, TrackData &td, const tetIndices &tetIs)
Overridable function to handle the particle hitting a wallPatch.
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:453
uint8_t direction
Definition: direction.H:45
scalar trackToFace(const vector &displacement, const scalar fraction)
As particle::track, but also stops on internal faces.
Definition: particle.C:622
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
label size() const
Definition: Cloud.H:162
virtual void reverseTransformDirection(vector &d, const label facei) const
Transform a patch-based direction from this side to nbr side.
static void readFields(CloudType &c)
Read the fields associated with the owner cloud.
virtual void transformProperties(const tensor &T)
Transform the physical properties of the particle.
Definition: particle.C:978
bool hitPatch(const polyPatch &, TrackData &td, const label patchi, const scalar trackFraction, const tetIndices &tetIs)
Overridable function to handle the particle hitting a.
void hitCyclicAMIPatch(const cyclicAMIPolyPatch &, TrackData &td, const vector &direction)
Overridable function to handle the particle hitting a cyclicAMIPatch.
virtual const vectorField & separation() const
If the planes are separated the separation vector.
virtual const tensorField & forwardT() const
Return face transformation tensor.
Base particle class.
Definition: particle.H:81
Neighbour processor patch.
vector normal() const
Return the normal of the tri on tetFacei_ for the.
Definition: particleI.H:168
virtual bool parallel() const
Are the cyclic planes parallel.
dimensionedScalar pos(const dimensionedScalar &ds)
void hitProcessorPatch(const processorPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().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))
static void writeFields(const CloudType &c)
Write the fields associated with the owner cloud.
const labelUList & faceCells() const
Return face-cell addressing.
Definition: polyPatch.C:315
static const Identity< scalar > I
Definition: Identity.H:93
Cyclic plane patch.
Foam::wallPolyPatch.
Definition: wallPolyPatch.H:48
Wedge front and back plane patch.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1049
Storage and named access for the indices of a tet which is part of the decomposition of a cell...
Definition: tetIndices.H:81
Cyclic patch for Arbitrary Mesh Interface (AMI)
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1036
void hitWedgePatch(const wedgePolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a wedgePatch.
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
void hitFace(TrackData &td)
Overridable function to handle the particle hitting a face.
label origId() const
Return the particle ID on the originating processor.
Definition: particleI.H:105
virtual bool write(const bool valid=true) const
Write using setting from DB.
Definition: IOPosition.C:51
bool onFace() const
Is the particle on a face?
Definition: particleI.H:180
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
const volScalarField & T
scalar stepFraction() const
Return the fraction of time-step completed.
Definition: particleI.H:81
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
virtual const cyclicAMIPolyPatch & neighbPatch() const
Return a reference to the neighbour patch.
const dimensionedScalar c
Speed of light in a vacuum.
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:300
void checkFieldIOobject(const Cloud< ParticleType > &c, const IOField< DataType > &data) const
Check lagrangian data field.
Definition: CloudIO.C:186
dimensioned< scalar > mag(const dimensioned< Type > &)
bool onInternalFace() const
Is the particle on an internal face?
Definition: particleI.H:186
void correctAfterParallelTransfer(const label patchi, TrackData &td)
Convert processor patch addressing to the global equivalents.
label transformGlobalFace(const label facei) const
volScalarField & p
Helper IO class to read and write particle positions.
Definition: Cloud.H:55
const cyclicPolyPatch & neighbPatch() const
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:92
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:69
IOobject fieldIOobject(const word &fieldName, const IOobject::readOption r) const
Helper to construct IOobject for field and current time.
Definition: CloudIO.C:166
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
A primitive field of type <T> with automated input and output.
Definition: IOField.H:50
vector position() const
Return current particle position.
Definition: particleI.H:204
void hitCyclicPatch(const cyclicPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a cyclicPatch.
label pointFace(const label facei, const vector &n, point &p) const
Return face index on neighbour patch which shares point p.
label patch() const
Return the index of patch that the particle is on.
Definition: particleI.H:198
void hitSymmetryPatch(const symmetryPolyPatch &, TrackData &td)
Overridable function to handle the particle hitting a.
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:377