mapLagrangian.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2018-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "MapLagrangianFields.H"
30 #include "passiveParticleCloud.H"
31 #include "meshSearch.H"
32 
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37 
38 static const scalar perturbFactor = 1e-6;
39 
40 
41 // Special version of findCell that generates a cell guaranteed to be
42 // compatible with tracking.
43 static label findCell(const Cloud<passiveParticle>& cloud, const point& pt)
44 {
45  label celli = -1;
46  label tetFacei = -1;
47  label tetPtI = -1;
48 
49  const polyMesh& mesh = cloud.pMesh();
50 
51  mesh.findCellFacePt(pt, celli, tetFacei, tetPtI);
52 
53  if (celli >= 0)
54  {
55  return celli;
56  }
57  else
58  {
59  // See if particle on face by finding nearest face and shifting
60  // particle.
61 
62  meshSearch meshSearcher
63  (
64  mesh,
65  polyMesh::FACE_PLANES // no decomposition needed
66  );
67 
68  label facei = meshSearcher.findNearestBoundaryFace(pt);
69 
70  if (facei >= 0)
71  {
72  const point& cc = mesh.cellCentres()[mesh.faceOwner()[facei]];
73 
74  const point perturbPt = (1-perturbFactor)*pt+perturbFactor*cc;
75 
76  mesh.findCellFacePt(perturbPt, celli, tetFacei, tetPtI);
77 
78  return celli;
79  }
80  }
81 
82  return -1;
83 }
84 
85 
86 void mapLagrangian(const meshToMesh& interp)
87 {
88  // Determine which particles are in meshTarget
89  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
90 
91  const polyMesh& meshSource = interp.srcRegion();
92  const polyMesh& meshTarget = interp.tgtRegion();
93  const labelListList& sourceToTarget = interp.srcToTgtCellAddr();
94 
95  const fileNameList cloudDirs
96  (
97  readDir
98  (
99  meshSource.time().timePath()/cloud::prefix,
101  )
102  );
103 
104  for (const fileName& cloudDir : cloudDirs)
105  {
106  // Search for list of lagrangian objects for this time
107  IOobjectList objects
108  (
109  meshSource,
110  meshSource.time().timeName(),
111  cloud::prefix/cloudDir
112  );
113 
114  if
115  (
117  (
118  objects.found("coordinates") || objects.found("positions")
119  )
120  )
121  {
122  // Has coordinates/positions - so must be a valid cloud
123  Info<< nl << " processing cloud " << cloudDir << endl;
124 
125  // Read positions & cell
126  passiveParticleCloud sourceParcels
127  (
128  meshSource,
129  cloudDir,
130  false
131  );
132  Info<< " read " << sourceParcels.size()
133  << " parcels from source mesh." << endl;
134 
135  // Construct empty target cloud
136  passiveParticleCloud targetParcels
137  (
138  meshTarget,
139  cloudDir,
140  IDLList<passiveParticle>()
141  );
142 
143  passiveParticle::trackingData td(targetParcels);
144 
145  label sourceParticleI = 0;
146 
147  // Indices of source particles that get added to targetParcels
148  DynamicList<label> addParticles(sourceParcels.size());
149 
150  // Unmapped particles
151  labelHashSet unmappedSource(sourceParcels.size());
152 
153 
154  // Initial: track from fine-mesh cell centre to particle position
155  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
156  // This requires there to be no boundary in the way.
157 
158 
159  for (const passiveParticle& p : sourceParcels)
160  {
161  bool foundCell = false;
162 
163  // Assume that cell from read parcel is the correct one...
164  if (p.cell() >= 0)
165  {
166  const labelList& targetCells =
167  sourceToTarget[p.cell()];
168 
169  // Particle probably in one of the targetcells. Try
170  // all by tracking from their cell centre to the parcel
171  // position.
172 
173  for (const label targetCell : targetCells)
174  {
175  // Track from its cellcentre to position to make sure.
176  autoPtr<passiveParticle> newPtr
177  (
178  new passiveParticle
179  (
180  meshTarget,
181  barycentric(1, 0, 0, 0),
182  targetCell,
183  meshTarget.cells()[targetCell][0],
184  1
185  )
186  );
187  passiveParticle& newP = newPtr();
188 
189  newP.track(p.position() - newP.position(), 0);
190 
191  if (!newP.onFace())
192  {
193  // Hit position.
194  foundCell = true;
195  addParticles.append(sourceParticleI);
196  targetParcels.addParticle(newPtr.ptr());
197  break;
198  }
199  }
200  }
201 
202  if (!foundCell)
203  {
204  // Store for closer analysis
205  unmappedSource.insert(sourceParticleI);
206  }
207 
208  sourceParticleI++;
209  }
210 
211  Info<< " after meshToMesh addressing found "
212  << targetParcels.size()
213  << " parcels in target mesh." << endl;
214 
215 
216  // Do closer inspection for unmapped particles
217  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218 
219  if (unmappedSource.size())
220  {
221  sourceParticleI = 0;
222 
223  for (passiveParticle& p : sourceParcels)
224  {
225  if (unmappedSource.found(sourceParticleI))
226  {
227  const label targetCell =
228  findCell(targetParcels, p.position());
229 
230  if (targetCell >= 0)
231  {
232  unmappedSource.erase(sourceParticleI);
233  addParticles.append(sourceParticleI);
234  targetParcels.addParticle
235  (
236  new passiveParticle
237  (
238  meshTarget,
239  p.position(),
240  targetCell
241  )
242  );
243  sourceParcels.remove(&p);
244  }
245  }
246  sourceParticleI++;
247  }
248  }
249  addParticles.shrink();
250 
251  Info<< " after additional mesh searching found "
252  << targetParcels.size() << " parcels in target mesh." << endl;
253 
254  if (addParticles.size())
255  {
256  IOPosition<passiveParticleCloud>(targetParcels).write();
257 
258  // addParticles now contains the indices of the sourceMesh
259  // particles that were appended to the target mesh.
260 
261  // Map lagrangian fields
262  // ~~~~~~~~~~~~~~~~~~~~~
263 
264  MapLagrangianFields<label>
265  (
266  cloudDir,
267  objects,
268  meshTarget,
269  addParticles
270  );
271  MapLagrangianFields<scalar>
272  (
273  cloudDir,
274  objects,
275  meshTarget,
276  addParticles
277  );
278  MapLagrangianFields<vector>
279  (
280  cloudDir,
281  objects,
282  meshTarget,
283  addParticles
284  );
285  MapLagrangianFields<sphericalTensor>
286  (
287  cloudDir,
288  objects,
289  meshTarget,
290  addParticles
291  );
292  MapLagrangianFields<symmTensor>
293  (
294  cloudDir,
295  objects,
296  meshTarget,
297  addParticles
298  );
299  MapLagrangianFields<tensor>
300  (
301  cloudDir,
302  objects,
303  meshTarget,
304  addParticles
305  );
306  }
307  }
308  }
309 }
310 
311 
312 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
313 
314 } // End namespace Foam
315 
316 // ************************************************************************* //
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
Barycentric< scalar > barycentric
A scalar version of the templated Barycentric.
Definition: barycentric.H:41
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
dynamicFvMesh & mesh
void findCellFacePt(const point &p, label &celli, label &tetFacei, label &tetPti) const
Find the cell, tetFacei and tetPti for point p.
Definition: polyMesh.C:1361
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1111
const vectorField & cellCentres() const
void mapLagrangian(const meshToMesh0 &meshToMesh0Interp)
Maps lagrangian positions and fields.
vector point
Point is a vector.
Definition: point.H:37
messageStream Info
Information stream (stdout output on master, null elsewhere)
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
List< fileName > fileNameList
List of fileName.
Definition: fileNameList.H:32
fileNameList readDir(const fileName &directory, const fileName::Type type=fileName::Type::FILE, const bool filtergz=true, const bool followLink=true)
Read a directory and return the entries as a fileName List.
Definition: POSIX.C:963
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
Namespace for OpenFOAM.
static const word prefix
The prefix to local: lagrangian.
Definition: cloud.H:93