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-2023 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"
31 #include "processorPolyPatch.H"
32 #include "symmetryPlanePolyPatch.H"
33 #include "symmetryPolyPatch.H"
34 #include "wallPolyPatch.H"
35 #include "wedgePolyPatch.H"
36 #include "meshTools.H"
37 
38 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
39 
40 template<class TrackCloudType>
41 void Foam::particle::readFields(TrackCloudType& c)
42 {
43  bool valid = c.size();
44 
46  (
47  c.fieldIOobject("origProcId", IOobject::MUST_READ)
48  );
49 
50  bool haveFile = procIO.headerOk();
51 
52  IOField<label> origProcId(procIO, valid && haveFile);
53  c.checkFieldIOobject(c, origProcId);
55  (
56  c.fieldIOobject("origId", IOobject::MUST_READ),
57  valid && haveFile
58  );
59  c.checkFieldIOobject(c, origId);
60 
61  label i = 0;
62  forAllIter(typename TrackCloudType, c, iter)
63  {
64  particle& p = iter();
65 
66  p.origProc_ = origProcId[i];
67  p.origId_ = origId[i];
68  i++;
69  }
70 }
71 
72 
73 template<class TrackCloudType>
74 void Foam::particle::writeFields(const TrackCloudType& c)
75 {
76  label np = c.size();
77 
79  ioP.write(np > 0);
80 
81  IOField<label> origProc
82  (
83  c.fieldIOobject("origProcId", IOobject::NO_READ),
84  np
85  );
86  IOField<label> origId
87  (
88  c.fieldIOobject("origId", IOobject::NO_READ),
89  np
90  );
91 
92  label i = 0;
93  forAllConstIter(typename TrackCloudType, c, iter)
94  {
95  origProc[i] = iter().origProc_;
96  origId[i] = iter().origId_;
97  i++;
98  }
99 
100  origProc.write(np > 0);
101  origId.write(np > 0);
102 }
103 
104 
105 template<class TrackCloudType>
107 (
108  TrackCloudType& cloud,
109  trackingData& td
110 )
111 {
112  if (td.sendFromPatch == patch(td.mesh))
113  {
114  prepareForProcessorTransfer(td);
115  }
116  else
117  {
118  prepareForNonConformalCyclicTransfer
119  (
120  td.mesh,
121  td.sendFromPatch,
122  td.sendToPatchFace,
123  td.sendToPosition
124  );
125  }
126 }
127 
128 
129 template<class TrackCloudType>
131 (
132  TrackCloudType& cloud,
133  trackingData& td
134 )
135 {
136  const polyPatch& pp = td.mesh.boundaryMesh()[td.sendToPatch];
137 
138  if (isA<processorPolyPatch>(pp))
139  {
140  correctAfterProcessorTransfer(td);
141  }
142  else if (isA<nonConformalCyclicPolyPatch>(pp))
143  {
144  correctAfterNonConformalCyclicTransfer
145  (
146  td.mesh,
147  td.sendToPatch,
149  );
150  }
151  else
152  {
154  << "Transfer patch type not recognised"
155  << exit(FatalError);
156  }
157 }
158 
159 
160 template<class TrackCloudType>
162 (
163  const vector& displacement,
164  const scalar fraction,
165  TrackCloudType& cloud,
166  trackingData& td
167 )
168 {
169  if (debug)
170  {
171  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
172  }
173 
174  typename TrackCloudType::particleType& p =
175  static_cast<typename TrackCloudType::particleType&>(*this);
176  typename TrackCloudType::particleType::trackingData& ttd =
177  static_cast<typename TrackCloudType::particleType::trackingData&>(td);
178 
179  if (!onFace())
180  {
181  return;
182  }
183  else if (onInternalFace(td.mesh))
184  {
185  changeCell(td.mesh);
186  }
187  else if (onBoundaryFace(td.mesh))
188  {
189  forAll(cloud.patchNonConformalCyclicPatches()[p.patch(td.mesh)], i)
190  {
191  if
192  (
193  p.hitNonConformalCyclicPatch
194  (
195  displacement,
196  fraction,
197  cloud.patchNonConformalCyclicPatches()[p.patch(td.mesh)][i],
198  cloud,
199  ttd
200  )
201  )
202  {
203  return;
204  }
205  }
206 
207  if (!p.hitPatch(cloud, ttd))
208  {
209  const polyPatch& patch = td.mesh.boundaryMesh()[p.patch(td.mesh)];
210 
211  if (isA<wedgePolyPatch>(patch))
212  {
213  p.hitWedgePatch(cloud, ttd);
214  }
215  else if (isA<symmetryPlanePolyPatch>(patch))
216  {
217  p.hitSymmetryPlanePatch(cloud, ttd);
218  }
219  else if (isA<symmetryPolyPatch>(patch))
220  {
221  p.hitSymmetryPatch(cloud, ttd);
222  }
223  else if (isA<cyclicPolyPatch>(patch))
224  {
225  p.hitCyclicPatch(cloud, ttd);
226  }
227  else if (isA<processorPolyPatch>(patch))
228  {
229  p.hitProcessorPatch(cloud, ttd);
230  }
231  else if (isA<wallPolyPatch>(patch))
232  {
233  p.hitWallPatch(cloud, ttd);
234  }
235  else
236  {
237  p.hitBasicPatch(cloud, ttd);
238  }
239  }
240  }
241 }
242 
243 
244 template<class TrackCloudType>
246 (
247  const vector& displacement,
248  const scalar fraction,
249  TrackCloudType& cloud,
250  trackingData& td
251 )
252 {
253  if (debug)
254  {
255  Info << "Particle " << origId() << nl << FUNCTION_NAME << nl << endl;
256  }
257 
258  const scalar f = trackToFace(td.mesh, displacement, fraction);
259 
260  hitFace(displacement, fraction, cloud, td);
261 
262  return f;
263 }
264 
265 
266 template<class TrackCloudType>
267 bool Foam::particle::hitPatch(TrackCloudType&, trackingData&)
268 {
269  return false;
270 }
271 
272 
273 template<class TrackCloudType>
275 {
277  << "Hitting a wedge patch should not be possible."
278  << abort(FatalError);
279 
280  hitSymmetryPatch(cloud, td);
281 }
282 
283 
284 template<class TrackCloudType>
286 (
287  TrackCloudType& cloud,
288  trackingData& td
289 )
290 {
291  hitSymmetryPatch(cloud, td);
292 }
293 
294 
295 template<class TrackCloudType>
297 {
298  const vector nf = normal(td.mesh);
299  transformProperties(transformer::rotation(I - 2.0*nf*nf));
300 }
301 
302 
303 template<class TrackCloudType>
305 {
306  const cyclicPolyPatch& cpp =
307  static_cast<const cyclicPolyPatch&>
308  (
309  td.mesh.boundaryMesh()[patch(td.mesh)]
310  );
311  const cyclicPolyPatch& receiveCpp = cpp.nbrPatch();
312 
313  // Set the topology
314  facei_ = tetFacei_ = cpp.transformGlobalFace(facei_);
315  celli_ = td.mesh.faceOwner()[facei_];
316 
317  // See note in correctAfterParallelTransfer for tetPti addressing ...
318  tetPti_ = td.mesh.faces()[tetFacei_].size() - 1 - tetPti_;
319 
320  // Reflect to account for the change of triangle orientation in the new cell
321  reflect();
322 
323  // Transform the properties
324  if (receiveCpp.transform().transformsPosition())
325  {
326  transformProperties(receiveCpp.transform());
327  }
328 }
329 
330 
331 template<class TrackCloudType>
333 (
334  const vector& displacement,
335  const scalar fraction,
336  const label patchi,
337  TrackCloudType& cloud,
338  trackingData& td
339 )
340 {
341  const nonConformalCyclicPolyPatch& nccpp =
342  static_cast<const nonConformalCyclicPolyPatch&>
343  (td.mesh.boundaryMesh()[patchi]);
344 
345  const point sendPos = position(td.mesh);
346 
347  // Get the send patch data
348  vector sendNormal, sendDisplacement;
349  patchData(td.mesh, sendNormal, sendDisplacement);
350 
351  // Project the particle through the non-conformal patch
352  point receivePos;
353  const remote receiveProcFace =
354  nccpp.ray
355  (
356  stepFraction_,
357  nccpp.origPatch().whichFace(facei_),
358  sendPos,
359  displacement - fraction*sendDisplacement,
360  receivePos
361  );
362 
363  // If we didn't hit anything then this particle is assumed to project to
364  // the orig patch, or another different non-conformal patch. Return, so
365  // these can be tried.
366  if (receiveProcFace.proci == -1) return false;
367 
368  // If we are transferring between processes then mark as such and return.
369  // The cloud will handle all processor transfers as a single batch.
370  if (receiveProcFace.proci != Pstream::myProcNo())
371  {
372  td.sendFromPatch = nccpp.index();
373  td.sendToProc = receiveProcFace.proci;
374  td.sendToPatch = nccpp.nbrPatchIndex();
375  td.sendToPatchFace = receiveProcFace.elementi;
376  td.sendToPosition = receivePos;
377 
378  return true;
379  }
380 
381  // If both sides are on the same process, then do the local transfer
382  prepareForNonConformalCyclicTransfer
383  (
384  td.mesh,
385  nccpp.index(),
386  receiveProcFace.elementi,
387  receivePos
388  );
389  correctAfterNonConformalCyclicTransfer
390  (
391  td.mesh,
392  nccpp.nbrPatchIndex(),
394  );
395 
396  return true;
397 }
398 
399 
400 template<class TrackCloudType>
402 {
403  td.sendToProc = cloud.patchNbrProc()[patch(td.mesh)];
404  td.sendFromPatch = patch(td.mesh);
405  td.sendToPatch = cloud.patchNbrProcPatch()[patch(td.mesh)];
406  td.sendToPatchFace =
407  td.mesh.boundaryMesh()[patch(td.mesh)].whichFace(face());
408 }
409 
410 
411 template<class TrackCloudType>
413 {}
414 
415 
416 template<class TrackCloudType>
417 void Foam::particle::hitBasicPatch(TrackCloudType&, trackingData& td)
418 {
419  td.keepParticle = false;
420 }
421 
422 
423 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:459
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
A primitive field of type <Type> with automated input and output.
Definition: IOField.H:53
Helper IO class to read and write particle positions.
Definition: IOPosition.H:60
virtual bool write(const bool write=true) const
Write using setting from DB.
Definition: IOPosition.C:59
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
A cloud is a collection of lagrangian particles.
Definition: cloud.H:55
Cyclic plane patch.
const cyclicPolyPatch & nbrPatch() const
virtual const transformer & transform() const
Return transformation between the coupled patches.
virtual label nbrPatchIndex() const
Neighbour patchID.
label transformGlobalFace(const label facei) const
For a given patch face index, return the corresponding index of the.
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
Non-conformal cyclic poly patch. As nonConformalCoupledPolyPatch, but the neighbouring patch is local...
remote ray(const scalar fraction, const label origFacei, const vector &p, const vector &n, point &nbrP) const
Compute a ray intersection across the coupling.
const polyPatch & origPatch() const
Original patch.
labelList patchNLocateBoundaryHits
Number of boundary hits that occurred during locate executions.
Definition: particle.H:129
label sendToProc
Processor to send the particle to. -1 indicates that this.
Definition: particle.H:113
label sendFromPatch
Patch from which to send the particle.
Definition: particle.H:116
vector sendToPosition
Position to which to send.
Definition: particle.H:125
bool keepParticle
Flag to indicate whether to keep particle (false = delete)
Definition: particle.H:109
label sendToPatch
Patch to which to send the particle.
Definition: particle.H:119
const polyMesh & mesh
Reference to the mesh.
Definition: particle.H:106
label sendToPatchFace
Patch face to which to send the particle.
Definition: particle.H:122
Base particle class.
Definition: particle.H:83
void prepareForParallelTransfer(TrackCloudType &, trackingData &)
Make changes prior to a parallel transfer. Runs either.
void hitBasicPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a basic.
static void readFields(TrackCloudType &c)
Read the fields associated with the owner cloud.
void hitCyclicPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a.
void hitProcessorPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a.
scalar trackToAndHitFace(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Convenience function. Combines trackToFace and hitFace.
bool hitPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a patch.
void hitFace(const vector &displacement, const scalar fraction, TrackCloudType &cloud, trackingData &td)
Hit the current face. If the current face is internal than this.
void hitSymmetryPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a.
void hitSymmetryPlanePatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a.
void hitWedgePatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a wedgePatch.
void correctAfterParallelTransfer(TrackCloudType &, trackingData &)
Make changes following a parallel transfer. Runs either.
bool hitNonConformalCyclicPatch(const vector &displacement, const scalar fraction, const label patchi, TrackCloudType &cloud, trackingData &td)
Overridable function to handle the particle hitting an.
label origId() const
Return the particle ID on the originating processor.
Definition: particleI.H:188
void hitWallPatch(TrackCloudType &, trackingData &)
Overridable function to handle the particle hitting a wallPatch.
static void writeFields(const TrackCloudType &c)
Write the fields associated with the owner cloud.
label index() const
Return the index of this patch in the boundaryMesh.
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1326
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1339
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:404
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:360
virtual bool write(const bool write=true) const
Write using setting from DB.
Struct for keeping processor, element (cell, face, point) index.
Definition: remote.H:57
label elementi
Element index.
Definition: remote.H:70
label proci
Processor index.
Definition: remote.H:67
static transformer rotation(const tensor &T)
Construct a pure rotation transformer.
Definition: transformerI.H:43
bool transformsPosition() const
Return true if the transformer transforms a point.
Definition: transformerI.H:146
Templated form of IOobject providing type information for file reading and header type checking.
Definition: IOobject.H:531
bool headerOk()
Read header (uses typeGlobalFile to find file) and check.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
#define FUNCTION_NAME
bool valid(const PtrList< ModelType > &l)
const dimensionedScalar c
Speed of light in a vacuum.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
errorManip< error > abort(error &err)
Definition: errorManip.H:131
messageStream Info
static const Identity< scalar > I
Definition: Identity.H:93
error FatalError
static const char nl
Definition: Ostream.H:266
labelList f(nPoints)
volScalarField & p