Skip to content
Snippets Groups Projects
primitiveMeshEdges.C 18.6 KiB
Newer Older
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
OpenFOAM bot's avatar
OpenFOAM bot committed
    \\  /    A nd           | www.openfoam.com
     \\/     M anipulation  |
-------------------------------------------------------------------------------
OpenFOAM bot's avatar
OpenFOAM bot committed
    Copyright (C) 2011-2016 OpenFOAM Foundation
    Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.

    OpenFOAM is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
    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
    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.

\*---------------------------------------------------------------------------*/

#include "primitiveMesh.H"
#include "DynamicList.H"
#include "demandDrivenData.H"
#include "SortableList.H"
#include "ListOps.H"

// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //

Mark Olesen's avatar
Mark Olesen committed
Foam::label Foam::primitiveMesh::getEdge
    DynamicList<edge>& es,

    // Find connection between pointi and nextPointi
    forAll(pe[pointi], ppI)
        if (e.start() == nextPointi || e.end() == nextPointi)
        {
            return eI;
        }
    }

    // Make new edge.
    label edgeI = es.size();

    if (nextPointi != pointi)
    {
        // Very occasionally (e.g. blockMesh) a face can have duplicate
        // vertices. Make sure we register pointEdges only once.
        pe[nextPointi].append(edgeI);
    }

Mark Olesen's avatar
Mark Olesen committed
void Foam::primitiveMesh::calcEdges(const bool doFaceEdges) const
{
    if (debug)
    {
        Pout<< "primitiveMesh::calcEdges(const bool) : "
            << "calculating edges, pointEdges and optionally faceEdges"
            << endl;
    }

    // It is an error to attempt to recalculate edges
    // if the pointer is already set
    if ((edgesPtr_ || pePtr_) || (doFaceEdges && fePtr_))
    {
            << "edges or pointEdges or faceEdges already calculated"
            << abort(FatalError);
    }
    else
    {
        // ALGORITHM:
        // Go through the faces list. Search pointEdges for existing edge.
        // If not found create edge and add to pointEdges.
        // In second loop sort edges in order of increasing neighbouring
        // point.
        // This algorithm replaces the one using pointFaces which used more
        // allocations but less memory and was on practical cases
        // quite a bit slower.

        const faceList& fcs = faces();

        // Size up lists
        // ~~~~~~~~~~~~~

        // Estimate pointEdges storage
            pe[pointi].setCapacity(primitiveMesh::edgesPerPoint_);
        }

        // Estimate edges storage
        DynamicList<edge> es(pe.size()*primitiveMesh::edgesPerPoint_/2);

        // Estimate faceEdges storage
        if (doFaceEdges)
        {
            fePtr_ = new labelListList(fcs.size());
            labelListList& faceEdges = *fePtr_;
                faceEdges[facei].setSize(fcs[facei].size());
            }
        }


        // Find consecutive face points in edge list
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        // Edges on boundary faces
        label nExtEdges = 0;
        // Edges using no boundary point
        nInternal0Edges_ = 0;
        // Edges using 1 boundary point
        label nInt1Edges = 0;
        // Edges using two boundary points but not on boundary face:
        // edges.size()-nExtEdges-nInternal0Edges_-nInt1Edges

        // Ordering is different if points are ordered.
        if (nInternalPoints_ == -1)
        {
            // No ordering. No distinction between types.
                const face& f = fcs[facei];
                    label pointi = f[fp];
                    label nextPointi = f[f.fcIndex(fp)];
                    label edgeI = getEdge(pe, es, pointi, nextPointi);
                        (*fePtr_)[facei][fp] = edgeI;
                    }
                }
            }
            // Assume all edges internal
            nExtEdges = 0;
            nInternal0Edges_ = es.size();
            nInt1Edges = 0;
        }
        else
        {
            // 1. Do external faces first. This creates external edges.
            for (label facei = nInternalFaces_; facei < fcs.size(); facei++)
                const face& f = fcs[facei];
                    label pointi = f[fp];
                    label nextPointi = f[f.fcIndex(fp)];

                    label oldNEdges = es.size();
                    label edgeI = getEdge(pe, es, pointi, nextPointi);

                    if (es.size() > oldNEdges)
                    {
                        nExtEdges++;
                    }
                    if (doFaceEdges)
                    {
                        (*fePtr_)[facei][fp] = edgeI;
                    }
                }
            }

            // 2. Do internal faces. This creates internal edges.
            for (label facei = 0; facei < nInternalFaces_; facei++)
                const face& f = fcs[facei];
                    label pointi = f[fp];
                    label nextPointi = f[f.fcIndex(fp)];

                    label oldNEdges = es.size();
                    label edgeI = getEdge(pe, es, pointi, nextPointi);

                    if (es.size() > oldNEdges)
                    {
                            {
                                nInt1Edges++;
                            }
                            else
                            {
                                // Internal edge with two points on boundary
                            }
                        }
                    }
                    if (doFaceEdges)
                    {
                        (*fePtr_)[facei][fp] = edgeI;
                    }
                }
            }
        }


        // For unsorted meshes the edges will be in order of occurrence inside
        // the faces. For sorted meshes the first nExtEdges will be the external
        // edges.

        if (nInternalPoints_ != -1)
        {
            nInternalEdges_ = es.size()-nExtEdges;
            nInternal1Edges_ = nInternal0Edges_+nInt1Edges;

            //Pout<< "Edge overview:" << nl
            //    << "    total number of edges           : " << es.size()
            //    << nl
            //    << "    boundary edges                  : " << nExtEdges
            //    << nl
            //    << "    edges using no boundary point   : "
            //    << nInternal0Edges_
            //    << nl
            //    << "    edges using one boundary points : " << nInt1Edges
            //   << nl
            //    << "    edges using two boundary points : "
            //    << es.size()-nExtEdges-nInternal0Edges_-nInt1Edges << endl;
        }


