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 scalarField globalAngle(surfaceDicts.size(), -GREAT);
63 List<Map<label> > regionMinLevel(surfaceDicts.size());
64 List<Map<label> > regionMaxLevel(surfaceDicts.size());
65 List<Map<scalar> > regionAngle(surfaceDicts.size());
67 //wordList globalPatchType(surfaceDicts.size());
68 //List<HashTable<word> > regionPatchType(surfaceDicts.size());
69 //List<HashTable<word> > regionPatchName(surfaceDicts.size());
71 forAll(surfaceDicts, surfI)
73 const dictionary& dict = surfaceDicts[surfI];
75 dict.lookup("name") >> names_[surfI];
77 surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
79 // Global refinement level
80 globalMinLevel[surfI] = readLabel(dict.lookup("minRefinementLevel"));
81 globalMaxLevel[surfI] = readLabel(dict.lookup("maxRefinementLevel"));
83 // Global zone names per surface
84 if (dict.found("faceZone"))
86 dict.lookup("faceZone") >> faceZoneNames_[surfI];
87 dict.lookup("cellZone") >> cellZoneNames_[surfI];
88 dict.lookup("zoneInside") >> zoneInside_[surfI];
91 // Global perpendicular angle
92 if (dict.found("perpendicularAngle"))
94 globalAngle[surfI] = readScalar(dict.lookup("perpendicularAngle"));
97 //// Global patch name per surface
98 //if (dict.found("patchType"))
100 // dict.lookup("patchType") >> globalPatchType[surfI];
104 if (dict.found("regions"))
106 PtrList<dictionary> regionDicts(dict.lookup("regions"));
108 const wordList& regionNames =
109 allGeometry_[surfaces_[surfI]].regions();
111 forAll(regionDicts, dictI)
113 const dictionary& regionDict = regionDicts[dictI];
115 const word regionName(regionDict.lookup("name"));
117 label regionI = findIndex(regionNames, regionName);
123 "refinementSurfaces::refinementSurfaces"
124 "(const IOobject&, const PtrList<dictionary>&)"
125 ) << "No region called " << regionName << " on surface "
126 << allGeometry_[surfaces_[surfI]].name() << endl
127 << "Valid regions are " << regionNames
132 label min = readLabel(regionDict.lookup("minRefinementLevel"));
133 label max = readLabel(regionDict.lookup("maxRefinementLevel"));
135 bool hasInserted = regionMinLevel[surfI].insert(regionI, min);
140 "refinementSurfaces::refinementSurfaces"
141 "(const IOobject&, const PtrList<dictionary>&)"
142 ) << "Duplicate region name " << regionName
143 << " on surface " << names_[surfI]
146 regionMaxLevel[surfI].insert(regionI, max);
148 if (regionDict.found("perpendicularAngle"))
150 regionAngle[surfI].insert
153 readScalar(regionDict.lookup("perpendicularAngle"))
161 // Check for duplicate surface names
163 HashTable<label> surfaceNames(names_.size());
165 forAll(names_, surfI)
167 if (!surfaceNames.insert(names_[surfI], surfI))
171 "refinementSurfaces::refinementSurfaces"
172 "(const IOobject&, const PtrList<dictionary>&)"
173 ) << "Duplicate surface name " << names_[surfI] << endl
174 << "Previous occurrence of name at surface "
175 << surfaceNames[names_[surfI]]
181 // Calculate local to global region offset
184 forAll(surfaceDicts, surfI)
186 regionOffset_[surfI] = nRegions;
188 nRegions += allGeometry_[surfaces_[surfI]].regions().size();
191 // Rework surface specific information into information per global region
192 minLevel_.setSize(nRegions);
194 maxLevel_.setSize(nRegions);
196 perpendicularAngle_.setSize(nRegions);
197 perpendicularAngle_ = -GREAT;
198 //patchName_.setSize(nRegions);
199 //patchType_.setSize(nRegions);
201 forAll(surfaceDicts, surfI)
203 label nRegions = allGeometry_[surfaces_[surfI]].regions().size();
205 // Initialise to global (i.e. per surface)
206 for (label i = 0; i < nRegions; i++)
208 minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI];
209 maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI];
210 perpendicularAngle_[regionOffset_[surfI] + i] = globalAngle[surfI];
213 // Overwrite with region specific information
214 forAllConstIter(Map<label>, regionMinLevel[surfI], iter)
216 label globalRegionI = regionOffset_[surfI] + iter.key();
218 minLevel_[globalRegionI] = iter();
219 maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()];
224 minLevel_[globalRegionI] < 0
225 || maxLevel_[globalRegionI] < minLevel_[globalRegionI]
230 "refinementSurfaces::refinementSurfaces"
231 "(const IOobject&, const PtrList<dictionary>&)"
232 ) << "Illegal level or layer specification for surface "
234 << " : minLevel:" << minLevel_[globalRegionI]
235 << " maxLevel:" << maxLevel_[globalRegionI]
239 forAllConstIter(Map<scalar>, regionAngle[surfI], iter)
241 label globalRegionI = regionOffset_[surfI] + iter.key();
243 perpendicularAngle_[globalRegionI] = regionAngle[surfI][iter.key()];
246 //// Optional patch names and patch types
247 //forAllConstIter(HashTable<word>, regionPatchName[surfI], iter)
249 // label regionI = findIndex(regionNames, iter.key());
250 // label globalRegionI = regionOffset_[surfI] + regionI;
252 // patchName_[globalRegionI] = iter();
253 // patchType_[globalRegionI] = regionPatchType[surfI][iter.key()];
259 Foam::refinementSurfaces::refinementSurfaces
261 const searchableSurfaces& allGeometry,
262 const dictionary& surfacesDict
265 allGeometry_(allGeometry),
266 surfaces_(surfacesDict.size()),
267 names_(surfacesDict.size()),
268 faceZoneNames_(surfacesDict.size()),
269 cellZoneNames_(surfacesDict.size()),
270 zoneInside_(surfacesDict.size()),
271 regionOffset_(surfacesDict.size())
273 labelList globalMinLevel(surfacesDict.size(), 0);
274 labelList globalMaxLevel(surfacesDict.size(), 0);
275 scalarField globalAngle(surfacesDict.size(), -GREAT);
276 List<Map<label> > regionMinLevel(surfacesDict.size());
277 List<Map<label> > regionMaxLevel(surfacesDict.size());
278 List<Map<scalar> > regionAngle(surfacesDict.size());
281 forAllConstIter(dictionary, surfacesDict, iter)
283 names_[surfI] = iter().keyword();
285 surfaces_[surfI] = allGeometry_.findSurfaceID(names_[surfI]);
287 if (surfaces_[surfI] == -1)
291 "refinementSurfaces::refinementSurfaces"
292 "(const searchableSurfaces&, const dictionary>&"
293 ) << "No surface called " << iter().keyword() << endl
294 << "Valid surfaces are " << allGeometry_.names()
297 const dictionary& dict = surfacesDict.subDict(iter().keyword());
299 const labelPair refLevel(dict.lookup("level"));
300 globalMinLevel[surfI] = refLevel[0];
301 globalMaxLevel[surfI] = refLevel[1];
303 // Global zone names per surface
304 if (dict.found("faceZone"))
306 dict.lookup("faceZone") >> faceZoneNames_[surfI];
307 dict.lookup("cellZone") >> cellZoneNames_[surfI];
308 dict.lookup("zoneInside") >> zoneInside_[surfI];
311 // Global perpendicular angle
312 if (dict.found("perpendicularAngle"))
314 globalAngle[surfI] = readScalar(dict.lookup("perpendicularAngle"));
317 if (dict.found("regions"))
319 const dictionary& regionsDict = dict.subDict("regions");
320 const wordList& regionNames =
321 allGeometry_[surfaces_[surfI]].regions();
323 forAllConstIter(dictionary, regionsDict, iter)
325 const word& key = iter().keyword();
327 if (regionsDict.isDict(key))
329 // Get the dictionary for region iter.keyword()
330 const dictionary& regionDict = regionsDict.subDict(key);
332 label regionI = findIndex(regionNames, key);
337 "refinementSurfaces::refinementSurfaces"
338 "(const searchableSurfaces&, const dictionary>&"
339 ) << "No region called " << key << " on surface "
340 << allGeometry_[surfaces_[surfI]].name() << endl
341 << "Valid regions are " << regionNames
345 const labelPair refLevel(regionDict.lookup("level"));
347 regionMinLevel[surfI].insert(regionI, refLevel[0]);
348 regionMaxLevel[surfI].insert(regionI, refLevel[1]);
350 if (regionDict.found("perpendicularAngle"))
352 regionAngle[surfI].insert
355 readScalar(regionDict.lookup("perpendicularAngle"))
364 // Calculate local to global region offset
367 forAll(surfacesDict, surfI)
369 regionOffset_[surfI] = nRegions;
370 nRegions += allGeometry_[surfaces_[surfI]].regions().size();
373 // Rework surface specific information into information per global region
374 minLevel_.setSize(nRegions);
376 maxLevel_.setSize(nRegions);
378 perpendicularAngle_.setSize(nRegions);
379 perpendicularAngle_ = -GREAT;
382 forAll(globalMinLevel, surfI)
384 label nRegions = allGeometry_[surfaces_[surfI]].regions().size();
386 // Initialise to global (i.e. per surface)
387 for (label i = 0; i < nRegions; i++)
389 minLevel_[regionOffset_[surfI] + i] = globalMinLevel[surfI];
390 maxLevel_[regionOffset_[surfI] + i] = globalMaxLevel[surfI];
391 perpendicularAngle_[regionOffset_[surfI] + i] = globalAngle[surfI];
394 // Overwrite with region specific information
395 forAllConstIter(Map<label>, regionMinLevel[surfI], iter)
397 label globalRegionI = regionOffset_[surfI] + iter.key();
399 minLevel_[globalRegionI] = iter();
400 maxLevel_[globalRegionI] = regionMaxLevel[surfI][iter.key()];
405 minLevel_[globalRegionI] < 0
406 || maxLevel_[globalRegionI] < minLevel_[globalRegionI]
411 "refinementSurfaces::refinementSurfaces"
412 "(const searchableSurfaces&, const dictionary>&"
413 ) << "Illegal level or layer specification for surface "
415 << " : minLevel:" << minLevel_[globalRegionI]
416 << " maxLevel:" << maxLevel_[globalRegionI]
421 forAllConstIter(Map<scalar>, regionAngle[surfI], iter)
423 label globalRegionI = regionOffset_[surfI] + iter.key();
425 perpendicularAngle_[globalRegionI] = regionAngle[surfI][iter.key()];
431 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
433 // Get indices of named surfaces (surfaces with cellZoneName)
434 Foam::labelList Foam::refinementSurfaces::getNamedSurfaces() const
436 labelList namedSurfaces(cellZoneNames_.size());
439 forAll(cellZoneNames_, surfI)
441 if (cellZoneNames_[surfI].size() > 0)
443 namedSurfaces[namedI++] = surfI;
446 namedSurfaces.setSize(namedI);
448 return namedSurfaces;
452 // Get indices of closed named surfaces
453 Foam::labelList Foam::refinementSurfaces::getClosedNamedSurfaces() const
455 labelList named(getNamedSurfaces());
457 labelList closed(named.size());
462 label surfI = named[i];
464 if (allGeometry_[surfaces_[surfI]].hasVolumeType())
466 closed[closedI++] = surfI;
469 closed.setSize(closedI);
475 // Orient surface (if they're closed) before any searching is done.
476 void Foam::refinementSurfaces::orientSurface
478 const point& keepPoint,
482 // Flip surface so keepPoint is outside.
483 bool anyFlipped = orientedSurface::orient(s, keepPoint, true);
487 // orientedSurface will have done a clearOut of the surface.
488 // we could do a clearout of the triSurfaceMeshes::trees()
489 // but these aren't affected by orientation (except for cached
490 // sideness which should not be set at this point. !!Should
493 Info<< "orientSurfaces : Flipped orientation of surface "
494 << s.searchableSurface::name()
495 << " so point " << keepPoint << " is outside." << endl;
500 // Count number of triangles per surface region
501 Foam::labelList Foam::refinementSurfaces::countRegions(const triSurface& s)
503 const geometricSurfacePatchList& regions = s.patches();
505 labelList nTris(regions.size(), 0);
509 nTris[s[triI].region()]++;
515 // Precalculate the refinement level for every element of the searchable
516 // surface. This is currently hardcoded for triSurfaceMesh only.
517 void Foam::refinementSurfaces::setMinLevelFields
519 const shellSurfaces& shells
522 minLevelFields_.setSize(surfaces_.size());
524 forAll(surfaces_, surfI)
526 const searchableSurface& geom = allGeometry_[surfaces_[surfI]];
528 if (isA<triSurfaceMesh>(geom))
530 const triSurfaceMesh& triMesh = refCast<const triSurfaceMesh>(geom);
535 new triSurfaceLabelField
539 triMesh.searchableSurface::name(),
540 triMesh.objectRegistry::time().constant(),// directory
541 "triSurface", // instance
544 IOobject::AUTO_WRITE,
551 triSurfaceLabelField& minLevelField = minLevelFields_[surfI];
553 const triSurface& s = static_cast<const triSurface&>(triMesh);
555 // Initialise fields to region wise minLevel
558 minLevelField[triI] = minLevel(surfI, s[triI].region());
561 // Find out if triangle inside shell with higher level
562 pointField fc(s.size());
565 fc[triI] = s[triI].centre(s.points());
567 // What level does shell want to refine fc to?
568 labelList shellLevel;
569 shells.findHigherLevel(fc, minLevelField, shellLevel);
571 forAll(minLevelField, triI)
573 minLevelField[triI] = max
584 // Find intersections of edge. Return -1 or first surface with higher minLevel
586 void Foam::refinementSurfaces::findHigherIntersection
588 const pointField& start,
589 const pointField& end,
590 const labelList& currentLevel, // current cell refinement level
593 labelList& surfaceLevel
596 surfaces.setSize(start.size());
598 surfaceLevel.setSize(start.size());
601 if (surfaces_.size() == 0)
607 labelList hitMap(identity(start.size()));
608 pointField p0(start);
610 List<pointIndexHit> hitInfo(start.size());
613 forAll(surfaces_, surfI)
615 allGeometry_[surfaces_[surfI]].findLineAny(p0, p1, hitInfo);
617 // Copy all hits into arguments, continue with misses
619 forAll(hitInfo, hitI)
621 // Get the minLevel for the point
622 label minLocalLevel = -1;
624 if (hitInfo[hitI].hit())
626 // Check if minLevelField for this surface.
629 minLevelFields_.set(surfI)
630 && minLevelFields_[surfI].size() > 0
634 minLevelFields_[surfI][hitInfo[hitI].index()];
638 // Use the min level for the surface instead. Assume
640 minLocalLevel = minLevel(surfI, 0);
644 label pointI = hitMap[hitI];
646 if (minLocalLevel > currentLevel[pointI])
648 surfaces[pointI] = surfI;
649 surfaceLevel[pointI] = minLocalLevel;
655 hitMap[newI] = hitMap[hitI];
663 // All done? Note that this decision should be synchronised
670 hitMap.setSize(newI);
673 hitInfo.setSize(newI);
678 void Foam::refinementSurfaces::findAllHigherIntersections
680 const pointField& start,
681 const pointField& end,
682 const labelList& currentLevel, // current cell refinement level
684 List<vectorList>& surfaceNormal,
685 labelListList& surfaceLevel
688 surfaceLevel.setSize(start.size());
689 surfaceNormal.setSize(start.size());
691 if (surfaces_.size() == 0)
697 List<List<pointIndexHit> > hitInfo;
699 vectorField pNormals;
701 forAll(surfaces_, surfI)
703 allGeometry_[surfaces_[surfI]].findLineAll(start, end, hitInfo);
705 forAll(hitInfo, pointI)
707 const List<pointIndexHit>& pHits = hitInfo[pointI];
708 allGeometry_[surfaces_[surfI]].getRegion(pHits, pRegions);
709 allGeometry_[surfaces_[surfI]].getNormal(pHits, pNormals);
711 // Extract those hits that are on higher levelled surfaces.
712 // Note: should move extraction of region, normal outside of loop
713 // below for if getRegion/getNormal have high overhead.
717 label region = globalRegion(surfI, pRegions[pHitI]);
719 if (maxLevel_[region] > currentLevel[pointI])
721 // Append to pointI info
722 label sz = surfaceNormal[pointI].size();
723 surfaceNormal[pointI].setSize(sz+1);
724 surfaceNormal[pointI][sz] = pNormals[pHitI];
726 surfaceLevel[pointI].setSize(sz+1);
727 surfaceLevel[pointI][sz] = maxLevel_[region];
735 void Foam::refinementSurfaces::findNearestIntersection
737 const labelList& surfacesToTest,
738 const pointField& start,
739 const pointField& end,
742 List<pointIndexHit>& hit1,
745 List<pointIndexHit>& hit2,
749 // 1. intersection from start to end
750 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
752 // Initialize arguments
753 surface1.setSize(start.size());
755 hit1.setSize(start.size());
756 region1.setSize(start.size());
758 // Current end of segment to test.
759 pointField nearest(end);
761 List<pointIndexHit> nearestInfo(start.size());
764 forAll(surfacesToTest, testI)
766 label surfI = surfacesToTest[testI];
768 // See if any intersection between start and current nearest
769 allGeometry_[surfaces_[surfI]].findLine
775 allGeometry_[surfaces_[surfI]].getRegion
781 forAll(nearestInfo, pointI)
783 if (nearestInfo[pointI].hit())
785 hit1[pointI] = nearestInfo[pointI];
786 surface1[pointI] = surfI;
787 region1[pointI] = region[pointI];
788 nearest[pointI] = hit1[pointI].hitPoint();
794 // 2. intersection from end to last intersection
795 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
797 // Find the nearest intersection from end to start. Note that we initialize
798 // to the first intersection (if any).
803 // Set current end of segment to test.
804 forAll(nearest, pointI)
806 if (hit1[pointI].hit())
808 nearest[pointI] = hit1[pointI].hitPoint();
812 // Disable testing by setting to end.
813 nearest[pointI] = end[pointI];
817 forAll(surfacesToTest, testI)
819 label surfI = surfacesToTest[testI];
821 // See if any intersection between end and current nearest
822 allGeometry_[surfaces_[surfI]].findLine
828 allGeometry_[surfaces_[surfI]].getRegion
834 forAll(nearestInfo, pointI)
836 if (nearestInfo[pointI].hit())
838 hit2[pointI] = nearestInfo[pointI];
839 surface2[pointI] = surfI;
840 region2[pointI] = region[pointI];
841 nearest[pointI] = hit2[pointI].hitPoint();
847 // Make sure that if hit1 has hit something, hit2 will have at least the
848 // same point (due to tolerances it might miss its end point)
851 if (hit1[pointI].hit() && !hit2[pointI].hit())
853 hit2[pointI] = hit1[pointI];
854 surface2[pointI] = surface1[pointI];
855 region2[pointI] = region1[pointI];
861 void Foam::refinementSurfaces::findAnyIntersection
863 const pointField& start,
864 const pointField& end,
866 labelList& hitSurface,
867 List<pointIndexHit>& hitInfo
870 searchableSurfacesQueries::findAnyIntersection
882 void Foam::refinementSurfaces::findNearest
884 const labelList& surfacesToTest,
885 const pointField& samples,
886 const scalarField& nearestDistSqr,
887 labelList& hitSurface,
888 List<pointIndexHit>& hitInfo
891 labelList geometries(IndirectList<label>(surfaces_, surfacesToTest));
893 // Do the tests. Note that findNearest returns index in geometries.
894 searchableSurfacesQueries::findNearest
904 // Rework the hitSurface to be surface (i.e. index into surfaces_)
905 forAll(hitSurface, pointI)
907 if (hitSurface[pointI] != -1)
909 hitSurface[pointI] = surfacesToTest[hitSurface[pointI]];
915 //// Find intersection with max of edge. Return -1 or the surface
916 //// with the highest maxLevel above currentLevel
917 //Foam::label Foam::refinementSurfaces::findHighestIntersection
919 // const point& start,
921 // const label currentLevel, // current cell refinement level
923 // pointIndexHit& maxHit
926 // // surface with highest maxlevel
927 // label maxSurface = -1;
928 // // maxLevel of maxSurface
929 // label maxLevel = currentLevel;
931 // forAll(*this, surfI)
933 // pointIndexHit hit = operator[](surfI).findLineAny(start, end);
937 // const triSurface& s = operator[](surfI);
939 // label region = globalRegion(surfI, s[hit.index()].region());
941 // if (maxLevel_[region] > maxLevel)
943 // maxSurface = surfI;
944 // maxLevel = maxLevel_[region];
950 // if (maxSurface == -1)
952 // // maxLevel unchanged. No interesting surface hit.
956 // return maxSurface;
960 void Foam::refinementSurfaces::findInside
962 const labelList& testSurfaces,
963 const pointField& pt,
964 labelList& insideSurfaces
967 insideSurfaces.setSize(pt.size());
970 forAll(testSurfaces, i)
972 label surfI = testSurfaces[i];
974 if (allGeometry_[surfaces_[surfI]].hasVolumeType())
976 List<searchableSurface::volumeType> volType;
977 allGeometry_[surfaces_[surfI]].getVolumeType(pt, volType);
979 forAll(volType, pointI)
981 if (insideSurfaces[pointI] == -1)
986 volType[pointI] == triSurfaceMesh::INSIDE
987 && zoneInside_[surfI]
990 volType[pointI] == triSurfaceMesh::OUTSIDE
991 && !zoneInside_[surfI]
995 insideSurfaces[pointI] = surfI;
1004 // ************************************************************************* //