BUG: UListIO: byteSize overflowing on really big faceLists
[OpenFOAM-2.0.x.git] / applications / utilities / mesh / manipulation / createPatch / createPatch.C
blob7afe8356a6f1e599e4ad5abecaac21a7c3ee33c0
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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.
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.
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/>.
24 Description
25     Utility to create patches out of selected boundary faces. Faces come either
26     from existing patches or from a faceSet.
28     More specifically it:
29     - creates new patches (from selected boundary faces). Synchronise faces
30       on coupled patches.
31     - synchronises points on coupled boundaries
32     - remove patches with 0 faces in them
34 \*---------------------------------------------------------------------------*/
36 #include "cyclicPolyPatch.H"
37 #include "syncTools.H"
38 #include "argList.H"
39 #include "polyMesh.H"
40 #include "Time.H"
41 #include "SortableList.H"
42 #include "OFstream.H"
43 #include "meshTools.H"
44 #include "faceSet.H"
45 #include "IOPtrList.H"
46 #include "polyTopoChange.H"
47 #include "polyModifyFace.H"
48 #include "wordReList.H"
50 using namespace Foam;
52 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
54 namespace Foam
56     defineTemplateTypeNameAndDebug(IOPtrList<dictionary>, 0);
59 void changePatchID
61     const polyMesh& mesh,
62     const label faceID,
63     const label patchID,
64     polyTopoChange& meshMod
67     const label zoneID = mesh.faceZones().whichZone(faceID);
69     bool zoneFlip = false;
71     if (zoneID >= 0)
72     {
73         const faceZone& fZone = mesh.faceZones()[zoneID];
75         zoneFlip = fZone.flipMap()[fZone.whichFace(faceID)];
76     }
78     meshMod.setAction
79     (
80         polyModifyFace
81         (
82             mesh.faces()[faceID],               // face
83             faceID,                             // face ID
84             mesh.faceOwner()[faceID],           // owner
85             -1,                                 // neighbour
86             false,                              // flip flux
87             patchID,                            // patch ID
88             false,                              // remove from zone
89             zoneID,                             // zone ID
90             zoneFlip                            // zone flip
91         )
92     );
96 // Filter out the empty patches.
97 void filterPatches(polyMesh& mesh)
99     const polyBoundaryMesh& patches = mesh.boundaryMesh();
101     // Patches to keep
102     DynamicList<polyPatch*> allPatches(patches.size());
104     label nOldPatches = returnReduce(patches.size(), sumOp<label>());
106     // Copy old patches.
107     forAll(patches, patchI)
108     {
109         const polyPatch& pp = patches[patchI];
111         // Note: reduce possible since non-proc patches guaranteed in same order
112         if (!isA<processorPolyPatch>(pp))
113         {
114             if (returnReduce(pp.size(), sumOp<label>()) > 0)
115             {
116                 allPatches.append
117                 (
118                     pp.clone
119                     (
120                         patches,
121                         allPatches.size(),
122                         pp.size(),
123                         pp.start()
124                     ).ptr()
125                 );
126             }
127             else
128             {
129                 Info<< "Removing empty patch " << pp.name() << " at position "
130                     << patchI << endl;
131             }
132         }
133     }
134     // Copy non-empty processor patches
135     forAll(patches, patchI)
136     {
137         const polyPatch& pp = patches[patchI];
139         if (isA<processorPolyPatch>(pp))
140         {
141             if (pp.size())
142             {
143                 allPatches.append
144                 (
145                     pp.clone
146                     (
147                         patches,
148                         allPatches.size(),
149                         pp.size(),
150                         pp.start()
151                     ).ptr()
152                 );
153             }
154             else
155             {
156                 Info<< "Removing empty processor patch " << pp.name()
157                     << " at position " << patchI << endl;
158             }
159         }
160     }
162     label nAllPatches = returnReduce(allPatches.size(), sumOp<label>());
163     if (nAllPatches != nOldPatches)
164     {
165         Info<< "Removing patches." << endl;
166         allPatches.shrink();
167         mesh.removeBoundary();
168         mesh.addPatches(allPatches);
169     }
170     else
171     {
172         Info<< "No patches removed." << endl;
173     }
177 // Dump for all patches the current match
178 void dumpCyclicMatch(const fileName& prefix, const polyMesh& mesh)
180     const polyBoundaryMesh& patches = mesh.boundaryMesh();
182     forAll(patches, patchI)
183     {
184         if
185         (
186             isA<cyclicPolyPatch>(patches[patchI])
187          && refCast<const cyclicPolyPatch>(patches[patchI]).owner()
188         )
189         {
190             const cyclicPolyPatch& cycPatch =
191                 refCast<const cyclicPolyPatch>(patches[patchI]);
193             // Dump patches
194             {
195                 OFstream str(prefix+cycPatch.name()+".obj");
196                 Pout<< "Dumping " << cycPatch.name()
197                     << " faces to " << str.name() << endl;
198                 meshTools::writeOBJ
199                 (
200                     str,
201                     cycPatch,
202                     cycPatch.points()
203                 );
204             }
206             const cyclicPolyPatch& nbrPatch = cycPatch.neighbPatch();
207             {
208                 OFstream str(prefix+nbrPatch.name()+".obj");
209                 Pout<< "Dumping " << nbrPatch.name()
210                     << " faces to " << str.name() << endl;
211                 meshTools::writeOBJ
212                 (
213                     str,
214                     nbrPatch,
215                     nbrPatch.points()
216                 );
217             }
220             // Lines between corresponding face centres
221             OFstream str(prefix+cycPatch.name()+nbrPatch.name()+"_match.obj");
222             label vertI = 0;
224             Pout<< "Dumping cyclic match as lines between face centres to "
225                 << str.name() << endl;
227             forAll(cycPatch, faceI)
228             {
229                 const point& fc0 = mesh.faceCentres()[cycPatch.start()+faceI];
230                 meshTools::writeOBJ(str, fc0);
231                 vertI++;
232                 const point& fc1 = mesh.faceCentres()[nbrPatch.start()+faceI];
233                 meshTools::writeOBJ(str, fc1);
234                 vertI++;
236                 str<< "l " << vertI-1 << ' ' << vertI << nl;
237             }
238         }
239     }
243 void separateList
245     const vectorField& separation,
246     UList<vector>& field
249     if (separation.size() == 1)
250     {
251         // Single value for all.
253         forAll(field, i)
254         {
255             field[i] += separation[0];
256         }
257     }
258     else if (separation.size() == field.size())
259     {
260         forAll(field, i)
261         {
262             field[i] += separation[i];
263         }
264     }
265     else
266     {
267         FatalErrorIn
268         (
269             "separateList(const vectorField&, UList<vector>&)"
270         )   << "Sizes of field and transformation not equal. field:"
271             << field.size() << " transformation:" << separation.size()
272             << abort(FatalError);
273     }
277 // Synchronise points on both sides of coupled boundaries.
278 template <class CombineOp>
279 void syncPoints
281     const polyMesh& mesh,
282     pointField& points,
283     const CombineOp& cop,
284     const point& nullValue
287     if (points.size() != mesh.nPoints())
288     {
289         FatalErrorIn
290         (
291             "syncPoints"
292             "(const polyMesh&, pointField&, const CombineOp&, const point&)"
293         )   << "Number of values " << points.size()
294             << " is not equal to the number of points in the mesh "
295             << mesh.nPoints() << abort(FatalError);
296     }
298     const polyBoundaryMesh& patches = mesh.boundaryMesh();
300     // Is there any coupled patch with transformation?
301     bool hasTransformation = false;
303     if (Pstream::parRun())
304     {
305         // Send
307         forAll(patches, patchI)
308         {
309             const polyPatch& pp = patches[patchI];
311             if
312             (
313                 isA<processorPolyPatch>(pp)
314              && pp.nPoints() > 0
315              && refCast<const processorPolyPatch>(pp).owner()
316             )
317             {
318                 const processorPolyPatch& procPatch =
319                     refCast<const processorPolyPatch>(pp);
321                 // Get data per patchPoint in neighbouring point numbers.
322                 pointField patchInfo(procPatch.nPoints(), nullValue);
324                 const labelList& meshPts = procPatch.meshPoints();
325                 const labelList& nbrPts = procPatch.neighbPoints();
327                 forAll(nbrPts, pointI)
328                 {
329                     label nbrPointI = nbrPts[pointI];
330                     if (nbrPointI >= 0 && nbrPointI < patchInfo.size())
331                     {
332                         patchInfo[nbrPointI] = points[meshPts[pointI]];
333                     }
334                 }
336                 OPstream toNbr(Pstream::blocking, procPatch.neighbProcNo());
337                 toNbr << patchInfo;
338             }
339         }
342         // Receive and set.
344         forAll(patches, patchI)
345         {
346             const polyPatch& pp = patches[patchI];
348             if
349             (
350                 isA<processorPolyPatch>(pp)
351              && pp.nPoints() > 0
352              && !refCast<const processorPolyPatch>(pp).owner()
353             )
354             {
355                 const processorPolyPatch& procPatch =
356                     refCast<const processorPolyPatch>(pp);
358                 pointField nbrPatchInfo(procPatch.nPoints());
359                 {
360                     // We do not know the number of points on the other side
361                     // so cannot use Pstream::read.
362                     IPstream fromNbr
363                     (
364                         Pstream::blocking,
365                         procPatch.neighbProcNo()
366                     );
367                     fromNbr >> nbrPatchInfo;
368                 }
369                 // Null any value which is not on neighbouring processor
370                 nbrPatchInfo.setSize(procPatch.nPoints(), nullValue);
372                 if (!procPatch.parallel())
373                 {
374                     hasTransformation = true;
375                     transformList(procPatch.forwardT(), nbrPatchInfo);
376                 }
377                 else if (procPatch.separated())
378                 {
379                     hasTransformation = true;
380                     separateList(-procPatch.separation(), nbrPatchInfo);
381                 }
383                 const labelList& meshPts = procPatch.meshPoints();
385                 forAll(meshPts, pointI)
386                 {
387                     label meshPointI = meshPts[pointI];
388                     points[meshPointI] = nbrPatchInfo[pointI];
389                 }
390             }
391         }
392     }
394     // Do the cyclics.
395     forAll(patches, patchI)
396     {
397         const polyPatch& pp = patches[patchI];
399         if
400         (
401             isA<cyclicPolyPatch>(pp)
402          && refCast<const cyclicPolyPatch>(pp).owner()
403         )
404         {
405             const cyclicPolyPatch& cycPatch =
406                 refCast<const cyclicPolyPatch>(pp);
408             const edgeList& coupledPoints = cycPatch.coupledPoints();
409             const labelList& meshPts = cycPatch.meshPoints();
410             const cyclicPolyPatch& nbrPatch = cycPatch.neighbPatch();
411             const labelList& nbrMeshPts = nbrPatch.meshPoints();
413             pointField half0Values(coupledPoints.size());
415             forAll(coupledPoints, i)
416             {
417                 const edge& e = coupledPoints[i];
418                 label point0 = meshPts[e[0]];
419                 half0Values[i] = points[point0];
420             }
422             if (!cycPatch.parallel())
423             {
424                 hasTransformation = true;
425                 transformList(cycPatch.reverseT(), half0Values);
426             }
427             else if (cycPatch.separated())
428             {
429                 hasTransformation = true;
430                 separateList(cycPatch.separation(), half0Values);
431             }
433             forAll(coupledPoints, i)
434             {
435                 const edge& e = coupledPoints[i];
436                 label point1 = nbrMeshPts[e[1]];
437                 points[point1] = half0Values[i];
438             }
439         }
440     }
442     //- Note: hasTransformation is only used for warning messages so
443     //  reduction not strictly nessecary.
444     //reduce(hasTransformation, orOp<bool>());
446     // Synchronize multiple shared points.
447     const globalMeshData& pd = mesh.globalData();
449     if (pd.nGlobalPoints() > 0)
450     {
451         if (hasTransformation)
452         {
453             WarningIn
454             (
455                 "syncPoints"
456                 "(const polyMesh&, pointField&, const CombineOp&, const point&)"
457             )   << "There are decomposed cyclics in this mesh with"
458                 << " transformations." << endl
459                 << "This is not supported. The result will be incorrect"
460                 << endl;
461         }
464         // Values on shared points.
465         pointField sharedPts(pd.nGlobalPoints(), nullValue);
467         forAll(pd.sharedPointLabels(), i)
468         {
469             label meshPointI = pd.sharedPointLabels()[i];
470             // Fill my entries in the shared points
471             sharedPts[pd.sharedPointAddr()[i]] = points[meshPointI];
472         }
474         // Combine on master.
475         Pstream::listCombineGather(sharedPts, cop);
476         Pstream::listCombineScatter(sharedPts);
478         // Now we will all have the same information. Merge it back with
479         // my local information.
480         forAll(pd.sharedPointLabels(), i)
481         {
482             label meshPointI = pd.sharedPointLabels()[i];
483             points[meshPointI] = sharedPts[pd.sharedPointAddr()[i]];
484         }
485     }
489 // Main program:
491 int main(int argc, char *argv[])
493 #   include "addOverwriteOption.H"
494 #   include "addRegionOption.H"
496 #   include "setRootCase.H"
497 #   include "createTime.H"
498     runTime.functionObjects().off();
500     Foam::word meshRegionName = polyMesh::defaultRegion;
501     args.optionReadIfPresent("region", meshRegionName);
503     const bool overwrite = args.optionFound("overwrite");
505     Info<< "Reading createPatchDict." << nl << endl;
507     IOdictionary dict
508     (
509         IOobject
510         (
511             "createPatchDict",
512             runTime.system(),
513             (
514                 meshRegionName != polyMesh::defaultRegion
515               ? meshRegionName
516               : word::null
517             ),
518             runTime,
519             IOobject::MUST_READ_IF_MODIFIED,
520             IOobject::NO_WRITE,
521             false
522         )
523     );
526     // Whether to synchronise points
527     const Switch pointSync(dict.lookup("pointSync"));
529 #   include "createNamedPolyMesh.H"
531     const word oldInstance = mesh.pointsInstance();
533     const polyBoundaryMesh& patches = mesh.boundaryMesh();
535     // If running parallel check same patches everywhere
536     patches.checkParallelSync(true);
539     dumpCyclicMatch("initial_", mesh);
541     // Read patch construct info from dictionary
542     PtrList<dictionary> patchSources(dict.lookup("patches"));
546     // 1. Add all new patches
547     // ~~~~~~~~~~~~~~~~~~~~~~
549     if (patchSources.size())
550     {
551         // Old and new patches.
552         DynamicList<polyPatch*> allPatches(patches.size()+patchSources.size());
554         label startFaceI = mesh.nInternalFaces();
556         // Copy old patches.
557         forAll(patches, patchI)
558         {
559             const polyPatch& pp = patches[patchI];
561             if (!isA<processorPolyPatch>(pp))
562             {
563                 allPatches.append
564                 (
565                     pp.clone
566                     (
567                         patches,
568                         patchI,
569                         pp.size(),
570                         startFaceI
571                     ).ptr()
572                 );
573                 startFaceI += pp.size();
574             }
575         }
577         forAll(patchSources, addedI)
578         {
579             const dictionary& dict = patchSources[addedI];
581             word patchName(dict.lookup("name"));
583             label destPatchI = patches.findPatchID(patchName);
585             if (destPatchI == -1)
586             {
587                 dictionary patchDict(dict.subDict("patchInfo"));
589                 destPatchI = allPatches.size();
591                 Info<< "Adding new patch " << patchName
592                     << " as patch " << destPatchI
593                     << " from " << patchDict << endl;
595                 patchDict.set("nFaces", 0);
596                 patchDict.set("startFace", startFaceI);
598                 // Add an empty patch.
599                 allPatches.append
600                 (
601                     polyPatch::New
602                     (
603                         patchName,
604                         patchDict,
605                         destPatchI,
606                         patches
607                     ).ptr()
608                 );
609             }
610         }
612         // Copy old patches.
613         forAll(patches, patchI)
614         {
615             const polyPatch& pp = patches[patchI];
617             if (isA<processorPolyPatch>(pp))
618             {
619                 allPatches.append
620                 (
621                     pp.clone
622                     (
623                         patches,
624                         patchI,
625                         pp.size(),
626                         startFaceI
627                     ).ptr()
628                 );
629                 startFaceI += pp.size();
630             }
631         }
633         allPatches.shrink();
634         mesh.removeBoundary();
635         mesh.addPatches(allPatches);
637         Info<< endl;
638     }
642     // 2. Repatch faces
643     // ~~~~~~~~~~~~~~~~
645     polyTopoChange meshMod(mesh);
648     forAll(patchSources, addedI)
649     {
650         const dictionary& dict = patchSources[addedI];
652         const word patchName(dict.lookup("name"));
653         label destPatchI = patches.findPatchID(patchName);
655         if (destPatchI == -1)
656         {
657             FatalErrorIn(args.executable())
658                 << "patch " << patchName << " not added. Problem."
659                 << abort(FatalError);
660         }
662         const word sourceType(dict.lookup("constructFrom"));
664         if (sourceType == "patches")
665         {
666             labelHashSet patchSources
667             (
668                 patches.patchSet
669                 (
670                     wordReList(dict.lookup("patches"))
671                 )
672             );
674             // Repatch faces of the patches.
675             forAllConstIter(labelHashSet, patchSources, iter)
676             {
677                 const polyPatch& pp = patches[iter.key()];
679                 Info<< "Moving faces from patch " << pp.name()
680                     << " to patch " << destPatchI << endl;
682                 forAll(pp, i)
683                 {
684                     changePatchID
685                     (
686                         mesh,
687                         pp.start() + i,
688                         destPatchI,
689                         meshMod
690                     );
691                 }
692             }
693         }
694         else if (sourceType == "set")
695         {
696             const word setName(dict.lookup("set"));
698             faceSet faces(mesh, setName);
700             Info<< "Read " << returnReduce(faces.size(), sumOp<label>())
701                 << " faces from faceSet " << faces.name() << endl;
703             // Sort (since faceSet contains faces in arbitrary order)
704             labelList faceLabels(faces.toc());
706             SortableList<label> patchFaces(faceLabels);
708             forAll(patchFaces, i)
709             {
710                 label faceI = patchFaces[i];
712                 if (mesh.isInternalFace(faceI))
713                 {
714                     FatalErrorIn(args.executable())
715                         << "Face " << faceI << " specified in set "
716                         << faces.name()
717                         << " is not an external face of the mesh." << endl
718                         << "This application can only repatch existing boundary"
719                         << " faces." << exit(FatalError);
720                 }
722                 changePatchID
723                 (
724                     mesh,
725                     faceI,
726                     destPatchI,
727                     meshMod
728                 );
729             }
730         }
731         else
732         {
733             FatalErrorIn(args.executable())
734                 << "Invalid source type " << sourceType << endl
735                 << "Valid source types are 'patches' 'set'" << exit(FatalError);
736         }
737     }
738     Info<< endl;
741     // Change mesh, use inflation to reforce calculation of transformation
742     // tensors.
743     Info<< "Doing topology modification to order faces." << nl << endl;
744     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, true);
745     mesh.movePoints(map().preMotionPoints());
747     dumpCyclicMatch("coupled_", mesh);
749     // Synchronise points.
750     if (!pointSync)
751     {
752         Info<< "Not synchronising points." << nl << endl;
753     }
754     else
755     {
756         Info<< "Synchronising points." << nl << endl;
758         // This is a bit tricky. Both normal and position might be out and
759         // current separation also includes the normal
760         // ( separation_ = (nf&(Cr - Cf))*nf ).
762         // For cyclic patches:
763         // - for separated ones use user specified offset vector
765         forAll(mesh.boundaryMesh(), patchI)
766         {
767             const polyPatch& pp = mesh.boundaryMesh()[patchI];
769             if (pp.size() && isA<coupledPolyPatch>(pp))
770             {
771                 const coupledPolyPatch& cpp =
772                     refCast<const coupledPolyPatch>(pp);
774                 if (cpp.separated())
775                 {
776                     Info<< "On coupled patch " << pp.name()
777                         << " separation[0] was "
778                         << cpp.separation()[0] << endl;
780                     if (isA<cyclicPolyPatch>(pp) && pp.size())
781                     {
782                         const cyclicPolyPatch& cycpp =
783                             refCast<const cyclicPolyPatch>(pp);
785                         if (cycpp.transform() == cyclicPolyPatch::TRANSLATIONAL)
786                         {
787                             // Force to wanted separation
788                             Info<< "On cyclic translation patch " << pp.name()
789                                 << " forcing uniform separation of "
790                                 << cycpp.separationVector() << endl;
791                             const_cast<vectorField&>(cpp.separation()) =
792                                 pointField(1, cycpp.separationVector());
793                         }
794                         else
795                         {
796                             const cyclicPolyPatch& nbr = cycpp.neighbPatch();
797                             const_cast<vectorField&>(cpp.separation()) =
798                                 pointField
799                                 (
800                                     1,
801                                     nbr[0].centre(mesh.points())
802                                   - cycpp[0].centre(mesh.points())
803                                 );
804                         }
805                     }
806                     Info<< "On coupled patch " << pp.name()
807                         << " forcing uniform separation of "
808                         << cpp.separation() << endl;
809                 }
810                 else if (!cpp.parallel())
811                 {
812                     Info<< "On coupled patch " << pp.name()
813                         << " forcing uniform rotation of "
814                         << cpp.forwardT()[0] << endl;
816                     const_cast<tensorField&>
817                     (
818                         cpp.forwardT()
819                     ).setSize(1);
820                     const_cast<tensorField&>
821                     (
822                         cpp.reverseT()
823                     ).setSize(1);
825                     Info<< "On coupled patch " << pp.name()
826                         << " forcing uniform rotation of "
827                         << cpp.forwardT() << endl;
828                 }
829             }
830         }
832         Info<< "Synchronising points." << endl;
834         pointField newPoints(mesh.points());
836         syncPoints
837         (
838             mesh,
839             newPoints,
840             minMagSqrEqOp<vector>(),
841             point(GREAT, GREAT, GREAT)
842         );
844         scalarField diff(mag(newPoints-mesh.points()));
845         Info<< "Points changed by average:" << gAverage(diff)
846             << " max:" << gMax(diff) << nl << endl;
848         mesh.movePoints(newPoints);
849     }
851     // 3. Remove zeros-sized patches
852     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
854     Info<< "Removing patches with no faces in them." << nl<< endl;
855     filterPatches(mesh);
858     dumpCyclicMatch("final_", mesh);
861     // Set the precision of the points data to 10
862     IOstream::defaultPrecision(10);
864     if (!overwrite)
865     {
866         runTime++;
867     }
868     else
869     {
870         mesh.setInstance(oldInstance);
871     }
873     // Write resulting mesh
874     Info<< "Writing repatched mesh to " << runTime.timeName() << nl << endl;
875     mesh.write();
877     Info<< "End\n" << endl;
879     return 0;
883 // ************************************************************************* //