Andrew Heather's avatar
Andrew Heather committed
        // Like faces sort edges in order of increasing neighbouring point.
        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // Automatically if points are sorted into internal and external points
        // the edges will be sorted into
        // - internal point to internal point
        // - internal point to external point
        // - external point to external point
        // The problem is that the last one mixes external edges with internal
        // edges with two points on the boundary.


        // Map to sort into new upper-triangular order
        labelList oldToNew(es.size());
        if (debug)
        {
            oldToNew = -1;
        }

        // start of edges with 0 boundary points
        label internal0EdgeI = 0;

        // start of edges with 1 boundary points
        label internal1EdgeI = nInternal0Edges_;

        // start of edges with 2 boundary points
        label internal2EdgeI = nInternal1Edges_;

        // start of external edges
        label externalEdgeI = nInternalEdges_;


        // To sort neighbouring points in increasing order. Defined outside
        // for optimisation reasons: if all connectivity size same will need
        // no reallocations
        SortableList<label> nbrPoints(primitiveMesh::edgesPerPoint_);

            const DynamicList<label>& pEdges = pe[pointi];

            nbrPoints.setSize(pEdges.size());

            forAll(pEdges, i)
            {
                const edge& e = es[pEdges[i]];

                label nbrPointi = e.otherVertex(pointi);
                }
            }
            nbrPoints.sort();


            if (nInternalPoints_ == -1)
            {
                // Sort all upper-triangular
                forAll(nbrPoints, i)
                {
                    if (nbrPoints[i] != -1)
                    {
                        label edgeI = pEdges[nbrPoints.indices()[i]];

                        oldToNew[edgeI] = internal0EdgeI++;
                    }
Mark Olesen's avatar
Mark Olesen committed
                }

                        label edgeI = pEdges[nbrPoints.indices()[i]];

                        {
                            if (edgeI < nExtEdges)
                            {
                                // External edge
                                oldToNew[edgeI] = externalEdgeI++;
                            }
                            {
                                // Both points inside
                                oldToNew[edgeI] = internal0EdgeI++;
                            }
                            else
                            {
                                // One points inside, one outside
                                oldToNew[edgeI] = internal1EdgeI++;
                            }
                        }
                    }
                }
                else
                {
                    forAll(nbrPoints, i)
                    {

                        label edgeI = pEdges[nbrPoints.indices()[i]];

                        {
                            if (edgeI < nExtEdges)
                            {
                                // External edge
                                oldToNew[edgeI] = externalEdgeI++;
                            }
                                    << abort(FatalError);
                            }
                            else
                            {
                                // Both points outside
                                oldToNew[edgeI] = internal2EdgeI++;
                            }
                        }
                    }
                }
            }
        }


        if (debug)
        {
            label edgeI = oldToNew.find(-1);

            if (edgeI != -1)
            {
                const edge& e = es[edgeI];

                    << "Did not sort edge " << edgeI << " points:" << e
                    << " coords:" << points()[e[0]] << points()[e[1]]
                    << endl
                    << "Current buckets:" << endl
                    << "    internal0EdgeI:" << internal0EdgeI << endl
                    << "    internal1EdgeI:" << internal1EdgeI << endl
                    << "    internal2EdgeI:" << internal2EdgeI << endl
                    << "    externalEdgeI:" << externalEdgeI << endl
                    << abort(FatalError);
            }
        }



        // Renumber and transfer.

        // Edges
        edgesPtr_ = new edgeList(es.size());
        edgeList& edges = *edgesPtr_;
        forAll(es, edgeI)
        {
            edges[oldToNew[edgeI]] = es[edgeI];
        }

        // pointEdges
        pePtr_ = new labelListList(nPoints());
        labelListList& pointEdges = *pePtr_;
            DynamicList<label>& pEdges = pe[pointi];
