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 -------------------------------------------------------------------------------
11 License
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 
37 Foam::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 
82 void 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 
466 Foam::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 
579 void Foam::primitiveMesh::clearOutEdges()
580 {
581  deleteDemandDrivenData(edgesPtr_);
582  deleteDemandDrivenData(pePtr_);
583  deleteDemandDrivenData(fePtr_);
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 
625 const 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 
667 const Foam::labelList& Foam::primitiveMesh::cellEdges(const label celli) const
668 {
669  return cellEdges(celli, labelSet_, labels_);
670 }
671 
672 
673 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::BitOps::set
void set(List< bool > &bools, const labelRange &range)
Set the specified range 'on' in a boolList.
Definition: BitOps.C:37
Foam::edgeList
List< edge > edgeList
A List of edges.
Definition: edgeList.H:63
Foam::DynamicList< label >
demandDrivenData.H
Template functions to aid in the implementation of demand driven data.
primitiveMesh.H
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::DynamicList::capacity
label capacity() const noexcept
Size of the underlying storage.
Definition: DynamicListI.H:287
Foam::primitiveMesh::edges
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
Definition: primitiveMeshEdges.C:505
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::primitiveMesh::pointEdges
const labelListList & pointEdges() const
Definition: primitiveMeshEdges.C:516
Foam::HashSet< label, Hash< label > >
Foam::DynamicList::clear
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:391
Foam::inplaceRenumber
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values (not the indices) of a list.
Definition: ListOpsTemplates.C:61
Foam::DynamicList::setCapacity
void setCapacity(const label len)
Alter the size of the underlying storage.
Definition: DynamicListI.H:303
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::deleteDemandDrivenData
void deleteDemandDrivenData(DataPtr &dataPtr)
Definition: demandDrivenData.H:42
SortableList.H
Foam::primitiveMesh::cellEdges
const labelListList & cellEdges() const
Definition: primitiveMeshCellEdges.C:115
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
Foam::primitiveMesh::faceEdges
const labelListList & faceEdges() const
Definition: primitiveMeshEdges.C:528
Foam::sort
void sort(UList< T > &a)
Definition: UList.C:261
Foam::FatalError
error FatalError
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
f
labelList f(nPoints)
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::List< edge >
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
DynamicList.H
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
ListOps.H
Various functions to operate on Lists.
Foam::primitiveMesh::edgesPerPoint_
static const unsigned edgesPerPoint_
Estimated number of edges per point.
Definition: primitiveMesh.H:419