diff --git a/src/finiteVolume/Make/files b/src/finiteVolume/Make/files index c719265186cbc7ab7b9b710a9145769e220c7260..cde0f47b9e0911b84bfdc5916f1e918fa76280e8 100644 --- a/src/finiteVolume/Make/files +++ b/src/finiteVolume/Make/files @@ -3,6 +3,8 @@ fvMesh/fvMesh.C fvMesh/singleCellFvMesh/singleCellFvMesh.C +fvMesh/dummyFvMesh/dummyFvMesh.C + fvBoundaryMesh = fvMesh/fvBoundaryMesh $(fvBoundaryMesh)/fvBoundaryMesh.C diff --git a/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMesh.C b/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMesh.C new file mode 100644 index 0000000000000000000000000000000000000000..4813c5dd660b7040c639e4e24bf4a0260d22a1b8 --- /dev/null +++ b/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMesh.C @@ -0,0 +1,510 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "dummyFvMesh.H" +#include "Time.H" +#include "polyBoundaryMeshEntries.H" +#include "IOobjectList.H" +#include "fieldDictionary.H" +#include "topoSet.H" + +#include "calculatedFvPatchField.H" +#include "emptyPolyPatch.H" +#include "processorPolyPatch.H" +#include "processorCyclicPolyPatch.H" +#include "cyclicPolyPatch.H" +#include "cyclicAMIPolyPatch.H" +#include "cyclicACMIPolyPatch.H" + +#include "fvPatchField.H" +#include "pointPatchField.H" + +// * * * * * * * * * * * * * * * Static Members * * * * * * * * * * * * * * // + +namespace Foam +{ +defineTypeNameAndDebug(dummyFvMesh, 0); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::dummyFvMesh::fvPatchFieldExists(const word& patchType) +{ + if + ( + fvPatchField<scalar>::dictionaryConstructorTablePtr_->found(patchType) + || fvPatchField<vector>::dictionaryConstructorTablePtr_->found(patchType) + || fvPatchField<sphericalTensor>:: + dictionaryConstructorTablePtr_->found(patchType) + || fvPatchField<symmTensor>:: + dictionaryConstructorTablePtr_->found(patchType) + || fvPatchField<tensor>::dictionaryConstructorTablePtr_->found(patchType) + ) + { + return true; + } + + return false; +} + +Foam::autoPtr<Foam::fvMesh> Foam::dummyFvMesh::singleCellMesh +( + const Time& runTime, + const scalar d +) +{ + pointField points(8); + points[0] = vector(0, 0, 0); + points[1] = vector(d, 0, 0); + points[2] = vector(d, d, 0); + points[3] = vector(0, d, 0); + points[4] = vector(0, 0, d); + points[5] = vector(d, 0, d); + points[6] = vector(d, d, d); + points[7] = vector(0, d, d); + + faceList faces = cellModel::ref(cellModel::HEX).modelFaces(); + + autoPtr<fvMesh> meshPtr + ( + new Foam::fvMesh + ( + IOobject + ( + polyMesh::defaultRegion, + runTime.timeName(), + runTime, + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE + ), + std::move(points), + std::move(faces), + labelList(6, Zero), + labelList() + ) + ); + + fvMesh& mesh = meshPtr(); + + List<polyPatch*> patches(1); + + patches[0] = new emptyPolyPatch + ( + "boundary", + 6, + 0, + 0, + mesh.boundaryMesh(), + emptyPolyPatch::typeName + ); + + mesh.addFvPatches(patches); + + return meshPtr; +} + + +bool Foam::dummyFvMesh::setPatchEntries +( + const Time& runTime, + const word& instance, + dictionary& patchEntries, + label& nPatchWithFace +) +{ + IOobject boundaryIO + ( + "boundary", + instance, + polyMesh::meshSubDir, + runTime, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ); + + const wordHashSet constraintPatches(polyPatch::constraintTypes()); + + if (boundaryIO.typeHeaderOk<polyBoundaryMesh>(true)) + { + polyBoundaryMeshEntries allPatchEntries(boundaryIO); + + Info<< "Creating dummy mesh using " << allPatchEntries.path() << endl; + + for (const entry& e : allPatchEntries) + { + const word type(e.dict().lookup("type")); + + if (!constraintPatches.found(type)) + { + if (readLabel(e.dict().lookup("nFaces"))) + { + ++nPatchWithFace; + } + patchEntries.add(e.keyword(), e.dict()); + } + } + + return true; + } + else + { + // No boundary file - try reading from a field + IOobjectList objects(runTime, runTime.timeName()); + + if (objects.empty()) + { + // No fields - cannot create a mesh + return false; + } + + const IOobject& io = *objects.begin()(); + + if (io.instance() == runTime.constant()) + { + FatalErrorInFunction + << "No time directories found for field reading" + << exit(FatalError); + } + + const fieldDictionary fieldDict(io, io.headerClassName()); + + Info<< "Creating dummy mesh from field " + << fieldDict.objectPath() + << endl; + + const dictionary& boundaryFieldDict = + fieldDict.subDict("boundaryField"); + + for (const entry& e : boundaryFieldDict) + { + const word type(e.dict().lookup("type")); + + if (fvPatchFieldExists(type)) + { + if (!constraintPatches.found(type)) + { + ++nPatchWithFace; + dictionary dummyEntries; + dummyEntries.add("startFace", 0); + dummyEntries.add("nFaces", 1); + dummyEntries.add("type", "wall"); // default to wall type + + patchEntries.add(e.keyword(), dummyEntries); + } + } + else + { + Info<< "Ignoring unknown patch type " << type << endl; + } + } + + return false; + } +} + + +Foam::autoPtr<Foam::fvMesh> Foam::dummyFvMesh::equivalent1DMesh +( + const Time& runTime +) +{ + DebugInfo << "Constructing 1-D mesh" << nl << endl; + + const word instance = + runTime.findInstance + ( + polyMesh::meshSubDir, + "boundary", + IOobject::READ_IF_PRESENT + ); + + // Read patches - filter out proc patches for parallel runs + dictionary patchEntries; + label nPatchWithFace = 0; + bool createFromMesh = + setPatchEntries(runTime, instance, patchEntries, nPatchWithFace); + + const label nPatch = patchEntries.size(); + + DebugPout << "Read " << nPatch << " patches" << endl; + + /* + 3 ---- 7 + f5 |\ |\ f2 + | | 2 ---- 6 \ + | 0 |--- 4 | \ + | \| \| f3 + f4 1 ---- 5 + + f0 ----- f1 + */ + + // Create mesh with nPatchWithFace hex cells + // - hex face 1: set internal face to link to next hex cell + // - hex face 2,3,4,5: set to boundary condition + // + // TODO: Coupled patches: + // - separated/collocated cyclic - faces 2 and 3 + // - rotational cyclic - convert to separated and warn not handled? + // - proc patches - faces need to be collocated? + + pointField points(nPatchWithFace*4 + 4); + faceList faces(nPatchWithFace*5 + 1); + + labelList owner(faces.size(), label(-1)); + labelList neighbour(owner); + + vector dx(Zero); + { + // Determine the mesh bounds + IOobject pointsIO + ( + "points", + instance, + polyMesh::meshSubDir, + runTime, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ); + + scalar dxi = 0; + scalar dyi = 0; + scalar dzi = 0; + point origin(point::zero); + + if (pointsIO.typeHeaderOk<vectorIOField>(true)) + { + const pointIOField meshPoints(pointsIO); + + boundBox meshBb(meshPoints, true); + + Info<< "Mesh bounds: " << meshBb << endl; + + origin = meshBb.min(); + vector span = meshBb.span(); + dxi = span.x()/scalar(nPatchWithFace); + dyi = span.y(); + dzi = span.z(); + } + else + { + scalar Lref = GREAT; + origin = point(-Lref, -Lref, -Lref); + dxi = 2.0*Lref/scalar(nPatchWithFace); + dyi = Lref; + dzi = Lref; + } + + dx = vector(dxi, 0, 0); + const vector dy(0, dyi, 0); + const vector dz(0, 0, dzi); + + // End face + points[0] = origin; + points[1] = origin + dy; + points[2] = origin + dy + dz; + points[3] = origin + dz; + } + + label n = 4; + for (label i = 1; i <= nPatchWithFace; ++i) + { + const vector idx(i*dx); + points[i*n] = points[0] + idx; + points[i*n + 1] = points[1] + idx; + points[i*n + 2] = points[2] + idx; + points[i*n + 3] = points[3] + idx; + } + + if (debug) Pout<< "points:" << points << endl; + + label facei = 0; + + // Internal faces first + for (label i = 0; i < nPatchWithFace - 1; ++i) + { + label o = i*4; + faces[facei] = face({4 + o, 5 + o, 6 + o, 7 + o}); + owner[facei] = i; + neighbour[facei] = i + 1; + ++facei; + } + + // Boundary conditions + for (label i = 0; i < nPatchWithFace; ++i) + { + label o = i*4; + faces[facei] = face({0 + o, 4 + o, 7 + o, 3 + o}); + owner[facei] = i; + ++facei; + + faces[facei] = face({0 + o, 1 + o, 5 + o, 4 + o}); + owner[facei] = i; + ++facei; + + faces[facei] = face({1 + o, 2 + o, 6 + o, 5 + o}); + owner[facei] = i; + ++facei; + + faces[facei] = face({3 + o, 7 + o, 6 + o, 2 + o}); + owner[facei] = i; + ++facei; + } + { + // End caps + faces[facei] = face({0, 3, 2, 1}); + owner[facei] = 0; + ++facei; + + label o = 4*nPatchWithFace; + faces[facei] = face({0 + o, 1 + o, 2 + o, 3 + o}); + owner[facei] = nPatchWithFace - 1; + ++facei; + } + + DebugPout + << "faces:" << faces << nl + << "owner:" << owner << nl + << "neighbour:" << neighbour + << endl; + + autoPtr<fvMesh> meshPtr + ( + new Foam::fvMesh + ( + IOobject + ( + fvMesh::defaultRegion, + runTime.constant(), + runTime, + IOobject::NO_READ, // Do not read any existing mesh + IOobject::NO_WRITE + ), + std::move(points), + std::move(faces), + std::move(owner), + std::move(neighbour) + ) + ); + + Foam::fvMesh& mesh = meshPtr(); + + // Workaround to read fvSchemes and fvSolution + { + mesh.fvSchemes::readOpt() = IOobject::MUST_READ; + mesh.fvSchemes::read(); + mesh.fvSolution::readOpt() = IOobject::MUST_READ; + mesh.fvSolution::read(); + } + + List<polyPatch*> patches(nPatch + 1); + + label nInternalFace = nPatchWithFace - 1; + label startFace = nInternalFace; + label entryi = 0; + for (const entry& e : patchEntries) + { + // Re-create boundary types, but reset nFaces and startFace settings + dictionary patchDict = e.dict(); + const word& patchName = e.keyword(); + + DebugPout << "Setting " << patchName << endl; + + label nFaces0 = readLabel(patchDict.lookup("nFaces")); + + if (nFaces0) + { + // Only set to 4 faces if there were faces in the original patch + nFaces0 = 4; + patchDict.set("nFaces", nFaces0); + } + + patchDict.set("startFace", startFace); + patches[entryi] = + polyPatch::New + ( + patchName, + patchDict, + entryi, + mesh.boundaryMesh() + ).ptr(); + + ++entryi; + startFace += nFaces0; + } + + patches.last() = new emptyPolyPatch + ( + typeName + ":default", // name + 2, // number of faces + nInternalFace + 4*nPatchWithFace, // start face + nPatch - 1, // index in boundary list + mesh.boundaryMesh(), // polyBoundaryMesh + emptyPolyPatch::typeName // patchType + ); + + mesh.addFvPatches(patches); + + if (debug) + { + Pout<< "patches:" << nl << endl; + forAll(patches, patchi) + { + Pout<< "patch: " << patches[patchi]->name() << nl + << *patches[patchi] << endl; + } + } + + if (createFromMesh) + { + // Initialise the zones + initialiseZone<pointZoneMesh>("point", instance, mesh.pointZones()); + initialiseZone<faceZoneMesh>("face", instance, mesh.faceZones()); + initialiseZone<cellZoneMesh>("cell", instance, mesh.cellZones()); + + // Dummy sets created on demand + topoSet::disallowGenericSets = 1; + } + else + { + // Dummy zones and sets created on demand + cellZoneMesh::disallowGenericZones = 1; + topoSet::disallowGenericSets = 1; + } + + if (debug) + { + mesh.setInstance(runTime.timeName()); + mesh.objectRegistry::write(); + } + + return meshPtr; +} + + +// ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMesh.H b/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMesh.H new file mode 100644 index 0000000000000000000000000000000000000000..3bf4475819cdd9d5fb0e90cae985e1862caca378 --- /dev/null +++ b/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMesh.H @@ -0,0 +1,112 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::dummyFvMesh + +Description + Functions to generate dummy finite volume meshes + +SourceFiles + dummyFvMesh.C + +\*---------------------------------------------------------------------------*/ + +#ifndef dummyFvMesh_H +#define dummyFvMesh_H + +#include "className.H" +#include "autoPtr.H" +#include "HashSet.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class fvMesh; +class Time; +template<class Type> class List; + +/*---------------------------------------------------------------------------*\ + Class dummyFvMesh Declaration +\*---------------------------------------------------------------------------*/ + +class dummyFvMesh +{ + //- Helper function to see if the patch type exists in the run-time + //- selection tables + static bool fvPatchFieldExists(const word& patchType); + + //- Set the patch information. Returns true if setting based on a real mesh + static bool setPatchEntries + ( + const Time& runTime, + const word& instance, + dictionary& patchEntries, + label& nPatchWithFace + ); + + //- Helper function to initialise empty zones + template<class ZoneMeshType> + static void initialiseZone + ( + const word& zoneTypeName, + const fileName& instance, + ZoneMeshType& zoneType + ); + + +public: + + ClassName("dummyFvMesh"); + + //- Create a single cell mesh with empty boundary conditions all-round + static autoPtr<fvMesh> singleCellMesh + ( + const Time& runTime, + const scalar d = 1 + ); + + //- Create an equivalent 1D mesh using the same boundary types as + //- described in the polyMesh/boundary file, complete with (empty) + //- [point|face|cell] zones + static autoPtr<fvMesh> equivalent1DMesh(const Time& runTime); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "dummyFvMeshTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMeshTemplates.C b/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMeshTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..4226fb7888714cc1643d775a281752d2a17e087f --- /dev/null +++ b/src/finiteVolume/fvMesh/dummyFvMesh/dummyFvMeshTemplates.C @@ -0,0 +1,64 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "polyMesh.H" + +template<class ZoneMeshType> +void Foam::dummyFvMesh::initialiseZone +( + const word& zoneTypeName, + const fileName& instance, + ZoneMeshType& zoneType +) +{ + const wordList zoneNames + ( + ZoneMeshType + ( + IOobject + ( + zoneTypeName + "Zones", + instance, + polyMesh::meshSubDir, + zoneType.mesh(), + IOobject::READ_IF_PRESENT, + IOobject::NO_WRITE, + false + ), + zoneType.mesh() + ).names() + ); + + ZoneMeshType::disallowGenericZones = 1; + for (const word& name : zoneNames) + { + // Insert empty zone + (void)zoneType[name]; + } + ZoneMeshType::disallowGenericZones = 0; +} + + +// ************************************************************************* //