Loading...
Searching...
No Matches
primitiveMeshEdges.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2018-2024 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "primitiveMesh.H"
30#include "DynamicList.H"
31#include "SortableList.H"
32#include "ListOps.H"
34// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
35
36namespace Foam
37{
38
39// Helper: return (after optional creation) edge between two points
40static label getEdge
41(
44
45 const label pointi,
46 const label nextPointi
47)
48{
49 // Find connection between pointi and nextPointi
50 for (const label edgei : pe[pointi])
51 {
52 if (edgei < es.size() && es[edgei].contains(nextPointi))
53 {
54 return edgei;
55 }
56 }
57
58 // Make new edge.
59 const label edgei = es.size();
60 pe[pointi].push_back(edgei);
61
62 if (nextPointi != pointi)
63 {
64 // Very occasionally (e.g. blockMesh) a face can have duplicate
65 // vertices. Make sure we register pointEdges only once.
66 pe[nextPointi].push_back(edgei);
67 }
68
69 if (pointi < nextPointi)
70 {
71 es.emplace_back(pointi, nextPointi);
72 }
73 else
74 {
75 es.emplace_back(nextPointi, pointi);
76 }
77 return edgei;
78}
79
80} // End namespace Foam
81
82
83// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
84
85void Foam::primitiveMesh::calcEdges(const bool doFaceEdges) const
86{
87 if (debug)
88 {
89 Pout<< "primitiveMesh::calcEdges(const bool) : "
90 << "calculating edges, pointEdges and optionally faceEdges"
91 << endl;
92 }
93
94 // It is an error to attempt to recalculate edges
95 // if the pointer is already set
96 if ((edgesPtr_ || pePtr_) || (doFaceEdges && fePtr_))
97 {
99 << "edges or pointEdges or faceEdges already calculated"
100 << abort(FatalError);
101 }
102 else
103 {
104 // ALGORITHM:
105 // Go through the faces list. Search pointEdges for existing edge.
106 // If not found create edge and add to pointEdges.
107 // In second loop sort edges in order of increasing neighbouring
108 // point.
109 // This algorithm replaces the one using pointFaces which used more
110 // allocations but less memory and was on practical cases
111 // quite a bit slower.
112
113 const faceList& fcs = faces();
114
115 // Size up lists
116 // ~~~~~~~~~~~~~
117
118 // Estimate pointEdges storage
119 List<DynamicList<label>> pe(nPoints());
120 forAll(pe, pointi)
121 {
122 pe[pointi].setCapacity(primitiveMesh::edgesPerPoint_);
123 }
124
125 // Estimate edges storage
126 DynamicList<edge> es(pe.size()*primitiveMesh::edgesPerPoint_/2);
127
128 // Estimate faceEdges storage
129 if (doFaceEdges)
130 {
131 fePtr_ = std::make_unique<labelListList>(fcs.size());
132 auto& faceEdges = *fePtr_;
133 forAll(fcs, facei)
134 {
135 faceEdges[facei].setSize(fcs[facei].size());
136 }
137 }
138
139
140 // Find consecutive face points in edge list
141 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142
143 // Edges on boundary faces
144 label nExtEdges = 0;
145 // Edges using no boundary point
146 nInternal0Edges_ = 0;
147 // Edges using 1 boundary point
148 label nInt1Edges = 0;
149 // Edges using two boundary points but not on boundary face:
150 // edges.size()-nExtEdges-nInternal0Edges_-nInt1Edges
151
152 // Ordering is different if points are ordered.
153 if (nInternalPoints_ == -1)
154 {
155 // No ordering. No distinction between types.
156 forAll(fcs, facei)
157 {
158 const face& f = fcs[facei];
159
160 forAll(f, fp)
161 {
162 label pointi = f[fp];
163 label nextPointi = f[f.fcIndex(fp)];
164
165 label edgeI = getEdge(pe, es, pointi, nextPointi);
166
167 if (doFaceEdges)
168 {
169 (*fePtr_)[facei][fp] = edgeI;
170 }
171 }
172 }
173 // Assume all edges internal
174 nExtEdges = 0;
175 nInternal0Edges_ = es.size();
176 nInt1Edges = 0;
177 }
178 else
179 {
180 // 1. Do external faces first. This creates external edges.
181 for (label facei = nInternalFaces_; facei < fcs.size(); facei++)
182 {
183 const face& f = fcs[facei];
184
185 forAll(f, fp)
186 {
187 label pointi = f[fp];
188 label nextPointi = f[f.fcIndex(fp)];
189
190 label oldNEdges = es.size();
191 label edgeI = getEdge(pe, es, pointi, nextPointi);
192
193 if (es.size() > oldNEdges)
194 {
195 nExtEdges++;
196 }
197 if (doFaceEdges)
198 {
199 (*fePtr_)[facei][fp] = edgeI;
200 }
201 }
202 }
203
204 // 2. Do internal faces. This creates internal edges.
205 for (label facei = 0; facei < nInternalFaces_; facei++)
206 {
207 const face& f = fcs[facei];
208
209 forAll(f, fp)
210 {
211 label pointi = f[fp];
212 label nextPointi = f[f.fcIndex(fp)];
213
214 label oldNEdges = es.size();
215 label edgeI = getEdge(pe, es, pointi, nextPointi);
216
217 if (es.size() > oldNEdges)
218 {
219 if (pointi < nInternalPoints_)
220 {
221 if (nextPointi < nInternalPoints_)
222 {
223 nInternal0Edges_++;
224 }
225 else
226 {
227 nInt1Edges++;
228 }
229 }
230 else
231 {
232 if (nextPointi < nInternalPoints_)
233 {
234 nInt1Edges++;
235 }
236 else
237 {
238 // Internal edge with two points on boundary
239 }
240 }
241 }
242 if (doFaceEdges)
243 {
244 (*fePtr_)[facei][fp] = edgeI;
245 }
246 }
247 }
248 }
249
250
251 // For unsorted meshes the edges will be in order of occurrence inside
252 // the faces. For sorted meshes the first nExtEdges will be the external
253 // edges.
254
255 if (nInternalPoints_ != -1)
256 {
257 nInternalEdges_ = es.size()-nExtEdges;
258 nInternal1Edges_ = nInternal0Edges_+nInt1Edges;
259
260 //Pout<< "Edge overview:" << nl
261 // << " total number of edges : " << es.size()
262 // << nl
263 // << " boundary edges : " << nExtEdges
264 // << nl
265 // << " edges using no boundary point : "
266 // << nInternal0Edges_
267 // << nl
268 // << " edges using one boundary points : " << nInt1Edges
269 // << nl
270 // << " edges using two boundary points : "
271 // << es.size()-nExtEdges-nInternal0Edges_-nInt1Edges << endl;
272 }
273
274
275 // Like faces sort edges in order of increasing neighbouring point.
276 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
277 // Automatically if points are sorted into internal and external points
278 // the edges will be sorted into
279 // - internal point to internal point
280 // - internal point to external point
281 // - external point to external point
282 // The problem is that the last one mixes external edges with internal
283 // edges with two points on the boundary.
284
285
286 // Map to sort into new upper-triangular order
287 labelList oldToNew(es.size());
288 if (debug)
289 {
290 oldToNew = -1;
291 }
292
293 // start of edges with 0 boundary points
294 label internal0EdgeI = 0;
295
296 // start of edges with 1 boundary points
297 label internal1EdgeI = nInternal0Edges_;
298
299 // start of edges with 2 boundary points
300 label internal2EdgeI = nInternal1Edges_;
301
302 // start of external edges
303 label externalEdgeI = nInternalEdges_;
304
305
306 // To sort neighbouring points in increasing order. Defined outside
307 // for optimisation reasons: if all connectivity size same will need
308 // no reallocations
309 SortableList<label> nbrPoints(primitiveMesh::edgesPerPoint_);
310
311 forAll(pe, pointi)
312 {
313 const DynamicList<label>& pEdges = pe[pointi];
314
315 nbrPoints.setSize(pEdges.size());
316
317 forAll(pEdges, i)
318 {
319 const edge& e = es[pEdges[i]];
320
321 label nbrPointi = e.otherVertex(pointi);
322
323 if (nbrPointi < pointi)
324 {
325 nbrPoints[i] = -1;
326 }
327 else
328 {
329 nbrPoints[i] = nbrPointi;
330 }
331 }
332 nbrPoints.sort();
333
334
335 if (nInternalPoints_ == -1)
336 {
337 // Sort all upper-triangular
338 forAll(nbrPoints, i)
339 {
340 if (nbrPoints[i] != -1)
341 {
342 label edgeI = pEdges[nbrPoints.indices()[i]];
343
344 oldToNew[edgeI] = internal0EdgeI++;
345 }
346 }
347 }
348 else
349 {
350 if (pointi < nInternalPoints_)
351 {
352 forAll(nbrPoints, i)
353 {
354 label nbrPointi = nbrPoints[i];
355
356 label edgeI = pEdges[nbrPoints.indices()[i]];
357
358 if (nbrPointi != -1)
359 {
360 if (edgeI < nExtEdges)
361 {
362 // External edge
363 oldToNew[edgeI] = externalEdgeI++;
364 }
365 else if (nbrPointi < nInternalPoints_)
366 {
367 // Both points inside
368 oldToNew[edgeI] = internal0EdgeI++;
369 }
370 else
371 {
372 // One points inside, one outside
373 oldToNew[edgeI] = internal1EdgeI++;
374 }
375 }
376 }
377 }
378 else
379 {
380 forAll(nbrPoints, i)
381 {
382 label nbrPointi = nbrPoints[i];
383
384 label edgeI = pEdges[nbrPoints.indices()[i]];
385
386 if (nbrPointi != -1)
387 {
388 if (edgeI < nExtEdges)
389 {
390 // External edge
391 oldToNew[edgeI] = externalEdgeI++;
392 }
393 else if (nbrPointi < nInternalPoints_)
394 {
395 // Not possible!
397 << abort(FatalError);
398 }
399 else
400 {
401 // Both points outside
402 oldToNew[edgeI] = internal2EdgeI++;
403 }
404 }
405 }
406 }
407 }
408 }
409
410
411 if (debug)
412 {
413 label edgeI = oldToNew.find(-1);
414
415 if (edgeI != -1)
416 {
417 const edge& e = es[edgeI];
418
420 << "Did not sort edge " << edgeI << " points:" << e
421 << " coords:" << points()[e[0]] << points()[e[1]]
422 << endl
423 << "Current buckets:" << endl
424 << " internal0EdgeI:" << internal0EdgeI << endl
425 << " internal1EdgeI:" << internal1EdgeI << endl
426 << " internal2EdgeI:" << internal2EdgeI << endl
427 << " externalEdgeI:" << externalEdgeI << endl
428 << abort(FatalError);
429 }
430 }
431
432
433
434 // Renumber and transfer.
435
436 // Edges
437 edgesPtr_ = std::make_unique<edgeList>(es.size());
438 auto& edges = *edgesPtr_;
439 forAll(es, edgeI)
440 {
441 edges[oldToNew[edgeI]] = es[edgeI];
442 }
443
444 // pointEdges
445 pePtr_ = std::make_unique<labelListList>(nPoints());
446 auto& pointEdges = *pePtr_;
447 forAll(pe, pointi)
448 {
449 DynamicList<label>& pEdges = pe[pointi];
450 pEdges.shrink();
451 inplaceRenumber(oldToNew, pEdges);
452 pointEdges[pointi].transfer(pEdges);
453 Foam::sort(pointEdges[pointi]);
454 }
455
456 // faceEdges
457 if (doFaceEdges)
458 {
459 auto& faceEdges = *fePtr_;
460 forAll(faceEdges, facei)
461 {
462 inplaceRenumber(oldToNew, faceEdges[facei]);
463 }
464 }
465 }
466}
467
469// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
470
471namespace Foam
472{
473
474// Helper: for on-the-fly addressing calculation
476(
477 const labelUList& list1,
478 const labelUList& list2
479)
480{
481 label result = -1;
482
483 auto iter1 = list1.begin();
484 auto iter2 = list2.begin();
485
486 while (iter1 != list1.end() && iter2 != list2.end())
487 {
488 if (*iter1 < *iter2)
489 {
490 ++iter1;
491 }
492 else if (*iter1 > *iter2)
493 {
494 ++iter2;
495 }
496 else
497 {
498 result = *iter1;
499 break;
500 }
501 }
502 if (result == -1)
503 {
505 << "No common elements in lists " << list1 << " and " << list2
506 << abort(FatalError);
507 }
508 return result;
510
511} // End namespace Foam
512
513
514// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
515
517{
518 if (!edgesPtr_)
519 {
520 //calcEdges(true);
521 calcEdges(false);
522 }
523
524 return *edgesPtr_;
525}
526
528{
529 if (!pePtr_)
530 {
531 //calcEdges(true);
532 calcEdges(false);
533 }
534
535 return *pePtr_;
536}
537
538
540{
541 if (!fePtr_)
542 {
543 if (debug)
544 {
545 Pout<< "primitiveMesh::faceEdges() : "
546 << "calculating faceEdges" << endl;
547 }
548
549 //calcEdges(true);
550 const faceList& fcs = faces();
551 const labelListList& pe = pointEdges();
552 const edgeList& es = edges();
553
554 fePtr_ = std::make_unique<labelListList>(fcs.size());
555 auto& faceEdges = *fePtr_;
556
557 forAll(fcs, facei)
558 {
559 const face& f = fcs[facei];
560
561 labelList& fEdges = faceEdges[facei];
562 fEdges.setSize(f.size());
563
564 forAll(f, fp)
565 {
566 label pointi = f[fp];
567 label nextPointi = f[f.fcIndex(fp)];
568
569 // Find edge between pointi, nextPontI
570 const labelList& pEdges = pe[pointi];
571
572 forAll(pEdges, i)
573 {
574 label edgeI = pEdges[i];
575
576 if (es[edgeI].otherVertex(pointi) == nextPointi)
577 {
578 fEdges[fp] = edgeI;
579 break;
580 }
581 }
582 }
583 }
584 }
585
586 return *fePtr_;
587}
588
589
590void Foam::primitiveMesh::clearOutEdges()
591{
592 edgesPtr_.reset(nullptr);
593 pePtr_.reset(nullptr);
594 fePtr_.reset(nullptr);
595 labels_.clear();
596 labelSet_.clear();
597}
598
599
601(
602 const label facei,
603 DynamicList<label>& storage
604) const
605{
606 if (hasFaceEdges())
607 {
608 return faceEdges()[facei];
609 }
610
611 const labelListList& pointEs = pointEdges();
612 const face& f = faces()[facei];
613
614 storage.clear();
615 if (storage.capacity() < f.size())
616 {
617 storage.setCapacity(f.size());
618 }
619
620 forAll(f, fp)
621 {
622 storage.push_back
623 (
625 (
626 pointEs[f[fp]],
627 pointEs[f.nextLabel(fp)]
628 )
629 );
630 }
631
632 return storage;
633}
634
636const Foam::labelList& Foam::primitiveMesh::faceEdges(const label facei) const
637{
638 return faceEdges(facei, labels_);
639}
640
641
643(
644 const label celli,
645 labelHashSet& set,
646 DynamicList<label>& storage
647) const
648{
649 if (hasCellEdges())
650 {
651 return cellEdges()[celli];
652 }
653
654 const labelList& cFaces = cells()[celli];
655
656 set.clear();
657
658 for (const label facei : cFaces)
659 {
660 set.insert(faceEdges(facei));
661 }
662
663 storage.clear();
664 if (storage.capacity() < set.size())
665 {
666 storage.setCapacity(set.size());
667 }
668
669 for (const label edgei : set)
670 {
671 storage.push_back(edgei);
672 }
673
674 return storage;
675}
676
677
678const Foam::labelList& Foam::primitiveMesh::cellEdges(const label celli) const
679{
680 return cellEdges(celli, labelSet_, labels_);
681}
682
683
684// ************************************************************************* //
Various functions to operate on Lists.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
void push_back(const T &val)
Copy append an element to the end of this list.
label capacity() const noexcept
Size of the underlying storage.
void setCapacity(const label len)
Alter the size of the underlying storage.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void setSize(label n)
Alias for resize().
Definition List.H:536
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition UListI.H:410
bool contains(const T &val) const
True if the value is contained in the list.
Definition UListI.H:302
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition UListI.H:454
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition UListI.H:99
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
const labelListList & pointEdges() const
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const labelListList & cellEdges() const
bool hasCellEdges() const noexcept
virtual const faceList & faces() const =0
Return faces.
label nPoints() const noexcept
Number of mesh points.
static const unsigned edgesPerPoint_
Estimated number of edges per point.
const labelListList & faceEdges() const
bool hasFaceEdges() const noexcept
virtual const pointField & points() const =0
Return mesh points.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const cellShapeList & cells
void set(List< bool > &bools, const labelUList &locations)
Set the listed locations (assign 'true').
Definition BitOps.C:35
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
List< edge > edgeList
List of edge.
Definition edgeList.H:32
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values within a list.
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition HashSet.H:85
static label getEdge(List< DynamicList< label > > &pe, DynamicList< edge > &es, const label pointi, const label nextPointi)
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
void sort(UList< T > &list)
Sort the list.
Definition UList.C:283
errorManip< error > abort(error &err)
Definition errorManip.H:139
static label findFirstCommonElementFromSortedLists(const labelUList &list1, const labelUList &list2)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
UList< label > labelUList
A UList of labels.
Definition UList.H:75
labelList f(nPoints)
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299