particleTemplates.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2020 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 "particle.H"
27 #include "IOPosition.H"
28 
29 #include "cyclicPolyPatch.H"
30 #include "cyclicAMIPolyPatch.H"
31 #include "cyclicACMIPolyPatch.H"
33 #include "processorPolyPatch.H"
34 #include "symmetryPlanePolyPatch.H"
35 #include "symmetryPolyPatch.H"
36 #include "wallPolyPatch.H"
37 #include "wedgePolyPatch.H"
38 #include "meshTools.H"
39 
40 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
41 
42 template<class TrackCloudType>
43 void Foam::particle::readFields(TrackCloudType& c)
44 {
45  bool valid = c.size();
46 
47  IOobject procIO(c.fieldIOobject("origProcId", IOobject::MUST_READ));
48 
49  bool haveFile = procIO.typeHeaderOk<IOField<label>>(true);
50 
51  IOField<label> origProcId(procIO, valid && haveFile);
52  c.checkFieldIOobject(c, origProcId);
54  (
55  c.fieldIOobject("origId", IOobject::MUST_READ),
56  valid && haveFile
57  );
58  c.checkFieldIOobject(c, origId);
59 
60  label i = 0;
61  forAllIter(typename TrackCloudType, c, iter)
62  {
63  particle& p = iter();
64 
65  p.origProc_ = origProcId[i];
66  p.origId_ = origId[i];
67  i++;
68  }
69 }
70 
71 
72 template<class TrackCloudType>
73 void Foam::particle::writeFields(const TrackCloudType& c)
74 {
75  label np = c.size();
76 
78  ioP.write(np > 0);
79 
81  (
82  c.fieldIOobject("origProcId", IOobject::NO_READ),
83  np
84  );
86  (
87  c.fieldIOobject("origId", IOobject::NO_READ),
88  np
89  );
90 
91  label i = 0;
92  forAllConstIter(typename TrackCloudType, c, iter)
93  {
94  origProc[i] = iter().origProc_;
95  origId[i] = iter().origId_;
96  i++;
97  }
98 
99  origProc.write(np > 0);
100  origId.write(np > 0);
101 }
102 
103 
104 template<class TrackCloudType>
106 (
107  const vector& displacement,
108  const scalar fraction,
109  TrackCloudType& cloud,
110  trackingData& td
111 )
112 {
113  if (debug)
114  {
115  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
116  }
117 
118  if (onBoundaryFace())
119  {
120  changeToMasterPatch();
121  }
122 
123  hitFaceNoChangeToMasterPatch(displacement, fraction, cloud, td);
124 }
125 
126 
127 template<class TrackCloudType>
129 (
130  const vector& displacement,
131  const scalar fraction,
132  TrackCloudType& cloud,
133  trackingData& td
134 )
135 {
136  if (debug)
137  {
138  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
139  }
140 
141  typename TrackCloudType::particleType& p =
142  static_cast<typename TrackCloudType::particleType&>(*this);
143  typename TrackCloudType::particleType::trackingData& ttd =
144  static_cast<typename TrackCloudType::particleType::trackingData&>(td);
145 
146  if (!onFace())
147  {
148  return;
149  }
150  else if (onInternalFace())
151  {
152  changeCell();
153  }
154  else if (onBoundaryFace())
155  {
156  if (!p.hitPatch(cloud, ttd))
157  {
158  const polyPatch& patch = mesh_.boundaryMesh()[p.patch()];
159 
160  if (isA<wedgePolyPatch>(patch))
161  {
162  p.hitWedgePatch(cloud, ttd);
163  }
164  else if (isA<symmetryPlanePolyPatch>(patch))
165  {
166  p.hitSymmetryPlanePatch(cloud, ttd);
167  }
168  else if (isA<symmetryPolyPatch>(patch))
169  {
170  p.hitSymmetryPatch(cloud, ttd);
171  }
172  else if (isA<cyclicPolyPatch>(patch))
173  {
174  p.hitCyclicPatch(cloud, ttd);
175  }
176  else if (isA<cyclicACMIPolyPatch>(patch))
177  {
178  p.hitCyclicACMIPatch(displacement, fraction, cloud, ttd);
179  }
180  else if (isA<cyclicAMIPolyPatch>(patch))
181  {
182  p.hitCyclicAMIPatch(displacement, fraction, cloud, ttd);
183  }
184  else if (isA<cyclicRepeatAMIPolyPatch>(patch))
185  {
186  p.hitCyclicRepeatAMIPatch(displacement, fraction, cloud, ttd);
187  }
188  else if (isA<processorPolyPatch>(patch))
189  {
190  p.hitProcessorPatch(cloud, ttd);
191  }
192  else if (isA<wallPolyPatch>(patch))
193  {
194  p.hitWallPatch(cloud, ttd);
195  }
196  else
197  {
198  td.keepParticle = false;
199  }
200  }
201  }
202 }
203 
204 
205 template<class TrackCloudType>
207 (
208  const vector& displacement,
209  const scalar fraction,
210  TrackCloudType& cloud,
211  trackingData& td
212 )
213 {
214  if (debug)
215  {
216  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
217  }
218 
219  const scalar f = trackToFace(displacement, fraction);
220 
221  hitFace(displacement, fraction, cloud, td);
222 
223  return f;
224 }
225 
226 
227 template<class TrackCloudType>
228 bool Foam::particle::hitPatch(TrackCloudType&, trackingData&)
229 {
230  return false;
231 }
232 
233 
234 template<class TrackCloudType>
235 void Foam::particle::hitWedgePatch(TrackCloudType& cloud, trackingData& td)
236 {
238  << "Hitting a wedge patch should not be possible."
239  << abort(FatalError);
240 
241  hitSymmetryPatch(cloud, td);
242 }
243 
244 
245 template<class TrackCloudType>
247 (
248  TrackCloudType& cloud,
249  trackingData& td
250 )
251 {
252  hitSymmetryPatch(cloud, td);
253 }
254 
255 
256 template<class TrackCloudType>
258 {
259  const vector nf = normal();
261 }
262 
263 
264 template<class TrackCloudType>
266 {
267  const cyclicPolyPatch& cpp =
268  static_cast<const cyclicPolyPatch&>(mesh_.boundaryMesh()[patch()]);
269  const cyclicPolyPatch& receiveCpp = cpp.nbrPatch();
270 
271  // Set the topology
272  facei_ = tetFacei_ = cpp.transformGlobalFace(facei_);
273  celli_ = mesh_.faceOwner()[facei_];
274 
275  // See note in correctAfterParallelTransfer for tetPti addressing ...
276  tetPti_ = mesh_.faces()[tetFacei_].size() - 1 - tetPti_;
277 
278  // Reflect to account for the change of triangle orientation in the new cell
279  reflect();
280 
281  // Transform the properties
282  if (receiveCpp.transform().transformsPosition())
283  {
284  transformProperties(receiveCpp.transform());
285  }
286 }
287 
288 
289 template<class TrackCloudType>
291 (
292  const vector& displacement,
293  const scalar fraction,
294  TrackCloudType& cloud,
295  trackingData& td
296 )
297 {
298  const cyclicAMIPolyPatch& cpp =
299  static_cast<const cyclicAMIPolyPatch&>(mesh_.boundaryMesh()[patch()]);
300  const cyclicAMIPolyPatch& receiveCpp = cpp.nbrPatch();
301 
302  if (debug)
303  {
304  Info<< "Particle " << origId() << " crossing AMI from " << cpp.name()
305  << " to " << receiveCpp.name() << endl << endl;
306  }
307 
308  // Get the send patch data
309  vector sendNormal, sendDisplacement;
310  patchData(sendNormal, sendDisplacement);
311 
312  vector pos = position();
313 
314  const labelPair receiveIs =
315  cpp.pointAMIAndFace
316  (
317  cpp.whichFace(facei_),
318  displacement - fraction*sendDisplacement,
319  pos
320  );
321  const label receiveAMIi = receiveIs.first();
322  const label receiveFacei = receiveIs.second();
323 
324  // If the receiving face could not be found then issue a warning and remove
325  // the particle
326  if (receiveFacei < 0)
327  {
328  td.keepParticle = false;
330  << "Particle transfer from " << cyclicAMIPolyPatch::typeName
331  << " patches " << cpp.name() << " to " << receiveCpp.name()
332  << " failed at position " << pos << " and with displacement "
333  << (displacement - fraction*sendDisplacement) << nl
334  << " A receiving face could not be found" << nl
335  << " The particle has been removed" << nl << endl;
336  return;
337  }
338 
339  // Set the topology
340  facei_ = tetFacei_ = receiveFacei + receiveCpp.start();
341 
342  // Locate the particle on the receiving side
343  locate
344  (
345  pos,
346  mesh_.faceOwner()[facei_],
347  false,
348  "Particle crossed between " + cyclicAMIPolyPatch::typeName +
349  " patches " + cpp.name() + " and " + receiveCpp.name() +
350  " to a location outside of the mesh."
351  );
352 
353  // The particle must remain associated with a face for the tracking to
354  // register as incomplete
355  facei_ = tetFacei_;
356 
357  // Transform the properties
358  vector displacementT = displacement;
359 
360  const transformer AMITransform =
361  receiveCpp.owner()
362  ? receiveCpp.AMITransforms()[receiveAMIi]
363  : inv(cpp.AMITransforms()[receiveAMIi]);
364 
365  if (AMITransform.transformsPosition())
366  {
367  transformProperties(AMITransform);
368  displacementT = AMITransform.transform(displacementT);
369  }
370 
371  if (receiveCpp.transform().transformsPosition())
372  {
373  transformProperties(receiveCpp.transform());
374  displacementT = receiveCpp.transform().transform(displacementT);
375  }
376 
377  // If on a boundary and the displacement points into the receiving face
378  // then issue a warning and remove the particle
379  if (onBoundaryFace())
380  {
381  vector receiveNormal, receiveDisplacement;
382  patchData(receiveNormal, receiveDisplacement);
383 
384  if (((displacementT - fraction*receiveDisplacement)&receiveNormal) > 0)
385  {
386  td.keepParticle = false;
388  << "Particle transfer from " << cyclicAMIPolyPatch::typeName
389  << " patches " << cpp.name() << " to " << receiveCpp.name()
390  << " failed at position " << pos << " and with displacement "
391  << (displacementT - fraction*receiveDisplacement) << nl
392  << " The displacement points into both the source and "
393  << "receiving faces, so the tracking cannot proceed" << nl
394  << " The particle has been removed" << nl << endl;
395  return;
396  }
397  }
398 }
399 
400 
401 template<class TrackCloudType>
403 (
404  const vector& displacement,
405  const scalar fraction,
406  TrackCloudType& cloud,
407  trackingData& td
408 )
409 {
410  typename TrackCloudType::particleType& p =
411  static_cast<typename TrackCloudType::particleType&>(*this);
412 
413  const cyclicACMIPolyPatch& cpp =
414  static_cast<const cyclicACMIPolyPatch&>(mesh_.boundaryMesh()[patch()]);
415 
416  vector patchNormal, patchDisplacement;
417  patchData(patchNormal, patchDisplacement);
418 
419  const label localFacei = cpp.whichFace(facei_);
420 
421  // If the mask is within the patch tolerance at either end, then we can
422  // assume an interaction with the appropriate part of the ACMI pair.
423  const scalar mask = cpp.mask()[localFacei];
424  bool couple = mask >= 1 - cpp.tolerance();
425  bool nonOverlap = mask <= cpp.tolerance();
426 
427  // If the mask is an intermediate value, then we search for a location on
428  // the other side of the AMI. If we can't find a location, then we assume
429  // that we have hit the non-overlap patch.
430  if (!couple && !nonOverlap)
431  {
432  vector pos = position();
433  couple =
434  cpp.pointAMIAndFace
435  (
436  localFacei,
437  displacement - fraction*patchDisplacement,
438  pos
439  ).first() >= 0;
440  nonOverlap = !couple;
441  }
442 
443  if (couple)
444  {
445  p.hitCyclicAMIPatch(displacement, fraction, cloud, td);
446  }
447  else
448  {
449  // Move to the face associated with the non-overlap patch and redo the
450  // face interaction.
451  tetFacei_ = facei_ = cpp.nonOverlapPatch().start() + localFacei;
452  p.hitFaceNoChangeToMasterPatch(displacement, fraction, cloud, td);
453  }
454 }
455 
456 
457 template<class TrackCloudType>
459 (
460  const vector& displacement,
461  const scalar fraction,
462  TrackCloudType& cloud,
463  trackingData& td
464 )
465 {
466  typename TrackCloudType::particleType& p =
467  static_cast<typename TrackCloudType::particleType&>(*this);
468 
469  p.hitCyclicAMIPatch(displacement, fraction, cloud, td);
470 }
471 
472 
473 template<class TrackCloudType>
475 {}
476 
477 
478 template<class TrackCloudType>
480 {}
481 
482 
483 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:434
void hitFace(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Hit the current face. If the current face is internal than this.
label origProc() const
Return the originating processor ID.
Definition: particleI.H:173
Cyclic patch for Arbitrarily Coupled Mesh Interface (ACMI)
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.
Vector-tensor class used to perform translations, rotations and scaling operations in 3D space...
Definition: transformer.H:83
static transformer rotation(const tensor &T)
Construct a pure rotation transformer.
Definition: transformerI.H:43
bool onBoundaryFace() const
Is the particle on a boundary face?
Definition: particleI.H:266
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:459
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
scalar trackToFace(const vector &displacement, const scalar fraction)
As particle::track, but stops when a face is hit.
Definition: particle.C:645
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
labelPair pointAMIAndFace(const label facei, const vector &n, point &p) const
Return the transform and face indices on neighbour patch which.
scalar trackToAndHitFace(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Convenience function. Combines trackToFace and hitFace.
void hitWallPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a wallPatch.
void hitSymmetryPlanePatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a.
virtual const transformer & transform() const
Return transformation between the coupled patches.
const cyclicPolyPatch & nbrPatch() const
virtual void transformProperties(const transformer &)
Transform the physical properties of the particle.
Definition: particle.C:1048
void hitSymmetryPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a symmetryPatch.
const dimensionedScalar c
Speed of light in a vacuum.
Base particle class.
Definition: particle.H:83
const List< transformer > & AMITransforms() const
Return a reference to the AMI transforms.
const polyPatch & nonOverlapPatch() const
Return a const reference to the non-overlapping patch.
virtual const cyclicAMIPolyPatch & nbrPatch() const
Return a reference to the neighbour patch.
vector normal() const
Return the normal of the tri on tetFacei_ for the.
Definition: particleI.H:248
void patchData(vector &normal, vector &displacement) const
Get the normal and displacement of the current patch location.
Definition: particleI.H:292
dimensionedScalar pos(const dimensionedScalar &ds)
void hitFaceNoChangeToMasterPatch(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
As above, but does not change the master patch. Needed in order for.
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
static const Identity< scalar > I
Definition: Identity.H:93
void hitProcessorPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a processorPatch.
Cyclic plane patch.
virtual bool write(const bool write=true) const
Write using setting from DB.
Definition: IOPosition.C:52
void hitCyclicACMIPatch(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting a.
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1169
virtual const transformer & transform() const
Return transformation between the coupled patches.
void hitCyclicPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a cyclicPatch.
Cyclic patch for Arbitrary Mesh Interface (AMI)
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1156
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
label origId() const
Return the particle ID on the originating processor.
Definition: particleI.H:185
static const char nl
Definition: Ostream.H:260
bool onFace() const
Is the particle on a face?
Definition: particleI.H:254
#define FUNCTION_NAME
labelList f(nPoints)
bool transformsPosition() const
Return true if the transformer transforms a point.
Definition: transformerI.H:146
const Type & second() const
Return second.
Definition: Pair.H:110
void hitWedgePatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a wedgePatch.
const scalarField & mask() const
Mask field where 1 = overlap, 0 = no-overlap.
#define WarningInFunction
Report a warning using Foam::Warning.
bool keepParticle
Flag to indicate whether to keep particle (false = delete)
Definition: particle.H:112
static void readFields(TrackCloudType &c)
Read the fields associated with the owner cloud.
virtual bool owner() const
Does this side own the patch?
static void writeFields(const TrackCloudType &c)
Write the fields associated with the owner cloud.
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:309
messageStream Info
bool hitPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a patch.
Type transform(const Type &) const
Transform the given type.
bool onInternalFace() const
Is the particle on an internal face?
Definition: particleI.H:260
void hitCyclicAMIPatch(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting a cyclicAMIPatch.
label transformGlobalFace(const label facei) const
For a given patch face index, return the corresponding index of the.
volScalarField & p
Helper IO class to read and write particle positions.
Definition: Cloud.H:55
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
const Type & first() const
Return first.
Definition: Pair.H:98
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:278
label patch() const
Return the index of patch that the particle is on.
Definition: particleI.H:272
void hitCyclicRepeatAMIPatch(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting an.
static scalar tolerance()
Overlap tolerance.
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:389