mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: add dictionary-driven multi-pass stitchMesh facility
- the dictionary-driven variant of stitchMesh allows sequential
application of 'stitch' operation with requiring intermediate
writing to disk.
- Without arguments:
* stitchMesh uses a system/stitchMeshDict or -dict dict
- With arguments:
* master/slave patches specified on the command-line as in previous
versions.
This commit is contained in:
@ -66,34 +66,35 @@ Description
|
|||||||
#include "fvCFD.H"
|
#include "fvCFD.H"
|
||||||
#include "polyTopoChanger.H"
|
#include "polyTopoChanger.H"
|
||||||
#include "mapPolyMesh.H"
|
#include "mapPolyMesh.H"
|
||||||
#include "ListOps.H"
|
|
||||||
#include "slidingInterface.H"
|
#include "slidingInterface.H"
|
||||||
#include "perfectInterface.H"
|
#include "perfectInterface.H"
|
||||||
#include "IOobjectList.H"
|
#include "IOobjectList.H"
|
||||||
#include "ReadFields.H"
|
#include "ReadFields.H"
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
// Checks whether patch present
|
// Checks whether patch present and non-zero
|
||||||
void checkPatch(const polyBoundaryMesh& bMesh, const word& name)
|
bool checkPatch(const polyBoundaryMesh& bMesh, const word& name)
|
||||||
{
|
{
|
||||||
const label patchi = bMesh.findPatchID(name);
|
const label patchi = bMesh.findPatchID(name);
|
||||||
|
|
||||||
if (patchi == -1)
|
if (patchi == -1)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
Info<< "No patch " << name << " in mesh" << nl
|
||||||
<< "Cannot find patch " << name << endl
|
<< "Known patches: " << bMesh.names() << endl;
|
||||||
<< "It should be present and of non-zero size" << endl
|
|
||||||
<< "Valid patches are " << bMesh.names()
|
return false;
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bMesh[patchi].empty())
|
if (bMesh[patchi].empty())
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
Info<< "Patch " << name << " has zero size" << nl;
|
||||||
<< "Patch " << name << " is present but zero size"
|
|
||||||
<< exit(FatalError);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -101,28 +102,38 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
argList::addNote
|
argList::addNote
|
||||||
(
|
(
|
||||||
"Merge the faces on the specified patches (if geometrically possible)\n"
|
"Merge the faces on specified patches (if geometrically possible)"
|
||||||
"so the faces become internal.\n"
|
" so that the\n"
|
||||||
"Integral matching is used when the options -partial and -perfect are "
|
"faces become internal.\n"
|
||||||
"omitted.\n"
|
"This utility can be called without arguments (uses stitchMeshDict)"
|
||||||
|
" or with\n"
|
||||||
|
"two arguments (master/slave patch names)."
|
||||||
);
|
);
|
||||||
|
|
||||||
argList::noParallel();
|
argList::noParallel();
|
||||||
#include "addOverwriteOption.H"
|
#include "addOverwriteOption.H"
|
||||||
#include "addRegionOption.H"
|
#include "addRegionOption.H"
|
||||||
|
#include "addDictOption.H"
|
||||||
argList::validArgs.append("masterPatch");
|
|
||||||
argList::validArgs.append("slavePatch");
|
|
||||||
|
|
||||||
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"integral",
|
||||||
|
"couple integral master/slave patches (2 argument mode: default)"
|
||||||
|
);
|
||||||
argList::addBoolOption
|
argList::addBoolOption
|
||||||
(
|
(
|
||||||
"partial",
|
"partial",
|
||||||
"couple partially overlapping patches (optional)"
|
"couple partially overlapping master/slave patches (2 argument mode)"
|
||||||
);
|
);
|
||||||
argList::addBoolOption
|
argList::addBoolOption
|
||||||
(
|
(
|
||||||
"perfect",
|
"perfect",
|
||||||
"couple perfectly aligned patches (optional)"
|
"couple perfectly aligned master/slave patches (2 argument mode)"
|
||||||
|
);
|
||||||
|
argList::addBoolOption
|
||||||
|
(
|
||||||
|
"intermediate",
|
||||||
|
"write intermediate stages, not just the final result"
|
||||||
);
|
);
|
||||||
argList::addOption
|
argList::addOption
|
||||||
(
|
(
|
||||||
@ -131,69 +142,239 @@ int main(int argc, char *argv[])
|
|||||||
"dictionary file with tolerances"
|
"dictionary file with tolerances"
|
||||||
);
|
);
|
||||||
|
|
||||||
#include "setRootCase.H"
|
// The arguments are non-mandatory when using dictionary mode
|
||||||
|
argList::validArgs.append("masterPatch");
|
||||||
|
argList::validArgs.append("slavePatch");
|
||||||
|
|
||||||
|
#include "setRootCaseNonMandatoryArgs.H"
|
||||||
|
|
||||||
|
// We now handle checking args and general sanity etc.
|
||||||
|
const bool useCommandArgs = (args.size() > 1);
|
||||||
|
|
||||||
|
if (useCommandArgs)
|
||||||
|
{
|
||||||
|
if (args.optionFound("dict"))
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Cannot specify both dictionary and command-line arguments"
|
||||||
|
<< nl
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have arguments - we require all arguments!
|
||||||
|
if (!args.check(true, false))
|
||||||
|
{
|
||||||
|
FatalError.exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Carp about inapplicable options
|
||||||
|
|
||||||
|
if (args.optionFound("integral"))
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Only specify -integral with command-line arguments"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.optionFound("partial"))
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Only specify -partial with command-line arguments"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.optionFound("perfect"))
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Only specify -perfect with command-line arguments"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#include "createTime.H"
|
#include "createTime.H"
|
||||||
runTime.functionObjects().off();
|
runTime.functionObjects().off();
|
||||||
#include "createNamedMesh.H"
|
#include "createNamedMesh.H"
|
||||||
|
|
||||||
const word oldInstance = mesh.pointsInstance();
|
const word oldInstance = mesh.pointsInstance();
|
||||||
|
|
||||||
const word masterPatchName = args[1];
|
const bool intermediate = args.optionFound("intermediate");
|
||||||
const word slavePatchName = args[2];
|
const bool overwrite = args.optionFound("overwrite");
|
||||||
|
|
||||||
const bool partialCover = args.optionFound("partial");
|
const word dictName("stitchMeshDict");
|
||||||
const bool perfectCover = args.optionFound("perfect");
|
|
||||||
const bool overwrite = args.optionFound("overwrite");
|
|
||||||
|
|
||||||
if (partialCover && perfectCover)
|
// A validated input dictionary
|
||||||
|
dictionary validatedDict;
|
||||||
|
|
||||||
|
if (useCommandArgs)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
// Command argument driven:
|
||||||
<< "Cannot supply both partial and perfect." << endl
|
const int integralCover = args.optionFound("integral");
|
||||||
<< "Use perfect match option if the patches perfectly align"
|
const int partialCover = args.optionFound("partial");
|
||||||
<< " (both vertex positions and face centres)" << endl
|
const int perfectCover = args.optionFound("perfect");
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if ((integralCover + partialCover + perfectCover) > 1)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Can only specify one of -integral | -partial | -perfect."
|
||||||
|
<< nl
|
||||||
|
<< "Use perfect match option if the patches perfectly align"
|
||||||
|
<< " (both vertex positions and face centres)" << endl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
const word mergePatchName(masterPatchName + slavePatchName);
|
// Patch names
|
||||||
const word cutZoneName(mergePatchName + "CutFaceZone");
|
const word masterPatchName(args[1]);
|
||||||
|
const word slavePatchName(args[2]);
|
||||||
|
|
||||||
slidingInterface::typeOfMatch tom = slidingInterface::INTEGRAL;
|
// Patch names
|
||||||
|
Info<< " " << masterPatchName
|
||||||
|
<< " / " << slavePatchName << nl;
|
||||||
|
|
||||||
if (partialCover)
|
// Bail out if either patch has problems
|
||||||
{
|
if
|
||||||
Info<< "Coupling partially overlapping patches "
|
(
|
||||||
<< masterPatchName << " and " << slavePatchName << nl
|
!checkPatch(mesh.boundaryMesh(), masterPatchName)
|
||||||
<< "Resulting internal faces will be in faceZone " << cutZoneName
|
|| !checkPatch(mesh.boundaryMesh(), slavePatchName)
|
||||||
<< nl
|
)
|
||||||
<< "Any uncovered faces will remain in their patch"
|
{
|
||||||
<< endl;
|
FatalErrorInFunction
|
||||||
|
<< "Cannot continue"
|
||||||
|
<< exit(FatalError);
|
||||||
|
|
||||||
tom = slidingInterface::PARTIAL;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (perfectCover)
|
|
||||||
{
|
// Input was validated
|
||||||
Info<< "Coupling perfectly aligned patches "
|
dictionary dict;
|
||||||
<< masterPatchName << " and " << slavePatchName << nl
|
|
||||||
<< "Resulting (internal) faces will be in faceZone " << cutZoneName
|
if (perfectCover)
|
||||||
<< nl << nl
|
{
|
||||||
<< "Note: both patches need to align perfectly." << nl
|
dict.add("match", word("perfect"));
|
||||||
<< "Both the vertex"
|
}
|
||||||
<< " positions and the face centres need to align to within" << nl
|
else if (partialCover)
|
||||||
<< "a tolerance given by the minimum edge length on the patch"
|
{
|
||||||
<< endl;
|
dict.add
|
||||||
|
(
|
||||||
|
"match",
|
||||||
|
slidingInterface::typeOfMatchNames[slidingInterface::PARTIAL]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dict.add
|
||||||
|
(
|
||||||
|
"match",
|
||||||
|
slidingInterface::typeOfMatchNames[slidingInterface::INTEGRAL]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch names
|
||||||
|
dict.add("master", masterPatchName);
|
||||||
|
dict.add("slave", slavePatchName);
|
||||||
|
|
||||||
|
validatedDict.add("stitchMesh", dict);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Info<< "Coupling patches " << masterPatchName << " and "
|
// dictionary-driven:
|
||||||
<< slavePatchName << nl
|
|
||||||
<< "Resulting (internal) faces will be in faceZone " << cutZoneName
|
#include "setSystemRunTimeDictionaryIO.H"
|
||||||
<< nl << nl
|
|
||||||
<< "Note: the overall area covered by both patches should be"
|
Info<< "Reading " << dictName;
|
||||||
<< " identical (\"integral\" interface)." << endl
|
|
||||||
<< "If this is not the case use the -partial option" << nl << endl;
|
IOdictionary stitchDict(dictIO);
|
||||||
|
|
||||||
|
Info<< " with " << stitchDict.size() << " entries" << nl;
|
||||||
|
|
||||||
|
// Suppress duplicate names
|
||||||
|
wordHashSet requestedPatches;
|
||||||
|
|
||||||
|
forAllConstIters(stitchDict, iter)
|
||||||
|
{
|
||||||
|
if (!iter().isDict())
|
||||||
|
{
|
||||||
|
Info<< "Ignoring non-dictionary entry: "
|
||||||
|
<< iter().keyword() << nl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dictionary& dict = iter().dict();
|
||||||
|
|
||||||
|
// Match type
|
||||||
|
word matchName;
|
||||||
|
if (dict.readIfPresent("match", matchName))
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
matchName != "perfect"
|
||||||
|
&& !slidingInterface::typeOfMatchNames.hasEnum(matchName)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< "Error: unknown match type - " << matchName
|
||||||
|
<< " should be one of "
|
||||||
|
<< slidingInterface::typeOfMatchNames.toc() << nl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch names
|
||||||
|
const word masterPatchName(dict["master"]);
|
||||||
|
const word slavePatchName(dict["slave"]);
|
||||||
|
|
||||||
|
// Patch names
|
||||||
|
Info<< " " << masterPatchName
|
||||||
|
<< " / " << slavePatchName << nl;
|
||||||
|
|
||||||
|
if (!requestedPatches.insert(masterPatchName))
|
||||||
|
{
|
||||||
|
Info<< "Error: patch specified multiple times - "
|
||||||
|
<< masterPatchName << nl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestedPatches.insert(slavePatchName))
|
||||||
|
{
|
||||||
|
Info<< "Error: patch specified multiple times - "
|
||||||
|
<< slavePatchName << nl;
|
||||||
|
|
||||||
|
requestedPatches.erase(masterPatchName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bail out if either patch has problems
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!checkPatch(mesh.boundaryMesh(), masterPatchName)
|
||||||
|
|| !checkPatch(mesh.boundaryMesh(), slavePatchName)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
requestedPatches.erase(masterPatchName);
|
||||||
|
requestedPatches.erase(slavePatchName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input was validated
|
||||||
|
|
||||||
|
validatedDict.add(iter().keyword(), iter().dict());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const label nActions = validatedDict.size();
|
||||||
|
|
||||||
|
Info<< nl << nActions << " validated actions" << endl;
|
||||||
|
|
||||||
|
if (!nActions)
|
||||||
|
{
|
||||||
|
Info<<"\nStopping" << nl << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// This is where the real work begins
|
||||||
|
|
||||||
// set up the tolerances for the sliding mesh
|
// set up the tolerances for the sliding mesh
|
||||||
dictionary slidingTolerances;
|
dictionary slidingTolerances;
|
||||||
if (args.optionFound("toleranceDict"))
|
if (args.optionFound("toleranceDict"))
|
||||||
@ -212,120 +393,6 @@ int main(int argc, char *argv[])
|
|||||||
slidingTolerances += toleranceFile;
|
slidingTolerances += toleranceFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for non-empty master and slave patches
|
|
||||||
checkPatch(mesh.boundaryMesh(), masterPatchName);
|
|
||||||
checkPatch(mesh.boundaryMesh(), slavePatchName);
|
|
||||||
|
|
||||||
// Create and add face zones and mesh modifiers
|
|
||||||
|
|
||||||
// Master patch
|
|
||||||
const polyPatch& masterPatch = mesh.boundaryMesh()[masterPatchName];
|
|
||||||
|
|
||||||
// Make list of masterPatch faces
|
|
||||||
labelList isf(masterPatch.size());
|
|
||||||
|
|
||||||
forAll(isf, i)
|
|
||||||
{
|
|
||||||
isf[i] = masterPatch.start() + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
polyTopoChanger stitcher(mesh, IOobject::NO_READ);
|
|
||||||
stitcher.clear();
|
|
||||||
stitcher.setSize(1);
|
|
||||||
|
|
||||||
mesh.pointZones().clearAddressing();
|
|
||||||
mesh.faceZones().clearAddressing();
|
|
||||||
mesh.cellZones().clearAddressing();
|
|
||||||
|
|
||||||
if (perfectCover)
|
|
||||||
{
|
|
||||||
// Starts as master zone, but receives the resulting internal faces
|
|
||||||
mesh.faceZones()
|
|
||||||
(
|
|
||||||
cutZoneName,
|
|
||||||
true // verbose
|
|
||||||
).resetAddressing(isf.xfer(), false);
|
|
||||||
|
|
||||||
// Add the perfect interface mesh modifier
|
|
||||||
stitcher.set
|
|
||||||
(
|
|
||||||
0,
|
|
||||||
new perfectInterface
|
|
||||||
(
|
|
||||||
"couple",
|
|
||||||
0,
|
|
||||||
stitcher,
|
|
||||||
cutZoneName,
|
|
||||||
masterPatchName,
|
|
||||||
slavePatchName
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// An empty point zone
|
|
||||||
mesh.pointZones()
|
|
||||||
(
|
|
||||||
mergePatchName + "CutPointZone",
|
|
||||||
true // verbose
|
|
||||||
) = labelList();
|
|
||||||
|
|
||||||
// The master zone
|
|
||||||
mesh.faceZones()
|
|
||||||
(
|
|
||||||
mergePatchName + "MasterZone",
|
|
||||||
true // verbose
|
|
||||||
).resetAddressing(isf.xfer(), false);
|
|
||||||
|
|
||||||
// Slave patch
|
|
||||||
const polyPatch& slavePatch = mesh.boundaryMesh()[slavePatchName];
|
|
||||||
|
|
||||||
labelList osf(slavePatch.size());
|
|
||||||
|
|
||||||
forAll(osf, i)
|
|
||||||
{
|
|
||||||
osf[i] = slavePatch.start() + i;
|
|
||||||
}
|
|
||||||
|
|
||||||
mesh.faceZones()
|
|
||||||
(
|
|
||||||
mergePatchName + "SlaveZone",
|
|
||||||
true // verbose
|
|
||||||
).resetAddressing(osf.xfer(), false);
|
|
||||||
|
|
||||||
// An empty zone for cut faces
|
|
||||||
mesh.faceZones()
|
|
||||||
(
|
|
||||||
cutZoneName,
|
|
||||||
true // verbose
|
|
||||||
).resetAddressing(labelList(), false);
|
|
||||||
|
|
||||||
|
|
||||||
// Add the sliding interface mesh modifier
|
|
||||||
stitcher.set
|
|
||||||
(
|
|
||||||
0,
|
|
||||||
new slidingInterface
|
|
||||||
(
|
|
||||||
"couple",
|
|
||||||
0,
|
|
||||||
stitcher,
|
|
||||||
mergePatchName + "MasterZone",
|
|
||||||
mergePatchName + "SlaveZone",
|
|
||||||
mergePatchName + "CutPointZone",
|
|
||||||
cutZoneName,
|
|
||||||
masterPatchName,
|
|
||||||
slavePatchName,
|
|
||||||
tom, // integral or partial
|
|
||||||
true // couple/decouple mode
|
|
||||||
)
|
|
||||||
);
|
|
||||||
static_cast<slidingInterface&>(stitcher[0]).setTolerances
|
|
||||||
(
|
|
||||||
slidingTolerances,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for list of objects for this time
|
// Search for list of objects for this time
|
||||||
IOobjectList objects(mesh, runTime.timeName());
|
IOobjectList objects(mesh, runTime.timeName());
|
||||||
@ -358,51 +425,231 @@ int main(int argc, char *argv[])
|
|||||||
//PtrList<surfaceTensorField> surfaceTensorFields;
|
//PtrList<surfaceTensorField> surfaceTensorFields;
|
||||||
//ReadFields(mesh, objects, surfaceTensorFields);
|
//ReadFields(mesh, objects, surfaceTensorFields);
|
||||||
|
|
||||||
if (!overwrite)
|
// Increase precision for output mesh points
|
||||||
{
|
|
||||||
runTime++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute all polyMeshModifiers
|
|
||||||
autoPtr<mapPolyMesh> morphMap = stitcher.changeMesh(true);
|
|
||||||
|
|
||||||
mesh.movePoints(morphMap->preMotionPoints());
|
|
||||||
|
|
||||||
// Write mesh
|
|
||||||
if (overwrite)
|
|
||||||
{
|
|
||||||
mesh.setInstance(oldInstance);
|
|
||||||
stitcher.instance() = oldInstance;
|
|
||||||
}
|
|
||||||
Info<< nl << "Writing polyMesh to time " << runTime.timeName() << endl;
|
|
||||||
|
|
||||||
IOstream::defaultPrecision(max(10u, IOstream::defaultPrecision()));
|
IOstream::defaultPrecision(max(10u, IOstream::defaultPrecision()));
|
||||||
|
|
||||||
// Bypass runTime write (since only writes at writeTime)
|
polyTopoChanger stitcher(mesh, IOobject::NO_READ);
|
||||||
if
|
|
||||||
(
|
// Step through the topology changes
|
||||||
!runTime.objectRegistry::writeObject
|
label actioni = 0;
|
||||||
(
|
forAllConstIters(validatedDict, iter)
|
||||||
runTime.writeFormat(),
|
|
||||||
IOstream::currentVersion,
|
|
||||||
runTime.writeCompression(),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
const dictionary& dict = iter().dict();
|
||||||
<< "Failed writing polyMesh."
|
|
||||||
<< exit(FatalError);
|
// Match type
|
||||||
|
bool perfect = false;
|
||||||
|
slidingInterface::typeOfMatch matchType = slidingInterface::PARTIAL;
|
||||||
|
|
||||||
|
word matchName;
|
||||||
|
if (dict.readIfPresent("match", matchName))
|
||||||
|
{
|
||||||
|
if (matchName == "perfect")
|
||||||
|
{
|
||||||
|
perfect = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matchType = slidingInterface::typeOfMatchNames[matchName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch names
|
||||||
|
const word masterPatchName(dict["master"]);
|
||||||
|
const word slavePatchName(dict["slave"]);
|
||||||
|
|
||||||
|
// Zone names
|
||||||
|
const word mergePatchName(masterPatchName + slavePatchName);
|
||||||
|
const word cutZoneName(mergePatchName + "CutFaceZone");
|
||||||
|
|
||||||
|
Info<< nl << "========================================" << nl;
|
||||||
|
|
||||||
|
// Information messages
|
||||||
|
if (perfect)
|
||||||
|
{
|
||||||
|
Info<< "Coupling PERFECTLY aligned patches "
|
||||||
|
<< masterPatchName << " / " << slavePatchName << nl << nl
|
||||||
|
<< "Resulting (internal) faces in faceZone "
|
||||||
|
<< cutZoneName << nl << nl
|
||||||
|
<< "The patch vertices and face centres must align within a"
|
||||||
|
<< " tolerance relative to the minimum edge length on the patch"
|
||||||
|
<< nl << endl;
|
||||||
|
}
|
||||||
|
else if (matchType == slidingInterface::INTEGRAL)
|
||||||
|
{
|
||||||
|
Info<< "Coupling INTEGRALLY matching of patches "
|
||||||
|
<< masterPatchName << " / " << slavePatchName << nl << nl
|
||||||
|
<< "Resulting (internal) faces in faceZone "
|
||||||
|
<< cutZoneName << nl << nl
|
||||||
|
<< "The overall area covered by both patches should be"
|
||||||
|
<< " identical!" << endl
|
||||||
|
<< "If this is not the case use partial"
|
||||||
|
<< nl << endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< "Coupling PARTIALLY overlapping patches "
|
||||||
|
<< masterPatchName << " / " << slavePatchName << nl
|
||||||
|
<< "Resulting internal faces in faceZone "
|
||||||
|
<< cutZoneName << nl
|
||||||
|
<< "Uncovered faces remain in their patch"
|
||||||
|
<< nl << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Master/slave patches
|
||||||
|
const polyPatch& masterPatch = mesh.boundaryMesh()[masterPatchName];
|
||||||
|
const polyPatch& slavePatch = mesh.boundaryMesh()[slavePatchName];
|
||||||
|
|
||||||
|
mesh.pointZones().clearAddressing();
|
||||||
|
mesh.faceZones().clearAddressing();
|
||||||
|
mesh.cellZones().clearAddressing();
|
||||||
|
|
||||||
|
// Lists of master and slave faces:
|
||||||
|
labelList faceIds;
|
||||||
|
|
||||||
|
// Markup master face ids
|
||||||
|
faceIds.setSize(masterPatch.size());
|
||||||
|
std::iota(faceIds.begin(), faceIds.end(), masterPatch.start());
|
||||||
|
|
||||||
|
stitcher.clear();
|
||||||
|
stitcher.setSize(1);
|
||||||
|
|
||||||
|
if (perfect)
|
||||||
|
{
|
||||||
|
// Add new (empty) zone for resulting internal faces
|
||||||
|
mesh.faceZones()
|
||||||
|
(
|
||||||
|
cutZoneName,
|
||||||
|
true // verbose
|
||||||
|
).resetAddressing(faceIds.xfer(), false);
|
||||||
|
|
||||||
|
|
||||||
|
// Add the perfect interface mesh modifier
|
||||||
|
stitcher.set
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
new perfectInterface
|
||||||
|
(
|
||||||
|
"couple" + Foam::name(actioni),
|
||||||
|
0,
|
||||||
|
stitcher,
|
||||||
|
cutZoneName,
|
||||||
|
masterPatchName,
|
||||||
|
slavePatchName
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mesh.pointZones()
|
||||||
|
(
|
||||||
|
mergePatchName + "CutPointZone",
|
||||||
|
true // verbose
|
||||||
|
) = labelList();
|
||||||
|
|
||||||
|
mesh.faceZones()
|
||||||
|
(
|
||||||
|
mergePatchName + "MasterZone",
|
||||||
|
true // verbose
|
||||||
|
).resetAddressing(faceIds.xfer(), false);
|
||||||
|
|
||||||
|
// Markup slave face ids
|
||||||
|
faceIds.setSize(slavePatch.size());
|
||||||
|
std::iota(faceIds.begin(), faceIds.end(), slavePatch.start());
|
||||||
|
|
||||||
|
mesh.faceZones()
|
||||||
|
(
|
||||||
|
mergePatchName + "SlaveZone",
|
||||||
|
true // verbose
|
||||||
|
).resetAddressing(faceIds.xfer(), false);
|
||||||
|
|
||||||
|
// Add empty zone for cut faces
|
||||||
|
mesh.faceZones()
|
||||||
|
(
|
||||||
|
cutZoneName,
|
||||||
|
true // verbose
|
||||||
|
).resetAddressing(labelList(), false);
|
||||||
|
|
||||||
|
|
||||||
|
// Add the sliding interface mesh modifier
|
||||||
|
stitcher.set
|
||||||
|
(
|
||||||
|
0,
|
||||||
|
new slidingInterface
|
||||||
|
(
|
||||||
|
"couple" + Foam::name(actioni),
|
||||||
|
0,
|
||||||
|
stitcher,
|
||||||
|
mergePatchName + "MasterZone",
|
||||||
|
mergePatchName + "SlaveZone",
|
||||||
|
mergePatchName + "CutPointZone",
|
||||||
|
cutZoneName,
|
||||||
|
masterPatchName,
|
||||||
|
slavePatchName,
|
||||||
|
matchType, // integral or partial
|
||||||
|
true // couple/decouple mode
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
static_cast<slidingInterface&>(stitcher[0]).setTolerances
|
||||||
|
(
|
||||||
|
slidingTolerances,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
++actioni;
|
||||||
|
|
||||||
|
// Advance time for intermediate results or only on final
|
||||||
|
if (!overwrite && (intermediate || actioni == nActions))
|
||||||
|
{
|
||||||
|
runTime++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute all polyMeshModifiers
|
||||||
|
autoPtr<mapPolyMesh> morphMap = stitcher.changeMesh(true);
|
||||||
|
|
||||||
|
mesh.movePoints(morphMap->preMotionPoints());
|
||||||
|
|
||||||
|
// Write mesh
|
||||||
|
if (overwrite)
|
||||||
|
{
|
||||||
|
mesh.setInstance(oldInstance);
|
||||||
|
stitcher.instance() = oldInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intermediate || actioni == nActions)
|
||||||
|
{
|
||||||
|
Info<< nl << "Writing polyMesh to time "
|
||||||
|
<< runTime.timeName() << endl;
|
||||||
|
|
||||||
|
// Bypass runTime write (since only writes at writeTime)
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!runTime.objectRegistry::writeObject
|
||||||
|
(
|
||||||
|
runTime.writeFormat(),
|
||||||
|
IOstream::currentVersion,
|
||||||
|
runTime.writeCompression(),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Failed writing polyMesh."
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.faceZones().write();
|
||||||
|
mesh.pointZones().write();
|
||||||
|
mesh.cellZones().write();
|
||||||
|
|
||||||
|
// Write fields
|
||||||
|
runTime.write();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.faceZones().write();
|
Info<< "\nEnd\n" << endl;
|
||||||
mesh.pointZones().write();
|
|
||||||
mesh.cellZones().write();
|
|
||||||
|
|
||||||
// Write fields
|
|
||||||
runTime.write();
|
|
||||||
|
|
||||||
Info<< nl << "End" << nl << endl;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
| ========= | |
|
||||||
|
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||||
|
| \\ / O peration | Version: plus |
|
||||||
|
| \\ / A nd | Web: www.OpenFOAM.com |
|
||||||
|
| \\/ M anipulation | |
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
FoamFile
|
||||||
|
{
|
||||||
|
version 2.0;
|
||||||
|
format ascii;
|
||||||
|
class dictionary;
|
||||||
|
object stitchMeshDict;
|
||||||
|
}
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
outerx
|
||||||
|
{
|
||||||
|
match partial; // partial | integral | perfect
|
||||||
|
master outerx;
|
||||||
|
slave innerx;
|
||||||
|
}
|
||||||
|
|
||||||
|
outery
|
||||||
|
{
|
||||||
|
match partial;
|
||||||
|
master outery;
|
||||||
|
slave innery;
|
||||||
|
}
|
||||||
|
|
||||||
|
outerz
|
||||||
|
{
|
||||||
|
match partial;
|
||||||
|
master outerz;
|
||||||
|
slave innerz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -79,7 +79,6 @@ Foam::pointField Foam::perfectInterface::calcFaceCentres
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
// Construct from components
|
|
||||||
Foam::perfectInterface::perfectInterface
|
Foam::perfectInterface::perfectInterface
|
||||||
(
|
(
|
||||||
const word& name,
|
const word& name,
|
||||||
@ -97,7 +96,6 @@ Foam::perfectInterface::perfectInterface
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
// Construct from dictionary
|
|
||||||
Foam::perfectInterface::perfectInterface
|
Foam::perfectInterface::perfectInterface
|
||||||
(
|
(
|
||||||
const word& name,
|
const word& name,
|
||||||
|
|||||||
@ -45,6 +45,7 @@ namespace Foam
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
Foam::setUpdater::setUpdater
|
Foam::setUpdater::setUpdater
|
||||||
|
|||||||
@ -52,7 +52,7 @@ const Foam::Enum
|
|||||||
<
|
<
|
||||||
Foam::slidingInterface::typeOfMatch
|
Foam::slidingInterface::typeOfMatch
|
||||||
>
|
>
|
||||||
Foam::slidingInterface::typeOfMatchNames_
|
Foam::slidingInterface::typeOfMatchNames
|
||||||
{
|
{
|
||||||
{ typeOfMatch::INTEGRAL, "integral" },
|
{ typeOfMatch::INTEGRAL, "integral" },
|
||||||
{ typeOfMatch::PARTIAL, "partial" },
|
{ typeOfMatch::PARTIAL, "partial" },
|
||||||
@ -112,8 +112,6 @@ void Foam::slidingInterface::clearOut() const
|
|||||||
|
|
||||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
|
||||||
// Construct from components
|
|
||||||
Foam::slidingInterface::slidingInterface
|
Foam::slidingInterface::slidingInterface
|
||||||
(
|
(
|
||||||
const word& name,
|
const word& name,
|
||||||
@ -204,7 +202,6 @@ Foam::slidingInterface::slidingInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Construct from components
|
|
||||||
Foam::slidingInterface::slidingInterface
|
Foam::slidingInterface::slidingInterface
|
||||||
(
|
(
|
||||||
const word& name,
|
const word& name,
|
||||||
@ -244,7 +241,7 @@ Foam::slidingInterface::slidingInterface
|
|||||||
dict.lookup("slavePatchName"),
|
dict.lookup("slavePatchName"),
|
||||||
mme.mesh().boundaryMesh()
|
mme.mesh().boundaryMesh()
|
||||||
),
|
),
|
||||||
matchType_(typeOfMatchNames_.lookup("typeOfMatch", dict)),
|
matchType_(typeOfMatchNames.lookup("typeOfMatch", dict)),
|
||||||
coupleDecouple_(dict.lookup("coupleDecouple")),
|
coupleDecouple_(dict.lookup("coupleDecouple")),
|
||||||
attached_(dict.lookup("attached")),
|
attached_(dict.lookup("attached")),
|
||||||
projectionAlgo_
|
projectionAlgo_
|
||||||
@ -749,7 +746,7 @@ void Foam::slidingInterface::write(Ostream& os) const
|
|||||||
<< cutFaceZoneID_.name() << nl
|
<< cutFaceZoneID_.name() << nl
|
||||||
<< masterPatchID_.name() << nl
|
<< masterPatchID_.name() << nl
|
||||||
<< slavePatchID_.name() << nl
|
<< slavePatchID_.name() << nl
|
||||||
<< typeOfMatchNames_[matchType_] << nl
|
<< typeOfMatchNames[matchType_] << nl
|
||||||
<< coupleDecouple_ << nl
|
<< coupleDecouple_ << nl
|
||||||
<< attached_ << endl;
|
<< attached_ << endl;
|
||||||
}
|
}
|
||||||
@ -776,7 +773,7 @@ void Foam::slidingInterface::writeDict(Ostream& os) const
|
|||||||
os.writeEntry("cutFaceZoneName", cutFaceZoneID_.name());
|
os.writeEntry("cutFaceZoneName", cutFaceZoneID_.name());
|
||||||
os.writeEntry("masterPatchName", masterPatchID_.name());
|
os.writeEntry("masterPatchName", masterPatchID_.name());
|
||||||
os.writeEntry("slavePatchName", slavePatchID_.name());
|
os.writeEntry("slavePatchName", slavePatchID_.name());
|
||||||
os.writeEntry("typeOfMatch", typeOfMatchNames_[matchType_]);
|
os.writeEntry("typeOfMatch", typeOfMatchNames[matchType_]);
|
||||||
os.writeEntry("coupleDecouple", coupleDecouple_);
|
os.writeEntry("coupleDecouple", coupleDecouple_);
|
||||||
os.writeEntry("projection", intersection::algorithmNames_[projectionAlgo_]);
|
os.writeEntry("projection", intersection::algorithmNames_[projectionAlgo_]);
|
||||||
os.writeEntry("attached", attached_);
|
os.writeEntry("attached", attached_);
|
||||||
|
|||||||
@ -84,8 +84,8 @@ public:
|
|||||||
PARTIAL
|
PARTIAL
|
||||||
};
|
};
|
||||||
|
|
||||||
//- Direction names
|
//- Names for the types of matches
|
||||||
static const Enum<typeOfMatch> typeOfMatchNames_;
|
static const Enum<typeOfMatch> typeOfMatchNames;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,11 @@ cd ${0%/*} || exit 1 # Run from this directory
|
|||||||
|
|
||||||
runApplication ./Allmesh
|
runApplication ./Allmesh
|
||||||
|
|
||||||
for dir in x y z
|
# Use stitchMesh with dictionary
|
||||||
do
|
|
||||||
runApplication -s dir-$dir stitchMesh -partial outer$dir inner$dir
|
# runApplication stitchMesh -intermediate
|
||||||
done
|
runApplication stitchMesh -overwrite
|
||||||
|
|
||||||
|
runApplication checkMesh
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
15
tutorials/mesh/stitchMesh/simple-cube1/Allrun-args
Executable file
15
tutorials/mesh/stitchMesh/simple-cube1/Allrun-args
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd ${0%/*} || exit 1 # Run from this directory
|
||||||
|
. $WM_PROJECT_DIR/bin/tools/RunFunctions # Tutorial run functions
|
||||||
|
|
||||||
|
runApplication ./Allmesh
|
||||||
|
|
||||||
|
# Use stitchMesh with command arguments (no dictionary)
|
||||||
|
for dir in x y z
|
||||||
|
do
|
||||||
|
runApplication -s dir-$dir stitchMesh -partial outer$dir inner$dir
|
||||||
|
done
|
||||||
|
|
||||||
|
runApplication checkMesh
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
38
tutorials/mesh/stitchMesh/simple-cube1/system/stitchMeshDict
Normal file
38
tutorials/mesh/stitchMesh/simple-cube1/system/stitchMeshDict
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
| ========= | |
|
||||||
|
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||||
|
| \\ / O peration | Version: plus |
|
||||||
|
| \\ / A nd | Web: www.OpenFOAM.com |
|
||||||
|
| \\/ M anipulation | |
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
FoamFile
|
||||||
|
{
|
||||||
|
version 2.0;
|
||||||
|
format ascii;
|
||||||
|
class dictionary;
|
||||||
|
object stitchMeshDict;
|
||||||
|
}
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
outerx
|
||||||
|
{
|
||||||
|
match partial; // partial | integral | perfect
|
||||||
|
master outerx;
|
||||||
|
slave innerx;
|
||||||
|
}
|
||||||
|
|
||||||
|
outery
|
||||||
|
{
|
||||||
|
match partial;
|
||||||
|
master outery;
|
||||||
|
slave innery;
|
||||||
|
}
|
||||||
|
|
||||||
|
outerz
|
||||||
|
{
|
||||||
|
match partial;
|
||||||
|
master outerz;
|
||||||
|
slave innerz;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user