00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #include <OpenFOAM/cyclicPolyPatch.H>
00062 #include <OpenFOAM/syncTools.H>
00063 #include <OpenFOAM/argList.H>
00064 #include <OpenFOAM/polyMesh.H>
00065 #include <OpenFOAM/Time.H>
00066 #include <OpenFOAM/SortableList.H>
00067 #include <OpenFOAM/OFstream.H>
00068 #include <meshTools/meshTools.H>
00069 #include <meshTools/faceSet.H>
00070 #include <OpenFOAM/IOPtrList.H>
00071 #include <dynamicMesh/polyTopoChange.H>
00072 #include <dynamicMesh/polyModifyFace.H>
00073
00074 using namespace Foam;
00075
00076
00077
00078 namespace Foam
00079 {
00080 defineTemplateTypeNameAndDebug(IOPtrList<dictionary>, 0);
00081 }
00082
00083
00084
00085 class nearestEqOp
00086 {
00087
00088 public:
00089
00090 void operator()(vector& x, const vector& y) const
00091 {
00092 if (magSqr(y) < magSqr(x))
00093 {
00094 x = y;
00095 }
00096 }
00097 };
00098
00099
00100 void changePatchID
00101 (
00102 const polyMesh& mesh,
00103 const label faceID,
00104 const label patchID,
00105 polyTopoChange& meshMod
00106 )
00107 {
00108 const label zoneID = mesh.faceZones().whichZone(faceID);
00109
00110 bool zoneFlip = false;
00111
00112 if (zoneID >= 0)
00113 {
00114 const faceZone& fZone = mesh.faceZones()[zoneID];
00115
00116 zoneFlip = fZone.flipMap()[fZone.whichFace(faceID)];
00117 }
00118
00119 meshMod.setAction
00120 (
00121 polyModifyFace
00122 (
00123 mesh.faces()[faceID],
00124 faceID,
00125 mesh.faceOwner()[faceID],
00126 -1,
00127 false,
00128 patchID,
00129 false,
00130 zoneID,
00131 zoneFlip
00132 )
00133 );
00134 }
00135
00136
00137
00138 void filterPatches(polyMesh& mesh)
00139 {
00140 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00141
00142
00143 DynamicList<polyPatch*> allPatches(patches.size());
00144
00145 label nOldPatches = returnReduce(patches.size(), sumOp<label>());
00146
00147
00148 forAll(patches, patchI)
00149 {
00150 const polyPatch& pp = patches[patchI];
00151
00152
00153 if (!isA<processorPolyPatch>(pp))
00154 {
00155 if (returnReduce(pp.size(), sumOp<label>()) > 0)
00156 {
00157 allPatches.append
00158 (
00159 pp.clone
00160 (
00161 patches,
00162 allPatches.size(),
00163 pp.size(),
00164 pp.start()
00165 ).ptr()
00166 );
00167 }
00168 else
00169 {
00170 Info<< "Removing empty patch " << pp.name() << " at position "
00171 << patchI << endl;
00172 }
00173 }
00174 }
00175
00176 forAll(patches, patchI)
00177 {
00178 const polyPatch& pp = patches[patchI];
00179
00180 if (isA<processorPolyPatch>(pp))
00181 {
00182 if (pp.size())
00183 {
00184 allPatches.append
00185 (
00186 pp.clone
00187 (
00188 patches,
00189 allPatches.size(),
00190 pp.size(),
00191 pp.start()
00192 ).ptr()
00193 );
00194 }
00195 else
00196 {
00197 Info<< "Removing empty processor patch " << pp.name()
00198 << " at position " << patchI << endl;
00199 }
00200 }
00201 }
00202
00203 label nAllPatches = returnReduce(allPatches.size(), sumOp<label>());
00204 if (nAllPatches != nOldPatches)
00205 {
00206 Info<< "Removing patches." << endl;
00207 allPatches.shrink();
00208 mesh.removeBoundary();
00209 mesh.addPatches(allPatches);
00210 }
00211 else
00212 {
00213 Info<< "No patches removed." << endl;
00214 }
00215 }
00216
00217
00218
00219 void dumpCyclicMatch(const fileName& prefix, const polyMesh& mesh)
00220 {
00221 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00222
00223 forAll(patches, patchI)
00224 {
00225 if (isA<cyclicPolyPatch>(patches[patchI]))
00226 {
00227 const cyclicPolyPatch& cycPatch =
00228 refCast<const cyclicPolyPatch>(patches[patchI]);
00229
00230 label halfSize = cycPatch.size()/2;
00231
00232
00233 {
00234 OFstream str(prefix+cycPatch.name()+"_half0.obj");
00235 Pout<< "Dumping " << cycPatch.name()
00236 << " half0 faces to " << str.name() << endl;
00237 meshTools::writeOBJ
00238 (
00239 str,
00240 static_cast<faceList>
00241 (
00242 SubList<face>
00243 (
00244 cycPatch,
00245 halfSize
00246 )
00247 ),
00248 cycPatch.points()
00249 );
00250 }
00251 {
00252 OFstream str(prefix+cycPatch.name()+"_half1.obj");
00253 Pout<< "Dumping " << cycPatch.name()
00254 << " half1 faces to " << str.name() << endl;
00255 meshTools::writeOBJ
00256 (
00257 str,
00258 static_cast<faceList>
00259 (
00260 SubList<face>
00261 (
00262 cycPatch,
00263 halfSize,
00264 halfSize
00265 )
00266 ),
00267 cycPatch.points()
00268 );
00269 }
00270
00271
00272
00273 OFstream str(prefix+cycPatch.name()+"_match.obj");
00274 label vertI = 0;
00275
00276 Pout<< "Dumping cyclic match as lines between face centres to "
00277 << str.name() << endl;
00278
00279 for (label faceI = 0; faceI < halfSize; faceI++)
00280 {
00281 const point& fc0 = mesh.faceCentres()[cycPatch.start()+faceI];
00282 meshTools::writeOBJ(str, fc0);
00283 vertI++;
00284
00285 label nbrFaceI = halfSize + faceI;
00286 const point& fc1 =
00287 mesh.faceCentres()[cycPatch.start()+nbrFaceI];
00288 meshTools::writeOBJ(str, fc1);
00289 vertI++;
00290
00291 str<< "l " << vertI-1 << ' ' << vertI << nl;
00292 }
00293 }
00294 }
00295 }
00296
00297
00298 void separateList
00299 (
00300 const vectorField& separation,
00301 UList<vector>& field
00302 )
00303 {
00304 if (separation.size() == 1)
00305 {
00306
00307
00308 forAll(field, i)
00309 {
00310 field[i] += separation[0];
00311 }
00312 }
00313 else if (separation.size() == field.size())
00314 {
00315 forAll(field, i)
00316 {
00317 field[i] += separation[i];
00318 }
00319 }
00320 else
00321 {
00322 FatalErrorIn
00323 (
00324 "separateList(const vectorField&, UList<vector>&)"
00325 ) << "Sizes of field and transformation not equal. field:"
00326 << field.size() << " transformation:" << separation.size()
00327 << abort(FatalError);
00328 }
00329 }
00330
00331
00332
00333 template <class CombineOp>
00334 void syncPoints
00335 (
00336 const polyMesh& mesh,
00337 pointField& points,
00338 const CombineOp& cop,
00339 const point& nullValue
00340 )
00341 {
00342 if (points.size() != mesh.nPoints())
00343 {
00344 FatalErrorIn
00345 (
00346 "syncPoints"
00347 "(const polyMesh&, pointField&, const CombineOp&, const point&)"
00348 ) << "Number of values " << points.size()
00349 << " is not equal to the number of points in the mesh "
00350 << mesh.nPoints() << abort(FatalError);
00351 }
00352
00353 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00354
00355
00356 bool hasTransformation = false;
00357
00358 if (Pstream::parRun())
00359 {
00360
00361
00362 forAll(patches, patchI)
00363 {
00364 const polyPatch& pp = patches[patchI];
00365
00366 if
00367 (
00368 isA<processorPolyPatch>(pp)
00369 && pp.nPoints() > 0
00370 && refCast<const processorPolyPatch>(pp).owner()
00371 )
00372 {
00373 const processorPolyPatch& procPatch =
00374 refCast<const processorPolyPatch>(pp);
00375
00376
00377 pointField patchInfo(procPatch.nPoints(), nullValue);
00378
00379 const labelList& meshPts = procPatch.meshPoints();
00380 const labelList& nbrPts = procPatch.neighbPoints();
00381
00382 forAll(nbrPts, pointI)
00383 {
00384 label nbrPointI = nbrPts[pointI];
00385 if (nbrPointI >= 0 && nbrPointI < patchInfo.size())
00386 {
00387 patchInfo[nbrPointI] = points[meshPts[pointI]];
00388 }
00389 }
00390
00391 OPstream toNbr(Pstream::blocking, procPatch.neighbProcNo());
00392 toNbr << patchInfo;
00393 }
00394 }
00395
00396
00397
00398
00399 forAll(patches, patchI)
00400 {
00401 const polyPatch& pp = patches[patchI];
00402
00403 if
00404 (
00405 isA<processorPolyPatch>(pp)
00406 && pp.nPoints() > 0
00407 && !refCast<const processorPolyPatch>(pp).owner()
00408 )
00409 {
00410 const processorPolyPatch& procPatch =
00411 refCast<const processorPolyPatch>(pp);
00412
00413 pointField nbrPatchInfo(procPatch.nPoints());
00414 {
00415
00416
00417 IPstream fromNbr
00418 (
00419 Pstream::blocking,
00420 procPatch.neighbProcNo()
00421 );
00422 fromNbr >> nbrPatchInfo;
00423 }
00424
00425 nbrPatchInfo.setSize(procPatch.nPoints(), nullValue);
00426
00427 if (!procPatch.parallel())
00428 {
00429 hasTransformation = true;
00430 transformList(procPatch.forwardT(), nbrPatchInfo);
00431 }
00432 else if (procPatch.separated())
00433 {
00434 hasTransformation = true;
00435 separateList(-procPatch.separation(), nbrPatchInfo);
00436 }
00437
00438 const labelList& meshPts = procPatch.meshPoints();
00439
00440 forAll(meshPts, pointI)
00441 {
00442 label meshPointI = meshPts[pointI];
00443 points[meshPointI] = nbrPatchInfo[pointI];
00444 }
00445 }
00446 }
00447 }
00448
00449
00450 forAll(patches, patchI)
00451 {
00452 const polyPatch& pp = patches[patchI];
00453
00454 if (isA<cyclicPolyPatch>(pp))
00455 {
00456 const cyclicPolyPatch& cycPatch =
00457 refCast<const cyclicPolyPatch>(pp);
00458
00459 const edgeList& coupledPoints = cycPatch.coupledPoints();
00460 const labelList& meshPts = cycPatch.meshPoints();
00461
00462 pointField half0Values(coupledPoints.size());
00463
00464 forAll(coupledPoints, i)
00465 {
00466 const edge& e = coupledPoints[i];
00467 label point0 = meshPts[e[0]];
00468 half0Values[i] = points[point0];
00469 }
00470
00471 if (!cycPatch.parallel())
00472 {
00473 hasTransformation = true;
00474 transformList(cycPatch.reverseT(), half0Values);
00475 }
00476 else if (cycPatch.separated())
00477 {
00478 hasTransformation = true;
00479 const vectorField& v = cycPatch.coupledPolyPatch::separation();
00480 separateList(v, half0Values);
00481 }
00482
00483 forAll(coupledPoints, i)
00484 {
00485 const edge& e = coupledPoints[i];
00486 label point1 = meshPts[e[1]];
00487 points[point1] = half0Values[i];
00488 }
00489 }
00490 }
00491
00492
00493
00494
00495
00496
00497 const globalMeshData& pd = mesh.globalData();
00498
00499 if (pd.nGlobalPoints() > 0)
00500 {
00501 if (hasTransformation)
00502 {
00503 WarningIn
00504 (
00505 "syncPoints"
00506 "(const polyMesh&, pointField&, const CombineOp&, const point&)"
00507 ) << "There are decomposed cyclics in this mesh with"
00508 << " transformations." << endl
00509 << "This is not supported. The result will be incorrect"
00510 << endl;
00511 }
00512
00513
00514
00515 pointField sharedPts(pd.nGlobalPoints(), nullValue);
00516
00517 forAll(pd.sharedPointLabels(), i)
00518 {
00519 label meshPointI = pd.sharedPointLabels()[i];
00520
00521 sharedPts[pd.sharedPointAddr()[i]] = points[meshPointI];
00522 }
00523
00524
00525 Pstream::listCombineGather(sharedPts, cop);
00526 Pstream::listCombineScatter(sharedPts);
00527
00528
00529
00530 forAll(pd.sharedPointLabels(), i)
00531 {
00532 label meshPointI = pd.sharedPointLabels()[i];
00533 points[meshPointI] = sharedPts[pd.sharedPointAddr()[i]];
00534 }
00535 }
00536 }
00537
00538
00539
00540
00541 int main(int argc, char *argv[])
00542 {
00543 # include <OpenFOAM/addRegionOption.H>
00544 argList::validOptions.insert("overwrite", "");
00545
00546 # include <OpenFOAM/setRootCase.H>
00547 # include <OpenFOAM/createTime.H>
00548 runTime.functionObjects().off();
00549
00550 Foam::word meshRegionName = polyMesh::defaultRegion;
00551 args.optionReadIfPresent("region", meshRegionName);
00552
00553 const bool overwrite = args.optionFound("overwrite");
00554
00555 Info<< "Reading createPatchDict." << nl << endl;
00556
00557 IOdictionary dict
00558 (
00559 IOobject
00560 (
00561 "createPatchDict",
00562 runTime.system(),
00563 (
00564 meshRegionName != polyMesh::defaultRegion
00565 ? meshRegionName
00566 : word::null
00567 ),
00568 runTime,
00569 IOobject::MUST_READ,
00570 IOobject::NO_WRITE,
00571 false
00572 )
00573 );
00574
00575
00576
00577 const Switch pointSync(dict.lookup("pointSync"));
00578
00579
00580
00581 scalar tol = readScalar(dict.lookup("matchTolerance"));
00582 Info<< "Using relative tolerance " << tol
00583 << " to match up faces and points" << nl << endl;
00584 coupledPolyPatch::matchTol = tol;
00585
00586 # include <OpenFOAM/createNamedPolyMesh.H>
00587
00588 const word oldInstance = mesh.pointsInstance();
00589
00590 const polyBoundaryMesh& patches = mesh.boundaryMesh();
00591
00592
00593 patches.checkParallelSync(true);
00594
00595
00596 dumpCyclicMatch("initial_", mesh);
00597
00598
00599 PtrList<dictionary> patchSources(dict.lookup("patchInfo"));
00600
00601
00602
00603
00604
00605
00606 if (patchSources.size())
00607 {
00608
00609 DynamicList<polyPatch*> allPatches(patches.size()+patchSources.size());
00610
00611 label startFaceI = mesh.nInternalFaces();
00612
00613
00614 forAll(patches, patchI)
00615 {
00616 const polyPatch& pp = patches[patchI];
00617
00618 if (!isA<processorPolyPatch>(pp))
00619 {
00620 allPatches.append
00621 (
00622 pp.clone
00623 (
00624 patches,
00625 patchI,
00626 pp.size(),
00627 startFaceI
00628 ).ptr()
00629 );
00630 startFaceI += pp.size();
00631 }
00632 }
00633
00634 forAll(patchSources, addedI)
00635 {
00636 const dictionary& dict = patchSources[addedI];
00637
00638 word patchName(dict.lookup("name"));
00639
00640 label destPatchI = patches.findPatchID(patchName);
00641
00642 if (destPatchI == -1)
00643 {
00644 dictionary patchDict(dict.subDict("dictionary"));
00645
00646 destPatchI = allPatches.size();
00647
00648 Info<< "Adding new patch " << patchName
00649 << " as patch " << destPatchI
00650 << " from " << patchDict << endl;
00651
00652 patchDict.set("nFaces", 0);
00653 patchDict.set("startFace", startFaceI);
00654
00655
00656 allPatches.append
00657 (
00658 polyPatch::New
00659 (
00660 patchName,
00661 patchDict,
00662 destPatchI,
00663 patches
00664 ).ptr()
00665 );
00666 }
00667 }
00668
00669
00670 forAll(patches, patchI)
00671 {
00672 const polyPatch& pp = patches[patchI];
00673
00674 if (isA<processorPolyPatch>(pp))
00675 {
00676 allPatches.append
00677 (
00678 pp.clone
00679 (
00680 patches,
00681 patchI,
00682 pp.size(),
00683 startFaceI
00684 ).ptr()
00685 );
00686 startFaceI += pp.size();
00687 }
00688 }
00689
00690 allPatches.shrink();
00691 mesh.removeBoundary();
00692 mesh.addPatches(allPatches);
00693
00694 Info<< endl;
00695 }
00696
00697
00698
00699
00700
00701
00702 polyTopoChange meshMod(mesh);
00703
00704
00705 forAll(patchSources, addedI)
00706 {
00707 const dictionary& dict = patchSources[addedI];
00708
00709 word patchName(dict.lookup("name"));
00710
00711 label destPatchI = patches.findPatchID(patchName);
00712
00713 if (destPatchI == -1)
00714 {
00715 FatalErrorIn(args.executable()) << "patch " << patchName
00716 << " not added. Problem." << abort(FatalError);
00717 }
00718
00719 word sourceType(dict.lookup("constructFrom"));
00720
00721 if (sourceType == "patches")
00722 {
00723 labelHashSet patchSources(patches.patchSet(dict.lookup("patches")));
00724
00725
00726 forAllConstIter(labelHashSet, patchSources, iter)
00727 {
00728 const polyPatch& pp = patches[iter.key()];
00729
00730 Info<< "Moving faces from patch " << pp.name()
00731 << " to patch " << destPatchI << endl;
00732
00733 forAll(pp, i)
00734 {
00735 changePatchID
00736 (
00737 mesh,
00738 pp.start() + i,
00739 destPatchI,
00740 meshMod
00741 );
00742 }
00743 }
00744 }
00745 else if (sourceType == "set")
00746 {
00747 word setName(dict.lookup("set"));
00748
00749 faceSet faces(mesh, setName);
00750
00751 Info<< "Read " << returnReduce(faces.size(), sumOp<label>())
00752 << " faces from faceSet " << faces.name() << endl;
00753
00754
00755 labelList faceLabels(faces.toc());
00756
00757 SortableList<label> patchFaces(faceLabels);
00758
00759 forAll(patchFaces, i)
00760 {
00761 label faceI = patchFaces[i];
00762
00763 if (mesh.isInternalFace(faceI))
00764 {
00765 FatalErrorIn(args.executable())
00766 << "Face " << faceI << " specified in set "
00767 << faces.name()
00768 << " is not an external face of the mesh." << endl
00769 << "This application can only repatch existing boundary"
00770 << " faces." << exit(FatalError);
00771 }
00772
00773 changePatchID
00774 (
00775 mesh,
00776 faceI,
00777 destPatchI,
00778 meshMod
00779 );
00780 }
00781 }
00782 else
00783 {
00784 FatalErrorIn(args.executable())
00785 << "Invalid source type " << sourceType << endl
00786 << "Valid source types are 'patches' 'set'" << exit(FatalError);
00787 }
00788 }
00789 Info<< endl;
00790
00791
00792
00793
00794 Info<< "Doing topology modification to order faces." << nl << endl;
00795 autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, true);
00796 mesh.movePoints(map().preMotionPoints());
00797
00798 dumpCyclicMatch("coupled_", mesh);
00799
00800
00801 if (!pointSync)
00802 {
00803 Info<< "Not synchronising points." << nl << endl;
00804 }
00805 else
00806 {
00807 Info<< "Synchronising points." << nl << endl;
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821 forAll(mesh.boundaryMesh(), patchI)
00822 {
00823 const polyPatch& pp = mesh.boundaryMesh()[patchI];
00824
00825 if (pp.size() && isA<coupledPolyPatch>(pp))
00826 {
00827 const coupledPolyPatch& cpp =
00828 refCast<const coupledPolyPatch>(pp);
00829
00830 if (cpp.separated())
00831 {
00832 Info<< "On coupled patch " << pp.name()
00833 << " separation[0] was "
00834 << cpp.separation()[0] << endl;
00835
00836 if (isA<cyclicPolyPatch>(pp))
00837 {
00838 const cyclicPolyPatch& cycpp =
00839 refCast<const cyclicPolyPatch>(pp);
00840
00841 if (cycpp.transform() == cyclicPolyPatch::TRANSLATIONAL)
00842 {
00843 Info<< "On cyclic translation patch " << pp.name()
00844 << " forcing uniform separation of "
00845 << cycpp.separationVector() << endl;
00846 const_cast<vectorField&>(cpp.separation()) =
00847 pointField(1, cycpp.separationVector());
00848 }
00849 else
00850 {
00851 const_cast<vectorField&>(cpp.separation()) =
00852 pointField
00853 (
00854 1,
00855 pp[pp.size()/2].centre(mesh.points())
00856 - pp[0].centre(mesh.points())
00857 );
00858 }
00859 }
00860 else
00861 {
00862 const_cast<vectorField&>(cpp.separation())
00863 .setSize(1);
00864 }
00865 Info<< "On coupled patch " << pp.name()
00866 << " forcing uniform separation of "
00867 << cpp.separation() << endl;
00868 }
00869 else if (!cpp.parallel())
00870 {
00871 Info<< "On coupled patch " << pp.name()
00872 << " forcing uniform rotation of "
00873 << cpp.forwardT()[0] << endl;
00874
00875 const_cast<tensorField&>
00876 (
00877 cpp.forwardT()
00878 ).setSize(1);
00879 const_cast<tensorField&>
00880 (
00881 cpp.reverseT()
00882 ).setSize(1);
00883
00884 Info<< "On coupled patch " << pp.name()
00885 << " forcing uniform rotation of "
00886 << cpp.forwardT() << endl;
00887 }
00888 }
00889 }
00890
00891 Info<< "Synchronising points." << endl;
00892
00893 pointField newPoints(mesh.points());
00894
00895 syncPoints
00896 (
00897 mesh,
00898 newPoints,
00899 nearestEqOp(),
00900 point(GREAT, GREAT, GREAT)
00901 );
00902
00903 scalarField diff(mag(newPoints-mesh.points()));
00904 Info<< "Points changed by average:" << gAverage(diff)
00905 << " max:" << gMax(diff) << nl << endl;
00906
00907 mesh.movePoints(newPoints);
00908 }
00909
00910
00911
00912
00913 Info<< "Removing patches with no faces in them." << nl<< endl;
00914 filterPatches(mesh);
00915
00916
00917 dumpCyclicMatch("final_", mesh);
00918
00919
00920
00921 IOstream::defaultPrecision(10);
00922
00923 if (!overwrite)
00924 {
00925 runTime++;
00926 }
00927 else
00928 {
00929 mesh.setInstance(oldInstance);
00930 }
00931
00932
00933 Info<< "Writing repatched mesh to " << runTime.timeName() << nl << endl;
00934 mesh.write();
00935
00936 Info<< "End\n" << endl;
00937
00938 return 0;
00939 }
00940
00941
00942