1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation, either version 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "MapLagrangianFields.H"
27 #include "CloudTemplate.H"
28 #include "passiveParticle.H"
29 #include "meshSearch.H"
31 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 static const scalar perturbFactor = 1E-6;
39 // Special version of findCell that generates a cell guaranteed to be
40 // compatible with tracking.
41 static label findCell(const meshSearch& meshSearcher, const point& pt)
43 const polyMesh& mesh = meshSearcher.mesh();
45 // Use tracking to find cell containing pt
46 label cellI = meshSearcher.findCell(pt);
54 // See if particle on face by finding nearest face and shifting
57 label faceI = meshSearcher.findNearestBoundaryFace(pt);
61 const point& cc = mesh.cellCentres()[mesh.faceOwner()[faceI]];
62 const point perturbPt = (1-perturbFactor)*pt+perturbFactor*cc;
64 return meshSearcher.findCell(perturbPt);
71 void mapLagrangian(const meshToMesh& meshToMeshInterp)
73 // Determine which particles are in meshTarget
74 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
76 // target to source cell map
77 const labelList& cellAddressing = meshToMeshInterp.cellAddressing();
79 // Invert celladdressing to get source to target(s).
80 // Note: could use sparse addressing but that is too storage inefficient
82 labelListList sourceToTargets
84 invertOneToMany(meshToMeshInterp.fromMesh().nCells(), cellAddressing)
87 const fvMesh& meshSource = meshToMeshInterp.fromMesh();
88 const fvMesh& meshTarget = meshToMeshInterp.toMesh();
89 const pointField& targetCc = meshTarget.cellCentres();
92 fileNameList cloudDirs
96 meshSource.time().timePath()/cloud::prefix,
101 forAll(cloudDirs, cloudI)
103 // Search for list of lagrangian objects for this time
107 meshSource.time().timeName(),
108 cloud::prefix/cloudDirs[cloudI]
111 IOobject* positionsPtr = objects.lookup("positions");
115 Info<< nl << " processing cloud " << cloudDirs[cloudI] << endl;
117 // Read positions & cell
118 Cloud<passiveParticle> sourceParcels
124 Info<< " read " << sourceParcels.size()
125 << " parcels from source mesh." << endl;
127 // Construct empty target cloud
128 Cloud<passiveParticle> targetParcels
132 IDLList<passiveParticle>()
135 label sourceParticleI = 0;
137 // Indices of source particles that get added to targetParcels
138 DynamicList<label> addParticles(sourceParcels.size());
140 // Unmapped particles
141 labelHashSet unmappedSource(sourceParcels.size());
144 // Initial: track from fine-mesh cell centre to particle position
145 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146 // This requires there to be no boundary in the way.
149 forAllConstIter(Cloud<passiveParticle>, sourceParcels, iter)
151 bool foundCell = false;
153 // Assume that cell from read parcel is the correct one...
154 if (iter().cell() >= 0)
156 const labelList& targetCells =
157 sourceToTargets[iter().cell()];
159 // Particle probably in one of the targetcells. Try
160 // all by tracking from their cell centre to the parcel
163 forAll(targetCells, i)
165 // Track from its cellcentre to position to make sure.
166 autoPtr<passiveParticle> newPtr
171 targetCc[targetCells[i]],
175 passiveParticle& newP = newPtr();
178 label faceI = newP.track(iter().position(), fraction);
180 if (faceI < 0 && newP.cell() >= 0)
184 addParticles.append(sourceParticleI);
185 targetParcels.addParticle(newPtr.ptr());
193 // Store for closer analysis
194 unmappedSource.insert(sourceParticleI);
200 Info<< " after meshToMesh addressing found "
201 << targetParcels.size()
202 << " parcels in target mesh." << endl;
205 // Do closer inspection for unmapped particles
206 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
208 if (unmappedSource.size())
210 meshSearch targetSearcher(meshTarget, false);
214 forAllIter(Cloud<passiveParticle>, sourceParcels, iter)
216 if (unmappedSource.found(sourceParticleI))
219 findCell(targetSearcher, iter().position());
223 unmappedSource.erase(sourceParticleI);
224 addParticles.append(sourceParticleI);
225 iter().cell()=targetCell;
226 targetParcels.addParticle
228 sourceParcels.remove(&iter())
235 addParticles.shrink();
237 Info<< " after additional mesh searching found "
238 << targetParcels.size() << " parcels in target mesh." << endl;
240 if (addParticles.size())
242 IOPosition<passiveParticle>(targetParcels).write();
244 // addParticles now contains the indices of the sourceMesh
245 // particles that were appended to the target mesh.
247 // Map lagrangian fields
248 // ~~~~~~~~~~~~~~~~~~~~~
250 MapLagrangianFields<label>
251 (cloudDirs[cloudI], objects, meshToMeshInterp, addParticles);
252 MapLagrangianFields<scalar>
253 (cloudDirs[cloudI], objects, meshToMeshInterp, addParticles);
254 MapLagrangianFields<vector>
255 (cloudDirs[cloudI], objects, meshToMeshInterp, addParticles);
256 MapLagrangianFields<sphericalTensor>
257 (cloudDirs[cloudI], objects, meshToMeshInterp, addParticles);
258 MapLagrangianFields<symmTensor>
259 (cloudDirs[cloudI], objects, meshToMeshInterp, addParticles);
260 MapLagrangianFields<tensor>
261 (cloudDirs[cloudI], objects, meshToMeshInterp, addParticles);
268 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
270 } // End namespace Foam
272 // ************************************************************************* //