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 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"
31#include "DynamicField.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
134 DynamicList<vectorTensorTransform> localTransforms;
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 (
149 isA<coupledPolyPatch>(pp)
150 && !(
151 isA<cyclicPolyPatch>(pp)
152 && refCast<const cyclicPolyPatch>(pp).transform()
154 )
155 && !(
156 refCast<const coupledPolyPatch>(pp).transform()
158 )
159 )
160 {
161 const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>(pp);
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 {
173 vectorTensorTransform transform(sepVec);
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 {
203 vectorTensorTransform transform(transT);
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
228 List<List<vectorTensorTransform>> allTransforms(Pstream::nProcs());
229 allTransforms[Pstream::myProcNo()] = localTransforms;
230 Pstream::gatherList(allTransforms);
231
232 // Collect matching tolerance on master
233 List<scalarField> allTols(Pstream::nProcs());
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::scatter(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 {
284 vectorTensorTransform transform;
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 (
333 isA<coupledPolyPatch>(pp)
334 && !(
335 isA<cyclicPolyPatch>(pp)
336 && refCast<const cyclicPolyPatch>(pp).transform()
338 )
339 && !(
340 refCast<const coupledPolyPatch>(pp).transform()
342 )
343 )
344 {
345 const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>(pp);
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 }
449
450 return false;
451}
452
453
454// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
455
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// ************************************************************************* //
T & first() noexcept
The first element of the list, position [0].
Definition: FixedListI.H:207
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:65
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
A list of faces which address into the list of points.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
static void scatter(const List< commsStruct > &comms, T &value, const int tag, const label comm)
Broadcast data: Distribute without modification.
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:151
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
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 data using default commsType.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1310
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1083
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:75
label nPoints() const noexcept
Number of mesh points.
int myProcNo() const noexcept
Return processor number.
splitCell * master() const
Definition: splitCell.H:113
Tensor of scalars, i.e. Tensor<scalar>.
Vector-tensor class used to perform translations and rotations in 3D space.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
const polyBoundaryMesh & patches
dynamicFvMesh & mesh
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:57
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
List< labelPair > labelPairList
List of labelPairs.
Definition: labelPair.H:64
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:536
dimensionedScalar sign(const dimensionedScalar &ds)
List< label > labelList
A List of labels.
Definition: List.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
static const Identity< scalar > I
Definition: Identity.H:94
vector point
Point is a vector.
Definition: point.H:43
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
dimensionedScalar sqrt(const dimensionedScalar &ds)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Field< vector > vectorField
Specialisation of Field<T> for vector.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
messageStream Warning
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
volScalarField & b
Definition: createFields.H:27
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333