FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

createPatch.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 Application
00025     createPatch
00026 
00027 Description
00028     Utility to create patches out of selected boundary faces.
00029 
00030     Faces come either from existing patches or from a faceSet. More
00031     specifically it:
00032     - creates new patches (from selected boundary faces). Synchronise faces
00033       on coupled patches.
00034     - synchronises points on coupled boundaries
00035     - remove patches with 0 faces in them
00036 
00037 Usage
00038 
00039     - createPatch [OPTIONS]
00040 
00041     @param -overwrite \n
00042     Overwrite existing data.
00043 
00044     @param -case <dir>\n
00045     Case directory.
00046 
00047     @param -parallel \n
00048     Run in parallel.
00049 
00050     @param -help \n
00051     Display help message.
00052 
00053     @param -doc \n
00054     Display Doxygen API documentation page for this application.
00055 
00056     @param -srcDoc \n
00057     Display Doxygen source documentation page for this application.
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 // Combine operator to synchronise points. We choose point nearest to origin so
00084 // we can use e.g. great,great,great as null value.
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],               // face
00124             faceID,                             // face ID
00125             mesh.faceOwner()[faceID],           // owner
00126             -1,                                 // neighbour
00127             false,                              // flip flux
00128             patchID,                            // patch ID
00129             false,                              // remove from zone
00130             zoneID,                             // zone ID
00131             zoneFlip                            // zone flip
00132         )
00133     );
00134 }
00135 
00136 
00137 // Filter out the empty patches.
00138 void filterPatches(polyMesh& mesh)
00139 {
00140     const polyBoundaryMesh& patches = mesh.boundaryMesh();
00141 
00142     // Patches to keep
00143     DynamicList<polyPatch*> allPatches(patches.size());
00144 
00145     label nOldPatches = returnReduce(patches.size(), sumOp<label>());
00146 
00147     // Copy old patches.
00148     forAll(patches, patchI)
00149     {
00150         const polyPatch& pp = patches[patchI];
00151 
00152         // Note: reduce possible since non-proc patches guaranteed in same order
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     // Copy non-empty processor patches
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 // Dump for all patches the current match
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             // Dump halves
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             // Lines between corresponding face centres
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         // Single value for all.
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 // Synchronise points on both sides of coupled boundaries.
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     // Is there any coupled patch with transformation?
00356     bool hasTransformation = false;
00357 
00358     if (Pstream::parRun())
00359     {
00360         // Send
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                 // Get data per patchPoint in neighbouring point numbers.
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         // Receive and set.
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                     // We do not know the number of points on the other side
00416                     // so cannot use Pstream::read.
00417                     IPstream fromNbr
00418                     (
00419                         Pstream::blocking,
00420                         procPatch.neighbProcNo()
00421                     );
00422                     fromNbr >> nbrPatchInfo;
00423                 }
00424                 // Null any value which is not on neighbouring processor
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     // Do the cyclics.
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     //- Note: hasTransformation is only used for warning messages so
00493     //  reduction not strictly nessecary.
00494     //reduce(hasTransformation, orOp<bool>());
00495 
00496     // Synchronize multiple shared points.
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         // Values on shared points.
00515         pointField sharedPts(pd.nGlobalPoints(), nullValue);
00516 
00517         forAll(pd.sharedPointLabels(), i)
00518         {
00519             label meshPointI = pd.sharedPointLabels()[i];
00520             // Fill my entries in the shared points
00521             sharedPts[pd.sharedPointAddr()[i]] = points[meshPointI];
00522         }
00523 
00524         // Combine on master.
00525         Pstream::listCombineGather(sharedPts, cop);
00526         Pstream::listCombineScatter(sharedPts);
00527 
00528         // Now we will all have the same information. Merge it back with
00529         // my local information.
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 // Main program:
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     // Whether to synchronise points
00577     const Switch pointSync(dict.lookup("pointSync"));
00578 
00579 
00580     // Set the matching tolerance so we can read illegal meshes
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     // If running parallel check same patches everywhere
00593     patches.checkParallelSync(true);
00594 
00595 
00596     dumpCyclicMatch("initial_", mesh);
00597 
00598     // Read patch construct info from dictionary
00599     PtrList<dictionary> patchSources(dict.lookup("patchInfo"));
00600 
00601 
00602 
00603     // 1. Add all new patches
00604     // ~~~~~~~~~~~~~~~~~~~~~~
00605 
00606     if (patchSources.size())
00607     {
00608         // Old and new patches.
00609         DynamicList<polyPatch*> allPatches(patches.size()+patchSources.size());
00610 
00611         label startFaceI = mesh.nInternalFaces();
00612 
00613         // Copy old patches.
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                 // Add an empty patch.
00656                 allPatches.append
00657                 (
00658                     polyPatch::New
00659                     (
00660                         patchName,
00661                         patchDict,
00662                         destPatchI,
00663                         patches
00664                     ).ptr()
00665                 );
00666             }
00667         }
00668 
00669         // Copy old patches.
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     // 2. Repatch faces
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             // Repatch faces of the patches.
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             // Sort (since faceSet contains faces in arbitrary order)
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     // Change mesh, use inflation to reforce calculation of transformation
00793     // tensors.
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     // Synchronise points.
00801     if (!pointSync)
00802     {
00803         Info<< "Not synchronising points." << nl << endl;
00804     }
00805     else
00806     {
00807         Info<< "Synchronising points." << nl << endl;
00808 
00809         // This is a bit tricky. Both normal and position might be out and
00810         // current separation also includes the normal
00811         // ( separation_ = (nf&(Cr - Cf))*nf ).
00812 
00813         // For processor patches:
00814         // - disallow multiple separation/transformation. This basically
00815         //   excludes decomposed cyclics. Use the (probably 0) separation
00816         //   to align the points.
00817         // For cyclic patches:
00818         // - for separated ones use our own recalculated offset vector
00819         // - for rotational ones use current one.
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     // 3. Remove zeros-sized patches
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     // Set the precision of the points data to 10
00921     IOstream::defaultPrecision(10);
00922 
00923     if (!overwrite)
00924     {
00925         runTime++;
00926     }
00927     else
00928     {
00929         mesh.setInstance(oldInstance);
00930     }
00931 
00932     // Write resulting mesh
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 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines