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-2022 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"
32 #include "processorPolyPatch.H"
33 #include "symmetryPlanePolyPatch.H"
34 #include "symmetryPolyPatch.H"
35 #include "wallPolyPatch.H"
36 #include "wedgePolyPatch.H"
37 #include "meshTools.H"
38 
39 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
40 
41 template<class TrackCloudType>
42 void Foam::particle::readFields(TrackCloudType& c)
43 {
44  bool valid = c.size();
45 
47  (
48  c.fieldIOobject("origProcId", IOobject::MUST_READ)
49  );
50 
51  bool haveFile = procIO.headerOk();
52 
53  IOField<label> origProcId(procIO, valid && haveFile);
54  c.checkFieldIOobject(c, origProcId);
56  (
57  c.fieldIOobject("origId", IOobject::MUST_READ),
58  valid && haveFile
59  );
60  c.checkFieldIOobject(c, origId);
61 
62  label i = 0;
63  forAllIter(typename TrackCloudType, c, iter)
64  {
65  particle& p = iter();
66 
67  p.origProc_ = origProcId[i];
68  p.origId_ = origId[i];
69  i++;
70  }
71 }
72 
73 
74 template<class TrackCloudType>
75 void Foam::particle::writeFields(const TrackCloudType& c)
76 {
77  label np = c.size();
78 
80  ioP.write(np > 0);
81 
83  (
84  c.fieldIOobject("origProcId", IOobject::NO_READ),
85  np
86  );
88  (
89  c.fieldIOobject("origId", IOobject::NO_READ),
90  np
91  );
92 
93  label i = 0;
94  forAllConstIter(typename TrackCloudType, c, iter)
95  {
96  origProc[i] = iter().origProc_;
97  origId[i] = iter().origId_;
98  i++;
99  }
100 
101  origProc.write(np > 0);
102  origId.write(np > 0);
103 }
104 
105 
106 template<class TrackCloudType>
108 (
109  const vector& displacement,
110  const scalar fraction,
111  TrackCloudType& cloud,
112  trackingData& td
113 )
114 {
115  if (debug)
116  {
117  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
118  }
119 
120  typename TrackCloudType::particleType& p =
121  static_cast<typename TrackCloudType::particleType&>(*this);
122  typename TrackCloudType::particleType::trackingData& ttd =
123  static_cast<typename TrackCloudType::particleType::trackingData&>(td);
124 
125  if (!onFace())
126  {
127  return;
128  }
129  else if (onInternalFace())
130  {
131  changeCell();
132  }
133  else if (onBoundaryFace())
134  {
135  forAll(cloud.patchNonConformalCyclicPatches()[p.patch()], i)
136  {
137  if
138  (
139  p.hitNonConformalCyclicPatch
140  (
141  displacement,
142  fraction,
143  cloud.patchNonConformalCyclicPatches()[p.patch()][i],
144  cloud,
145  ttd
146  )
147  )
148  {
149  return;
150  }
151  }
152 
153  if (!p.hitPatch(cloud, ttd))
154  {
155  const polyPatch& patch = mesh_.boundaryMesh()[p.patch()];
156 
157  if (isA<wedgePolyPatch>(patch))
158  {
159  p.hitWedgePatch(cloud, ttd);
160  }
161  else if (isA<symmetryPlanePolyPatch>(patch))
162  {
163  p.hitSymmetryPlanePatch(cloud, ttd);
164  }
165  else if (isA<symmetryPolyPatch>(patch))
166  {
167  p.hitSymmetryPatch(cloud, ttd);
168  }
169  else if (isA<cyclicPolyPatch>(patch))
170  {
171  p.hitCyclicPatch(cloud, ttd);
172  }
173  else if (isA<cyclicAMIPolyPatch>(patch))
174  {
175  p.hitCyclicAMIPatch(displacement, fraction, cloud, ttd);
176  }
177  else if (isA<processorPolyPatch>(patch))
178  {
179  p.hitProcessorPatch(cloud, ttd);
180  }
181  else if (isA<wallPolyPatch>(patch))
182  {
183  p.hitWallPatch(cloud, ttd);
184  }
185  else
186  {
187  td.keepParticle = false;
188  }
189  }
190  }
191 }
192 
193 
194 template<class TrackCloudType>
196 (
197  const vector& displacement,
198  const scalar fraction,
199  TrackCloudType& cloud,
200  trackingData& td
201 )
202 {
203  if (debug)
204  {
205  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
206  }
207 
208  const scalar f = trackToFace(displacement, fraction);
209 
210  hitFace(displacement, fraction, cloud, td);
211 
212  return f;
213 }
214 
215 
216 template<class TrackCloudType>
217 bool Foam::particle::hitPatch(TrackCloudType&, trackingData&)
218 {
219  return false;
220 }
221 
222 
223 template<class TrackCloudType>
224 void Foam::particle::hitWedgePatch(TrackCloudType& cloud, trackingData& td)
225 {
227  << "Hitting a wedge patch should not be possible."
228  << abort(FatalError);
229 
230  hitSymmetryPatch(cloud, td);
231 }
232 
233 
234 template<class TrackCloudType>
236 (
237  TrackCloudType& cloud,
238  trackingData& td
239 )
240 {
241  hitSymmetryPatch(cloud, td);
242 }
243 
244 
245 template<class TrackCloudType>
247 {
248  const vector nf = normal();
250 }
251 
252 
253 template<class TrackCloudType>
255 {
256  const cyclicPolyPatch& cpp =
257  static_cast<const cyclicPolyPatch&>(mesh_.boundaryMesh()[patch()]);
258  const cyclicPolyPatch& receiveCpp = cpp.nbrPatch();
259 
260  // Set the topology
261  facei_ = tetFacei_ = cpp.transformGlobalFace(facei_);
262  celli_ = mesh_.faceOwner()[facei_];
263 
264  // See note in correctAfterParallelTransfer for tetPti addressing ...
265  tetPti_ = mesh_.faces()[tetFacei_].size() - 1 - tetPti_;
266 
267  // Reflect to account for the change of triangle orientation in the new cell
268  reflect();
269 
270  // Transform the properties
271  if (receiveCpp.transform().transformsPosition())
272  {
273  transformProperties(receiveCpp.transform());
274  }
275 }
276 
277 
278 template<class TrackCloudType>
280 (
281  const vector& displacement,
282  const scalar fraction,
283  TrackCloudType& cloud,
284  trackingData& td
285 )
286 {
287  const cyclicAMIPolyPatch& cpp =
288  static_cast<const cyclicAMIPolyPatch&>(mesh_.boundaryMesh()[patch()]);
289  const cyclicAMIPolyPatch& receiveCpp = cpp.nbrPatch();
290 
291  if (debug)
292  {
293  Info<< "Particle " << origId() << " crossing AMI from " << cpp.name()
294  << " to " << receiveCpp.name() << endl << endl;
295  }
296 
297  // Get the send patch data
298  vector sendNormal, sendDisplacement;
299  patchData(sendNormal, sendDisplacement);
300 
301  vector pos = position();
302 
303  const labelPair receiveIs =
304  cpp.pointAMIAndFace
305  (
306  cpp.whichFace(facei_),
307  displacement - fraction*sendDisplacement,
308  pos
309  );
310  const label receiveAMIi = receiveIs.first();
311  const label receiveFacei = receiveIs.second();
312 
313  // If the receiving face could not be found then issue a warning and remove
314  // the particle
315  if (receiveFacei < 0)
316  {
317  td.keepParticle = false;
319  << "Particle transfer from " << cyclicAMIPolyPatch::typeName
320  << " patches " << cpp.name() << " to " << receiveCpp.name()
321  << " failed at position " << pos << " and with displacement "
322  << (displacement - fraction*sendDisplacement) << nl
323  << " A receiving face could not be found" << nl
324  << " The particle has been removed" << nl << endl;
325  return;
326  }
327 
328  // Set the topology
329  facei_ = tetFacei_ = receiveFacei + receiveCpp.start();
330 
331  // Locate the particle on the receiving side
332  locate
333  (
334  pos,
335  mesh_.faceOwner()[facei_],
336  false,
337  "Particle crossed between " + cyclicAMIPolyPatch::typeName +
338  " patches " + cpp.name() + " and " + receiveCpp.name() +
339  " to a location outside of the mesh."
340  );
341 
342  // The particle must remain associated with a face for the tracking to
343  // register as incomplete
344  facei_ = tetFacei_;
345 
346  // Transform the properties
347  vector displacementT = displacement;
348 
349  const transformer AMITransform =
350  receiveCpp.owner()
351  ? receiveCpp.AMITransforms()[receiveAMIi]
352  : inv(cpp.AMITransforms()[receiveAMIi]);
353 
354  if (AMITransform.transformsPosition())
355  {
356  transformProperties(AMITransform);
357  displacementT = AMITransform.transform(displacementT);
358  }
359 
360  if (receiveCpp.transform().transformsPosition())
361  {
362  transformProperties(receiveCpp.transform());
363  displacementT = receiveCpp.transform().transform(displacementT);
364  }
365 
366  // If on a boundary and the displacement points into the receiving face
367  // then issue a warning and remove the particle
368  if (onBoundaryFace())
369  {
370  vector receiveNormal, receiveDisplacement;
371  patchData(receiveNormal, receiveDisplacement);
372 
373  if (((displacementT - fraction*receiveDisplacement)&receiveNormal) > 0)
374  {
375  td.keepParticle = false;
377  << "Particle transfer from " << cyclicAMIPolyPatch::typeName
378  << " patches " << cpp.name() << " to " << receiveCpp.name()
379  << " failed at position " << pos << " and with displacement "
380  << (displacementT - fraction*receiveDisplacement) << nl
381  << " The displacement points into both the source and "
382  << "receiving faces, so the tracking cannot proceed" << nl
383  << " The particle has been removed" << nl << endl;
384  return;
385  }
386  }
387 }
388 
389 
390 template<class TrackCloudType>
392 (
393  const vector& displacement,
394  const scalar fraction,
395  const label patchi,
396  TrackCloudType& cloud,
397  trackingData& td
398 )
399 {
400  const nonConformalCyclicPolyPatch& nccpp =
401  static_cast<const nonConformalCyclicPolyPatch&>
402  (mesh_.boundaryMesh()[patchi]);
403 
404  const point sendPos = this->position();
405 
406  // Get the send patch data
407  vector sendNormal, sendDisplacement;
408  patchData(sendNormal, sendDisplacement);
409 
410  // Project the particle through the non-conformal patch
411  point receivePos;
412  const patchToPatch::procFace receiveProcFace =
413  nccpp.ray
414  (
415  stepFractionSpan()[0] + stepFraction_*stepFractionSpan()[1],
416  nccpp.origPatch().whichFace(facei_),
417  sendPos,
418  displacement - fraction*sendDisplacement,
419  receivePos
420  );
421 
422  // If we didn't hit anything then this particle is assumed to project to
423  // the orig patch, or another different non-conformal patch. Return, so
424  // these can be tried.
425  if (receiveProcFace.proci == -1) return false;
426 
427  // If we are transferring between processes then mark as such and return.
428  // The cloud will handle all processor transfers as a single batch.
429  if (receiveProcFace.proci != Pstream::myProcNo())
430  {
431  td.sendFromPatch = nccpp.index();
432  td.sendToProc = receiveProcFace.proci;
433  td.sendToPatch = nccpp.nbrPatchID();
434  td.sendToPatchFace = receiveProcFace.facei;
435 
436  return true;
437  }
438 
439  // If both sides are on the same process, then do the local transfer
441  (
442  nccpp.index(),
443  receiveProcFace.facei
444  );
446  (
447  nccpp.nbrPatchID()
448  );
449 
450  return true;
451 }
452 
453 
454 template<class TrackCloudType>
455 void Foam::particle::hitProcessorPatch(TrackCloudType& cloud, trackingData& td)
456 {
457  td.sendToProc = cloud.patchNbrProc()[patch()];
458  td.sendFromPatch = patch();
459  td.sendToPatch = cloud.patchNbrProcPatch()[patch()];
460  td.sendToPatchFace = mesh().boundaryMesh()[patch()].whichFace(face());
461 }
462 
463 
464 template<class TrackCloudType>
466 {}
467 
468 
469 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:453
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
const polyMesh & mesh() const
Return the mesh database.
Definition: particleI.H:125
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
const word & name() const
Return name.
Vector-tensor class used to perform translations, rotations and scaling operations in 3D space...
Definition: transformer.H:83
bool headerOk()
Read header (uses typeGlobalFile to find file) and check.
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:306
Structure to conveniently store processor and face indices.
Definition: patchToPatch.H:60
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
label facei
The face index.
Definition: patchToPatch.H:66
void correctAfterNonConformalCyclicTransfer(const label sendToPatch)
Make changes following a transfer across a non conformal cyclic.
Definition: particle.C:1139
Templated form of IOobject providing type information for file reading and header type checking...
Definition: IOobject.H:537
#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:606
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
label proci
The processor index.
Definition: patchToPatch.H:63
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
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.
Pair< scalar > stepFractionSpan() const
Return the step fraction change within the overall time-step.
Definition: particleI.H:197
virtual const transformer & transform() const
Return transformation between the coupled patches.
const cyclicPolyPatch & nbrPatch() const
label sendFromPatch
Patch from which to send the particle.
Definition: particle.H:114
virtual void transformProperties(const transformer &)
Transform the physical properties of the particle.
Definition: particle.C:1023
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:81
const List< transformer > & AMITransforms() const
Return a reference to the AMI transforms.
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)
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
label face() const
Return current face particle is on otherwise -1.
Definition: particleI.H:155
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.
patchToPatch::procFace ray(const scalar fraction, const label origFacei, const vector &p, const vector &n, point &nbrP) const
Compute a ray intersection across the coupling.
virtual bool write(const bool write=true) const
Write using setting from DB.
Definition: IOPosition.C:52
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1237
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:1224
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Non-conformal cyclic poly patch. As nonConformalCoupledPolyPatch, but the neighbouring patch is local...
label origId() const
Return the particle ID on the originating processor.
Definition: particleI.H:185
const polyPatch & origPatch() const
Original patch.
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.
label patchi
label sendToPatch
Patch to which to send the particle.
Definition: particle.H:117
#define WarningInFunction
Report a warning using Foam::Warning.
bool keepParticle
Flag to indicate whether to keep particle (false = delete)
Definition: particle.H:107
static void readFields(TrackCloudType &c)
Read the fields associated with the owner cloud.
virtual bool owner() const
Does this side own the patch?
label index() const
Return the index of this patch in the boundaryMesh.
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:306
messageStream Info
bool hitPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a patch.
Type transform(const Type &) const
Transform the given type.
void prepareForNonConformalCyclicTransfer(const label sendToPatch, const label sendToPatchFace)
Make changes prior to a transfer across a non conformal cyclic.
Definition: particle.C:1107
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
bool hitNonConformalCyclicPatch(const vector &displacement, const scalar fraction, const label patchi, TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting an.
label sendToProc
Processor to send the particle to. -1 indicates that this.
Definition: particle.H:111
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
virtual label nbrPatchID() const
Neighbour patchID.
label patch() const
Return the index of patch that the particle is on.
Definition: particleI.H:272
label sendToPatchFace
Patch face to which to send the particle.
Definition: particle.H:120
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:386