Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\/ M anipulation |
-------------------------------------------------------------------------------
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 * * * * * * * * * * * //
Henry Weller
committed
List<DynamicList<label>>& pe,
DynamicList<edge>& es,
Henry Weller
committed
const label pointi,
const label nextPointi
Henry Weller
committed
// Find connection between pointi and nextPointi
forAll(pe[pointi], ppI)
Henry Weller
committed
label eI = pe[pointi][ppI];
const edge& e = es[eI];
Henry Weller
committed
if (e.start() == nextPointi || e.end() == nextPointi)
{
return eI;
}
}
// Make new edge.
label edgeI = es.size();
Henry Weller
committed
pe[pointi].append(edgeI);
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);
}
Henry Weller
committed
if (pointi < nextPointi)
Henry Weller
committed
es.append(edge(pointi, nextPointi));
Henry Weller
committed
es.append(edge(nextPointi, pointi));
}
return edgeI;
}
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_))
{
FatalErrorInFunction
<< "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
Henry Weller
committed
List<DynamicList<label>> pe(nPoints());
Henry Weller
committed
forAll(pe, pointi)
Henry Weller
committed
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];
Henry Weller
committed
label pointi = f[fp];
label nextPointi = f[f.fcIndex(fp)];
Henry Weller
committed
label edgeI = getEdge(pe, es, pointi, nextPointi);
if (doFaceEdges)
{
(*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];
Henry Weller
committed
label pointi = f[fp];
label nextPointi = f[f.fcIndex(fp)];
label oldNEdges = es.size();
Henry Weller
committed
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];
Henry Weller
committed
label pointi = f[fp];
label nextPointi = f[f.fcIndex(fp)];
label oldNEdges = es.size();
Henry Weller
committed
label edgeI = getEdge(pe, es, pointi, nextPointi);
if (es.size() > oldNEdges)
{
Henry Weller
committed
if (pointi < nInternalPoints_)
Henry Weller
committed
if (nextPointi < nInternalPoints_)
{
nInternal0Edges_++;
}
else
{
nInt1Edges++;
}
}
else
{
Henry Weller
committed
if (nextPointi < nInternalPoints_)
{
nInt1Edges++;
}
else
{
// Internal edge with two points on boundary
}
}
}
if (doFaceEdges)
{
(*fePtr_)[facei][fp] = edgeI;
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
}
}
}
}
// 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;
}
// Like faces sort edges in order of increasing neighbouring point.
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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_);
Henry Weller
committed
forAll(pe, pointi)
Henry Weller
committed
const DynamicList<label>& pEdges = pe[pointi];
nbrPoints.setSize(pEdges.size());
forAll(pEdges, i)
{
const edge& e = es[pEdges[i]];
Henry Weller
committed
label nbrPointi = e.otherVertex(pointi);
Henry Weller
committed
if (nbrPointi < pointi)
{
nbrPoints[i] = -1;
}
else
{
Henry Weller
committed
nbrPoints[i] = nbrPointi;
}
}
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++;
}
Henry Weller
committed
if (pointi < nInternalPoints_)
{
forAll(nbrPoints, i)
{
Henry Weller
committed
label nbrPointi = nbrPoints[i];
label edgeI = pEdges[nbrPoints.indices()[i]];
Henry Weller
committed
if (nbrPointi != -1)
{
if (edgeI < nExtEdges)
{
// External edge
oldToNew[edgeI] = externalEdgeI++;
}
Henry Weller
committed
else if (nbrPointi < nInternalPoints_)
{
// Both points inside
oldToNew[edgeI] = internal0EdgeI++;
}
else
{
// One points inside, one outside
oldToNew[edgeI] = internal1EdgeI++;
}
}
}
}
else
{
forAll(nbrPoints, i)
{
Henry Weller
committed
label nbrPointi = nbrPoints[i];
label edgeI = pEdges[nbrPoints.indices()[i]];
Henry Weller
committed
if (nbrPointi != -1)
{
if (edgeI < nExtEdges)
{
// External edge
oldToNew[edgeI] = externalEdgeI++;
}
Henry Weller
committed
else if (nbrPointi < nInternalPoints_)
FatalErrorInFunction
<< abort(FatalError);
}
else
{
// Both points outside
oldToNew[edgeI] = internal2EdgeI++;
}
}
}
}
}
}
if (debug)
{
label edgeI = oldToNew.find(-1);
if (edgeI != -1)
{
const edge& e = es[edgeI];
FatalErrorInFunction
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
<< "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_;
Henry Weller
committed
forAll(pe, pointi)
Henry Weller
committed
DynamicList<label>& pEdges = pe[pointi];
Henry Weller
committed
pointEdges[pointi].transfer(pEdges);
Foam::sort(pointEdges[pointi]);
}
// faceEdges
if (doFaceEdges)
{
labelListList& faceEdges = *fePtr_;
forAll(faceEdges, facei)
inplaceRenumber(oldToNew, faceEdges[facei]);
}
}
}
}
Foam::label Foam::primitiveMesh::findFirstCommonElementFromSortedLists
(
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())
{
{
++iter1;
}
else if (*iter1 > *iter2)
{
++iter2;
}
else
{
result = *iter1;
break;
}
}
if (result == -1)
{
FatalErrorInFunction
<< "No common elements in lists " << list1 << " and " << list2
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::edgeList& Foam::primitiveMesh::edges() const
{
if (!edgesPtr_)
{
//calcEdges(true);
calcEdges(false);
}
return *edgesPtr_;
}
const Foam::labelListList& Foam::primitiveMesh::pointEdges() const
{
if (!pePtr_)
{
//calcEdges(true);
calcEdges(false);
}
return *pePtr_;
}
const Foam::labelListList& Foam::primitiveMesh::faceEdges() const
{
if (!fePtr_)
{
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)
{
Henry Weller
committed
label pointi = f[fp];
label nextPointi = f[f.fcIndex(fp)];
Henry Weller
committed
// Find edge between pointi, nextPontI
const labelList& pEdges = pe[pointi];
forAll(pEdges, i)
{
label edgeI = pEdges[i];
Henry Weller
committed
if (es[edgeI].otherVertex(pointi) == nextPointi)
{
fEdges[fp] = edgeI;
break;
}
}
}
}
}
return *fePtr_;
}
{
deleteDemandDrivenData(edgesPtr_);
deleteDemandDrivenData(pePtr_);
deleteDemandDrivenData(fePtr_);
const Foam::labelList& Foam::primitiveMesh::faceEdges
return faceEdges()[facei];
const labelListList& pointEs = pointEdges();
const face& f = faces()[facei];
storage.clear();
if (f.size() > storage.capacity())
{
storage.setCapacity(f.size());
}
forAll(f, fp)
{
storage.append
(
findFirstCommonElementFromSortedLists
(
pointEs[f[fp]],
pointEs[f.nextLabel(fp)]
)
);
const Foam::labelList& Foam::primitiveMesh::faceEdges(const label facei) const
return faceEdges(facei, labels_);
const Foam::labelList& Foam::primitiveMesh::cellEdges
labelHashSet& set,
return cellEdges()[celli];
const labelList& cFaces = cells()[celli];
for (const label facei : cFaces)
{
set.insert(faceEdges(facei));
storage.clear();
if (set.size() > storage.capacity())
{
storage.setCapacity(set.size());
}
for (const label edgei : set)
{
storage.append(edgei);
const Foam::labelList& Foam::primitiveMesh::cellEdges(const label celli) const
return cellEdges(celli, labelSet_, labels_);
// ************************************************************************* //