mattijs's avatar
mattijs committed
            inplaceRenumber(oldToNew, pEdges);
            pointEdges[pointi].transfer(pEdges);
            Foam::sort(pointEdges[pointi]);
        }

        // faceEdges
        if (doFaceEdges)
        {
            labelListList& faceEdges = *fePtr_;
            forAll(faceEdges, facei)
                inplaceRenumber(oldToNew, faceEdges[facei]);
Mark Olesen's avatar
Mark Olesen committed
Foam::label Foam::primitiveMesh::findFirstCommonElementFromSortedLists
(
mattijs's avatar
mattijs committed
    const labelList& list1,
    const labelList& list2
)
{
    label result = -1;

    labelList::const_iterator iter1 = list1.begin();
    labelList::const_iterator iter2 = list2.begin();

    while (iter1 != list1.end() && iter2 != list2.end())
    {
        if (*iter1 < *iter2)
mattijs's avatar
mattijs committed
        {
            ++iter1;
        }
        else if (*iter1 > *iter2)
        {
            ++iter2;
        }
        else
        {
            result = *iter1;
            break;
        }
    }
    if (result == -1)
    {
        FatalErrorInFunction
            << "No common elements in lists " << list1 << " and " << list2
Mark Olesen's avatar
Mark Olesen committed
            << abort(FatalError);
mattijs's avatar
mattijs committed
    }
    return result;
}


// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //

Mark Olesen's avatar
Mark Olesen committed
const Foam::edgeList& Foam::primitiveMesh::edges() const
        //calcEdges(true);
        calcEdges(false);
Mark Olesen's avatar
Mark Olesen committed
const Foam::labelListList& Foam::primitiveMesh::pointEdges() const
        //calcEdges(true);
        calcEdges(false);
Mark Olesen's avatar
Mark Olesen committed
const Foam::labelListList& Foam::primitiveMesh::faceEdges() const
        if (debug)
        {
            Pout<< "primitiveMesh::faceEdges() : "
                << "calculating faceEdges" << endl;
        }

        //calcEdges(true);
        const faceList& fcs = faces();
        const labelListList& pe = pointEdges();
        const edgeList& es = edges();

        fePtr_ = new labelListList(fcs.size());
        labelListList& faceEdges = *fePtr_;

            const face& f = fcs[facei];
            labelList& fEdges = faceEdges[facei];
            fEdges.setSize(f.size());

            forAll(f, fp)
            {
                label pointi = f[fp];
                label nextPointi = f[f.fcIndex(fp)];
                // Find edge between pointi, nextPontI
                const labelList& pEdges = pe[pointi];

                forAll(pEdges, i)
                {
                    label edgeI = pEdges[i];

                    if (es[edgeI].otherVertex(pointi) == nextPointi)
Mark Olesen's avatar
Mark Olesen committed
void Foam::primitiveMesh::clearOutEdges()
{
    deleteDemandDrivenData(edgesPtr_);
    deleteDemandDrivenData(pePtr_);
    deleteDemandDrivenData(fePtr_);
mattijs's avatar
mattijs committed
    labels_.clear();
mattijs's avatar
mattijs committed
    labelSet_.clear();
Mark Olesen's avatar
Mark Olesen committed
const Foam::labelList& Foam::primitiveMesh::faceEdges
mattijs's avatar
mattijs committed
(
mattijs's avatar
mattijs committed
    DynamicList<label>& storage
) const
mattijs's avatar
mattijs committed
{
    if (hasFaceEdges())
    {
        return faceEdges()[facei];
mattijs's avatar
mattijs committed
    }

    const labelListList& pointEs = pointEdges();
    const face& f = faces()[facei];
mattijs's avatar
mattijs committed

    storage.clear();
    if (f.size() > storage.capacity())
    {
        storage.setCapacity(f.size());
    }
mattijs's avatar
mattijs committed

    forAll(f, fp)
    {
        storage.append
        (
            findFirstCommonElementFromSortedLists
            (
                pointEs[f[fp]],
                pointEs[f.nextLabel(fp)]
            )
        );
mattijs's avatar
mattijs committed
    }
const Foam::labelList& Foam::primitiveMesh::faceEdges(const label facei) const
mattijs's avatar
mattijs committed
{
    return faceEdges(facei, labels_);
Mark Olesen's avatar
Mark Olesen committed
const Foam::labelList& Foam::primitiveMesh::cellEdges
mattijs's avatar
mattijs committed
(
mattijs's avatar
mattijs committed
    DynamicList<label>& storage
) const
mattijs's avatar
mattijs committed
{
    if (hasCellEdges())
    {
        return cellEdges()[celli];
mattijs's avatar
mattijs committed
    }

    const labelList& cFaces = cells()[celli];
mattijs's avatar
mattijs committed

    set.clear();
mattijs's avatar
mattijs committed

    for (const label facei : cFaces)
    {
mattijs's avatar
mattijs committed

    storage.clear();
    if (set.size() > storage.capacity())
    {
        storage.setCapacity(set.size());
    }
mattijs's avatar
mattijs committed

    for (const label edgei : set)
    {
        storage.append(edgei);
mattijs's avatar
mattijs committed
    }
const Foam::labelList& Foam::primitiveMesh::cellEdges(const label celli) const
mattijs's avatar
mattijs committed
{
    return cellEdges(celli, labelSet_, labels_);
// ************************************************************************* //