motionSmootherAlgo.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 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 
26 #include "motionSmootherAlgo.H"
27 #include "twoDPointCorrector.H"
28 #include "faceSet.H"
29 #include "pointSet.H"
31 #include "pointConstraints.H"
32 #include "syncTools.H"
33 #include "meshTools.H"
34 #include "meshCheck.H"
35 #include "OFstream.H"
36 
37 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38 
39 namespace Foam
40 {
42 }
43 
44 
45 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
46 
47 void Foam::motionSmootherAlgo::testSyncPositions
48 (
49  const pointField& fld,
50  const scalar maxMag
51 ) const
52 {
53  pointField syncedFld(fld);
54 
56  (
57  mesh_,
58  syncedFld,
59  minEqOp<point>(), // combine op
60  point(great,great,great) // null
61  );
62 
63  forAll(syncedFld, i)
64  {
65  if (mag(syncedFld[i] - fld[i]) > maxMag)
66  {
68  << "On point " << i << " point:" << fld[i]
69  << " synchronised point:" << syncedFld[i]
70  << abort(FatalError);
71  }
72  }
73 }
74 
75 
76 void Foam::motionSmootherAlgo::checkFld(const pointScalarField& fld)
77 {
78  forAll(fld, pointi)
79  {
80  const scalar val = fld[pointi];
81 
82  if ((val > -great) && (val < great))
83  {}
84  else
85  {
87  << "Problem : point:" << pointi << " value:" << val
88  << abort(FatalError);
89  }
90  }
91 }
92 
93 
94 Foam::labelHashSet Foam::motionSmootherAlgo::getPoints
95 (
96  const labelHashSet& faceLabels
97 ) const
98 {
99  labelHashSet usedPoints(mesh_.nPoints()/100);
100 
101  forAllConstIter(labelHashSet, faceLabels, iter)
102  {
103  const face& f = mesh_.faces()[iter.key()];
104 
105  forAll(f, fp)
106  {
107  usedPoints.insert(f[fp]);
108  }
109  }
110 
111  return usedPoints;
112 }
113 
114 
115 Foam::tmp<Foam::scalarField> Foam::motionSmootherAlgo::calcEdgeWeights
116 (
117  const pointField& points
118 ) const
119 {
120  const edgeList& edges = mesh_.edges();
121 
122  tmp<scalarField> twght(new scalarField(edges.size()));
123  scalarField& wght = twght.ref();
124 
125  forAll(edges, edgeI)
126  {
127  wght[edgeI] = 1.0/(edges[edgeI].mag(points)+small);
128  }
129  return twght;
130 }
131 
132 
133 // Smooth on selected points (usually patch points)
134 void Foam::motionSmootherAlgo::minSmooth
135 (
136  const scalarField& edgeWeights,
137  const PackedBoolList& isAffectedPoint,
138  const labelList& meshPoints,
139  const pointScalarField& fld,
140  pointScalarField& newFld
141 ) const
142 {
143  tmp<pointScalarField> tavgFld = avg
144  (
145  fld,
146  edgeWeights // scalarField(mesh_.nEdges(), 1.0) // uniform weighting
147  );
148  const pointScalarField& avgFld = tavgFld();
149 
150  forAll(meshPoints, i)
151  {
152  label pointi = meshPoints[i];
153  if (isAffectedPoint.get(pointi) == 1)
154  {
155  newFld[pointi] = min
156  (
157  fld[pointi],
158  0.5*fld[pointi] + 0.5*avgFld[pointi]
159  );
160  }
161  }
162 
163  // Single and multi-patch constraints
164  pointConstraints::New(pMesh()).constrain(newFld, false);
165 }
166 
167 
168 // Smooth on all internal points
169 void Foam::motionSmootherAlgo::minSmooth
170 (
171  const scalarField& edgeWeights,
172  const PackedBoolList& isAffectedPoint,
173  const pointScalarField& fld,
174  pointScalarField& newFld
175 ) const
176 {
177  tmp<pointScalarField> tavgFld = avg
178  (
179  fld,
180  edgeWeights // scalarField(mesh_.nEdges(), 1.0) // uniform weighting
181  );
182  const pointScalarField& avgFld = tavgFld();
183 
184  forAll(fld, pointi)
185  {
186  if (isAffectedPoint.get(pointi) == 1 && isInternalPoint(pointi))
187  {
188  newFld[pointi] = min
189  (
190  fld[pointi],
191  0.5*fld[pointi] + 0.5*avgFld[pointi]
192  );
193  }
194  }
195 
196  // Single and multi-patch constraints
197  pointConstraints::New(pMesh()).constrain(newFld, false);
198 
199 }
200 
201 
202 // Scale on all internal points
203 void Foam::motionSmootherAlgo::scaleField
204 (
205  const labelHashSet& pointLabels,
206  const scalar scale,
208 ) const
209 {
211  {
212  if (isInternalPoint(iter.key()))
213  {
214  fld[iter.key()] *= scale;
215  }
216  }
217 
218  // Single and multi-patch constraints
219  pointConstraints::New(pMesh()).constrain(fld, false);
220 }
221 
222 
223 // Scale on selected points (usually patch points)
224 void Foam::motionSmootherAlgo::scaleField
225 (
226  const labelList& meshPoints,
227  const labelHashSet& pointLabels,
228  const scalar scale,
230 ) const
231 {
232  forAll(meshPoints, i)
233  {
234  label pointi = meshPoints[i];
235 
236  if (pointLabels.found(pointi))
237  {
238  fld[pointi] *= scale;
239  }
240  }
241 }
242 
243 
244 // Lower on internal points
245 void Foam::motionSmootherAlgo::subtractField
246 (
247  const labelHashSet& pointLabels,
248  const scalar f,
250 ) const
251 {
253  {
254  if (isInternalPoint(iter.key()))
255  {
256  fld[iter.key()] = max(0.0, fld[iter.key()]-f);
257  }
258  }
259 
260  // Single and multi-patch constraints
262 }
263 
264 
265 // Scale on selected points (usually patch points)
266 void Foam::motionSmootherAlgo::subtractField
267 (
268  const labelList& meshPoints,
269  const labelHashSet& pointLabels,
270  const scalar f,
272 ) const
273 {
274  forAll(meshPoints, i)
275  {
276  label pointi = meshPoints[i];
277 
278  if (pointLabels.found(pointi))
279  {
280  fld[pointi] = max(0.0, fld[pointi]-f);
281  }
282  }
283 }
284 
285 
286 bool Foam::motionSmootherAlgo::isInternalPoint(const label pointi) const
287 {
288  return isInternalPoint_.get(pointi) == 1;
289 }
290 
291 
292 void Foam::motionSmootherAlgo::getAffectedFacesAndPoints
293 (
294  const label nPointIter,
295  const faceSet& wrongFaces,
296 
297  labelList& affectedFaces,
298  PackedBoolList& isAffectedPoint
299 ) const
300 {
301  isAffectedPoint.setSize(mesh_.nPoints());
302  isAffectedPoint = 0;
303 
304  faceSet nbrFaces(mesh_, "checkFaces", wrongFaces);
305 
306  // Find possible points influenced by nPointIter iterations of
307  // scaling and smoothing by doing pointCellpoint walk.
308  // Also update faces-to-be-checked to extend one layer beyond the points
309  // that will get updated.
310 
311  for (label i = 0; i < nPointIter; i++)
312  {
313  pointSet nbrPoints(mesh_, "grownPoints", getPoints(nbrFaces.toc()));
314 
315  forAllConstIter(pointSet, nbrPoints, iter)
316  {
317  const labelList& pCells = mesh_.pointCells(iter.key());
318 
319  forAll(pCells, pCelli)
320  {
321  const cell& cFaces = mesh_.cells()[pCells[pCelli]];
322 
323  forAll(cFaces, cFacei)
324  {
325  nbrFaces.insert(cFaces[cFacei]);
326  }
327  }
328  }
329  nbrFaces.sync(mesh_);
330 
331  if (i == nPointIter - 2)
332  {
333  forAllConstIter(faceSet, nbrFaces, iter)
334  {
335  const face& f = mesh_.faces()[iter.key()];
336  forAll(f, fp)
337  {
338  isAffectedPoint.set(f[fp], 1);
339  }
340  }
341  }
342  }
343 
344  affectedFaces = nbrFaces.toc();
345 }
346 
347 
348 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
349 
351 (
352  polyMesh& mesh,
353  pointMesh& pMesh,
355  pointVectorField& displacement,
356  pointScalarField& scale,
357  pointField& oldPoints,
358  const labelList& adaptPatchIDs,
359  const dictionary& paramDict
360 )
361 :
362  mesh_(mesh),
363  pMesh_(pMesh),
364  pp_(pp),
365  displacement_(displacement),
366  scale_(scale),
367  oldPoints_(oldPoints),
368  adaptPatchIndices_(adaptPatchIDs),
369  paramDict_(paramDict),
370  isInternalPoint_(mesh_.nPoints(), 1)
371 {
372  topoChange();
373 }
374 
375 
376 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
377 
379 {}
380 
381 
382 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
383 
385 {
386  return mesh_;
387 }
388 
389 
391 {
392  return pMesh_;
393 }
394 
395 
397 {
398  return pp_;
399 }
400 
401 
403 {
404  return adaptPatchIndices_;
405 }
406 
407 
409 {
410  return paramDict_;
411 }
412 
413 
415 {
416  oldPoints_ = mesh_.points();
417 
418  scale_ = 1.0;
419 
420  // No need to update twoDmotion corrector since only holds edge labels
421  // which will remain the same as before. So unless the mesh was distorted
422  // severely outside of motionSmootherAlgo there will be no need.
423 }
424 
425 
427 (
428  const labelList& patchIDs,
429  pointVectorField& displacement
430 )
431 {
432  pointVectorField::Boundary& displacementBf =
433  displacement.boundaryFieldRef();
434 
435  // Adapt the fixedValue bc's (i.e. copy internal point data to
436  // boundaryField for all affected patches)
437  forAll(patchIDs, i)
438  {
439  label patchi = patchIDs[i];
440 
441  displacementBf[patchi] ==
442  displacementBf[patchi].patchInternalField();
443  }
444 
445  // Make consistent with non-adapted bc's by evaluating those now and
446  // resetting the displacement from the values.
447  // Note that we're just doing a correctBoundaryConditions with
448  // fixedValue bc's first.
449  labelHashSet adaptPatchSet(patchIDs);
450 
451  const lduSchedule& patchSchedule = displacement.mesh().globalData().
452  patchSchedule();
453 
454  forAll(patchSchedule, patchEvalI)
455  {
456  label patchi = patchSchedule[patchEvalI].patch;
457 
458  if (!adaptPatchSet.found(patchi))
459  {
460  if (patchSchedule[patchEvalI].init)
461  {
462  displacementBf[patchi]
463  .initEvaluate(Pstream::commsTypes::scheduled);
464  }
465  else
466  {
467  displacementBf[patchi]
469  }
470  }
471  }
472 
473  // Multi-patch constraints
474  pointConstraints::New(displacement.mesh()).constrainCorners(displacement);
475 
476  // Adapt the fixedValue bc's (i.e. copy internal point data to
477  // boundaryField for all affected patches) to take the changes caused
478  // by multi-corner constraints into account.
479  forAll(patchIDs, i)
480  {
481  label patchi = patchIDs[i];
482 
483  displacementBf[patchi] ==
484  displacementBf[patchi].patchInternalField();
485  }
486 }
487 
488 
490 {
491  setDisplacementPatchFields(adaptPatchIndices_, displacement_);
492 }
493 
494 
496 (
497  const labelList& patchIDs,
498  const indirectPrimitivePatch& pp,
499  pointField& patchDisp,
500  pointVectorField& displacement
501 )
502 {
503  const polyMesh& mesh = displacement.mesh()();
504 
505  // See comment in .H file about shared points.
506  // We want to disallow effect of loose coupled points - we only
507  // want to see effect of proper fixedValue boundary conditions
508 
509  const labelList& cppMeshPoints =
511 
512  forAll(cppMeshPoints, i)
513  {
514  displacement[cppMeshPoints[i]] = vector::zero;
515  }
516 
517  const labelList& ppMeshPoints = pp.meshPoints();
518 
519  // Set internal point data from displacement on combined patch points.
520  forAll(ppMeshPoints, patchPointi)
521  {
522  displacement[ppMeshPoints[patchPointi]] = patchDisp[patchPointi];
523  }
524 
525 
526  // Combine any coupled points
528  (
529  mesh,
530  displacement,
531  maxMagEqOp(), // combine op
532  vector::zero // null value
533  );
534 
535 
536  // Adapt the fixedValue bc's (i.e. copy internal point data to
537  // boundaryField for all affected patches)
538  setDisplacementPatchFields(patchIDs, displacement);
539 
540 
541  if (debug)
542  {
543  OFstream str(mesh.db().path()/"changedPoints.obj");
544  label nVerts = 0;
545  forAll(ppMeshPoints, patchPointi)
546  {
547  const vector& newDisp = displacement[ppMeshPoints[patchPointi]];
548 
549  if (mag(newDisp-patchDisp[patchPointi]) > small)
550  {
551  const point& pt = mesh.points()[ppMeshPoints[patchPointi]];
552 
553  meshTools::writeOBJ(str, pt);
554  nVerts++;
555  // Pout<< "Point:" << pt
556  // << " oldDisp:" << patchDisp[patchPointi]
557  // << " newDisp:" << newDisp << endl;
558  }
559  }
560  Pout<< "Written " << nVerts << " points that are changed to file "
561  << str.name() << endl;
562  }
563 
564  // Now reset input displacement
565  forAll(ppMeshPoints, patchPointi)
566  {
567  patchDisp[patchPointi] = displacement[ppMeshPoints[patchPointi]];
568  }
569 }
570 
571 
573 {
574  setDisplacement(adaptPatchIndices_, pp_, patchDisp, displacement_);
575 }
576 
577 
578 // correctBoundaryConditions with fixedValue bc's first.
580 (
581  pointVectorField& displacement
582 ) const
583 {
584  labelHashSet adaptPatchSet(adaptPatchIndices_);
585 
586  const lduSchedule& patchSchedule = mesh_.globalData().patchSchedule();
587 
588  pointVectorField::Boundary& displacementBf =
589  displacement.boundaryFieldRef();
590 
591  // 1. evaluate on adaptPatches
592  forAll(patchSchedule, patchEvalI)
593  {
594  label patchi = patchSchedule[patchEvalI].patch;
595 
596  if (adaptPatchSet.found(patchi))
597  {
598  if (patchSchedule[patchEvalI].init)
599  {
600  displacementBf[patchi]
601  .initEvaluate(Pstream::commsTypes::scheduled);
602  }
603  else
604  {
605  displacementBf[patchi]
607  }
608  }
609  }
610 
611 
612  // 2. evaluate on non-AdaptPatches
613  forAll(patchSchedule, patchEvalI)
614  {
615  label patchi = patchSchedule[patchEvalI].patch;
616 
617  if (!adaptPatchSet.found(patchi))
618  {
619  if (patchSchedule[patchEvalI].init)
620  {
621  displacementBf[patchi]
622  .initEvaluate(Pstream::commsTypes::scheduled);
623  }
624  else
625  {
626  displacementBf[patchi]
628  }
629  }
630  }
631 
632  // Multi-patch constraints
633  pointConstraints::New(displacement.mesh()).constrainCorners(displacement);
634 
635  // Correct for problems introduced by corner constraints
637  (
638  mesh_,
639  displacement,
640  maxMagEqOp(), // combine op
641  vector::zero // null value
642  );
643 }
644 
645 
646 
648 {
649  // Correct for 2-D motion
650  const twoDPointCorrector& twoDCorrector = twoDPointCorrector::New(mesh_);
651 
652  if (twoDCorrector.required())
653  {
654  Info<< "Correcting 2-D mesh motion";
655 
656  if (mesh_.globalData().parallel())
657  {
659  << "2D mesh-motion probably not correct in parallel" << endl;
660  }
661 
662  // We do not want to move 3D planes so project all points onto those
663  const pointField& oldPoints = mesh_.points();
664  const edgeList& edges = mesh_.edges();
665 
666  const labelList& neIndices = twoDCorrector.normalEdgeIndices();
667  const vector& pn = twoDCorrector.planeNormal();
668 
669  forAll(neIndices, i)
670  {
671  const edge& e = edges[neIndices[i]];
672 
673  point& pStart = newPoints[e.start()];
674 
675  pStart += pn*(pn & (oldPoints[e.start()] - pStart));
676 
677  point& pEnd = newPoints[e.end()];
678 
679  pEnd += pn*(pn & (oldPoints[e.end()] - pEnd));
680  }
681 
682  // Correct tangentially
683  twoDCorrector.correctPoints(newPoints);
684  Info<< " ...done" << endl;
685  }
686 
687  if (debug)
688  {
689  Pout<< "motionSmootherAlgo::modifyMotionPoints :"
690  << " testing sync of newPoints."
691  << endl;
692  testSyncPositions(newPoints, 1e-6*mesh_.bounds().mag());
693  }
694 }
695 
696 
698 {
699  // Make sure to clear out tetPtIs since used in checks (sometimes, should
700  // really check)
701  mesh_.clearTetBasePtIs();
702  pp_.clearGeom();
703 }
704 
705 
707 (
708  const scalar errorReduction
709 )
710 {
711  scalar oldErrorReduction = paramDict_.lookup<scalar>("errorReduction");
712 
713  paramDict_.remove("errorReduction");
714  paramDict_.add("errorReduction", errorReduction);
715 
716  return oldErrorReduction;
717 }
718 
719 
721 (
722  const labelList& checkFaces,
723  const bool smoothMesh,
724  const label nAllowableErrors
725 )
726 {
727  List<labelPair> emptyBaffles;
728  return scaleMesh
729  (
730  checkFaces,
731  emptyBaffles,
732  smoothMesh,
733  nAllowableErrors
734  );
735 }
736 
737 
739 (
740  const labelList& checkFaces,
741  const List<labelPair>& baffles,
742  const bool smoothMesh,
743  const label nAllowableErrors
744 )
745 {
746  return scaleMesh
747  (
748  checkFaces,
749  baffles,
750  paramDict_,
751  paramDict_,
752  smoothMesh,
753  nAllowableErrors
754  );
755 }
756 
757 
759 {
760  // Set newPoints as old + scale*displacement
761 
762  // Create overall displacement with same b.c.s as displacement_
763  wordList actualPatchTypes;
764  {
765  const pointBoundaryMesh& pbm = displacement_.mesh().boundary();
766  actualPatchTypes.setSize(pbm.size());
767  forAll(pbm, patchi)
768  {
769  actualPatchTypes[patchi] = pbm[patchi].type();
770  }
771  }
772 
773  wordList actualPatchFieldTypes;
774  {
775  const pointVectorField::Boundary& pfld =
776  displacement_.boundaryField();
777  actualPatchFieldTypes.setSize(pfld.size());
778  forAll(pfld, patchi)
779  {
781  {
782  // Get rid of funny
783  actualPatchFieldTypes[patchi] =
785  }
786  else
787  {
788  actualPatchFieldTypes[patchi] = pfld[patchi].type();
789  }
790  }
791  }
792 
793  pointVectorField totalDisplacement
794  (
795  IOobject
796  (
797  "totalDisplacement",
798  mesh_.time().name(),
799  mesh_,
802  false
803  ),
804  scale_*displacement_,
805  actualPatchFieldTypes,
806  actualPatchTypes
807  );
808  correctBoundaryConditions(totalDisplacement);
809 
810  if (debug)
811  {
812  Pout<< "scaleMesh : testing sync of totalDisplacement" << endl;
813  testSyncField
814  (
815  totalDisplacement,
816  maxMagEqOp(),
817  vector::zero, // null value
818  1e-6*mesh_.bounds().mag()
819  );
820  }
821 
822  tmp<pointField> tnewPoints(oldPoints_ + totalDisplacement.primitiveField());
823 
824  // Correct for 2-D motion
825  modifyMotionPoints(tnewPoints.ref());
826 
827  return tnewPoints;
828 }
829 
830 
832 (
833  const labelList& checkFaces,
834  const List<labelPair>& baffles,
835  const dictionary& paramDict,
836  const dictionary& meshQualityDict,
837  const bool smoothMesh,
838  const label nAllowableErrors
839 )
840 {
841  if (!smoothMesh && adaptPatchIndices_.empty())
842  {
844  << "You specified both no movement on the internal mesh points"
845  << " (smoothMesh = false)" << nl
846  << "and no movement on the patch (adaptPatchIDs is empty)" << nl
847  << "Hence nothing to adapt."
848  << exit(FatalError);
849  }
850 
851  if (debug)
852  {
853  // Had a problem with patches moved non-synced. Check transformations.
854  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
855 
856  Pout<< "Entering scaleMesh : coupled patches:" << endl;
858  {
859  if (patches[patchi].coupled())
860  {
861  const coupledPolyPatch& pp =
862  refCast<const coupledPolyPatch>(patches[patchi]);
863 
864  Pout<< '\t' << patchi << '\t' << pp.name()
865  << " transform:" << pp.transform()
866  << endl;
867  }
868  }
869  }
870 
871  const scalar errorReduction =
872  paramDict.lookup<scalar>("errorReduction");
873 
874  const label nSmoothScale =
875  paramDict.lookup<label>("nSmoothScale");
876 
877 
878  // Note: displacement_ should already be synced already from setDisplacement
879  // but just to make sure.
881  (
882  mesh_,
883  displacement_,
884  maxMagEqOp(),
885  vector::zero // null value
886  );
887 
888  Info<< "Moving mesh using displacement scaling :"
889  << " min:" << gMin(scale_.primitiveField())
890  << " max:" << gMax(scale_.primitiveField())
891  << endl;
892 
893  // Get points using current displacement and scale. Optionally 2D corrected.
894  pointField newPoints(curPoints());
895 
896  // Move. No need to do 2D correction since curPoints already done that.
897  mesh_.setPoints(newPoints);
898  movePoints();
899 
900 
901  // Check. Returns parallel number of incorrect faces.
902  faceSet wrongFaces(mesh_, "wrongFaces", mesh_.nFaces()/100+100);
904  (
905  false,
906  mesh_,
907  meshQualityDict,
908  checkFaces,
909  baffles,
910  wrongFaces
911  );
912 
913  if (returnReduce(wrongFaces.size(), sumOp<label>()) <= nAllowableErrors)
914  {
915  return true;
916  }
917  else
918  {
919  // Sync across coupled faces by extending the set.
920  wrongFaces.sync(mesh_);
921 
922  // Special case:
923  // if errorReduction is set to zero, extend wrongFaces
924  // to face-Cell-faces to ensure quick return to previously valid mesh
925 
926  if (mag(errorReduction) < small)
927  {
928  labelHashSet newWrongFaces(wrongFaces);
929  forAllConstIter(labelHashSet, wrongFaces, iter)
930  {
931  label own = mesh_.faceOwner()[iter.key()];
932  const cell& ownFaces = mesh_.cells()[own];
933 
934  forAll(ownFaces, cfI)
935  {
936  newWrongFaces.insert(ownFaces[cfI]);
937  }
938 
939  if (iter.key() < mesh_.nInternalFaces())
940  {
941  label nei = mesh_.faceNeighbour()[iter.key()];
942  const cell& neiFaces = mesh_.cells()[nei];
943 
944  forAll(neiFaces, cfI)
945  {
946  newWrongFaces.insert(neiFaces[cfI]);
947  }
948  }
949  }
950  wrongFaces.transfer(newWrongFaces);
951  wrongFaces.sync(mesh_);
952  }
953 
954 
955  // Find out points used by wrong faces and scale displacement.
956  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
957 
958  pointSet usedPoints(mesh_, "usedPoints", getPoints(wrongFaces));
959  usedPoints.sync(mesh_);
960 
961 
962 
963  // Grow a few layers to determine
964  // - points to be smoothed
965  // - faces to be checked in next iteration
966  PackedBoolList isAffectedPoint(mesh_.nPoints());
967  labelList affectedFaces(checkFaces);
968  getAffectedFacesAndPoints
969  (
970  nSmoothScale, // smoothing iterations
971  wrongFaces, // error faces
972  affectedFaces,
973  isAffectedPoint
974  );
975 
976  if (debug)
977  {
978  Pout<< "Faces in error:" << wrongFaces.size()
979  << " with points:" << usedPoints.size()
980  << endl;
981  }
982 
983  if (adaptPatchIndices_.size())
984  {
985  // Scale conflicting patch points
986  scaleField(pp_.meshPoints(), usedPoints, errorReduction, scale_);
987  // subtractField(pp_.meshPoints(), usedPoints, 0.1, scale_);
988  }
989  if (smoothMesh)
990  {
991  // Scale conflicting internal points
992  scaleField(usedPoints, errorReduction, scale_);
993  // subtractField(usedPoints, 0.1, scale_);
994  }
995 
996  scalarField eWeights(calcEdgeWeights(oldPoints_));
997 
998  for (label i = 0; i < nSmoothScale; i++)
999  {
1000  if (adaptPatchIndices_.size())
1001  {
1002  // Smooth patch values
1003  pointScalarField oldScale(scale_);
1004  minSmooth
1005  (
1006  eWeights,
1007  isAffectedPoint,
1008  pp_.meshPoints(),
1009  oldScale,
1010  scale_
1011  );
1012  checkFld(scale_);
1013  }
1014  if (smoothMesh)
1015  {
1016  // Smooth internal values
1017  pointScalarField oldScale(scale_);
1018  minSmooth(eWeights, isAffectedPoint, oldScale, scale_);
1019  checkFld(scale_);
1020  }
1021  }
1022 
1024  (
1025  mesh_,
1026  scale_,
1027  maxEqOp<scalar>(),
1028  -great // null value
1029  );
1030 
1031 
1032  if (debug)
1033  {
1034  Pout<< "scale_ after smoothing :"
1035  << " min:" << Foam::gMin(scale_)
1036  << " max:" << Foam::gMax(scale_)
1037  << endl;
1038  }
1039 
1040  return false;
1041  }
1042 }
1043 
1044 
1046 {
1047  const pointBoundaryMesh& patches = pMesh_.boundary();
1048 
1049  // Check whether displacement has fixed value b.c. on adaptPatchID
1050  forAll(adaptPatchIndices_, i)
1051  {
1052  label patchi = adaptPatchIndices_[i];
1053 
1054  if
1055  (
1056  !isA<fixedValuePointPatchVectorField>
1057  (
1058  displacement_.boundaryField()[patchi]
1059  )
1060  )
1061  {
1063  << "Patch " << patches[patchi].name()
1064  << " has wrong boundary condition "
1065  << displacement_.boundaryField()[patchi].type()
1066  << " on field " << displacement_.name() << nl
1067  << "Only type allowed is "
1068  << fixedValuePointPatchVectorField::typeName
1069  << exit(FatalError);
1070  }
1071  }
1072 
1073 
1074  // Determine internal points. Note that for twoD there are no internal
1075  // points so we use the points of adaptPatchIDs instead
1076 
1077  const labelList& meshPoints = pp_.meshPoints();
1078 
1079  forAll(meshPoints, i)
1080  {
1081  isInternalPoint_.unset(meshPoints[i]);
1082  }
1083 
1084  // Calculate master edge addressing
1085  isMasterEdge_ = syncTools::getMasterEdges(mesh_);
1086 }
1087 
1088 
1089 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
static pointConstraints & New(const word &name, const pointMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
const Mesh & mesh() const
Return mesh.
Generic GeometricBoundaryField class.
void evaluate()
Evaluate boundary conditions.
const Internal::FieldType & primitiveField() const
Return a const-reference to the primitive field.
Boundary & boundaryFieldRef()
Return a reference to the boundary field.
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
void transfer(HashTable< T, Key, Hash > &)
Transfer the contents of the argument table into this table.
Definition: HashTable.C:587
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:138
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
const objectRegistry & db() const
Return the local objectRegistry.
Definition: IOobject.C:312
void setSize(const label)
Reset size of List.
Definition: List.C:281
Output to file stream.
Definition: OFstream.H:86
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:120
A bit-packed bool list.
const labelList & meshPoints() const
Return labelList of mesh points in patch. They are constructed.
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static const Form zero
Definition: VectorSpace.H:118
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:60
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
virtual const transformer & transform() const =0
Return transformation between the coupled patches.
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:710
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:61
A list of face labels.
Definition: faceSet.H:51
virtual void sync(const polyMesh &mesh)
Sync faceSet across coupled patches.
Definition: faceSet.C:113
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
Given a displacement moves the mesh by scaling the displacement back until there are no more mesh err...
void setDisplacementPatchFields()
Set patch fields on displacement to be consistent with.
motionSmootherAlgo(polyMesh &, pointMesh &, indirectPrimitivePatch &pp, pointVectorField &displacement, pointScalarField &scale, pointField &oldPoints, const labelList &adaptPatchIDs, const dictionary &paramDict)
Construct from mesh, patches to work on and smoothing parameters.
tmp< pointField > curPoints() const
Get the current points (oldPoints+scale*displacement)
void topoChange()
Update for new mesh topology.
scalar setErrorReduction(const scalar)
Set the errorReduction (by how much to scale the displacement.
static void setDisplacement(const labelList &patchIDs, const indirectPrimitivePatch &pp, pointField &patchDisp, pointVectorField &displacement)
Set displacement field from displacement on patch points.
void correct()
Take over existing mesh position.
const polyMesh & mesh() const
Reference to mesh.
bool scaleMesh(const labelList &checkFaces, const bool smoothMesh=true, const label nAllow=0)
Move mesh with given scale. Return true if mesh ok or has.
void movePoints()
Update for new mesh geometry.
const indirectPrimitivePatch & patch() const
Reference to patch.
const pointMesh & pMesh() const
Reference to pointMesh.
const labelList & adaptPatchIndices() const
Patch labels that are being adapted.
const dictionary & paramDict() const
void correctBoundaryConditions(pointVectorField &) const
Special correctBoundaryConditions which evaluates fixedValue.
void modifyMotionPoints(pointField &newPoints) const
Apply optional point constraint (2d correction)
fileName path(const word &instance, const fileName &local="") const
Return complete path with alternative instance and local.
const word & name() const
Return name.
Foam::pointBoundaryMesh.
const pointMesh & mesh() const
Return the mesh reference.
void constrain(PointField< Type > &pf, const bool overrideValue=false) const
Apply boundary conditions (single-patch constraints) and.
void constrainCorners(PointField< Type > &pf) const
Apply patch-patch constraints only.
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:53
const pointBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: pointMesh.H:125
A set of point labels.
Definition: pointSet.H:51
virtual void sync(const polyMesh &mesh)
Sync set across coupled patches. Adds coupled points to set.
Definition: pointSet.C:113
Foam::polyBoundaryMesh.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1515
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1313
static void syncPointList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh points.
static PackedBoolList getMasterEdges(const polyMesh &)
Get per edge whether it is uncoupled or a master of a.
Definition: syncTools.C:109
static void syncPointPositions(const polyMesh &mesh, List< point > &l, const CombineOp &cop, const point &nullValue)
Synchronise locations on all mesh points.
Definition: syncTools.H:196
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:181
Class applies a two-dimensional correction to mesh motion point field.
bool required() const
Is 2D correction required, i.e. is the mesh a wedge or slab.
void correctPoints(pointField &p) const
Correct motion points.
const labelList & normalEdgeIndices() const
Return indices of normal edges.
const vector & planeNormal() const
Return plane normal.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
const pointField & points
label nPoints
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const fvPatchList & patches
U correctBoundaryConditions()
Functions for checking mesh topology and geometry.
#define WarningInFunction
Report a warning using Foam::Warning.
bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, const labelList &checkFaces, const List< labelPair > &baffles, labelHashSet &wrongFaces)
Check (subset of mesh including baffles) with mesh settings in dict.
Definition: checkMesh.C:33
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
const doubleScalar e
Definition: doubleScalar.H:106
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:257
errorManip< error > abort(error &err)
Definition: errorManip.H:131
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
vector point
Point is a vector.
Definition: point.H:41
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
PointField< scalar > pointScalarField
bool isA(const Type &t)
Check if a dynamic_cast to typeid is possible.
Definition: typeInfo.H:166
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< scalar > mag(const dimensioned< Type > &)
defineTypeNameAndDebug(combustionModel, 0)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:213
error FatalError
List< edge > edgeList
Definition: edgeList.H:38
Type gMin(const FieldField< Field, Type > &f)
static const char nl
Definition: Ostream.H:266
Type gMax(const FieldField< Field, Type > &f)
labelList f(nPoints)
labelList pointLabels(nPoints, -1)