1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*----------------------------------------------------------------------------*/
27 #include "refinementSurfaces.H"
28 #include "orientedSurface.H"
30 #include "searchableSurfaces.H"
31 #include "shellSurfaces.H"
32 #include "triSurfaceMesh.H"
33 #include "labelPair.H"
34 #include "searchableSurfacesQueries.H"
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
45 // Construct from components
46 Foam::refinementSurfaces::refinementSurfaces
48 const searchableSurfaces& allGeometry,
49 const PtrList<dictionary>& surfaceDicts
52 allGeometry_(allGeometry),
53 surfaces_(surfaceDicts.size()),
54 names_(surfaceDicts.size()),
55 faceZoneNames_(surfaceDicts.size()),
56 cellZoneNames_(surfaceDicts.size()),
57 zoneInside_(surfaceDicts.size()),
58 regionOffset_(surfaceDicts.size())
60 labelList globalMinLevel(surfaceDicts.size(), 0);
61 labelList globalMaxLevel(surfaceDicts.size(), 0);
62 List<Map<label> > regionMinLevel(surfaceDicts.size());
63 List<Map<label> > regionMaxLevel(surfaceDicts.size());
65 //wordList globalPatchType(surfaceDicts.size());
66 //List<HashTable<word> > regionPatchType(surfaceDicts.size());
67 //List<HashTable<word> > regionPatchName(surfaceDicts.size());
69 forAll(surfaceDicts, surfI)
71 const dictionary& dict = surfaceDicts[surfI];
73 dict.lookup("name") >> names_[surfI];
75 surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
77 // Global refinement level
78 globalMinLevel[surfI] = readLabel(dict.lookup("minRefinementLevel"));
79 globalMaxLevel[surfI] = readLabel(dict.lookup("maxRefinementLevel"));
81 // Global zone names per surface
82 if (dict.found("faceZone"))
84 dict.lookup("faceZone") >> faceZoneNames_[surfI];
85 dict.lookup("cellZone") >> cellZoneNames_[surfI];
86 dict.lookup("zoneInside") >> zoneInside_[surfI];
89 //// Global patch name per surface
90 //if (dict.found("patchType"))
92 // dict.lookup("patchType") >> globalPatchType[surfI];
96 if (dict.found("regions"))
98 PtrList<dictionary> regionDicts(dict.lookup("regions"));
100 const wordList& regionNames =
101 allGeometry_[surfaces_[surfI]].regions();
103 forAll(regionDicts, dictI)
105 const dictionary& regionDict = regionDicts[dictI];
107 const word regionName(regionDict.lookup("name"));
109 label regionI = findIndex(regionNames, regionName);
115 "refinementSurfaces::refinementSurfaces"
116 "(const IOobject&, const PtrList<dictionary>&)"
117 ) << "No region called " << regionName << " on surface "
118 << allGeometry_[surfaces_[surfI]].name() << endl
119 << "Valid regions are " << regionNames
124 label min = readLabel(regionDict.lookup("minRefinementLevel"));
125 label max = readLabel(regionDict.lookup("maxRefinementLevel"));
127 bool hasInserted = regionMinLevel[surfI].insert(regionI, min);
132 "refinementSurfaces::refinementSurfaces"
133 "(const IOobject&, const PtrList<dictionary>&)"
134 ) << "Duplicate region name " << regionName
135 << " on surface " << names_[surfI]
138 regionMaxLevel[surfI].insert(regionI, max);
144 // Check for duplicate surface names
146 HashTable<label> surfaceNames(names_.size());
148 forAll(names_, surfI)
150 if (!surfaceNames.insert(names_[surfI], surfI))
154 "refinementSurfaces::refinementSurfaces"
155 "(const IOobject&, const PtrList<dictionary>&)"
156 ) << "Duplicate surface name " << names_[surfI] << endl
157 << "Previous occurrence of name at surface "
158 << surfaceNames[names_[surfI]]
164 // Calculate local to global region offset
167 forAll(surfaceDicts, surfI)
169 regionOffset_[surfI] = nRegions;
171 nRegions += allGeometry_[surfaces_[surfI]].regions().size();
174 // Rework surface specific information into information per global region
175 minLevel_.setSize(nRegions);
177 maxLevel_.setSize(nRegions);
179 //patchName_.setSize(nRegions);
180 //patchType_.setSize(nRegions);
182 forAll(surfaceDicts, surfI)
184 label nRegions = allGeometry_[surfaces_[surfI]].regions().size();
186 // Initialise to global (i.e. per surface)
187 for (label i = 0; i < nRegions; i++)
189 minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI];
190 maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI];
193 // Overwrite with region specific information
194 forAllConstIter(Map<label>, regionMinLevel[surfI], iter)
196 label globalRegionI = regionOffset_[surfI] + iter.key();
198 minLevel_[globalRegionI] = iter();
199 maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()];
204 minLevel_[globalRegionI] < 0
205 || maxLevel_[globalRegionI] < minLevel_[globalRegionI]
210 "refinementSurfaces::refinementSurfaces"
211 "(const IOobject&, const PtrList<dictionary>&)"
212 ) << "Illegal level or layer specification for surface "
214 << " : minLevel:" << minLevel_[globalRegionI]
215 << " maxLevel:" << maxLevel_[globalRegionI]
220 //// Optional patch names and patch types
221 //forAllConstIter(HashTable<word>, regionPatchName[surfI], iter)
223 // label regionI = findIndex(regionNames, iter.key());
224 // label globalRegionI = regionOffset_[surfI] + regionI;
226 // patchName_[globalRegionI] = iter();
227 // patchType_[globalRegionI] = regionPatchType[surfI][iter.key()];
233 Foam::refinementSurfaces::refinementSurfaces
235 const searchableSurfaces& allGeometry,
236 const dictionary& surfacesDict
239 allGeometry_(allGeometry),
240 surfaces_(surfacesDict.size()),
241 names_(surfacesDict.size()),
242 faceZoneNames_(surfacesDict.size()),
243 cellZoneNames_(surfacesDict.size()),
244 zoneInside_(surfacesDict.size()),
245 regionOffset_(surfacesDict.size())
247 labelList globalMinLevel(surfacesDict.size(), 0);
248 labelList globalMaxLevel(surfacesDict.size(), 0);
249 List<Map<label> > regionMinLevel(surfacesDict.size());
250 List<Map<label> > regionMaxLevel(surfacesDict.size());
253 forAllConstIter(dictionary, surfacesDict, iter)
255 names_[surfI] = iter().keyword();
257 surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
259 if (surfaces_[surfI] == -1)
263 "refinementSurfaces::refinementSurfaces"
264 "(const searchableSurfaces&, const dictionary>&"
265 ) << "No surface called " << iter().keyword() << endl
266 << "Valid surfaces are " << allGeometry_.names()
269 const dictionary& dict = surfacesDict.subDict(iter().keyword());
271 const labelPair refLevel(dict.lookup("level"));
272 globalMinLevel[surfI] = refLevel[0];
273 globalMaxLevel[surfI] = refLevel[1];
275 // Global zone names per surface
276 if (dict.found("faceZone"))
278 dict.lookup("faceZone") >> faceZoneNames_[surfI];
279 dict.lookup("cellZone") >> cellZoneNames_[surfI];
280 dict.lookup("zoneInside") >> zoneInside_[surfI];
283 if (dict.found("regions"))
285 const dictionary& regionsDict = dict.subDict("regions");
286 const wordList& regionNames =
287 allGeometry_[surfaces_[surfI]].regions();
289 forAllConstIter(dictionary, regionsDict, iter)
291 const word& key = iter().keyword();
293 if (regionsDict.isDict(key))
295 // Get the dictionary for region iter.keyword()
296 const dictionary& regionDict = regionsDict.subDict(key);
298 label regionI = findIndex(regionNames, key);
303 "refinementSurfaces::refinementSurfaces"
304 "(const searchableSurfaces&, const dictionary>&"
305 ) << "No region called " << key << " on surface "
306 << allGeometry_[surfaces_[surfI]].name() << endl
307 << "Valid regions are " << regionNames
311 const labelPair refLevel(regionDict.lookup("level"));
313 regionMinLevel[surfI].insert(regionI, refLevel[0]);
314 regionMaxLevel[surfI].insert(regionI, refLevel[1]);
321 // Calculate local to global region offset
324 forAll(surfacesDict, surfI)
326 regionOffset_[surfI] = nRegions;
327 nRegions += allGeometry_[surfaces_[surfI]].regions().size();
330 // Rework surface specific information into information per global region
331 minLevel_.setSize(nRegions);
333 maxLevel_.setSize(nRegions);
337 forAll(globalMinLevel, surfI)
339 label nRegions = allGeometry_[surfaces_[surfI]].regions().size();
341 // Initialise to global (i.e. per surface)
342 for (label i = 0; i < nRegions; i++)
344 minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI];
345 maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI];
348 // Overwrite with region specific information
349 forAllConstIter(Map<label>, regionMinLevel[surfI], iter)
351 label globalRegionI = regionOffset_[surfI] + iter.key();
353 minLevel_[globalRegionI] = iter();
354 maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()];
359 minLevel_[globalRegionI] < 0
360 || maxLevel_[globalRegionI] < minLevel_[globalRegionI]
365 "refinementSurfaces::refinementSurfaces"
366 "(const searchableSurfaces&, const dictionary>&"
367 ) << "Illegal level or layer specification for surface "
369 << " : minLevel:" << minLevel_[globalRegionI]
370 << " maxLevel:" << maxLevel_[globalRegionI]
378 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
380 // Get indices of named surfaces (surfaces with cellZoneName)
381 Foam::labelList Foam::refinementSurfaces::getNamedSurfaces() const
383 labelList namedSurfaces(cellZoneNames_.size());
386 forAll(cellZoneNames_, surfI)
388 if (cellZoneNames_[surfI].size() > 0)
390 namedSurfaces[namedI++] = surfI;
393 namedSurfaces.setSize(namedI);
395 return namedSurfaces;
399 // Get indices of closed named surfaces
400 Foam::labelList Foam::refinementSurfaces::getClosedNamedSurfaces() const
402 labelList named(getNamedSurfaces());
404 labelList closed(named.size());
409 label surfI = named[i];
411 if (allGeometry_[surfaces_[surfI]].hasVolumeType())
413 closed[closedI++] = surfI;
416 closed.setSize(closedI);
422 // Orient surface (if they're closed) before any searching is done.
423 void Foam::refinementSurfaces::orientSurface
425 const point& keepPoint,
429 // Flip surface so keepPoint is outside.
430 bool anyFlipped = orientedSurface::orient(s, keepPoint, true);
434 // orientedSurface will have done a clearOut of the surface.
435 // we could do a clearout of the triSurfaceMeshes::trees()
436 // but these aren't affected by orientation (except for cached
437 // sideness which should not be set at this point. !!Should
440 Info<< "orientSurfaces : Flipped orientation of surface "
441 << s.searchableSurface::name()
442 << " so point " << keepPoint << " is outside." << endl;
447 // Count number of triangles per surface region
448 Foam::labelList Foam::refinementSurfaces::countRegions(const triSurface& s)
450 const geometricSurfacePatchList& regions = s.patches();
452 labelList nTris(regions.size(), 0);
456 nTris[s[triI].region()]++;
462 // Precalculate the refinement level for every element of the searchable
463 // surface. This is currently hardcoded for triSurfaceMesh only.
464 void Foam::refinementSurfaces::setMinLevelFields
466 const shellSurfaces& shells
469 minLevelFields_.setSize(surfaces_.size());
471 forAll(surfaces_, surfI)
473 const searchableSurface& geom = allGeometry_[surfaces_[surfI]];
475 if (isA<triSurfaceMesh>(geom))
477 const triSurfaceMesh& triMesh = refCast<const triSurfaceMesh>(geom);
482 new triSurfaceLabelField
486 triMesh.searchableSurface::name(),
487 triMesh.objectRegistry::time().constant(),// directory
488 "triSurface", // instance
491 IOobject::AUTO_WRITE,
498 triSurfaceLabelField& minLevelField = minLevelFields_[surfI];
500 const triSurface& s = static_cast<const triSurface&>(triMesh);
502 // Initialise fields to region wise minLevel
505 minLevelField[triI] = minLevel(surfI, s[triI].region());
508 // Find out if triangle inside shell with higher level
509 pointField fc(s.size());
512 fc[triI] = s[triI].centre(s.points());
514 // What level does shell want to refine fc to?
515 labelList shellLevel;
516 shells.findHigherLevel(fc, minLevelField, shellLevel);
518 forAll(minLevelField, triI)
520 minLevelField[triI] = max
531 // Find intersections of edge. Return -1 or first surface with higher minLevel
533 void Foam::refinementSurfaces::findHigherIntersection
535 const pointField& start,
536 const pointField& end,
537 const labelList& currentLevel, // current cell refinement level
540 labelList& surfaceLevel
543 surfaces.setSize(start.size());
545 surfaceLevel.setSize(start.size());
548 if (surfaces_.size() == 0)
554 labelList hitMap(identity(start.size()));
555 pointField p0(start);
557 List<pointIndexHit> hitInfo(start.size());
560 forAll(surfaces_, surfI)
562 allGeometry_[surfaces_[surfI]].findLineAny(p0, p1, hitInfo);
564 // Copy all hits into arguments, continue with misses
566 forAll(hitInfo, hitI)
568 // Get the minLevel for the point
569 label minLocalLevel = -1;
571 if (hitInfo[hitI].hit())
573 // Check if minLevelField for this surface.
576 minLevelFields_.set(surfI)
577 && minLevelFields_[surfI].size() > 0
581 minLevelFields_[surfI][hitInfo[hitI].index()];
585 // Use the min level for the surface instead. Assume
587 minLocalLevel = minLevel(surfI, 0);
591 label pointI = hitMap[hitI];
593 if (minLocalLevel > currentLevel[pointI])
595 surfaces[pointI] = surfI;
596 surfaceLevel[pointI] = minLocalLevel;
602 hitMap[newI] = hitMap[hitI];
610 // All done? Note that this decision should be synchronised
617 hitMap.setSize(newI);
620 hitInfo.setSize(newI);
625 void Foam::refinementSurfaces::findAllHigherIntersections
627 const pointField& start,
628 const pointField& end,
629 const labelList& currentLevel, // current cell refinement level
631 List<vectorList>& surfaceNormal,
632 labelListList& surfaceLevel
635 surfaceLevel.setSize(start.size());
636 surfaceNormal.setSize(start.size());
638 if (surfaces_.size() == 0)
644 List<List<pointIndexHit> > hitInfo;
646 vectorField pNormals;
648 forAll(surfaces_, surfI)
650 allGeometry_[surfaces_[surfI]].findLineAll(start, end, hitInfo);
652 forAll(hitInfo, pointI)
654 const List<pointIndexHit>& pHits = hitInfo[pointI];
655 allGeometry_[surfaces_[surfI]].getRegion(pHits, pRegions);
656 allGeometry_[surfaces_[surfI]].getNormal(pHits, pNormals);
658 // Extract those hits that are on higher levelled surfaces.
659 // Note: should move extraction of region, normal outside of loop
660 // below for if getRegion/getNormal have high overhead.
664 label region = globalRegion(surfI, pRegions[pHitI]);
666 if (maxLevel_[region] > currentLevel[pointI])
668 // Append to pointI info
669 label sz = surfaceNormal[pointI].size();
670 surfaceNormal[pointI].setSize(sz+1);
671 surfaceNormal[pointI][sz] = pNormals[pHitI];
673 surfaceLevel[pointI].setSize(sz+1);
674 surfaceLevel[pointI][sz] = maxLevel_[region];
682 void Foam::refinementSurfaces::findNearestIntersection
684 const labelList& surfacesToTest,
685 const pointField& start,
686 const pointField& end,
689 List<pointIndexHit>& hit1,
692 List<pointIndexHit>& hit2,
696 // 1. intersection from start to end
697 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
699 // Initialize arguments
700 surface1.setSize(start.size());
702 hit1.setSize(start.size());
703 region1.setSize(start.size());
705 // Current end of segment to test.
706 pointField nearest(end);
708 List<pointIndexHit> nearestInfo(start.size());
711 forAll(surfacesToTest, testI)
713 label surfI = surfacesToTest[testI];
715 // See if any intersection between start and current nearest
716 allGeometry_[surfaces_[surfI]].findLine
722 allGeometry_[surfaces_[surfI]].getRegion
728 forAll(nearestInfo, pointI)
730 if (nearestInfo[pointI].hit())
732 hit1[pointI] = nearestInfo[pointI];
733 surface1[pointI] = surfI;
734 region1[pointI] = region[pointI];
735 nearest[pointI] = hit1[pointI].hitPoint();
741 // 2. intersection from end to last intersection
742 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
744 // Find the nearest intersection from end to start. Note that we initialize
745 // to the first intersection (if any).
750 // Set current end of segment to test.
751 forAll(nearest, pointI)
753 if (hit1[pointI].hit())
755 nearest[pointI] = hit1[pointI].hitPoint();
759 // Disable testing by setting to end.
760 nearest[pointI] = end[pointI];
764 forAll(surfacesToTest, testI)
766 label surfI = surfacesToTest[testI];
768 // See if any intersection between end and current nearest
769 allGeometry_[surfaces_[surfI]].findLine
775 allGeometry_[surfaces_[surfI]].getRegion
781 forAll(nearestInfo, pointI)
783 if (nearestInfo[pointI].hit())
785 hit2[pointI] = nearestInfo[pointI];
786 surface2[pointI] = surfI;
787 region2[pointI] = region[pointI];
788 nearest[pointI] = hit2[pointI].hitPoint();
795 void Foam::refinementSurfaces::findAnyIntersection
797 const pointField& start,
798 const pointField& end,
800 labelList& hitSurface,
801 List<pointIndexHit>& hitInfo
804 searchableSurfacesQueries::findAnyIntersection
816 void Foam::refinementSurfaces::findNearest
818 const labelList& surfacesToTest,
819 const pointField& samples,
820 const scalarField& nearestDistSqr,
821 labelList& hitSurface,
822 List<pointIndexHit>& hitInfo
825 labelList geometries(IndirectList<label>(surfaces_, surfacesToTest));
827 // Do the tests. Note that findNearest returns index in geometries.
828 searchableSurfacesQueries::findNearest
838 // Rework the hitSurface to be surface (i.e. index into surfaces_)
839 forAll(hitSurface, pointI)
841 if (hitSurface[pointI] != -1)
843 hitSurface[pointI] = surfacesToTest[hitSurface[pointI]];
849 //// Find intersection with max of edge. Return -1 or the surface
850 //// with the highest maxLevel above currentLevel
851 //Foam::label Foam::refinementSurfaces::findHighestIntersection
853 // const point& start,
855 // const label currentLevel, // current cell refinement level
857 // pointIndexHit& maxHit
860 // // surface with highest maxlevel
861 // label maxSurface = -1;
862 // // maxLevel of maxSurface
863 // label maxLevel = currentLevel;
865 // forAll(*this, surfI)
867 // pointIndexHit hit = operator[](surfI).findLineAny(start, end);
871 // const triSurface& s = operator[](surfI);
873 // label region = globalRegion(surfI, s[hit.index()].region());
875 // if (maxLevel_[region] > maxLevel)
877 // maxSurface = surfI;
878 // maxLevel = maxLevel_[region];
884 // if (maxSurface == -1)
886 // // maxLevel unchanged. No interesting surface hit.
890 // return maxSurface;
894 void Foam::refinementSurfaces::findInside
896 const labelList& testSurfaces,
897 const pointField& pt,
898 labelList& insideSurfaces
901 insideSurfaces.setSize(pt.size());
904 forAll(testSurfaces, i)
906 label surfI = testSurfaces[i];
908 if (allGeometry_[surfaces_[surfI]].hasVolumeType())
910 List<searchableSurface::volumeType> volType;
911 allGeometry_[surfaces_[surfI]].getVolumeType(pt, volType);
913 forAll(volType, pointI)
915 if (insideSurfaces[pointI] == -1)
920 volType[pointI] == triSurfaceMesh::INSIDE
921 && zoneInside_[surfI]
924 volType[pointI] == triSurfaceMesh::OUTSIDE
925 && !zoneInside_[surfI]
929 insideSurfaces[pointI] = surfI;
938 // ************************************************************************* //