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 | Copyright (C) 2011-2016 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "cyclicPolyPatch.H"
28 #include "DynamicField.H"
29 #include "globalMeshData.H"
30 
31 // * * * * * * * * * * * * Private Static Data Members * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35  defineTypeNameAndDebug(globalIndexAndTransform, 0);
36 }
37 
38 
39 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40 
41 Foam::label Foam::globalIndexAndTransform::matchTransform
42 (
43  const List<vectorTensorTransform>& refTransforms,
44  label& matchedRefTransformI,
45  const vectorTensorTransform& testTransform,
46  scalar tolerance,
47  bool checkBothSigns
48 ) const
49 {
50  matchedRefTransformI = -1;
51 
52  forAll(refTransforms, i)
53  {
54  const vectorTensorTransform& refTransform = refTransforms[i];
55 
56  scalar maxVectorMag = sqrt
57  (
58  max(magSqr(testTransform.t()), magSqr(refTransform.t()))
59  );
60 
61  // Test the difference between vector parts to see if it is
62  // less than tolerance times the larger vector part magnitude.
63 
64  scalar vectorDiff =
65  mag(refTransform.t() - testTransform.t())
66  /(maxVectorMag + VSMALL)
67  /tolerance;
68 
69  // Test the difference between tensor parts to see if it is
70  // less than the tolerance. sqrt(3.0) factor used to scale
71  // differnces as this is magnitude of a rotation tensor. If
72  // neither transform has a rotation, then the test is not
73  // necessary.
74 
75  scalar tensorDiff = 0;
76 
77  if (refTransform.hasR() || testTransform.hasR())
78  {
79  tensorDiff =
80  mag(refTransform.R() - testTransform.R())
81  /sqrt(3.0)
82  /tolerance;
83  }
84 
85  // ...Diff result is < 1 if the test part matches the ref part
86  // within tolerance
87 
88  if (vectorDiff < 1 && tensorDiff < 1)
89  {
90  matchedRefTransformI = i;
91 
92  return +1;
93  }
94 
95  if (checkBothSigns)
96  {
97  // Test the inverse transform differences too
98 
99  vectorDiff =
100  mag(refTransform.t() + testTransform.t())
101  /(maxVectorMag + VSMALL)
102  /tolerance;
103 
104  tensorDiff = 0;
105 
106  if (refTransform.hasR() || testTransform.hasR())
107  {
108  tensorDiff =
109  mag(refTransform.R() - testTransform.R().T())
110  /sqrt(3.0)
111  /tolerance;
112  }
113 
114  if (vectorDiff < 1 && tensorDiff < 1)
115  {
116  matchedRefTransformI = i;
117 
118  return -1;
119  }
120  }
121  }
122 
123  return 0;
124 }
125 
126 
127 void Foam::globalIndexAndTransform::determineTransforms()
128 {
129  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
130 
131  DynamicList<vectorTensorTransform> localTransforms;
132  DynamicField<scalar> localTols;
133 
134  label dummyMatch = -1;
135 
136  forAll(patches, patchi)
137  {
138  const polyPatch& pp = patches[patchi];
139 
140  // Note: special check for unordered cyclics. These are in fact
141  // transform bcs and should probably be split off.
142  if
143  (
144  isA<coupledPolyPatch>(pp)
145  && !(
146  isA<cyclicPolyPatch>(pp)
147  && (
148  refCast<const cyclicPolyPatch>(pp).transform()
150  )
151  )
152  )
153  {
154  const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>(pp);
155 
156  if (cpp.separated())
157  {
158  const vectorField& sepVecs = cpp.separation();
159 
160  forAll(sepVecs, sVI)
161  {
162  const vector& sepVec = sepVecs[sVI];
163 
164  if (mag(sepVec) > SMALL)
165  {
166  vectorTensorTransform transform(sepVec);
167 
168  if
169  (
170  matchTransform
171  (
172  localTransforms,
173  dummyMatch,
174  transform,
175  cpp.matchTolerance(),
176  false
177  ) == 0
178  )
179  {
180  localTransforms.append(transform);
181  localTols.append(cpp.matchTolerance());
182  }
183  }
184  }
185  }
186  else if (!cpp.parallel())
187  {
188  const tensorField& transTensors = cpp.reverseT();
189 
190  forAll(transTensors, tTI)
191  {
192  const tensor& transT = transTensors[tTI];
193 
194  if (mag(transT - I) > SMALL)
195  {
196  vectorTensorTransform transform(transT);
197 
198  if
199  (
200  matchTransform
201  (
202  localTransforms,
203  dummyMatch,
204  transform,
205  cpp.matchTolerance(),
206  false
207  ) == 0
208  )
209  {
210  localTransforms.append(transform);
211  localTols.append(cpp.matchTolerance());
212  }
213  }
214  }
215  }
216  }
217  }
218 
219 
220  // Collect transforms on master
221  List<List<vectorTensorTransform>> allTransforms(Pstream::nProcs());
222  allTransforms[Pstream::myProcNo()] = localTransforms;
223  Pstream::gatherList(allTransforms);
224 
225  // Collect matching tolerance on master
226  List<scalarField> allTols(Pstream::nProcs());
227  allTols[Pstream::myProcNo()] = localTols;
228  Pstream::gatherList(allTols);
229 
230  if (Pstream::master())
231  {
232  localTransforms.clear();
233 
234  forAll(allTransforms, proci)
235  {
236  const List<vectorTensorTransform>& procTransVecs =
237  allTransforms[proci];
238 
239  forAll(procTransVecs, pSVI)
240  {
241  const vectorTensorTransform& transform = procTransVecs[pSVI];
242 
243  if (mag(transform.t()) > SMALL || transform.hasR())
244  {
245  if
246  (
247  matchTransform
248  (
249  localTransforms,
250  dummyMatch,
251  transform,
252  allTols[proci][pSVI],
253  true
254  ) == 0
255  )
256  {
257  localTransforms.append(transform);
258  }
259  }
260  }
261  }
262  }
263 
264  transforms_.transfer(localTransforms);
265  Pstream::scatter(transforms_);
266 }
267 
268 
269 void Foam::globalIndexAndTransform::determineTransformPermutations()
270 {
271  label nTransformPermutations = pow(label(3), transforms_.size());
272 
273  transformPermutations_.setSize(nTransformPermutations);
274 
275  forAll(transformPermutations_, tPI)
276  {
277  vectorTensorTransform transform;
278 
279  label transformIndex = tPI;
280 
281  // Invert the ternary index encoding using repeated division by
282  // three
283 
284  forAll(transforms_, b)
285  {
286  const label w = (transformIndex % 3) - 1;
287 
288  transformIndex /= 3;
289 
290  if (w > 0)
291  {
292  transform &= transforms_[b];
293  }
294  else if (w < 0)
295  {
296  transform &= inv(transforms_[b]);
297  }
298  }
299 
300  transformPermutations_[tPI] = transform;
301  }
302 
303 
304  // Encode index for 0 sign
305  labelList permutationIndices(nIndependentTransforms(), 0);
306  nullTransformIndex_ = encodeTransformIndex(permutationIndices);
307 }
308 
309 
310 void Foam::globalIndexAndTransform::determinePatchTransformSign()
311 {
312  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
313 
314  patchTransformSign_.setSize(patches.size(), labelPair(-1, 0));
315 
316  forAll(patches, patchi)
317  {
318  const polyPatch& pp = patches[patchi];
319 
320  // Note: special check for unordered cyclics. These are in fact
321  // transform bcs and should probably be split off.
322  if
323  (
324  isA<coupledPolyPatch>(pp)
325  && !(
326  isA<cyclicPolyPatch>(pp)
327  && (
328  refCast<const cyclicPolyPatch>(pp).transform()
330  )
331  )
332  )
333  {
334  const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>(pp);
335 
336  if (cpp.separated())
337  {
338  const vectorField& sepVecs = cpp.separation();
339 
340  // This loop is implicitly expecting only a single
341  // value for separation()
342  forAll(sepVecs, sVI)
343  {
344  const vector& sepVec = sepVecs[sVI];
345 
346  if (mag(sepVec) > SMALL)
347  {
348  vectorTensorTransform t(sepVec);
349 
350  label matchTransI;
351  label sign = matchTransform
352  (
353  transforms_,
354  matchTransI,
355  t,
356  cpp.matchTolerance(),
357  true
358  );
359  patchTransformSign_[patchi] =
360  labelPair(matchTransI, sign);
361  }
362  }
363 
364  }
365  else if (!cpp.parallel())
366  {
367  const tensorField& transTensors = cpp.reverseT();
368 
369  // This loop is implicitly expecting only a single
370  // value for reverseT()
371  forAll(transTensors, tTI)
372  {
373  const tensor& transT = transTensors[tTI];
374 
375  if (mag(transT - I) > SMALL)
376  {
377  vectorTensorTransform t(transT);
378 
379  label matchTransI;
380  label sign = matchTransform
381  (
382  transforms_,
383  matchTransI,
384  t,
385  cpp.matchTolerance(),
386  true
387  );
388 
389  patchTransformSign_[patchi] =
390  labelPair(matchTransI, sign);
391  }
392  }
393  }
394  }
395  }
396 }
397 
398 
399 bool Foam::globalIndexAndTransform::uniqueTransform
400 (
401  const point& pt,
402  labelPairList& trafos,
403  const label patchi,
404  const labelPair& patchTrafo
405 ) const
406 {
407  if (findIndex(trafos, patchTrafo) == -1)
408  {
409  // New transform. Check if already have 3
410  if (trafos.size() == 3)
411  {
412  if (patchi > -1)
413  {
415  << "Point " << pt
416  << " is on patch " << mesh_.boundaryMesh()[patchi].name();
417  }
418  else
419  {
421  << "Point " << pt << " is on a coupled patch";
422  }
423  Warning
424  << " with transformation " << patchTrafo
425  << " but also on 3 other patches with transforms "
426  << trafos << nl
427  << "This is not a space filling tiling and might"
428  << " indicate a setup problem and give problems"
429  << " for e.g. lagrangian tracking or interpolation" << endl;
430 
431  // Already warned so no need to extend more
432  trafos.clear();
433  return false;
434  }
435 
436  return true;
437  }
438  else
439  {
440  return false;
441  }
442 }
443 
444 
445 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
446 
447 Foam::globalIndexAndTransform::globalIndexAndTransform(const polyMesh& mesh)
448 :
449  mesh_(mesh),
450  transforms_(),
451  transformPermutations_(),
452  patchTransformSign_()
453 {
454  determineTransforms();
455 
456  determineTransformPermutations();
457 
458  determinePatchTransformSign();
459 
460  if (debug && transforms_.size() > 0)
461  {
462  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
463 
464  Info<< "Determined global transforms :" << endl;
465  Info<< "\t\ttranslation\trotation" << endl;
466  forAll(transforms_, i)
467  {
468  Info<< '\t' << i << '\t';
469  const vectorTensorTransform& trafo = transforms_[i];
470  if (trafo.hasR())
471  {
472  Info<< trafo.t() << '\t' << trafo.R();
473  }
474  else
475  {
476  Info<< trafo.t() << '\t' << "---";
477  }
478  Info<< endl;
479  }
480  Info<< endl;
481 
482 
483  Info<< "\tpatch\ttransform\tsign" << endl;
484  forAll(patchTransformSign_, patchi)
485  {
486  if (patchTransformSign_[patchi].first() != -1)
487  {
488  Info<< '\t' << patches[patchi].name()
489  << '\t' << patchTransformSign_[patchi].first()
490  << '\t' << patchTransformSign_[patchi].second()
491  << endl;
492  }
493  }
494  Info<< endl;
495 
496 
497  Info<< "Permutations of transformations:" << endl
498  << "\t\ttranslation\trotation" << endl;
499  forAll(transformPermutations_, i)
500  {
501  Info<< '\t' << i << '\t';
502  const vectorTensorTransform& trafo = transformPermutations_[i];
503  if (trafo.hasR())
504  {
505  Info<< trafo.t() << '\t' << trafo.R();
506  }
507  else
508  {
509  Info<< trafo.t() << '\t' << "---";
510  }
511  Info<< endl;
512  }
513  Info<< "nullTransformIndex:" << nullTransformIndex() << endl
514  << endl;
515  }
516 
517 
518  if (transforms_.size() > 0)
519  {
520  // Check that the transforms are space filling : any point
521  // can only use up to three transforms
522 
523  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
524 
525 
526  // 1. Collect transform&sign per point and do local check
527 
528  List<labelPairList> pointToTrafos(mesh_.nPoints());
529 
530  forAll(patches, patchi)
531  {
532  const polyPatch& pp = patches[patchi];
533 
534  const labelPair& transSign = patchTransformSign_[patchi];
535 
536  if (transSign.first() > -1)
537  {
538  const labelList& mp = pp.meshPoints();
539  forAll(mp, i)
540  {
541  labelPairList& trafos = pointToTrafos[mp[i]];
542 
543  bool newTransform = uniqueTransform
544  (
545  mesh_.points()[mp[i]],
546  trafos,
547  patchi,
548  transSign
549  );
550 
551  if (newTransform)
552  {
553  trafos.append(transSign);
554  }
555  }
556  }
557  }
558 
559 
560  // Synchronise across collocated (= untransformed) points
561  // TBD: there is a big problem in that globalMeshData uses
562  // globalIndexAndTransform. Triggers recursion.
563  if (false)
564  {
565  const globalMeshData& gmd = mesh_.globalData();
566  const indirectPrimitivePatch& cpp = gmd.coupledPatch();
567  const labelList& meshPoints = cpp.meshPoints();
568  const mapDistribute& slavesMap = gmd.globalCoPointSlavesMap();
569  const labelListList& slaves = gmd.globalCoPointSlaves();
570 
571  List<labelPairList> elems(slavesMap.constructSize());
572  forAll(meshPoints, i)
573  {
574  elems[i] = pointToTrafos[meshPoints[i]];
575  }
576 
577  // Pull slave data onto master. No need to update transformed slots.
578  slavesMap.distribute(elems, false);
579 
580  // Combine master data with slave data
581  forAll(slaves, i)
582  {
583  labelPairList& trafos = elems[i];
584 
585  const labelList& slavePoints = slaves[i];
586 
587  // Combine master with untransformed slave data
588  forAll(slavePoints, j)
589  {
590  const labelPairList& slaveTrafos = elems[slavePoints[j]];
591 
592  forAll(slaveTrafos, slaveI)
593  {
594  bool newTransform = uniqueTransform
595  (
596  mesh_.points()[meshPoints[i]],
597  trafos,
598  -1,
599  slaveTrafos[slaveI]
600  );
601 
602  if (newTransform)
603  {
604  trafos.append(slaveTrafos[slaveI]);
605  }
606  }
607  }
608  }
609  }
610  }
611 }
612 
613 
614 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:424
dimensionedScalar sign(const dimensionedScalar &ds)
const mapDistribute & globalCoPointSlavesMap() const
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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:59
const word & name() const
Return name.
Definition: IOobject.H:291
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
Vector-tensor class used to perform translations and rotations in 3D space.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:60
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:418
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:412
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
const labelList & meshPoints() const
Return labelList of mesh points in patch. They are constructed.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1011
A list of faces which address into the list of points.
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
dynamicFvMesh & mesh
static const Identity< scalar > I
Definition: Identity.H:93
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
label nullTransformIndex() const
Return the transformIndex (index in transformPermutations)
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1182
List< label > labelList
A List of labels.
Definition: labelList.H:56
List< labelPair > labelPairList
List of labelPairs.
Definition: labelPair.H:49
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Foam::polyBoundaryMesh.
dimensioned< scalar > magSqr(const dimensioned< Type > &)
static const char nl
Definition: Ostream.H:262
defineTypeNameAndDebug(combustionModel, 0)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence of given element and return index,.
messageStream Warning
Field< tensor > tensorField
Specialisation of Field<T> for tensor.
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
label constructSize() const
Constructed data size.
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:400
label patchi
Class containing processor-to-processor mapping information.
vector point
Point is a vector.
Definition: point.H:41
#define WarningInFunction
Report a warning using Foam::Warning.
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
label nPoints() const
Field< vector > vectorField
Specialisation of Field<T> for vector.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
const Type & first() const
Return first.
Definition: Pair.H:87
Tensor< scalar > tensor
Tensor of scalars.
Definition: tensor.H:51
const dimensionedScalar mp
Proton mass.
Namespace for OpenFOAM.
dimensionSet transform(const dimensionSet &)
Definition: dimensionSet.C:477
const labelListList & globalCoPointSlaves() const