/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2023-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 .
Application
foamToTetDualMesh
Group
grpPostProcessingUtilities
Description
Convert polyMesh results to tetDualMesh.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "timeSelector.H"
#include "fvMesh.H"
#include "volFields.H"
#include "pointFields.H"
#include "Time.H"
#include "IOobjectList.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template
void ReadAndMapFields
(
const fvMesh& mesh,
const IOobjectList& objects,
const fvMesh& tetDualMesh,
const labelList& map,
const typename MappedGeoField::value_type& nullValue,
PtrList& tetFields
)
{
typedef typename MappedGeoField::value_type Type;
// Objects of wanted type
const UPtrList fieldObjects
(
objects.csorted()
);
tetFields.resize(fieldObjects.size());
label i = 0;
for (const IOobject& io : fieldObjects)
{
Info<< "Converting "
<< ReadGeoField::typeName << ' ' << io.name() << endl;
ReadGeoField readField(io, mesh);
tetFields.set
(
i,
new MappedGeoField
(
IOobject
(
readField.name(),
readField.instance(),
readField.local(),
tetDualMesh,
IOobjectOption::NO_READ,
IOobjectOption::AUTO_WRITE,
readField.registerObject()
),
pointMesh::New(tetDualMesh),
dimensioned(readField.dimensions(), Zero)
)
);
Field& fld = tetFields[i].primitiveFieldRef();
// Map from read field. Set unmapped entries to nullValue.
fld.setSize(map.size(), nullValue);
forAll(map, pointi)
{
label index = map[pointi];
if (index > 0)
{
label celli = index-1;
fld[pointi] = readField[celli];
}
else if (index < 0)
{
const label facei = -index-1;
const label patchi = mesh.boundaryMesh().patchID(facei);
if (patchi >= 0)
{
label localFacei = mesh.boundaryMesh()[patchi].whichFace
(
facei
);
fld[pointi] = readField.boundaryField()[patchi][localFacei];
}
//else
//{
// FatalErrorInFunction
// << "Face " << facei << " from index " << index
// << " is not a boundary face." << abort(FatalError);
//}
}
//else
//{
// WarningInFunction
// << "Point " << pointi << " at "
// << tetDualMesh.points()[pointi]
// << " has no dual correspondence." << endl;
//}
}
tetFields[i].correctBoundaryConditions();
i++;
}
}
int main(int argc, char *argv[])
{
argList::noFunctionObjects(); // Never use function objects
timeSelector::addOptions_singleTime(); // Single-time options
argList::addNote
(
"Convert polyMesh results to tetDualMesh"
);
#include "addOverwriteOption.H"
#include "setRootCase.H"
#include "createTime.H"
// Set time from specified time options, or force start from Time=0
timeSelector::setTimeIfPresent(runTime, args, true);
// Read the mesh
#include "createNamedMesh.H"
// Read the tetDualMesh
Info<< "Create tetDualMesh for time = "
<< runTime.timeName() << nl << endl;
fvMesh tetDualMesh
(
IOobject
(
"tetDualMesh",
runTime.timeName(),
runTime,
IOobject::MUST_READ
)
);
// From tet vertices to poly cells/faces
const labelIOList pointDualAddressing
(
IOobject
(
"pointDualAddressing",
tetDualMesh.facesInstance(),
polyMesh::meshSubDir,
tetDualMesh,
IOobject::MUST_READ
)
);
if (pointDualAddressing.size() != tetDualMesh.nPoints())
{
FatalErrorInFunction
<< "Size " << pointDualAddressing.size()
<< " of addressing map " << pointDualAddressing.objectPath()
<< " differs from number of points in mesh "
<< tetDualMesh.nPoints()
<< exit(FatalError);
}
// Some stats on addressing
label nCells = 0;
label nPatchFaces = 0;
label nUnmapped = 0;
forAll(pointDualAddressing, pointi)
{
label index = pointDualAddressing[pointi];
if (index > 0)
{
nCells++;
}
else if (index == 0)
{
nUnmapped++;
}
else
{
label facei = -index-1;
if (facei < mesh.nInternalFaces())
{
FatalErrorInFunction
<< "Face " << facei << " from index " << index
<< " is not a boundary face."
<< " nInternalFaces:" << mesh.nInternalFaces()
<< exit(FatalError);
}
else
{
nPatchFaces++;
}
}
}
reduce(nCells, sumOp