Loading...
Searching...
No Matches
pointMeshTools.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) 2024 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "pointMeshTools.H"
29#include "syncTools.H"
30#include "PatchTools.H"
31#include "dummyTransform.H"
32#include "unitConversion.H"
33//#include "OFstream.H"
34
35// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
36
38(
39 const polyMesh& mesh,
40
41 const uindirectPrimitivePatch& allBoundary,
42
43 // Per boundary face to zone
44 const labelUList& faceToZone,
45 // Number of zones
46 const label nZones,
47
48 const scalar edgeFeatureAngle,
49 //const scalar pointFeatureAngle, //not yet done
50
51 // Feature edge(points) internal to a zone
52 labelListList& zoneToMeshPoints,
53 List<pointConstraintList>& zoneToConstraints,
54
55 // Feature edge(points) in between zones
56 labelList& twoZoneMeshPoints,
57 pointConstraintList& twoZoneConstraints,
58
59 // Feature points on > 2 zones
60 labelList& multiZoneMeshPoints,
61 pointConstraintList& multiZoneConstraints
62)
63{
64 // Analyses edges on mesh faces and splits them up according to topology
65 // and geometry:
66 // - edges in between faces on same zone but making a feature angle
67 // - edges in between faces on two different zones
68 // - points on faces on > 2 zones
69
70
71 const globalMeshData& globalData = mesh.globalData();
72 const indirectPrimitivePatch& cpp = globalData.coupledPatch();
73 const mapDistribute& map = globalData.globalEdgeSlavesMap();
74 const auto& mp = allBoundary.meshPoints();
75
76 const vector nullVector(vector::uniform(0));
77 const auto assignNonNull = [&](vector& x, const vector& y)
78 {
79 if (x == nullVector && y != nullVector)
80 {
81 x = y;
82 }
83 };
84
85 // Calculate parallel-consistent point normals (as unweighted average
86 // of faceNormals). Note: only valid on patch points, not on mesh points
87 // that are coupled to these.
88 const pointField pointNormals
89 (
91 (
92 mesh,
93 allBoundary
94 )
95 );
96
97
98 // Find correspondence between allBoundary and coupled edges
99 labelList allEdges;
100 labelList coupledEdges;
101 bitSet sameEdgeOrientation;
103 (
104 allBoundary,
105 cpp,
106 allEdges,
107 coupledEdges,
108 sameEdgeOrientation
109 );
110
111
112
113 // To construct the patches we need to know per edge:
114 // - patch on either side (if topological feature edge)
115 // - faceNormal on either side (if feature angle)
116 // We need to know per point:
117 // - patches on all connected faces
118 // - faceNormals on all connected faces? And compare to average?
119 // or edge normals on all connected edges
120
121
122 typedef Tuple2<label, vector> PN;
123 const PN nullPN(-1, nullVector);
124
125
126
127 // Point-based analysis
128 // ~~~~~~~~~~~~~~~~~~~~
129
130 // Collect per (mesh)point the zones (1, 2 or >2). Note: per mesh to
131 // make it easier to sync. See edge-based code below where we explicitly
132 // have to transfer from patch-edge to mesh-point etc. Note sure which one
133 // fits better....
134 // State:
135 // (-1, -1) : initial state
136 // (-2, -2) : more than 2 zones
137 // (>=0, >=0) : zones from connected faces
138 labelPairList pointToZones(mesh.nPoints(), labelPair(-1, -1));
139 {
140 // Combine zones.
141 const auto combineZones = [&](labelPair& x, const labelPair& y)
142 {
143 if (x == labelPair(-2, -2))
144 {
145 // Already marked as having >2 zones
146 }
147 else if (y == labelPair(-2, -2))
148 {
149 x = y;
150 }
151 else
152 {
153 // Find first free slot
154 if (x[0] == -1)
155 {
156 if (y[0] != -1)
157 {
158 x[0] = y[0];
159 }
160 else
161 {
162 x[0] = y[1];
163 }
164 }
165 else if (x[1] == -1)
166 {
167 if (y[0] != -1 && y[0] != x[0])
168 {
169 x[1] = y[0];
170 }
171 else if (y[1] != -1 && y[1] != x[1])
172 {
173 x[1] = y[1];
174 }
175 }
176 else
177 {
178 // Both x slots filled. See if y adds a 3rd element
179 if (y[0] != -1 && y[0] != x[0] && y[0] != x[1])
180 {
181 x = labelPair(-2, -2);
182 }
183 else if (y[1] != -1 && y[1] != x[0] && y[1] != x[1])
184 {
185 x = labelPair(-2, -2);
186 }
187 }
188 }
189 };
190
191
192 forAll(allBoundary, facei)
193 {
194 const auto& f = allBoundary[facei];
195 const label zonei = faceToZone[facei];
196 for (const label pointi : f)
197 {
198 auto& pZones = pointToZones[pointi];
199
200 if (pZones != labelPair(-2, -2) && !pZones.contains(zonei))
201 {
202 if (pZones.first() == -1)
203 {
204 pZones.first() = zonei;
205 }
206 else if (pZones.second() == -1)
207 {
208 pZones.second() = zonei;
209 }
210 else
211 {
212 // Mark as >2 zones
213 pZones = labelPair(-2, -2);
214 }
215 }
216 }
217 }
218
220 (
221 mesh,
222 pointToZones,
223 combineZones,
224 labelPair(-1, -1),
226 );
227 }
228
229
230
231
232 // Edge-based analysis
233 // ~~~~~~~~~~~~~~~~~~~~
234
235 // 1. Local analysis
236
237 List<Pair<PN>> allEdgeToFaces
238 (
239 allBoundary.nEdges(),
240 Pair<PN>(nullPN, nullPN)
241 );
242 {
243 const auto& edgeFaces = allBoundary.edgeFaces();
244 const auto& faceNormals = allBoundary.faceNormals();
245
246 forAll(edgeFaces, edgei)
247 {
248 const auto& eFaces = edgeFaces[edgei];
249 const vector& n0 = faceNormals[eFaces[0]];
250 const label zone0 = faceToZone[eFaces[0]];
251 if (eFaces.size() == 1)
252 {
253 allEdgeToFaces[edgei] = Pair<PN>(PN(zone0, n0), nullPN);
254 }
255 else
256 {
257 const vector& n1 = faceNormals[eFaces[1]];
258 const label zone1 = faceToZone[eFaces[1]];
259 allEdgeToFaces[edgei] = Pair<PN>
260 (
261 PN(zone0, n0),
262 PN(zone1, n1)
263 );
264 }
265 }
266 }
267
268
269 // 2. Sync across coupled patches
270
271 {
272 // Combine pair of normals
273 const auto vectorPairMax = [&](Pair<PN>& x, const Pair<PN>& y)
274 {
275 if (x[0] == nullPN)
276 {
277 if (y[0] != nullPN)
278 {
279 x[0] = y[0];
280 }
281 else
282 {
283 x[0] = y[1];
284 }
285 }
286 else if (x[1] == nullPN)
287 {
288 if (y[0] != nullPN && y[0] != x[0])
289 {
290 x[1] = y[0];
291 }
292 else
293 {
294 x[1] = y[1];
295 }
296 }
297 };
298
299 List<Pair<PN>> cppEdgeData
300 (
301 map.constructSize(),
302 Pair<PN>(nullPN, nullPN)
303 );
304 UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges) =
305 UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges);
306
307 globalData.syncData
308 (
309 cppEdgeData,
310 globalData.globalEdgeSlaves(),
311 globalData.globalEdgeTransformedSlaves(),
312 map,
313 globalData.globalTransforms(),
314 vectorPairMax,
316 );
317
318 UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges) =
319 UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges);
320 }
321
322
323 // Now we have all the per-patch edge information
324 // - do inter-patch edges
325 // - do feature-angle edges
326 // Store on mesh points
327
328 const auto assignNonNullPN = [&](PN& x, const PN& y)
329 {
330 if (x.second() == nullVector && y.second() != nullVector)
331 {
332 x = y;
333 }
334 };
335
336
337 const scalar featEdgeCos = Foam::cos(degToRad(edgeFeatureAngle));
338
339
340 //OFstream os("allBoundary.obj");
341 //Pout<< "Dumping feature edges to " << os.name() << endl;
342 //OFstream interOs("interZoneBoundary.obj");
343 //Pout<< "Dumping inter-zone edges to " << os.name() << endl;
344
345 // Storing the normal for points that are on inter-patch edges
346 vectorField patchEdgeNormal(mesh.nPoints(), nullVector);
347 // Storing the constraint for points that are on patch-internal feat edges
348 List<PN> featEdgeNormal(mesh.nPoints(), nullPN);
349
350 // Use point-based sync
351 {
352 forAll(allEdgeToFaces, edgei)
353 {
354 const edge& e = allBoundary.edges()[edgei];
355 const label mp0 = mp[e[0]];
356 const label mp1 = mp[e[1]];
357
358 const Pair<PN>& facesInfo = allEdgeToFaces[edgei];
359
360 if (facesInfo[1] == nullPN)
361 {
362 // Real boundary edge. On single patch only so no need
363 // to put in separate point patch ... (? tbd)
364 }
365 else
366 {
367 const label zone0 = facesInfo[0].first();
368 const label zone1 = facesInfo[1].first();
369
370 const point& p0 = allBoundary.points()[mp0];
371 const point& p1 = allBoundary.points()[mp1];
372 vector eVec(p1-p0);
373 eVec.normalise();
374
375 if (zone0 != zone1)
376 {
377 // Inter-patch. TBD: check for feature angle as well?
378
379 //patchEdgeNormal[mp0] = pointNormals[e[0]];
380 //patchEdgeNormal[mp1] = pointNormals[e[1]];
381
382 patchEdgeNormal[mp0] = eVec;
383 patchEdgeNormal[mp1] = eVec;
384 }
385 else
386 {
387 // Same patch - check for feature angle
388
389 const vector& n0 = facesInfo[0].second();
390 const vector& n1 = facesInfo[1].second();
391
392 if ((n0 & n1) < featEdgeCos)
393 {
394 //Pout<< "** feature edge:" << edgei
395 // << " points:" << allBoundary.points()[mp0]
396 // << allBoundary.points()[mp1]
397 // << nl
398 // << " faceNormal0:" << n0
399 // << " faceNormal1:" << n1 << nl
400 // << " zone0:" << zone0
401 // << " zone1:" << zone1 << nl
402 // << " pointNormals0:" << pointNormals[e[0]]
403 // << " pointNormals1:" << pointNormals[e[1]]
404 // << nl
405 // << endl;
406
407 if (patchEdgeNormal[mp0] == nullVector)
408 {
409 //featEdgeNormal[mp0] = PN
410 //(
411 // zone0, // zone
412 // pointNormals[e[0]]
413 //);
414 featEdgeNormal[mp0].first() = zone0;
415 // Assign edge direction. TBD: average & parallel
416 featEdgeNormal[mp0].second() = eVec;
417 }
418 if (patchEdgeNormal[mp1] == nullVector)
419 {
420 //featEdgeNormal[mp1] = PN
421 //(
422 // zone1, // zone
423 // pointNormals[e[1]]
424 //);
425 featEdgeNormal[mp1].first() = zone1;
426 // Assign edge direction. TBD: average & parallel
427 featEdgeNormal[mp1].second() = eVec;
428 }
429 }
430 }
431 }
432 }
433
435 (
436 mesh,
437 patchEdgeNormal,
438 assignNonNull,
439 nullVector
440 );
442 (
443 mesh,
444 featEdgeNormal,
445 assignNonNullPN,
446 nullPN,
448 );
449 }
450
451 // Make sure that inter-patch points are not also in feature-edge
452 // points. Note: not absolutely necessary since all inter-patch points
453 // will also be in the 'normal' facePointPatches.
454
455 DynamicList<label> dynMultiZoneMeshPoints(allBoundary.nPoints());
456 DynamicList<pointConstraint> dynMultiZoneConstraints(allBoundary.nPoints());
457 forAll(pointToZones, pointi)
458 {
459 if (pointToZones[pointi] == labelPair(-2, -2))
460 {
461 dynMultiZoneMeshPoints.append(pointi);
462 // Note: pointConstraint just a slip constraint for now
463 dynMultiZoneConstraints.append
464 (
466 (
467 3, // feature point
468 Zero //meshPointNormals[pointi]
469 )
470 );
471 // Unmark as feature angle point
472 patchEdgeNormal[pointi] = nullVector;
473 featEdgeNormal[pointi] = nullPN;
474 }
475 }
476 multiZoneMeshPoints = std::move(dynMultiZoneMeshPoints);
477 multiZoneConstraints = std::move(dynMultiZoneConstraints);
478
479
480 DynamicList<label> dynTwoZoneMeshPoints(allBoundary.nPoints());
481 DynamicList<pointConstraint> dynTwoZoneConstraints(allBoundary.nPoints());
482 forAll(patchEdgeNormal, pointi)
483 {
484 if (patchEdgeNormal[pointi] != nullVector)
485 {
486 dynTwoZoneMeshPoints.append(pointi);
487 // Note: pointConstraint just a slip constraint for now
488 dynTwoZoneConstraints.append
489 (
491 (
492 2, // feature edge
493 patchEdgeNormal[pointi]
494 )
495 );
496
497 // Unmark as feature angle point
498 featEdgeNormal[pointi] = nullPN;
499 }
500 }
501 twoZoneMeshPoints = std::move(dynTwoZoneMeshPoints);
502 twoZoneConstraints = std::move(dynTwoZoneConstraints);
503
504
505 // Sort featEdgeNormal according to zone
506 zoneToMeshPoints.resize_nocopy(nZones);
507 zoneToConstraints.resize_nocopy(nZones);
508 {
509 labelList sizes(nZones, 0);
510 forAll(featEdgeNormal, pointi)
511 {
512 const auto& pInfo = featEdgeNormal[pointi];
513 if (pInfo != nullPN)
514 {
515 const label zonei = pInfo.first();
516 sizes[zonei]++;
517 }
518 }
519 forAll(zoneToMeshPoints, zonei)
520 {
521 zoneToMeshPoints[zonei].setSize(sizes[zonei]);
522 zoneToConstraints[zonei].setSize(sizes[zonei]);
523 }
524 sizes = 0;
525 forAll(featEdgeNormal, pointi)
526 {
527 const auto& pInfo = featEdgeNormal[pointi];
528 if (pInfo != nullPN)
529 {
530 const label zonei = pInfo.first();
531 const label index = sizes[zonei]++;
532
533 zoneToMeshPoints[zonei][index] = pointi;
534 zoneToConstraints[zonei][index] =
535 pointConstraint(2, pInfo.second()); // constrained to slide
536 }
537 }
538 }
539}
540
541
542// ************************************************************************* //
scalar y
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
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 resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
void setSize(label n)
Alias for resize().
Definition List.H:536
An ordered pair of two objects of type <T> with first() and second() elements.
Definition Pair.H:66
const T & first() const noexcept
Access the first element.
Definition Pair.H:137
const T & second() const noexcept
Access the second element.
Definition Pair.H:147
static void matchEdges(const PrimitivePatch< FaceList1, PointField1 > &p1, const PrimitivePatch< FaceList2, PointField2 > &p2, labelList &p1EdgeLabels, labelList &p2EdgeLabels, bitSet &sameOrientation)
Find corresponding edges on patches sharing the same points.
static tmp< pointField > pointNormals(const polyMesh &, const PrimitivePatch< FaceList, PointField > &, const bitSet &flipMap=bitSet::null())
Return parallel consistent point normals for patches using mesh points.
label nEdges() const
Number of edges in patch.
label nPoints() const
Number of points supporting patch faces.
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
const Field< point_type > & points() const noexcept
Return reference to global points.
const labelListList & edgeFaces() const
Return edge-face addressing.
A 2-tuple for storing two objects of dissimilar types. The container is similar in purpose to std::pa...
Definition Tuple2.H:51
A List with indirect addressing. Like IndirectList but does not store addressing.
T & first()
Access first element of the list, position [0].
Definition UList.H:957
static Form uniform(const Cmpt &s)
Return a VectorSpace with all elements = s.
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Definition VectorI.H:114
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition bitSet.H:61
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const labelListList & globalEdgeTransformedSlaves() const
const mapDistribute & globalEdgeSlavesMap() const
static void syncData(List< Type > &elems, const labelListList &slaves, const labelListList &transformedSlaves, const mapDistribute &slavesMap, const globalIndexAndTransform &, const CombineOp &cop, const TransformOp &top)
Helper: synchronise data with transforms.
const globalIndexAndTransform & globalTransforms() const
Global transforms numbering.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
const labelListList & globalEdgeSlaves() const
label constructSize() const noexcept
Constructed data size.
Class containing processor-to-processor mapping information.
Accumulates point constraints through successive applications of the applyConstraint function.
static void featurePointsEdges(const polyMesh &mesh, const uindirectPrimitivePatch &boundary, const labelUList &faceToZone, const label nZones, const scalar edgeFeatureAngle, labelListList &zoneToMeshPoints, List< pointConstraintList > &zoneToConstraints, labelList &twoZoneMeshPoints, pointConstraintList &twoZoneConstraints, labelList &multiZoneMeshPoints, pointConstraintList &multiZoneConstraints)
Analyse patch for feature edges, feature points. Handles points not being on a face of patch but coup...
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
const volScalarField & p0
Definition EEqn.H:36
dynamicFvMesh & mesh
IOporosityModelList pZones(mesh)
Dummy transform to be used with syncTools.
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
List< labelPair > labelPairList
List of labelPair.
Definition labelPair.H:33
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
List< label > labelList
A List of labels.
Definition List.H:62
List< pointConstraint > pointConstraintList
List of pointConstraint.
constexpr scalar degToRad() noexcept
Multiplication factor for degrees to radians conversion.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
Field< vector > vectorField
Specialisation of Field<T> for vector.
vector point
Point is a vector.
Definition point.H:37
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
vectorField pointField
pointField is a vectorField.
Vector< scalar > vector
Definition vector.H:57
UList< label > labelUList
A UList of labels.
Definition UList.H:75
dimensionedScalar cos(const dimensionedScalar &ds)
labelList f(nPoints)
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Unit conversion functions.