Skip to content
Snippets Groups Projects
meshOctreeModifierRefineSelectedBoxes.C 19.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • franjo's avatar
    franjo committed
    /*---------------------------------------------------------------------------*\
      =========                 |
    
    franjo's avatar
    franjo committed
      \\      /  F ield         | cfMesh: A library for mesh generation
    
    franjo's avatar
    franjo committed
       \\    /   O peration     |
    
    franjo's avatar
    franjo committed
        \\  /    A nd           | Author: Franjo Juretic (franjo.juretic@c-fields.com)
         \\/     M anipulation  | Copyright (C) Creative Fields, Ltd.
    
    franjo's avatar
    franjo committed
    -------------------------------------------------------------------------------
    License
    
    franjo's avatar
    franjo committed
        This file is part of cfMesh.
    
    franjo's avatar
    franjo committed
    
    
    franjo's avatar
    franjo committed
        cfMesh is free software; you can redistribute it and/or modify it
    
    franjo's avatar
    franjo committed
        under the terms of the GNU General Public License as published by the
    
    franjo's avatar
    franjo committed
        Free Software Foundation; either version 3 of the License, or (at your
    
    franjo's avatar
    franjo committed
        option) any later version.
    
    
    franjo's avatar
    franjo committed
        cfMesh is distributed in the hope that it will be useful, but WITHOUT
    
    franjo's avatar
    franjo committed
        ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
        FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        for more details.
    
        You should have received a copy of the GNU General Public License
    
    franjo's avatar
    franjo committed
        along with cfMesh.  If not, see <http://www.gnu.org/licenses/>.
    
    franjo's avatar
    franjo committed
    
    Description
    
    \*---------------------------------------------------------------------------*/
    
    #include "meshOctreeModifier.H"
    #include "triSurf.H"
    #include "HashSet.H"
    
    #include "helperFunctions.H"
    
    #include "meshOctreeCubeCoordinatesScalar.H"
    
    franjo's avatar
    franjo committed
    
    
    franjo's avatar
    franjo committed
    # ifdef USE_OMP
    
    franjo's avatar
    franjo committed
    #include <omp.h>
    
    franjo's avatar
    franjo committed
    # endif
    
    
    franjo's avatar
    franjo committed
    #include <sys/stat.h>
    
    //#define OCTREETiming
    //#define DEBUGSearch
    
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    
    namespace Foam
    {
    
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    
    void meshOctreeModifier::markAdditionalLayers
    (
    
        labelList& refineBox,
        const label nLayers
    
    franjo's avatar
    franjo committed
    ) const
    {
        const LongList<meshOctreeCube*>& leaves = octree_.leaves_;
    
    
        //- this is needed for parallel runs to reduce the communication messages
    
    franjo's avatar
    franjo committed
        labelHashSet transferCoordinates;
    
    
        DynList<label> neiLeaves;
    
    franjo's avatar
    franjo committed
    
    
        for(label i=1;i<=nLayers;++i)
    
    franjo's avatar
    franjo committed
        {
            LongList<meshOctreeCubeCoordinates> processorChecks;
    
    
            transferCoordinates.clear();
    
            labelLongList activeLeaves;
            forAll(leaves, leafI)
                if( refineBox[leafI] == i )
                    activeLeaves.append(leafI);
    
    
    franjo's avatar
    franjo committed
            # ifdef USE_OMP
    
            # pragma omp parallel for private(neiLeaves) schedule(dynamic, 20)
    
    franjo's avatar
    franjo committed
            # endif
    
            forAll(activeLeaves, lI)
    
    franjo's avatar
    franjo committed
            {
    
                const label leafI = activeLeaves[lI];
    
    franjo's avatar
    franjo committed
    
    
                const meshOctreeCubeCoordinates& oc = leaves[leafI]->coordinates();
    
    franjo's avatar
    franjo committed
    
    
                octree_.findAllLeafNeighbours(oc, neiLeaves);
    
    franjo's avatar
    franjo committed
    
    
                forAll(neiLeaves, posI)
                {
                    const label neiLabel = neiLeaves[posI];
    
    franjo's avatar
    franjo committed
    
    
                    if( neiLabel == meshOctreeCubeBasic::OTHERPROC )
    
    franjo's avatar
    franjo committed
                    {
    
    franjo's avatar
    franjo committed
                        # ifdef USE_OMP
    
    franjo's avatar
    franjo committed
                        # pragma omp critical
    
    franjo's avatar
    franjo committed
                        # endif
    
    franjo's avatar
    franjo committed
                        {
                            if( !transferCoordinates.found(leafI) )
                            {
    
                                processorChecks.append(oc);
    
    franjo's avatar
    franjo committed
                                transferCoordinates.insert(leafI);
                            }
                        }
    
    franjo's avatar
    franjo committed
                    }
    
    
                    if( neiLabel < 0 )
                        continue;
    
    franjo's avatar
    franjo committed
    
    
                    if( !refineBox[neiLabel] )
                        refineBox[neiLabel] = i+1;
    
    franjo's avatar
    franjo committed
                }
            }
    
            if( octree_.neiProcs().size() )
            {
                LongList<meshOctreeCubeCoordinates> receivedCoords;
                octree_.exchangeRequestsWithNeighbourProcessors
                (
                    processorChecks,
                    receivedCoords
                );
    
                //- check consistency with received cube coordinates
    
    franjo's avatar
    franjo committed
                # ifdef USE_OMP
    
    franjo's avatar
    franjo committed
                # pragma omp parallel for if( receivedCoords.size() > 1000 ) \
    
                schedule(dynamic, 20) private(neiLeaves)
    
    franjo's avatar
    franjo committed
                # endif
    
    franjo's avatar
    franjo committed
                forAll(receivedCoords, ccI)
                {
    
                    octree_.findAllLeafNeighbours(receivedCoords[ccI], neiLeaves);
    
    franjo's avatar
    franjo committed
    
    
                    forAll(neiLeaves, posI)
                    {
                        if( neiLeaves[posI] < 0 )
                            continue;
    
    franjo's avatar
    franjo committed
    
    
                        if( !refineBox[neiLeaves[posI]] )
                            refineBox[neiLeaves[posI]] = i+1;
    
    void meshOctreeModifier::markAdditionalLayersOfFaceNeighbours
    (
        labelList& refineBox,
        const label nLayers
    ) const
    {
        const LongList<meshOctreeCube*>& leaves = octree_.leaves_;
    
        //- this is needed for parallel runs to reduce the communication messages
        labelHashSet transferCoordinates;
    
        DynList<label> neiLeaves;
    
        for(label i=1;i<=nLayers;++i)
        {
            LongList<meshOctreeCubeCoordinates> processorChecks;
    
            transferCoordinates.clear();
    
            labelLongList activeLeaves;
            forAll(leaves, leafI)
                if( refineBox[leafI] == i )
                    activeLeaves.append(leafI);
    
            # ifdef USE_OMP
            # pragma omp parallel for private(neiLeaves) schedule(dynamic, 20)
            # endif
            forAll(activeLeaves, lI)
            {
                const label leafI = activeLeaves[lI];
    
                const meshOctreeCubeCoordinates& oc = leaves[leafI]->coordinates();
    
                neiLeaves.clear();
                octree_.findNeighboursForLeaf(oc, neiLeaves);
    
                forAll(neiLeaves, posI)
                {
                    const label neiLabel = neiLeaves[posI];
    
                    if( neiLabel == meshOctreeCubeBasic::OTHERPROC )
                    {
                        # ifdef USE_OMP
                        # pragma omp critical
                        # endif
                        {
                            if( !transferCoordinates.found(leafI) )
                            {
                                processorChecks.append(oc);
                                transferCoordinates.insert(leafI);
                            }
                        }
    
                        continue;
                    }
    
                    if( neiLabel < 0 )
                        continue;
    
                    if( !refineBox[neiLabel] )
                        refineBox[neiLabel] = i+1;
                }
            }
    
            if( octree_.neiProcs().size() )
            {
                LongList<meshOctreeCubeCoordinates> receivedCoords;
                octree_.exchangeRequestsWithNeighbourProcessors
                (
                    processorChecks,
                    receivedCoords
                );
    
                //- check consistency with received cube coordinates
                # ifdef USE_OMP
                # pragma omp parallel for if( receivedCoords.size() > 1000 ) \
                schedule(dynamic, 20) private(neiLeaves)
                # endif
                forAll(receivedCoords, ccI)
                {
                    neiLeaves.clear();
                    octree_.findNeighboursForLeaf(receivedCoords[ccI], neiLeaves);
    
                    forAll(neiLeaves, posI)
                    {
                        if( neiLeaves[posI] < 0 )
                            continue;
    
                        if( !refineBox[neiLeaves[posI]] )
                            refineBox[neiLeaves[posI]] = i+1;
                    }
                }
            }
        }
    }
    
    # ifdef DEBUGSearch
    void writeLeaves
    (
        const fileName& fName,
        const meshOctree& octree,
        const labelList& markedBoxes,
        const label layer
    )
    {
        labelLongList activeLeaves;
    
        forAll(markedBoxes, leafI)
            if( markedBoxes[leafI] == layer )
                activeLeaves.append(leafI);
    
        OFstream file(fName);
    
        //- write the header
        file << "# vtk DataFile Version 3.0\n";
        file << "vtk output\n";
        file << "ASCII\n";
        file << "DATASET POLYDATA\n";
    
        //- write points
        file << "POINTS " << (8 * activeLeaves.size()) << " float\n";
        forAll(activeLeaves, i)
        {
            const label leafI = activeLeaves[i];
            FixedList<point, 8> vertices;
            octree.returnLeaf(leafI).vertices(octree.rootBox(), vertices);
    
            forAll(vertices, vI)
            {
                const point& p = vertices[vI];
    
                file << p.x() << ' ' << p.y() << ' ' << p.z() << nl;
            }
        }
    
        //- write lines
        file << "\nPOLYGONS " << (6*activeLeaves.size())
             << " " << 30*activeLeaves.size() << nl;
        forAll(activeLeaves, i)
        {
            const label startNode = 8 * i;
            for(label fI=0;fI<6;++fI)
            {
                file << 4;
    
                for(label pI=0;pI<4;++pI)
                    file << " " << (startNode+meshOctreeCube::faceNodes_[fI][pI]);
    
                file << nl;
            }
        }
    
        file << "\n";
    }
    # endif
    
    
    label meshOctreeModifier::markAdditionalLayers
    (
    
        labelList& refineBox,
    
        labelList& nLayers,
        List<direction>& targetRefLevel
    ) const
    {
        const LongList<meshOctreeCube*>& leaves = octree_.leaves_;
    
    
        # ifdef DEBUGSearch
        Info << "Marking additional layers " << endl;
        # endif
    
        //- sort leaves based on the number of additional layers
    
    Franjo's avatar
    Franjo committed
        label maxLevel = Foam::max(nLayers);
        reduce(maxLevel, maxOp<label>());
    
    Franjo's avatar
    Franjo committed
        List<labelLongList> leavesForLayer(maxLevel+1);
        forAll(nLayers, leafI)
    
    Franjo's avatar
    Franjo committed
                continue;
    
            leavesForLayer[nLayers[leafI]].append(leafI);
    
    Franjo's avatar
    Franjo committed
        //- set refinement flag to additional boxes marked separately
        label nMarked(0);
    
        forAllReverse(leavesForLayer, layerI)
    
    Franjo's avatar
    Franjo committed
            const labelLongList& activeLeaves = leavesForLayer[layerI];
    
    Franjo's avatar
    Franjo committed
            if( returnReduce(activeLeaves.size(), sumOp<label>()) == 0 )
                continue;
    
    Franjo's avatar
    Franjo committed
            //- find the max required refinement level
            direction maxLevel(0);
    
    Franjo's avatar
    Franjo committed
            # ifdef USE_OMP
            # pragma omp parallel
            # endif
    
    Franjo's avatar
    Franjo committed
                direction localMax(0);
    
    Franjo's avatar
    Franjo committed
                # ifdef USE_OMP
                # pragma omp for schedule(dynamic, 50)
                # endif
                forAll(activeLeaves, i)
                    localMax = Foam::max(localMax, targetRefLevel[activeLeaves[i]]);
    
    Franjo's avatar
    Franjo committed
                # ifdef USE_OMP
                # pragma omp critical
                # endif
                maxLevel = Foam::max(localMax, maxLevel);
            }
    
    Franjo's avatar
    Franjo committed
            label ml = maxLevel;
            reduce(ml, maxOp<label>());
            maxLevel = ml;
    
    Franjo's avatar
    Franjo committed
            //- mark additional boxes for refinement
            for(direction levelI=maxLevel;levelI>0;--levelI)
            {
    
                labelList markedBoxes(leaves.size(), 0);
    
    Franjo's avatar
    Franjo committed
                label counter(0);
                # ifdef USE_OMP
                # pragma omp parallel for reduction(+:counter)
                # endif
                forAll(activeLeaves, lI)
    
    Franjo's avatar
    Franjo committed
                    const label leafI = activeLeaves[lI];
    
                    if( targetRefLevel[leafI] == levelI )
    
    Franjo's avatar
    Franjo committed
                        markedBoxes[leafI] = 1;
                        ++counter;
    
    Franjo's avatar
    Franjo committed
                if( returnReduce(counter, sumOp<label>()) == 0 )
                    continue;
    
    Franjo's avatar
    Franjo committed
                //- mark additional cells at this refinement level
    
                markAdditionalLayersOfFaceNeighbours(markedBoxes, layerI);
    
                # ifdef DEBUGSearch
                for(label i=1;i<(layerI+1);++i)
                {
                    const fileName fName("leaves_"+help::labelToText(i)+".vtk");
                    writeLeaves(fName, octree_, markedBoxes, i);
                }
    
                Info << "LayerI " << layerI << endl;
                # endif
    
    Franjo's avatar
    Franjo committed
                //- update the main list
                # ifdef USE_OMP
                # pragma omp parallel for schedule(dynamic, 100) \
                reduction(+:nMarked)
                # endif
                forAll(markedBoxes, leafI)
    
    Franjo's avatar
    Franjo committed
                        continue;
    
    Franjo's avatar
    Franjo committed
    
    
    Franjo's avatar
    Franjo committed
                    if( leaves[leafI]->level() >= levelI )
                        continue;
    
    Franjo's avatar
    Franjo committed
                    if( !refineBox[leafI] )
                    {
                        refineBox[leafI] |= 1;
                        ++nMarked;
    
        reduce(nMarked, sumOp<label>());
    
    
        return nMarked;
    }
    
    
    franjo's avatar
    franjo committed
    void meshOctreeModifier::refineSelectedBoxes
    (
    
        labelList& refineBox,
    
    franjo's avatar
    franjo committed
        const bool hexRefinement
    )
    {
        # ifdef OCTREETiming
        const scalar startTime = omp_get_wtime();
        # endif
    
        //- ensure that refinement will produce 1-irregular octree
        do
        {
            ensureCorrectRegularity(refineBox);
        } while( hexRefinement && ensureCorrectRegularitySons(refineBox) );
    
        # ifdef OCTREETiming
        const scalar regTime = omp_get_wtime();
        Info << "Time for ensuring regularity " << (regTime-startTime) << endl;
        # endif
    
    
    franjo's avatar
    franjo committed
        const triSurf& surface = octree_.surface();
    
    franjo's avatar
    franjo committed
        const boundBox& rootBox = octree_.rootBox();
        const LongList<meshOctreeCube*>& leaves = octree_.leaves_;
    
        //- this is needed for thread safety
        //- such solutions make me a sad bunny :(
    
    franjo's avatar
    franjo committed
        surface.facetEdges();
        surface.edgeFacets();
    
    franjo's avatar
    franjo committed
        surface.edges();
    
    
    franjo's avatar
    franjo committed
        # ifdef USE_OMP
    
    franjo's avatar
    franjo committed
        # pragma omp parallel num_threads(octree_.dataSlots_.size())
    
    franjo's avatar
    franjo committed
        # endif
    
    franjo's avatar
    franjo committed
        {
    
    franjo's avatar
    franjo committed
            # ifdef USE_OMP
    
    franjo's avatar
    franjo committed
            meshOctreeSlot* slotPtr = &octree_.dataSlots_[omp_get_thread_num()];
    
    franjo's avatar
    franjo committed
            # else
            meshOctreeSlot* slotPtr = &octree_.dataSlots_[0];
            # endif
    
    franjo's avatar
    franjo committed
    
    
    franjo's avatar
    franjo committed
            if( !octree_.isQuadtree() )
    
    franjo's avatar
    franjo committed
            {
    
    franjo's avatar
    franjo committed
                # ifdef USE_OMP
                # pragma omp for schedule(dynamic, 100)
                # endif
                forAll(leaves, leafI)
                {
                    if( refineBox[leafI] )
                        leaves[leafI]->refineCube(surface, rootBox, slotPtr);
                }
            }
            else
            {
                # ifdef USE_OMP
                # pragma omp for schedule(dynamic, 100)
                # endif
                forAll(leaves, leafI)
                {
                    if( refineBox[leafI] )
                        leaves[leafI]->refineCube2D(surface, rootBox, slotPtr);
                }
    
    franjo's avatar
    franjo committed
            }
        }
    
        createListOfLeaves();
    
        # ifdef OCTREETiming
        Info << "Time for actual refinement " << (omp_get_wtime()-regTime) << endl;
        # endif
    }
    
    
    void meshOctreeModifier::refineSelectedBoxesAndAdditionalLayers
    (
        labelList& refineBox,
    
    Franjo's avatar
    Franjo committed
        const scalarList& refThickness
    
    )
    {
        const LongList<meshOctreeCube*>& leaves = octree_.leaves_;
    
    
    Franjo's avatar
    Franjo committed
        typedef std::pair<direction, label> mapKey;
        typedef std::map<mapKey, LongList<meshOctreeCube*> > lMap;
    
    Franjo's avatar
    Franjo committed
        Info << "Refining leaves and additional layers" << endl;
    
    Franjo's avatar
    Franjo committed
        //- find the maximum refinement level of leaves marked for refinement
    
    Franjo's avatar
    Franjo committed
        direction maxLevel(0);
    
    
    Franjo's avatar
    Franjo committed
        # ifdef USE_OMP
        # pragma omp parallel
        {
            direction localMax(0);
    
            forAll(refineBox, leafI)
            {
                if( refineBox[leafI] )
                    localMax = Foam::max(localMax, leaves[leafI]->level());
            }
    
            # pragma omp critical
            maxLevel = Foam::max(maxLevel, localMax);
        }
        # else
    
    Franjo's avatar
    Franjo committed
        forAll(refineBox, leafI)
    
    Franjo's avatar
    Franjo committed
        {
    
    Franjo's avatar
    Franjo committed
            if( refineBox[leafI] )
                maxLevel = Foam::max(maxLevel, leaves[leafI]->level());
    
    Franjo's avatar
    Franjo committed
        }
        # endif
    
    Franjo's avatar
    Franjo committed
    
        label ml = maxLevel;
        reduce(ml, maxOp<label>());
        maxLevel = ml;
    
        //- sort leaves based on the current level
    
        List<labelLongList> leavesForLevel(maxLevel+1);
    
    Franjo's avatar
    Franjo committed
        forAll(refineBox, leafI)
    
    Franjo's avatar
    Franjo committed
            if( !refineBox[leafI] )
                continue;
    
            leavesForLevel[leaves[leafI]->level()].append(leafI);
    
    Franjo's avatar
    Franjo committed
        //- find leaves with the same number of additional layers
    
        forAllReverse(leavesForLevel, levelI)
        {
            const labelLongList& activeLeaves = leavesForLevel[levelI];
    
            if( returnReduce(activeLeaves.size(), sumOp<label>()) == 0 )
                continue;
    
    
    Franjo's avatar
    Franjo committed
            labelLongList nLayersForActive(activeLeaves.size());
            label maxNLayers(0);
    
    Franjo's avatar
    Franjo committed
            # ifdef USE_OMP
            # pragma omp parallel
            {
                label localMaxNLayers(0);
    
                forAll(activeLeaves, i)
                {
                    const label leafI = activeLeaves[i];
    
                    const scalar cs = leaves[leafI]->size(octree_.rootBox());
    
                    nLayersForActive[i] = Foam::max(ceil(refThickness[leafI]/cs), 1);
    
                    localMaxNLayers =
                        Foam::max(localMaxNLayers, nLayersForActive[i]);
                }
    
                # pragma omp critical
                maxNLayers = Foam::max(maxNLayers, localMaxNLayers);
            }
            # else
    
    Franjo's avatar
    Franjo committed
            forAll(activeLeaves, i)
            {
                const label leafI = activeLeaves[i];
    
                const scalar cs = leaves[leafI]->size(octree_.rootBox());
    
                nLayersForActive[i] = Foam::max(ceil(refThickness[leafI]/cs), 1);
    
                maxNLayers = Foam::max(maxNLayers, nLayersForActive[i]);
            }
    
    Franjo's avatar
    Franjo committed
            # endif
    
    Franjo's avatar
    Franjo committed
    
            for(label layerI=0;layerI<=maxNLayers;++layerI)
            {
                mapKey key(levelI, layerI);
                LongList<meshOctreeCube*>& currLeaves = leavesMap[key];
                currLeaves.clear();
            }
    
    Franjo's avatar
    Franjo committed
            {
                mapKey key(levelI, nLayersForActive[i]);
                leavesMap[key].append(leaves[activeLeaves[i]]);
            }
    
    Franjo's avatar
    Franjo committed
        //- refine leaves
    
        forAllConstIter(lMap, leavesMap, it)
        {
    
    Franjo's avatar
    Franjo committed
            const label nLayers = it->first.second;
            const direction levelI = it->first.first;
    
    
            const LongList<meshOctreeCube*>& selectedLeaves = it->second;
    
    Franjo's avatar
    Franjo committed
    
            if( returnReduce(selectedLeaves.size(), sumOp<label>()) == 0 )
                continue;
    
    
    Franjo's avatar
    Franjo committed
            # ifdef DEBUGSearch
    
    Franjo's avatar
    Franjo committed
            Info << "Target level " << label(levelI) << endl;
            Info << "Target num layer " << nLayers << endl;
            Info << "Num selected leaves " << selectedLeaves.size() << endl;
    
    Franjo's avatar
    Franjo committed
            # endif
    
    Franjo's avatar
    Franjo committed
                //- mark current leaves for refinement
    
                labelList markedLeaves(leaves.size(), 0);
    
                # ifdef USE_OMP
    
    Franjo's avatar
    Franjo committed
                # pragma omp parallel for schedule(dynamic, 50) reduction(+:nMarked)
    
    Franjo's avatar
    Franjo committed
                    if( !selectedLeaves[i]->isLeaf() )
                        continue;
    
    Franjo's avatar
    Franjo committed
                    markedLeaves[selectedLeaves[i]->cubeLabel()] = 1;
                    ++nMarked;
                }
    
    Franjo's avatar
    Franjo committed
                reduce(nMarked, sumOp<label>());
    
    Franjo's avatar
    Franjo committed
                //- get out of the do-while loop if there are no selected leaves
                if( nMarked == 0 )
                    break;
    
    Franjo's avatar
    Franjo committed
                //- mark additional boxes for refinement
                markAdditionalLayers(markedLeaves, nLayers);
    
    Franjo's avatar
    Franjo committed
                //- find the leaves in the additional layers
                labelLongList activeLeaves;
                forAll(markedLeaves, leafI)
    
    Franjo's avatar
    Franjo committed
                    if( markedLeaves[leafI] )
                        activeLeaves.append(leafI);
                }
    
    Franjo's avatar
    Franjo committed
                //- check if there exist leaves at lower refinement level
                bool hasLowerLevel(false);
    
    Franjo's avatar
    Franjo committed
                # ifdef USE_OMP
                # pragma omp parallel for schedule(guided)
                # endif
                forAll(activeLeaves, i)
                {
    
    Franjo's avatar
    Franjo committed
                    const direction level = leaves[activeLeaves[i]]->level();
                    if( level < levelI )
                    {
                        //- found a neighbour at a lower refinement level
    
    Franjo's avatar
    Franjo committed
                        hasLowerLevel = true;
    
    Franjo's avatar
    Franjo committed
                    }
                    else if( level > levelI )
                    {
                        //- do not allow refinement of leaves at higher
                        //- refinement level
                        markedLeaves[activeLeaves[i]] = 0;
                    }
    
    Franjo's avatar
    Franjo committed
                }
    
    Franjo's avatar
    Franjo committed
                reduce(hasLowerLevel, maxOp<bool>());
    
                //- deselect leaves at the current level
    
    Franjo's avatar
    Franjo committed
                if( hasLowerLevel )
                {
    
    Franjo's avatar
    Franjo committed
                    # pragma omp parallel for schedule(guided)
    
    Franjo's avatar
    Franjo committed
                    forAll(activeLeaves, i)
    
    Franjo's avatar
    Franjo committed
                        if( leaves[activeLeaves[i]]->level() == levelI )
                            markedLeaves[activeLeaves[i]] = 0;
    
    Franjo's avatar
    Franjo committed
                //- refine selected octree boxes
    
                refineSelectedBoxes(markedLeaves);
            } while( nMarked );
        }
    }
    
    
    franjo's avatar
    franjo committed
    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
    
    } // End namespace Foam
    
    // ************************************************************************* //