Loading...
Searching...
No Matches
globalIndexAndTransform.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-2017 OpenFOAM Foundation
9 Copyright (C) 2019-2022 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
30#include "cyclicPolyPatch.H"
32#include "globalMeshData.H"
33
34// * * * * * * * * * * * * Private Static Data Members * * * * * * * * * * * //
35
36namespace Foam
37{
39}
40
41
42// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43
44Foam::label Foam::globalIndexAndTransform::matchTransform
45(
46 const List<vectorTensorTransform>& refTransforms,
47 label& matchedRefTransformI,
48 const vectorTensorTransform& testTransform,
49 scalar tolerance,
50 bool checkBothSigns
51) const
52{
53 matchedRefTransformI = -1;
54
55 forAll(refTransforms, i)
56 {
57 const vectorTensorTransform& refTransform = refTransforms[i];
58
59 scalar maxVectorMag = sqrt
60 (
61 max(magSqr(testTransform.t()), magSqr(refTransform.t()))
62 );
63
64 // Test the difference between vector parts to see if it is
65 // less than tolerance times the larger vector part magnitude.
66
67 scalar vectorDiff =
68 mag(refTransform.t() - testTransform.t())
69 /(maxVectorMag + VSMALL)
70 /tolerance;
71
72 // Test the difference between tensor parts to see if it is
73 // less than the tolerance. sqrt(3.0) factor used to scale
74 // differences as this is magnitude of a rotation tensor. If
75 // neither transform has a rotation, then the test is not
76 // necessary.
77
78 scalar tensorDiff = 0;
79
80 if (refTransform.hasR() || testTransform.hasR())
81 {
82 tensorDiff =
83 mag(refTransform.R() - testTransform.R())
84 /sqrt(3.0)
85 /tolerance;
86 }
87
88 // ...Diff result is < 1 if the test part matches the ref part
89 // within tolerance
90
91 if (vectorDiff < 1 && tensorDiff < 1)
92 {
93 matchedRefTransformI = i;
94
95 return +1;
96 }
97
98 if (checkBothSigns)
99 {
100 // Test the inverse transform differences too
101
102 vectorDiff =
103 mag(refTransform.t() + testTransform.t())
104 /(maxVectorMag + VSMALL)
105 /tolerance;
106
107 tensorDiff = 0;
108
109 if (refTransform.hasR() || testTransform.hasR())
110 {
111 tensorDiff =
112 mag(refTransform.R() - testTransform.R().T())
113 /sqrt(3.0)
114 /tolerance;
115 }
116
117 if (vectorDiff < 1 && tensorDiff < 1)
118 {
119 matchedRefTransformI = i;
120
121 return -1;
122 }
123 }
124 }
125
126 return 0;
127}
128
129
130void Foam::globalIndexAndTransform::determineTransforms()
131{
132 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
133
135 DynamicField<scalar> localTols;
136
137 label dummyMatch = -1;
138
139 forAll(patches, patchi)
140 {
141 const polyPatch& pp = patches[patchi];
142
143 // Note: special check for unordered cyclics. These are in fact
144 // transform bcs and should probably be split off.
145 // Note: We don't want to be finding transforms for patches marked as
146 // coincident full match. These should have no transform by definition.
147 if
148 (
150 && !(
154 )
155 && !(
158 )
159 )
160 {
162
163 if (cpp.separated())
164 {
165 const vectorField& sepVecs = cpp.separation();
166
167 forAll(sepVecs, sVI)
168 {
169 const vector& sepVec = sepVecs[sVI];
170
171 if (mag(sepVec) > SMALL)
172 {
174
175 if
176 (
177 matchTransform
178 (
179 localTransforms,
180 dummyMatch,
181 transform,
182 cpp.matchTolerance(),
183 false
184 ) == 0
185 )
186 {
187 localTransforms.append(transform);
188 localTols.append(cpp.matchTolerance());
189 }
190 }
191 }
192 }
193 else if (!cpp.parallel())
194 {
195 const tensorField& transTensors = cpp.reverseT();
196
197 forAll(transTensors, tTI)
198 {
199 const tensor& transT = transTensors[tTI];
200
201 if (mag(transT - I) > SMALL)
202 {
204
205 if
206 (
207 matchTransform
208 (
209 localTransforms,
210 dummyMatch,
211 transform,
212 cpp.matchTolerance(),
213 false
214 ) == 0
215 )
216 {
217 localTransforms.append(transform);
218 localTols.append(cpp.matchTolerance());
219 }
220 }
221 }
222 }
223 }
224 }
225
226
227 // Collect transforms on master
229 allTransforms[Pstream::myProcNo()] = localTransforms;
230 Pstream::gatherList(allTransforms);
231
232 // Collect matching tolerance on master
234 allTols[Pstream::myProcNo()] = localTols;
235 Pstream::gatherList(allTols);
236
237 if (Pstream::master())
238 {
239 localTransforms.clear();
240
241 forAll(allTransforms, proci)
242 {
243 const List<vectorTensorTransform>& procTransVecs =
244 allTransforms[proci];
245
246 forAll(procTransVecs, pSVI)
247 {
248 const vectorTensorTransform& transform = procTransVecs[pSVI];
249
250 if (mag(transform.t()) > SMALL || transform.hasR())
251 {
252 if
253 (
254 matchTransform
255 (
256 localTransforms,
257 dummyMatch,
258 transform,
259 allTols[proci][pSVI],
260 true
261 ) == 0
262 )
263 {
264 localTransforms.append(transform);
265 }
266 }
267 }
268 }
269 }
270
271 transforms_.transfer(localTransforms);
272 Pstream::broadcast(transforms_);
273}
274
275
276void Foam::globalIndexAndTransform::determineTransformPermutations()
277{
278 label nTransformPermutations = pow(label(3), transforms_.size());
279
280 transformPermutations_.setSize(nTransformPermutations);
281
282 forAll(transformPermutations_, tPI)
283 {
285
286 label transformIndex = tPI;
287
288 // Invert the ternary index encoding using repeated division by
289 // three
290
291 forAll(transforms_, b)
292 {
293 const label w = (transformIndex % 3) - 1;
294
295 transformIndex /= 3;
296
297 if (w > 0)
298 {
299 transform &= transforms_[b];
300 }
301 else if (w < 0)
302 {
303 transform &= inv(transforms_[b]);
304 }
305 }
306
307 transformPermutations_[tPI] = transform;
308 }
309
310
311 // Encode index for 0 sign
312 labelList permutationIndices(nIndependentTransforms(), Zero);
313 nullTransformIndex_ = encodeTransformIndex(permutationIndices);
314}
315
316
317void Foam::globalIndexAndTransform::determinePatchTransformSign()
318{
319 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
320
321 patchTransformSign_.setSize(patches.size(), labelPair(-1, 0));
322
323 forAll(patches, patchi)
324 {
325 const polyPatch& pp = patches[patchi];
326
327 // Note: special check for unordered cyclics. These are in fact
328 // transform bcs and should probably be split off.
329 // Note: We don't want to be finding transforms for patches marked as
330 // coincident full match. These should have no transform by definition.
331 if
332 (
334 && !(
338 )
339 && !(
342 )
343 )
344 {
346
347 if (cpp.separated())
348 {
349 const vectorField& sepVecs = cpp.separation();
350
351 // This loop is implicitly expecting only a single
352 // value for separation()
353 forAll(sepVecs, sVI)
354 {
355 const vector& sepVec = sepVecs[sVI];
356
357 if (mag(sepVec) > SMALL)
358 {
359 vectorTensorTransform t(sepVec);
360
361 label matchTransI;
362 label sign = matchTransform
363 (
364 transforms_,
365 matchTransI,
366 t,
367 cpp.matchTolerance(),
368 true
369 );
370 patchTransformSign_[patchi] =
371 labelPair(matchTransI, sign);
372 }
373 }
374
375 }
376 else if (!cpp.parallel())
377 {
378 const tensorField& transTensors = cpp.reverseT();
379
380 // This loop is implicitly expecting only a single
381 // value for reverseT()
382 forAll(transTensors, tTI)
383 {
384 const tensor& transT = transTensors[tTI];
385
386 if (mag(transT - I) > SMALL)
387 {
388 vectorTensorTransform t(transT);
389
390 label matchTransI;
391 label sign = matchTransform
392 (
393 transforms_,
394 matchTransI,
395 t,
396 cpp.matchTolerance(),
397 true
398 );
399
400 patchTransformSign_[patchi] =
401 labelPair(matchTransI, sign);
402 }
403 }
404 }
405 }
406 }
407}
408
409
410bool Foam::globalIndexAndTransform::uniqueTransform
411(
412 const point& pt,
413 labelPairList& trafos,
414 const label patchi,
415 const labelPair& patchTrafo
416) const
417{
418 if (!trafos.found(patchTrafo))
419 {
420 // New transform. Check if already have 3
421 if (trafos.size() == 3)
422 {
423 if (patchi > -1)
424 {
426 << "Point " << pt
427 << " is on patch " << mesh_.boundaryMesh()[patchi].name();
428 }
429 else
430 {
432 << "Point " << pt << " is on a coupled patch";
433 }
434 Warning
435 << " with transformation " << patchTrafo
436 << " but also on 3 other patches with transforms "
437 << trafos << nl
438 << "This is not a space filling tiling and might"
439 << " indicate a setup problem and give problems"
440 << " for e.g. lagrangian tracking or interpolation" << endl;
441
442 // Already warned so no need to extend more
443 trafos.clear();
444 return false;
445 }
446
447 return true;
448 }
450 return false;
451}
452
453
454// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
455
456Foam::globalIndexAndTransform::globalIndexAndTransform(const polyMesh& mesh)
457:
458 mesh_(mesh),
459 transforms_(),
460 transformPermutations_(),
461 patchTransformSign_()
462{
463 determineTransforms();
464
465 determineTransformPermutations();
466
467 determinePatchTransformSign();
468
469 if (debug && transforms_.size() > 0)
470 {
471 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
472
473 Info<< "Determined global transforms :" << endl;
474 Info<< "\t\ttranslation\trotation" << endl;
475 forAll(transforms_, i)
476 {
477 Info<< '\t' << i << '\t';
478 const vectorTensorTransform& trafo = transforms_[i];
479 if (trafo.hasR())
480 {
481 Info<< trafo.t() << '\t' << trafo.R();
482 }
483 else
484 {
485 Info<< trafo.t() << '\t' << "---";
486 }
487 Info<< endl;
488 }
489 Info<< endl;
490
491
492 Info<< "\tpatch\ttransform\tsign" << endl;
493 forAll(patchTransformSign_, patchi)
494 {
495 if (patchTransformSign_[patchi].first() != -1)
496 {
497 Info<< '\t' << patches[patchi].name()
498 << '\t' << patchTransformSign_[patchi].first()
499 << '\t' << patchTransformSign_[patchi].second()
500 << endl;
501 }
502 }
503 Info<< endl;
504
505
506 Info<< "Permutations of transformations:" << endl
507 << "\t\ttranslation\trotation" << endl;
508 forAll(transformPermutations_, i)
509 {
510 Info<< '\t' << i << '\t';
511 const vectorTensorTransform& trafo = transformPermutations_[i];
512 if (trafo.hasR())
513 {
514 Info<< trafo.t() << '\t' << trafo.R();
515 }
516 else
517 {
518 Info<< trafo.t() << '\t' << "---";
519 }
520 Info<< endl;
521 }
522 Info<< "nullTransformIndex:" << nullTransformIndex() << endl
523 << endl;
524 }
525
526
527 if (transforms_.size() > 0)
528 {
529 // Check that the transforms are space filling : any point
530 // can only use up to three transforms
531
532 const polyBoundaryMesh& patches = mesh_.boundaryMesh();
533
534
535 // 1. Collect transform&sign per point and do local check
536
537 List<labelPairList> pointToTrafos(mesh_.nPoints());
538
539 forAll(patches, patchi)
540 {
541 const polyPatch& pp = patches[patchi];
542
543 const labelPair& transSign = patchTransformSign_[patchi];
544
545 if (transSign.first() > -1)
546 {
547 const labelList& mp = pp.meshPoints();
548 forAll(mp, i)
549 {
550 labelPairList& trafos = pointToTrafos[mp[i]];
551
552 bool newTransform = uniqueTransform
553 (
554 mesh_.points()[mp[i]],
555 trafos,
556 patchi,
557 transSign
558 );
559
560 if (newTransform)
561 {
562 trafos.append(transSign);
563 }
564 }
565 }
566 }
567
568
569 // Synchronise across collocated (= untransformed) points
570 // TBD: there is a big problem in that globalMeshData uses
571 // globalIndexAndTransform. Triggers recursion.
572 if (false)
573 {
574 const globalMeshData& gmd = mesh_.globalData();
575 const indirectPrimitivePatch& cpp = gmd.coupledPatch();
576 const labelList& meshPoints = cpp.meshPoints();
577 const mapDistribute& slavesMap = gmd.globalCoPointSlavesMap();
578 const labelListList& slaves = gmd.globalCoPointSlaves();
579
580 List<labelPairList> elems(slavesMap.constructSize());
581 forAll(meshPoints, i)
582 {
583 elems[i] = pointToTrafos[meshPoints[i]];
584 }
585
586 // Pull slave data onto master. No need to update transformed slots.
587 slavesMap.distribute(elems, false);
588
589 // Combine master data with slave data
590 forAll(slaves, i)
591 {
592 labelPairList& trafos = elems[i];
593
594 const labelList& slavePoints = slaves[i];
595
596 // Combine master with untransformed slave data
597 forAll(slavePoints, j)
598 {
599 const labelPairList& slaveTrafos = elems[slavePoints[j]];
600
601 forAll(slaveTrafos, slaveI)
602 {
603 bool newTransform = uniqueTransform
604 (
605 mesh_.points()[meshPoints[i]],
606 trafos,
607 -1,
608 slaveTrafos[slaveI]
609 );
610
611 if (newTransform)
612 {
613 trafos.append(slaveTrafos[slaveI]);
614 }
615 }
616 }
617 }
618 }
619 }
620}
621
622
623// ************************************************************************* //
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Dynamically sized Field. Similar to DynamicList, but inheriting from a Field instead of a List.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
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 append(const T &val)
Append an element at the end of the list.
Definition List.H:497
const T & first() const noexcept
Access the first element.
Definition Pair.H:137
const labelList & meshPoints() const
Return labelList of mesh points in patch.
void setSize(const label n)
Same as resize().
Definition PtrList.H:357
T & first()
Access first element of the list, position [0].
Definition UList.H:957
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run.
Definition UPstream.H:1697
@ gatherList
gatherList [manual algorithm]
Definition UPstream.H:194
@ broadcast
broadcast [MPI]
Definition UPstream.H:189
label size() const noexcept
The number of entries in the list.
Definition UPtrListI.H:106
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
Determination and storage of the possible independent transforms introduced by coupledPolyPatches,...
label nullTransformIndex() const
Return the transformIndex (index in transformPermutations).
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
const mapDistribute & globalCoPointSlavesMap() const
const labelListList & globalCoPointSlaves() const
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
label constructSize() const noexcept
Constructed data size.
Class containing processor-to-processor mapping information.
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute List data using default commsType, default flip/negate operator.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
virtual const pointField & points() const
Return raw points.
Definition polyMesh.C:1063
A patch is a list of labels that address the faces in the global face list.
Definition polyPatch.H:73
label nPoints() const noexcept
Number of mesh points.
Vector-tensor class used to perform translations and rotations in 3D space.
const tensor & R() const noexcept
The (forward) rotation tensor.
const vector & t() const noexcept
The translation vector.
bool hasR() const noexcept
True if it has a non-identity rotation tensor.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
Type & refCast(U &obj)
A dynamic_cast (for references) to Type reference.
Definition typeInfo.H:172
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:40
List< labelPair > labelPairList
List of labelPair.
Definition labelPair.H:33
List< labelList > labelListList
List of labelList.
Definition labelList.H:38
dimensionedScalar sign(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition List.H:62
refinementData transform(const tensor &, const refinementData val)
No-op rotational transform for base types.
messageStream Info
Information stream (stdout output on master, null elsewhere).
static const Identity< scalar > I
Definition Identity.H:100
Tensor< scalar > tensor
Definition symmTensor.H:57
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensionedScalar sqrt(const dimensionedScalar &ds)
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
Definition typeInfo.H:87
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
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
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
Vector< scalar > vector
Definition vector.H:57
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
messageStream Warning
Warning stream (stdout output on master, null elsewhere), with additional 'FOAM Warning' header text.
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
volScalarField & b
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299