enrichedPatchFaces.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) 2017 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 "enrichedPatch.H"
30 #include "DynamicList.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 const Foam::label Foam::enrichedPatch::enrichedFaceRatio_ = 3;
35 
36 
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38 
40 (
41  const labelListList& pointsIntoMasterEdges,
42  const labelListList& pointsIntoSlaveEdges,
43  const pointField& projectedSlavePoints
44 )
45 {
46  if (enrichedFacesPtr_)
47  {
49  << "Enriched faces already calculated."
50  << abort(FatalError);
51  }
52 
53  // Create a list of enriched faces
54  // Algorithm:
55  // 1) Grab the original face and start from point zero.
56  // 2) If the point has been merged away, grab the merge label;
57  // otherwise, keep the original label.
58  // 3) Go to the next edge. Collect all the points to be added along
59  // the edge; order them in the necessary direction and insert onto the
60  // face.
61  // 4) Grab the next point and return on step 2.
62  enrichedFacesPtr_ = new faceList(masterPatch_.size() + slavePatch_.size());
63  faceList& enrichedFaces = *enrichedFacesPtr_;
64 
65  label nEnrichedFaces = 0;
66 
67  const pointField& masterLocalPoints = masterPatch_.localPoints();
68  const faceList& masterLocalFaces = masterPatch_.localFaces();
69  const labelListList& masterFaceEdges = masterPatch_.faceEdges();
70 
71  const faceList& slaveLocalFaces = slavePatch_.localFaces();
72  const labelListList& slaveFaceEdges = slavePatch_.faceEdges();
73 
74  // For correct functioning of the enrichedPatch class, the slave
75  // faces need to be inserted first. See comments in
76  // enrichedPatch.H
77 
78  // Get reference to the point merge map
79  const Map<label>& pmm = pointMergeMap();
80 
81  // Add slave faces into the enriched faces list
82 
83  forAll(slavePatch_, facei)
84  {
85  const face& oldFace = slavePatch_[facei];
86  const face& oldLocalFace = slaveLocalFaces[facei];
87  const labelList& curEdges = slaveFaceEdges[facei];
88 
89  // Info<< "old slave face[" << facei << "] " << oldFace << endl;
90 
91  DynamicList<label> newFace(oldFace.size()*enrichedFaceRatio_);
92 
93  // Note: The number of points and edges in a face is always identical
94  // so both can be done is the same loop
95  forAll(oldFace, i)
96  {
97  // Add the point.
98  // Using the mapped point id if possible
99 
100  const label mappedPointi = pmm.lookup(oldFace[i], oldFace[i]);
101 
102  newFace.append(mappedPointi);
103 
104  // Add the projected point into the patch support
105  pointMap().insert
106  (
107  mappedPointi, // Global label of point
108  projectedSlavePoints[oldLocalFace[i]] // Projected position
109  );
110 
111  // Grab the edge points
112 
113  const labelList& pointsOnEdge =
114  pointsIntoSlaveEdges[curEdges[i]];
115 
116  // Info<< "slave pointsOnEdge for "
117  // << curEdges[i] << ": " << pointsOnEdge
118  // << endl;
119 
120  // If there are no points on the edge, skip everything
121  // If there is only one point, no need for sorting
122  if (pointsOnEdge.size())
123  {
124  // Sort edge points in order
125  scalarField weightOnEdge(pointsOnEdge.size());
126 
127  const point& startPoint =
128  projectedSlavePoints[oldLocalFace[i]];
129 
130  const point& endPoint =
131  projectedSlavePoints[oldLocalFace.nextLabel(i)];
132 
133  vector e = (endPoint - startPoint);
134 
135  const scalar magSqrE = magSqr(e);
136 
137  if (magSqrE > SMALL)
138  {
139  e /= magSqrE;
140  }
141  else
142  {
144  << "Zero length edge in slave patch for face " << i
145  << ". This is not allowed."
146  << abort(FatalError);
147  }
148 
149  pointField positionOnEdge(pointsOnEdge.size());
150 
151  forAll(pointsOnEdge, edgePointi)
152  {
153  positionOnEdge[edgePointi] =
154  pointMap()[pointsOnEdge[edgePointi]];
155 
156  weightOnEdge[edgePointi] =
157  (
158  e
159  &
160  (
161  positionOnEdge[edgePointi]
162  - startPoint
163  )
164  );
165  }
166 
167  if (debug)
168  {
169  // Check weights: all new points should be on the edge
170  if (min(weightOnEdge) < 0 || max(weightOnEdge) > 1)
171  {
173  << " not on the edge for edge " << curEdges[i]
174  << " of face " << facei << " in slave patch." << nl
175  << "Min weight: " << min(weightOnEdge)
176  << " Max weight: " << max(weightOnEdge)
177  << abort(FatalError);
178  }
179  }
180 
181  // Go through the points and collect them based on
182  // weights from lower to higher. This gives the
183  // correct order of points along the edge.
184  forAll(weightOnEdge, passI)
185  {
186  // Max weight can only be one, so the sorting is
187  // done by elimination.
188  label nextPoint = -1;
189  scalar dist = 2;
190 
191  forAll(weightOnEdge, wI)
192  {
193  if (weightOnEdge[wI] < dist)
194  {
195  dist = weightOnEdge[wI];
196  nextPoint = wI;
197  }
198  }
199 
200  // Insert the next point and reset its weight to exclude it
201  // from future picks
202  newFace.append(pointsOnEdge[nextPoint]);
203  weightOnEdge[nextPoint] = GREAT;
204 
205  // Add the point into patch support
206  pointMap().insert
207  (
208  pointsOnEdge[nextPoint],
209  positionOnEdge[nextPoint]
210  );
211  }
212  }
213  }
214 
215  // Info<< "New slave face[" << facei << "] "
216  // << flatOutput(newFace) << " was " << flatOutput(oldFace)
217  // << endl;
218 
219  // Add the new face to the list
220  enrichedFaces[nEnrichedFaces].transfer(newFace);
221  nEnrichedFaces++;
222  }
223 
224 
225  // Add master faces into the enriched faces list
226 
227  forAll(masterPatch_, facei)
228  {
229  const face& oldFace = masterPatch_[facei];
230  const face& oldLocalFace = masterLocalFaces[facei];
231  const labelList& curEdges = masterFaceEdges[facei];
232 
233  // Info<< "old master face[" << facei << "] " << oldFace << endl;
234 
235  DynamicList<label> newFace(oldFace.size()*enrichedFaceRatio_);
236 
237  // Note: The number of points and edges in a face is always identical
238  // so both can be done is the same loop
239  forAll(oldFace, i)
240  {
241  // Add the point.
242  // Using the mapped point id if possible
243 
244  const label mappedPointi = pmm.lookup(oldFace[i], oldFace[i]);
245 
246  newFace.append(mappedPointi);
247 
248  // Add the point into patch support
249  pointMap().insert
250  (
251  mappedPointi, // Global label of point
252  masterLocalPoints[oldLocalFace[i]]
253  );
254 
255  // Grab the edge points
256 
257  const labelList& pointsOnEdge =
258  pointsIntoMasterEdges[curEdges[i]];
259 
260  // If there are no points on the edge, skip everything
261  // If there is only one point, no need for sorting
262  if (pointsOnEdge.size())
263  {
264  // Sort edge points in order
265  scalarField weightOnEdge(pointsOnEdge.size());
266 
267  const point& startPoint =
268  masterLocalPoints[oldLocalFace[i]];
269 
270  const point& endPoint =
271  masterLocalPoints[oldLocalFace.nextLabel(i)];
272 
273  vector e = (endPoint - startPoint);
274 
275  const scalar magSqrE = magSqr(e);
276 
277  if (magSqrE > SMALL)
278  {
279  e /= magSqrE;
280  }
281  else
282  {
284  << "Zero length edge in master patch for face " << i
285  << ". This is not allowed."
286  << abort(FatalError);
287  }
288 
289  pointField positionOnEdge(pointsOnEdge.size());
290 
291  forAll(pointsOnEdge, edgePointi)
292  {
293  positionOnEdge[edgePointi] =
294  pointMap()[pointsOnEdge[edgePointi]];
295 
296  weightOnEdge[edgePointi] =
297  (
298  e
299  &
300  (
301  positionOnEdge[edgePointi] - startPoint
302  )
303  );
304  }
305 
306  if (debug)
307  {
308  // Check weights: all new points should be on the edge
309  if (min(weightOnEdge) < 0 || max(weightOnEdge) > 1)
310  {
312  << " not on the edge for edge " << curEdges[i]
313  << " of face " << facei << " in master patch." << nl
314  << "Min weight: " << min(weightOnEdge)
315  << " Max weight: " << max(weightOnEdge)
316  << abort(FatalError);
317  }
318  }
319 
320  // Go through the points and collect them based on
321  // weights from lower to higher. This gives the
322  // correct order of points along the edge.
323  forAll(weightOnEdge, passI)
324  {
325  // Max weight can only be one, so the sorting is
326  // done by elimination.
327  label nextPoint = -1;
328  scalar dist = 2;
329 
330  forAll(weightOnEdge, wI)
331  {
332  if (weightOnEdge[wI] < dist)
333  {
334  dist = weightOnEdge[wI];
335  nextPoint = wI;
336  }
337  }
338 
339  // Insert the next point and reset its weight to exclude it
340  // from future picks
341  newFace.append(pointsOnEdge[nextPoint]);
342  weightOnEdge[nextPoint] = GREAT;
343 
344  // Add the point into patch support
345  pointMap().insert
346  (
347  pointsOnEdge[nextPoint],
348  positionOnEdge[nextPoint]
349  );
350  }
351  }
352  }
353 
354  // Info<< "New master face[" << facei << "] "
355  // << flatOutput(newFace) << " was " << flatOutput(oldFace)
356  // << endl;
357 
358  // Add the new face to the list
359  enrichedFaces[nEnrichedFaces].transfer(newFace);
360  nEnrichedFaces++;
361  }
362 
363  // Check the support for the enriched patch
364  if (debug)
365  {
366  if (!checkSupport())
367  {
368  Info<< "Enriched patch support OK. Slave faces: "
369  << slavePatch_.size() << " Master faces: "
370  << masterPatch_.size() << endl;
371  }
372  else
373  {
375  << "Error in enriched patch support"
376  << abort(FatalError);
377  }
378  }
379 }
380 
381 
382 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
383 
385 {
386  if (!enrichedFacesPtr_)
387  {
389  << "void enrichedPatch::calcEnrichedFaces\n"
390  << "(\n"
391  << " const labelListList& pointsIntoMasterEdges,\n"
392  << " const labelListList& pointsIntoSlaveEdges,\n"
393  << " const pointField& projectedSlavePoints\n"
394  << ")"
395  << " before trying to access faces."
396  << abort(FatalError);
397  }
398 
399  return *enrichedFacesPtr_;
400 }
401 
402 
403 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::DynamicList< label >
Foam::enrichedPatch::calcEnrichedFaces
void calcEnrichedFaces(const labelListList &pointsIntoMasterEdges, const labelListList &pointsIntoSlaveEdges, const pointField &projectedSlavePoints)
Calculate enriched faces.
Definition: enrichedPatchFaces.C:40
Foam::Map< label >
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:290
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::label
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:62
Foam::Field< vector >
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::FatalError
error FatalError
Foam::enrichedPatch::enrichedFaces
const faceList & enrichedFaces() const
Return enriched faces.
Definition: enrichedPatchFaces.C:384
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:137
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:355
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::faceList
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
Foam::Vector< scalar >
Foam::List< labelList >
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:74
DynamicList.H
enrichedPatch.H