1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
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
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/>.
25 Manipulate a cell/face/point/ set or zone interactively.
27 \*---------------------------------------------------------------------------*/
32 #include "globalMeshData.H"
33 #include "IStringStream.H"
37 #include "topoSetSource.H"
40 #include "demandDrivenData.H"
41 #include "writePatch.H"
42 #include "writePointSet.H"
43 #include "IOobjectList.H"
44 #include "cellZoneSet.H"
45 #include "faceZoneSet.H"
46 #include "pointZoneSet.H"
47 #include "timeSelector.H"
53 # include <readline/readline.h>
54 # include <readline/history.h>
59 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
63 static const char* historyFile = ".setSet";
67 // Write set to VTK readable files
71 const topoSet& currentSet,
72 const fileName& vtkName
75 if (isA<faceSet>(currentSet))
77 // Faces of set with OpenFOAM faceID as value
79 faceList setFaces(currentSet.size());
80 labelList faceValues(currentSet.size());
83 forAllConstIter(topoSet, currentSet, iter)
85 setFaces[setFaceI] = mesh.faces()[iter.key()];
86 faceValues[setFaceI] = iter.key();
90 primitiveFacePatch fp(setFaces, mesh.points());
99 mesh.time().path()/vtkName
102 else if (isA<cellSet>(currentSet))
104 // External faces of cellset with OpenFOAM cellID as value
106 Map<label> cellFaces(currentSet.size());
108 forAllConstIter(cellSet, currentSet, iter)
110 label cellI = iter.key();
112 const cell& cFaces = mesh.cells()[cellI];
116 label faceI = cFaces[i];
118 if (mesh.isInternalFace(faceI))
120 label otherCellI = mesh.faceOwner()[faceI];
122 if (otherCellI == cellI)
124 otherCellI = mesh.faceNeighbour()[faceI];
127 if (!currentSet.found(otherCellI))
129 cellFaces.insert(faceI, cellI);
134 cellFaces.insert(faceI, cellI);
139 faceList setFaces(cellFaces.size());
140 labelList faceValues(cellFaces.size());
143 forAllConstIter(Map<label>, cellFaces, iter)
145 setFaces[setFaceI] = mesh.faces()[iter.key()];
146 faceValues[setFaceI] = iter(); // Cell ID
150 primitiveFacePatch fp(setFaces, mesh.points());
159 mesh.time().path()/vtkName
162 else if (isA<pointSet>(currentSet))
169 mesh.time().path()/vtkName
177 "(const polyMesh& mesh, const topoSet& currentSet,"
178 "const fileName& vtkName)"
179 ) << "Don't know how to handle set of type " << currentSet.type()
185 void printHelp(Ostream& os)
187 os << "Please type 'help', 'list', 'quit', 'time ddd'"
188 << " or a set command after prompt." << endl
189 << "'list' will show all current cell/face/point sets." << endl
190 << "'time ddd' will change the current time." << endl
192 << "A set command should be of the following form" << endl
194 << " cellSet|faceSet|pointSet <setName> <action> <source>"
197 << "The <action> is one of" << endl
198 << " list - prints the contents of the set" << endl
199 << " clear - clears the set" << endl
200 << " invert - inverts the set" << endl
201 << " remove - remove the set" << endl
202 << " new <source> - sets to set to the source set" << endl
203 << " add <source> - adds all elements from the source set" << endl
204 << " delete <source> - deletes ,," << endl
205 << " subset <source> - combines current set with the source set"
208 << "The sources come in various forms. Type a wrong source"
209 << " to see all the types available." << endl
211 << "Example: pick up all cells connected by point or face to patch"
212 << " movingWall" << endl
214 << "Pick up all faces of patch:" << endl
215 << " faceSet f0 new patchToFace movingWall" << endl
216 << "Add faces 0,1,2:" << endl
217 << " faceSet f0 add labelToFace (0 1 2)" << endl
218 << "Pick up all points used by faces in faceSet f0:" << endl
219 << " pointSet p0 new faceToPoint f0 all" << endl
220 << "Pick up cell which has any face in f0:" << endl
221 << " cellSet c0 new faceToCell f0 any" << endl
222 << "Add cells which have any point in p0:" << endl
223 << " cellSet c0 add pointToCell p0 any" << endl
224 << "List set:" << endl
225 << " cellSet c0 list" << endl
227 << "Zones can be set using zoneSets from corresponding sets:" << endl
228 << " cellZoneSet c0Zone new setToCellZone c0" << endl
229 << " faceZoneSet f0Zone new setToFaceZone f0" << endl
231 << "or if orientation is important:" << endl
232 << " faceZoneSet f0Zone new setsToFaceZone f0 c0" << endl
234 << "ZoneSets can be manipulated using the general actions:" << endl
235 << " list - prints the contents of the set" << endl
236 << " clear - clears the set" << endl
237 << " invert - inverts the set (undefined orientation)"
239 << " remove - remove the set" << endl
244 void printAllSets(const polyMesh& mesh, Ostream& os)
249 mesh.time().findInstance
251 polyMesh::meshSubDir/"sets",
253 IOobject::READ_IF_PRESENT,
256 polyMesh::meshSubDir/"sets"
258 IOobjectList cellSets(objects.lookupClass(cellSet::typeName));
261 os << "cellSets:" << endl;
262 forAllConstIter(IOobjectList, cellSets, iter)
264 cellSet set(*iter());
265 os << '\t' << set.name() << "\tsize:" << set.size() << endl;
268 IOobjectList faceSets(objects.lookupClass(faceSet::typeName));
271 os << "faceSets:" << endl;
272 forAllConstIter(IOobjectList, faceSets, iter)
274 faceSet set(*iter());
275 os << '\t' << set.name() << "\tsize:" << set.size() << endl;
278 IOobjectList pointSets(objects.lookupClass(pointSet::typeName));
279 if (pointSets.size())
281 os << "pointSets:" << endl;
282 forAllConstIter(IOobjectList, pointSets, iter)
284 pointSet set(*iter());
285 os << '\t' << set.name() << "\tsize:" << set.size() << endl;
289 const cellZoneMesh& cellZones = mesh.cellZones();
290 if (cellZones.size())
292 os << "cellZones:" << endl;
295 const cellZone& zone = cellZones[i];
296 os << '\t' << zone.name() << "\tsize:" << zone.size() << endl;
299 const faceZoneMesh& faceZones = mesh.faceZones();
300 if (faceZones.size())
302 os << "faceZones:" << endl;
305 const faceZone& zone = faceZones[i];
306 os << '\t' << zone.name() << "\tsize:" << zone.size() << endl;
309 const pointZoneMesh& pointZones = mesh.pointZones();
310 if (pointZones.size())
312 os << "pointZones:" << endl;
313 forAll(pointZones, i)
315 const pointZone& zone = pointZones[i];
316 os << '\t' << zone.name() << "\tsize:" << zone.size() << endl;
324 template<class ZoneType>
327 ZoneMesh<ZoneType, polyMesh>& zones,
331 label zoneID = zones.findZoneID(setName);
335 Info<< "Removing zone " << setName << " at index " << zoneID << endl;
336 // Shuffle to last position
337 labelList oldToNew(zones.size());
343 oldToNew[i] = newI++;
346 oldToNew[zoneID] = newI;
347 zones.reorder(oldToNew);
348 // Remove last element
349 zones.setSize(zones.size()-1);
350 zones.clearAddressing();
356 // Physically remove a set
359 const polyMesh& mesh,
368 mesh.time().findInstance
370 polyMesh::meshSubDir/"sets",
372 IOobject::READ_IF_PRESENT,
375 polyMesh::meshSubDir/"sets"
378 if (objects.found(setName))
381 fileName object = objects[setName]->objectPath();
382 Info<< "Removing file " << object << endl;
387 if (setType == cellZoneSet::typeName)
391 const_cast<cellZoneMesh&>(mesh.cellZones()),
395 else if (setType == faceZoneSet::typeName)
399 const_cast<faceZoneMesh&>(mesh.faceZones()),
403 else if (setType == pointZoneSet::typeName)
407 const_cast<pointZoneMesh&>(mesh.pointZones()),
414 // Read command and execute. Return true if ok, false otherwise.
417 const polyMesh& mesh,
420 const word& actionName,
421 const bool writeVTKFile,
422 const bool writeCurrentTime,
427 // Get some size estimate for set.
428 const globalMeshData& parData = mesh.globalData();
433 parData.nTotalCells(),
436 parData.nTotalFaces(),
437 parData.nTotalPoints()
440 / (10*Pstream::nProcs());
446 autoPtr<topoSet> currentSetPtr;
452 topoSetSource::setAction action =
453 topoSetSource::toAction(actionName);
456 IOobject::readOption r;
458 if (action == topoSetSource::REMOVE)
460 removeSet(mesh, setType, setName);
464 (action == topoSetSource::NEW)
465 || (action == topoSetSource::CLEAR)
468 r = IOobject::NO_READ;
469 currentSetPtr = topoSet::New(setType, mesh, setName, typSize);
473 r = IOobject::MUST_READ;
474 currentSetPtr = topoSet::New(setType, mesh, setName, r);
475 topoSet& currentSet = currentSetPtr();
476 // Presize it according to current mesh data.
477 currentSet.resize(max(currentSet.size(), typSize));
480 if (currentSetPtr.valid())
482 topoSet& currentSet = currentSetPtr();
484 Info<< " Set:" << currentSet.name()
485 << " Size:" << returnReduce(currentSet.size(), sumOp<label>())
486 << " Action:" << actionName
491 case topoSetSource::CLEAR:
493 // Already handled above by not reading
496 case topoSetSource::INVERT:
498 currentSet.invert(currentSet.maxSize(mesh));
501 case topoSetSource::LIST:
503 currentSet.writeDebug(Pout, mesh, 100);
507 case topoSetSource::SUBSET:
509 if (is >> sourceType)
511 autoPtr<topoSetSource> setSource
521 // Backup current set.
522 autoPtr<topoSet> oldSet
528 currentSet.name() + "_old2",
534 setSource().applyToSet(topoSetSource::NEW, currentSet);
536 // Combine new value of currentSet with old one.
537 currentSet.subset(oldSet);
543 if (is >> sourceType)
545 autoPtr<topoSetSource> setSource
555 setSource().applyToSet(action, currentSet);
561 if (action != topoSetSource::LIST)
563 // Set will have been modified.
565 // Synchronize for coupled patches.
566 if (!noSync) currentSet.sync(mesh);
571 mkDir(mesh.time().path()/"VTK"/currentSet.name());
575 "VTK"/currentSet.name()/currentSet.name()
577 + name(mesh.time().timeIndex())
581 Info<< " Writing " << currentSet.name()
583 << returnReduce(currentSet.size(), sumOp<label>())
585 << currentSet.instance()/currentSet.local()
587 << " and to vtk file " << vtkName << endl << endl;
589 writeVTK(mesh, currentSet, vtkName);
593 Info<< " Writing " << currentSet.name()
595 << returnReduce(currentSet.size(), sumOp<label>())
597 << currentSet.instance()/currentSet.local()
598 /currentSet.name() << endl << endl;
601 if (writeCurrentTime)
603 currentSet.instance() = mesh.time().timeName();
609 catch (Foam::IOerror& fIOErr)
613 Pout<< fIOErr.message().c_str() << endl;
615 if (sourceType.size())
617 Pout<< topoSetSource::usage(sourceType).c_str();
620 catch (Foam::error& fErr)
624 Pout<< fErr.message().c_str() << endl;
626 if (sourceType.size())
628 Pout<< topoSetSource::usage(sourceType).c_str();
636 // Status returned from parsing the first token of the line
639 QUIT, // quit program
640 INVALID, // token is not a valid set manipulation command
641 VALIDSETCMD, // ,, is a valid ,,
642 VALIDZONECMD // ,, is a valid zone ,,
646 void printMesh(const Time& runTime, const polyMesh& mesh)
648 Info<< "Time:" << runTime.timeName()
649 << " cells:" << mesh.globalData().nTotalCells()
650 << " faces:" << mesh.globalData().nTotalFaces()
651 << " points:" << mesh.globalData().nTotalPoints()
652 << " patches:" << mesh.boundaryMesh().size()
653 << " bb:" << mesh.bounds() << nl;
657 polyMesh::readUpdateState meshReadUpdate(polyMesh& mesh)
659 polyMesh::readUpdateState stat = mesh.readUpdate();
663 case polyMesh::UNCHANGED:
665 Info<< " mesh not changed." << endl;
668 case polyMesh::POINTS_MOVED:
670 Info<< " points moved; topology unchanged." << endl;
673 case polyMesh::TOPO_CHANGE:
675 Info<< " topology changed; patches unchanged." << nl
677 printMesh(mesh.time(), mesh);
680 case polyMesh::TOPO_PATCH_CHANGE:
682 Info<< " topology changed and patches changed." << nl
684 printMesh(mesh.time(), mesh);
690 FatalErrorIn("meshReadUpdate(polyMesh&)")
691 << "Illegal mesh update state "
692 << stat << abort(FatalError);
700 commandStatus parseType
710 Info<< "Type 'help' for usage information" << endl;
714 else if (setType == "help")
720 else if (setType == "list")
722 printAllSets(mesh, Info);
726 else if (setType == "time")
728 scalar requestedTime = readScalar(is);
729 instantList Times = runTime.times();
731 label nearestIndex = Time::findClosestTimeIndex(Times, requestedTime);
733 Info<< "Changing time from " << runTime.timeName()
734 << " to " << Times[nearestIndex].name()
738 runTime.setTime(Times[nearestIndex], nearestIndex);
739 // Optionally re-read mesh
740 meshReadUpdate(mesh);
744 else if (setType == "quit")
746 Info<< "Quitting ..." << endl;
753 || setType == "faceSet"
754 || setType == "pointSet"
761 setType == "cellZoneSet"
762 || setType == "faceZoneSet"
763 || setType == "pointZoneSet"
772 "commandStatus parseType(Time&, polyMesh&, const word&"
774 ) << "Illegal command " << setType << endl
775 << "Should be one of 'help', 'list', 'time' or a set type :"
776 << " 'cellSet', 'faceSet', 'pointSet', 'faceZoneSet'"
784 commandStatus parseAction(const word& actionName)
786 commandStatus stat = INVALID;
788 if (actionName.size())
792 (void)topoSetSource::toAction(actionName);
796 catch (Foam::IOerror& fIOErr)
800 catch (Foam::error& fErr)
811 int main(int argc, char *argv[])
813 timeSelector::addOptions(true, false);
814 # include "addRegionOption.H"
815 argList::addBoolOption("noVTK", "do not write VTK files");
816 argList::addBoolOption("loop", "execute batch commands for all timesteps");
821 "process in batch mode, using input from specified file"
823 argList::addBoolOption
826 "do not synchronise selection across coupled patches"
829 # include "setRootCase.H"
830 # include "createTime.H"
831 instantList timeDirs = timeSelector::select0(runTime, args);
833 const bool writeVTK = !args.optionFound("noVTK");
834 const bool loop = args.optionFound("loop");
835 const bool batch = args.optionFound("batch");
836 const bool noSync = args.optionFound("noSync");
840 FatalErrorIn(args.executable())
841 << "Can only loop in batch mode."
846 # include "createNamedPolyMesh.H"
848 // Print some mesh info
849 printMesh(runTime, mesh);
851 // Print current sets
852 printAllSets(mesh, Info);
854 // Read history if interactive
856 if (!batch && !read_history(historyFile))
858 Info<< "Successfully read history from " << historyFile << endl;
867 forAll(timeDirs, timeI)
869 runTime.setTime(timeDirs[timeI], timeI);
870 Info<< "Time = " << runTime.timeName() << endl;
872 // Handle geometry/topology changes
873 meshReadUpdate(mesh);
876 // Main command read & execute loop
877 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
879 autoPtr<IFstream> fileStreamPtr(NULL);
883 const fileName batchFile = args["batch"];
885 Info<< "Reading commands from file " << batchFile << endl;
887 // we cannot handle .gz files
888 if (!isFile(batchFile, false))
890 FatalErrorIn(args.executable())
891 << "Cannot open file " << batchFile << exit(FatalError);
894 fileStreamPtr.reset(new IFstream(batchFile));
897 Info<< "Please type 'help', 'quit' or a set command after prompt."
903 FatalError.throwExceptions();
904 FatalIOError.throwExceptions();
910 // Type: cellSet, faceSet, pointSet
912 // Name of destination set.
914 // Action (new, invert etc.)
917 commandStatus stat = INVALID;
919 if (fileStreamPtr.valid())
921 if (!fileStreamPtr().good())
923 Info<< "End of batch file" << endl;
928 fileStreamPtr().getLine(rawLine);
932 Info<< "Doing:" << rawLine << endl;
939 char* linePtr = readline("readline>");
943 rawLine = string(linePtr);
947 add_history(linePtr);
948 write_history(historyFile);
951 free(linePtr); // readline uses malloc, not new.
960 if (!std::cin.good())
962 Info<< "End of cin" << endl;
966 Info<< "Command>" << flush;
967 std::getline(std::cin, rawLine);
972 // Strip off anything after #
973 string::size_type i = rawLine.find_first_of("#");
974 if (i != string::npos)
976 rawLine = rawLine(0, i);
984 IStringStream is(rawLine + ' ');
986 // Type: cellSet, faceSet, pointSet, faceZoneSet
989 stat = parseType(runTime, mesh, setType, is);
991 if (stat == VALIDSETCMD || stat == VALIDZONECMD)
995 if (is >> actionName)
997 stat = parseAction(actionName);
1004 // Make sure to quit
1007 else if (stat == VALIDSETCMD || stat == VALIDZONECMD)
1016 loop, // if in looping mode dump sets to time directory
1037 Info<< "\nEnd\n" << endl;
1043 // ************************************************************************* //