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 -------------------------------------------------------------------------------
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 
30 #include "cyclicPolyPatch.H"
31 #include "DynamicField.H"
32 #include "globalMeshData.H"
33 
34 // * * * * * * * * * * * * Private Static Data Members * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38  defineTypeNameAndDebug(globalIndexAndTransform, 0);
39 }
40 
41 
42 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
43 
44 Foam::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 
130 void 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 
276 void 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 
317 void 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 
410 bool 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 
456 Foam::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 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1069
Foam::constant::atomic::mp
const dimensionedScalar mp
Proton mass.
Foam::globalMeshData::globalCoPointSlavesMap
const mapDistribute & globalCoPointSlavesMap() const
Definition: globalMeshData.C:2363
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:63
cyclicPolyPatch.H
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
globalMeshData.H
Foam::labelPairList
List< labelPair > labelPairList
List of labelPairs.
Definition: labelPair.H:64
Foam::Warning
messageStream Warning
Foam::tensorField
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
Definition: primitiveFieldsFwd.H:57
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:457
Foam::Pstream::scatter
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Definition: gatherScatter.C:150
Foam::polyMesh::boundaryMesh
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:444
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::sign
dimensionedScalar sign(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:166
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
Foam::polyMesh
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:77
Foam::primitiveMesh::nPoints
label nPoints() const noexcept
Number of mesh points.
Definition: primitiveMeshI.H:37
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::vectorField
Field< vector > vectorField
Specialisation of Field<T> for vector.
Definition: primitiveFieldsFwd.H:54
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Foam::labelPair
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:54
Foam::globalIndexAndTransform::nullTransformIndex
label nullTransformIndex() const
Return the transformIndex (index in transformPermutations)
Definition: globalIndexAndTransformI.H:394
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::coupledPolyPatch::NOORDERING
Definition: coupledPolyPatch.H:67
Foam::inv
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:73
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
globalIndexAndTransform.H
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::mapDistribute
Class containing processor-to-processor mapping information.
Definition: mapDistribute.H:163
Foam::PtrList::setSize
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:151
Foam::coupledPolyPatch::COINCIDENTFULLMATCH
Definition: coupledPolyPatch.H:65
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:75
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::mapDistribute::distribute
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
Definition: mapDistributeTemplates.C:152
Foam::globalMeshData
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
Definition: globalMeshData.H:107
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::vectorTensorTransform::t
const vector & t() const
Definition: vectorTensorTransformI.H:69
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::vectorTensorTransform::hasR
bool hasR() const
Definition: vectorTensorTransformI.H:81
Foam::mapDistributeBase::constructSize
label constructSize() const
Constructed data size.
Definition: mapDistributeBase.H:277
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:52
DynamicField.H
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:463
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::Pair< label >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::globalMeshData::coupledPatch
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
Definition: globalMeshData.C:2046
Foam::vectorTensorTransform
Vector-tensor class used to perform translations and rotations in 3D space.
Definition: vectorTensorTransform.H:63
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::vectorTensorTransform::R
const tensor & R() const
Definition: vectorTensorTransformI.H:75
patches
const polyBoundaryMesh & patches
Definition: convertProcessorPatches.H:65
Foam::polyMesh::globalData
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1295
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::PrimitivePatch::meshPoints
const labelList & meshPoints() const
Return labelList of mesh points in patch.
Definition: PrimitivePatch.C:330
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328
Foam::tensor
Tensor< scalar > tensor
Tensor of scalars, i.e. Tensor<scalar>.
Definition: symmTensor.H:61
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
Foam::globalMeshData::globalCoPointSlaves
const labelListList & globalCoPointSlaves() const
Definition: globalMeshData.C:2353
Foam::I
static const Identity< scalar > I
Definition: Identity.H:95
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:79