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