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 \*---------------------------------------------------------------------------*/
28 #include "cellIOList.H"
29 #include "wedgePolyPatch.H"
30 #include "emptyPolyPatch.H"
31 #include "globalMeshData.H"
32 #include "processorPolyPatch.H"
33 #include "indexedOctree.H"
34 #include "treeDataCell.H"
35 #include "MeshObject.H"
36 #include "pointMesh.H"
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 defineTypeNameAndDebug(Foam::polyMesh, 0);
43 Foam::word Foam::polyMesh::defaultRegion = "region0";
44 Foam::word Foam::polyMesh::meshSubDir = "polyMesh";
47 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
49 void Foam::polyMesh::calcDirections() const
51 for (direction cmpt = 0; cmpt < vector::nComponents; cmpt++)
56 // Knock out empty and wedge directions. Note:they will be present on all
59 vector emptyDirVec = vector::zero;
60 vector wedgeDirVec = vector::zero;
62 forAll (boundaryMesh(), patchi)
64 if (boundaryMesh()[patchi].size())
66 if (isA<emptyPolyPatch>(boundaryMesh()[patchi]))
69 sum(cmptMag(boundaryMesh()[patchi].faceAreas()));
71 else if (isA<wedgePolyPatch>(boundaryMesh()[patchi]))
73 const wedgePolyPatch& wpp = refCast<const wedgePolyPatch>
75 boundaryMesh()[patchi]
78 wedgeDirVec += cmptMag(wpp.centreNormal());
83 vector globalEmptyDirVec = emptyDirVec;
84 reduce(globalEmptyDirVec, sumOp<vector>());
86 if (mag(emptyDirVec) > SMALL)
88 emptyDirVec /= mag(emptyDirVec);
91 if (Pstream::parRun() && mag(globalEmptyDirVec) > SMALL)
93 globalEmptyDirVec /= mag(globalEmptyDirVec);
95 // Check if all processors see the same 2-D from empty patches
96 if (mag(globalEmptyDirVec - emptyDirVec) > SMALL)
100 "void polyMesh::calcDirections() const"
101 ) << "Some processors detect different empty (2-D) "
102 << "directions. Probably using empty patches on a "
103 << "bad parallel decomposition." << nl
104 << "Please check your geometry and empty patches"
105 << abort(FatalError);
109 if (mag(emptyDirVec) > SMALL)
111 for (direction cmpt = 0; cmpt < vector::nComponents; cmpt++)
113 if (emptyDirVec[cmpt] > 1e-6)
115 solutionD_[cmpt] = -1;
119 solutionD_[cmpt] = 1;
125 // Knock out wedge directions
127 geometricD_ = solutionD_;
129 vector globalWedgeDirVec = wedgeDirVec;
130 reduce(globalWedgeDirVec, sumOp<vector>());
132 if (mag(wedgeDirVec) > SMALL)
134 wedgeDirVec /= mag(wedgeDirVec);
137 if (Pstream::parRun() && mag(globalWedgeDirVec) > SMALL)
139 globalWedgeDirVec /= mag(globalWedgeDirVec);
141 // Check if all processors see the same 2-D from wedge patches
142 if (mag(globalWedgeDirVec - wedgeDirVec) > SMALL)
146 "void polyMesh::calcDirections() const"
147 ) << "Some processors detect different wedge (2-D) "
148 << "directions. Probably using wedge patches on a "
149 << "bad parallel decomposition." << nl
150 << "Please check your geometry and wedge patches"
151 << abort(FatalError);
155 if (mag(wedgeDirVec) > SMALL)
157 for (direction cmpt = 0; cmpt < vector::nComponents; cmpt++)
159 if (wedgeDirVec[cmpt] > 1e-6)
161 geometricD_[cmpt] = -1;
165 geometricD_[cmpt] = 1;
172 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
174 Foam::polyMesh::polyMesh(const IOobject& io)
183 time().findInstance(meshDir(), "points"),
190 // To be re-sliced later. HJ, 19/oct/2008
191 points_(allPoints_, allPoints_.size()),
197 time().findInstance(meshDir(), "faces"),
204 // To be re-sliced later. HJ, 19/oct/2008
205 faces_(allFaces_, allFaces_.size()),
211 time().findInstance(meshDir(), "faces"),
214 IOobject::READ_IF_PRESENT,
223 time().findInstance(meshDir(), "faces"),
226 IOobject::READ_IF_PRESENT,
230 clearedPrimitives_(false),
236 time().findInstance(meshDir(), "boundary"),
245 geometricD_(Vector<label>::zero),
246 solutionD_(Vector<label>::zero),
256 IOobject::READ_IF_PRESENT
260 IOobject::READ_IF_PRESENT,
274 IOobject::READ_IF_PRESENT
278 IOobject::READ_IF_PRESENT,
292 IOobject::READ_IF_PRESENT
296 IOobject::READ_IF_PRESENT,
301 globalMeshDataPtr_(NULL),
304 curMotionTimeIndex_(time().timeIndex()),
305 oldAllPointsPtr_(NULL),
308 if (exists(owner_.objectPath()))
319 // Find the cells file on the basis of the faces file
321 // time().findInstance(meshDir(), "cells"),
322 time().findInstance(meshDir(), "faces"),
331 // Set the primitive mesh
338 // Calculate topology for the patches (processor-processor comms etc.)
339 boundary_.updateMesh();
341 // Calculate the geometry for the patches (transformation tensors etc.)
342 boundary_.calcGeometry();
344 // Warn if global empty mesh (constructs globalData!)
345 if (globalData().nTotalPoints() == 0)
347 WarningIn("polyMesh(const IOobject&)")
348 << "no points in mesh" << endl;
350 if (globalData().nTotalCells() == 0)
352 WarningIn("polyMesh(const IOobject&)")
353 << "no cells in mesh" << endl;
358 Foam::polyMesh::polyMesh
361 const Xfer<pointField>& points,
362 const Xfer<faceList>& faces,
363 const Xfer<labelList>& owner,
364 const Xfer<labelList>& neighbour,
383 // To be re-sliced later. HJ, 19/Oct/2008
384 points_(allPoints_, allPoints_.size()),
398 // To be re-sliced later. HJ, 19/Oct/2008
399 faces_(allFaces_, allFaces_.size()),
426 clearedPrimitives_(false),
441 bounds_(allPoints_, syncPar),
442 geometricD_(Vector<label>::zero),
443 solutionD_(Vector<label>::zero),
486 globalMeshDataPtr_(NULL),
489 curMotionTimeIndex_(time().timeIndex()),
490 oldAllPointsPtr_(NULL),
493 // Check if the faces and cells are valid
494 forAll (allFaces_, faceI)
496 const face& curFace = allFaces_[faceI];
498 if (min(curFace) < 0 || max(curFace) > allPoints_.size())
502 "polyMesh::polyMesh\n"
504 " const IOobject& io,\n"
505 " const pointField& points,\n"
506 " const faceList& faces,\n"
507 " const cellList& cells\n"
509 ) << "Face " << faceI << "contains vertex labels out of range: "
510 << curFace << " Max point index = " << allPoints_.size()
511 << abort(FatalError);
515 // Set the primitive mesh
520 Foam::polyMesh::polyMesh
523 const Xfer<pointField>& points,
524 const Xfer<faceList>& faces,
525 const Xfer<cellList>& cells,
544 // To be re-sliced later. HJ, 19/Oct/2008
545 points_(allPoints_, allPoints_.size()),
559 faces_(allFaces_, allFaces_.size()),
586 clearedPrimitives_(false),
601 bounds_(allPoints_, syncPar),
602 geometricD_(Vector<label>::zero),
603 solutionD_(Vector<label>::zero),
646 globalMeshDataPtr_(NULL),
649 curMotionTimeIndex_(time().timeIndex()),
650 oldAllPointsPtr_(NULL),
653 // Check if the faces and cells are valid
654 forAll (allFaces_, faceI)
656 const face& curFace = allFaces_[faceI];
658 if (min(curFace) < 0 || max(curFace) > allPoints_.size())
662 "polyMesh::polyMesh\n"
664 " const IOobject&,\n"
665 " const Xfer<pointField>&,\n"
666 " const Xfer<faceList>&,\n"
667 " const Xfer<cellList>&\n"
669 ) << "Face " << faceI << "contains vertex labels out of range: "
670 << curFace << " Max point index = " << allPoints_.size()
671 << abort(FatalError);
675 // transfer in cell list
676 cellList cLst(cells);
678 // Check if cells are valid
681 const cell& curCell = cLst[cellI];
683 if (min(curCell) < 0 || max(curCell) > allFaces_.size())
687 "polyMesh::polyMesh\n"
689 " const IOobject&,\n"
690 " const Xfer<pointField>&,\n"
691 " const Xfer<faceList>&,\n"
692 " const Xfer<cellList>&\n"
694 ) << "Cell " << cellI << "contains face labels out of range: "
695 << curCell << " Max face index = " << allFaces_.size()
696 << abort(FatalError);
700 // Set the primitive mesh
705 void Foam::polyMesh::resetPrimitives
707 const Xfer<pointField>& pts,
708 const Xfer<faceList>& fcs,
709 const Xfer<labelList>& own,
710 const Xfer<labelList>& nei,
711 const labelList& patchSizes,
712 const labelList& patchStarts,
713 const bool validBoundary
716 // Clear addressing. Keep geometric props for mapping.
719 // Take over new primitive data.
720 // Optimized to avoid overwriting data at all
723 allPoints_.transfer(pts());
725 // Recalculate bounds with all points. HJ, 17/Oct/2008
726 // ... if points have change. HJ, 19/Aug/2010
727 bounds_ = boundBox(allPoints_, validBoundary);
732 allFaces_.transfer(fcs());
733 // Faces will be reset in initMesh(), using size of owner list
738 owner_.transfer(own());
743 neighbour_.transfer(nei());
747 // Reset patch sizes and starts
748 forAll (boundary_, patchI)
750 boundary_[patchI] = polyPatch
752 boundary_[patchI].name(),
761 // Flags the mesh files as being changed
762 setInstance(time().timeName());
764 // Check if the faces and cells are valid
765 forAll (allFaces_, faceI)
767 const face& curFace = allFaces_[faceI];
769 if (curFace.size() == 0)
773 "polyMesh::polyMesh::resetPrimitives\n"
775 " const Xfer<pointField>& points,\n"
776 " const Xfer<faceList>& faces,\n"
777 " const Xfer<labelList>& owner,\n"
778 " const Xfer<labelList>& neighbour,\n"
779 " const labelList& patchSizes,\n"
780 " const labelList& patchStarts\n"
782 ) << "Face " << faceI << " contains no vertex labels"
783 << abort(FatalError);
785 else if (min(curFace) < 0 || max(curFace) > allPoints_.size())
789 "polyMesh::polyMesh::resetPrimitives\n"
791 " const Xfer<pointField>& points,\n"
792 " const Xfer<faceList>& faces,\n"
793 " const Xfer<labelList>& owner,\n"
794 " const Xfer<labelList>& neighbour,\n"
795 " const labelList& patchSizes,\n"
796 " const labelList& patchStarts\n"
798 ) << "Face " << faceI << " contains vertex labels out of range: "
799 << curFace << " Max point index = " << allPoints_.size()
800 << abort(FatalError);
805 // Set the primitive mesh from the owner_, neighbour_.
806 // Works out from patch end where the active faces stop.
812 // Note that we assume that all the patches stay the same and are
813 // correct etc. so we can already use the patches to do
814 // processor-processor comms.
816 // Calculate topology for the patches (processor-processor comms etc.)
817 boundary_.updateMesh();
819 // Calculate the geometry for the patches (transformation tensors etc.)
820 boundary_.calcGeometry();
822 // Warn if global empty mesh (constructs globalData!)
825 globalData().nTotalPoints() == 0
826 || globalData().nTotalCells() == 0
831 "polyMesh::polyMesh::resetPrimitives\n"
833 " const Xfer<pointField>&,\n"
834 " const Xfer<faceList>&,\n"
835 " const Xfer<labelList>& owner,\n"
836 " const Xfer<labelList>& neighbour,\n"
837 " const labelList& patchSizes,\n"
838 " const labelList& patchStarts\n"
841 << "no points or no cells in mesh" << endl;
845 // Update zones. 1.6.x merge. HJ, 30/Aug/2010
846 pointZones_.updateMesh();
847 faceZones_.updateMesh();
848 cellZones_.updateMesh();
852 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
854 Foam::polyMesh::~polyMesh()
861 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
863 const Foam::fileName& Foam::polyMesh::dbDir() const
865 if (objectRegistry::dbDir() == defaultRegion)
867 return parent().dbDir();
871 return objectRegistry::dbDir();
876 Foam::fileName Foam::polyMesh::meshDir() const
878 return dbDir()/meshSubDir;
882 const Foam::fileName& Foam::polyMesh::pointsInstance() const
884 return allPoints_.instance();
888 const Foam::fileName& Foam::polyMesh::facesInstance() const
890 return allFaces_.instance();
894 const Foam::Vector<Foam::label>& Foam::polyMesh::geometricD() const
896 if (geometricD_.x() == 0)
905 Foam::label Foam::polyMesh::nGeometricD() const
907 return cmptSum(geometricD() + Vector<label>::one)/2;
911 const Foam::Vector<Foam::label>& Foam::polyMesh::solutionD() const
913 if (solutionD_.x() == 0)
922 Foam::label Foam::polyMesh::nSolutionD() const
924 return cmptSum(solutionD() + Vector<label>::one)/2;
928 // Add boundary patches. Constructor helper
929 void Foam::polyMesh::addPatches
931 const List<polyPatch*>& p,
932 const bool validBoundary
935 if (boundaryMesh().size())
939 "void polyMesh::addPatches(const List<polyPatch*>&, const bool)"
940 ) << "boundary already exists"
941 << abort(FatalError);
944 // Reset valid directions
945 geometricD_ = Vector<label>::zero;
946 solutionD_ = Vector<label>::zero;
948 boundary_.setSize(p.size());
950 // Copy the patch pointers
953 boundary_.set(pI, p[pI]);
956 // parallelData depends on the processorPatch ordering so force
957 // recalculation. Problem: should really be done in removeBoundary but
958 // there is some info in parallelData which might be interesting inbetween
959 // removeBoundary and addPatches.
960 deleteDemandDrivenData(globalMeshDataPtr_);
964 // Calculate topology for the patches (processor-processor comms etc.)
965 boundary_.updateMesh();
967 // Calculate the geometry for the patches (transformation tensors etc.)
968 boundary_.calcGeometry();
970 boundary_.checkDefinition();
975 // Add mesh zones. Constructor helper
976 void Foam::polyMesh::addZones
978 const List<pointZone*>& pz,
979 const List<faceZone*>& fz,
980 const List<cellZone*>& cz
985 pointZones().size() > 0
986 || faceZones().size() > 0
987 || cellZones().size() > 0
994 " const List<pointZone*>&,\n"
995 " const List<faceZone*>&,\n"
996 " const List<cellZone*>&\n"
998 ) << "point, face or cell zone already exists"
999 << abort(FatalError);
1005 pointZones_.setSize(pz.size());
1007 // Copy the zone pointers
1010 pointZones_.set(pI, pz[pI]);
1013 pointZones_.writeOpt() = IOobject::AUTO_WRITE;
1015 // Temporarily disable zone writing on creation
1016 // Auto-write should be sufficient. HJ, 20/Aug/2009
1017 // pointZones_.write();
1023 faceZones_.setSize(fz.size());
1025 // Copy the zone pointers
1028 faceZones_.set(fI, fz[fI]);
1031 faceZones_.writeOpt() = IOobject::AUTO_WRITE;
1033 // Temporarily disable zone writing on creation
1034 // Auto-write should be sufficient. HJ, 20/Aug/2009
1035 // faceZones_.write();
1041 cellZones_.setSize(cz.size());
1043 // Copy the zone pointers
1046 cellZones_.set(cI, cz[cI]);
1049 cellZones_.writeOpt() = IOobject::AUTO_WRITE;
1051 // Temporarily disable zone writing on creation
1052 // Auto-write should be sufficient. HJ, 20/Aug/2009
1053 // cellZones_.write();
1058 const Foam::pointField& Foam::polyMesh::allPoints() const
1060 if (clearedPrimitives_)
1062 FatalErrorIn("const pointField& polyMesh::allPoints() const")
1063 << "allPoints deallocated"
1064 << abort(FatalError);
1071 const Foam::pointField& Foam::polyMesh::points() const
1073 if (clearedPrimitives_)
1075 FatalErrorIn("const pointField& polyMesh::points() const")
1076 << "points deallocated"
1077 << abort(FatalError);
1084 const Foam::faceList& Foam::polyMesh::allFaces() const
1086 if (clearedPrimitives_)
1088 FatalErrorIn("const faceList& polyMesh::allFaces() const")
1089 << "allFaces deallocated"
1090 << abort(FatalError);
1097 const Foam::faceList& Foam::polyMesh::faces() const
1099 if (clearedPrimitives_)
1101 FatalErrorIn("const faceList& polyMesh::faces() const")
1102 << "faces deallocated"
1103 << abort(FatalError);
1110 const Foam::labelList& Foam::polyMesh::faceOwner() const
1116 const Foam::labelList& Foam::polyMesh::faceNeighbour() const
1122 // Return old mesh motion points
1123 const Foam::pointField& Foam::polyMesh::oldAllPoints() const
1125 if (!oldAllPointsPtr_)
1129 WarningIn("const pointField& polyMesh::oldAllPoints() const")
1130 << "Old points not available. Forcing storage of old points"
1134 oldAllPointsPtr_ = new pointField(allPoints_);
1135 curMotionTimeIndex_ = time().timeIndex();
1138 return *oldAllPointsPtr_;
1142 // Return old mesh motion points
1143 const Foam::pointField& Foam::polyMesh::oldPoints() const
1147 oldPointsPtr_ = new pointField::subField(oldAllPoints(), nPoints());
1150 return *oldPointsPtr_;
1154 Foam::tmp<Foam::scalarField> Foam::polyMesh::movePoints
1156 const pointField& newPoints
1161 Info<< "tmp<scalarField> polyMesh::movePoints(const pointField&) : "
1162 << " Moving points for time " << time().value()
1163 << " index " << time().timeIndex() << endl;
1168 // Pick up old points
1169 if (curMotionTimeIndex_ != time().timeIndex())
1171 // Mesh motion in the new time step
1172 deleteDemandDrivenData(oldAllPointsPtr_);
1173 deleteDemandDrivenData(oldPointsPtr_);
1174 oldAllPointsPtr_ = new pointField(allPoints_);
1175 curMotionTimeIndex_ = time().timeIndex();
1178 allPoints_ = newPoints;
1182 // Check mesh motion
1183 if (primitiveMesh::checkMeshMotion(allPoints_, true))
1185 Info<< "tmp<scalarField> polyMesh::movePoints"
1186 << "(const pointField&) : "
1187 << "Moving the mesh with given points will "
1188 << "invalidate the mesh." << nl
1189 << "Mesh motion should not be executed." << endl;
1193 allPoints_.writeOpt() = IOobject::AUTO_WRITE;
1194 allPoints_.instance() = time().timeName();
1196 points_.reset(allPoints_, nPoints());
1198 tmp<scalarField> sweptVols = primitiveMesh::movePoints
1204 // Adjust parallel shared points
1205 if (globalMeshDataPtr_)
1207 globalMeshDataPtr_->movePoints(allPoints_);
1210 // Force recalculation of all geometric data with new points
1212 bounds_ = boundBox(allPoints_);
1213 boundary_.movePoints(allPoints_);
1215 pointZones_.movePoints(allPoints_);
1216 faceZones_.movePoints(allPoints_);
1217 cellZones_.movePoints(allPoints_);
1219 // Reset valid directions (could change with rotation)
1220 geometricD_ = Vector<label>::zero;
1221 solutionD_ = Vector<label>::zero;
1223 // Update all function objects
1224 // Moved from fvMesh.C in 1.6.x merge. HJ, 29/Aug/2010
1225 meshObjectBase::allMovePoints<polyMesh>(*this);
1231 // Reset motion by deleting old points
1232 void Foam::polyMesh::resetMotion() const
1234 curMotionTimeIndex_ = 0;
1235 deleteDemandDrivenData(oldAllPointsPtr_);
1236 deleteDemandDrivenData(oldPointsPtr_);
1240 // Reset motion by deleting old points
1241 void Foam::polyMesh::setOldPoints
1243 const pointField& setPoints
1246 if(setPoints.size() != allPoints_.size())
1250 "polyMesh::setOldPoints\n"
1252 " const pointField& setPoints\n"
1254 ) << "setPoints size " << setPoints.size()
1255 << "different from the mesh points size "
1256 << allPoints_.size()
1257 << abort(FatalError);
1262 // Mesh motion in the new time step
1263 deleteDemandDrivenData(oldAllPointsPtr_);
1264 deleteDemandDrivenData(oldPointsPtr_);
1265 allPoints_ = setPoints;
1266 oldAllPointsPtr_ = new pointField(allPoints_);
1267 oldPointsPtr_ = new pointField::subField(oldAllPoints(), nPoints());
1268 curMotionTimeIndex_ = 0;
1269 primitiveMesh::clearGeom();
1273 // Return parallel info
1274 const Foam::globalMeshData& Foam::polyMesh::globalData() const
1276 if (!globalMeshDataPtr_)
1280 Pout<< "polyMesh::globalData() const : "
1281 << "Constructing parallelData from processor topology"
1284 // Construct globalMeshData using processorPatch information only.
1285 globalMeshDataPtr_ = new globalMeshData(*this);
1287 // Old method. HJ, 6/Dec/2006
1289 // // Check for parallel boundaries
1290 // bool parBoundaries = false;
1292 // forAll (boundaryMesh(), patchI)
1296 // typeid(boundaryMesh()[patchI])
1297 // == typeid(processorPolyPatch)
1300 // parBoundaries = true;
1305 // if (parBoundaries)
1307 // // All is well - read the parallel data
1310 // new globalMeshData
1315 // time().findInstance(meshDir(), "globalData"),
1318 // IOobject::MUST_READ,
1319 // IOobject::NO_WRITE
1326 // // The mesh has no parallel boundaries. Create and hook a
1327 // // "non-parallel" parallel info
1329 // new globalMeshData
1333 // false, // cyclicParallel. Remove when fixed
1345 return *globalMeshDataPtr_;
1349 // Remove all files and some subdirs (eg, sets)
1350 void Foam::polyMesh::removeFiles(const fileName& instanceDir) const
1352 fileName meshFilesPath = thisDb().path()/instanceDir/meshDir();
1354 rm(meshFilesPath/"points");
1355 rm(meshFilesPath/"faces");
1356 rm(meshFilesPath/"owner");
1357 rm(meshFilesPath/"neighbour");
1358 rm(meshFilesPath/"cells");
1359 rm(meshFilesPath/"boundary");
1360 rm(meshFilesPath/"pointZones");
1361 rm(meshFilesPath/"faceZones");
1362 rm(meshFilesPath/"cellZones");
1363 rm(meshFilesPath/"meshModifiers");
1364 rm(meshFilesPath/"parallelData");
1366 // remove subdirectories
1367 if (isDir(meshFilesPath/"sets"))
1369 rmDir(meshFilesPath/"sets");
1374 void Foam::polyMesh::removeFiles() const
1376 removeFiles(instance());
1380 Foam::label Foam::polyMesh::findCell
1382 const point& location
1390 // Find the nearest cell centre to this location
1391 label cellI = findNearestCell(location);
1393 // If point is in the nearest cell return
1394 if (pointInCell(location, cellI))
1398 else // point is not in the nearest cell so search all cells
1400 for (label cellI = 0; cellI < nCells(); cellI++)
1402 if (pointInCell(location, cellI))
1412 // ************************************************************************* //