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