/*---------------------------------------------------------------------------*\
========= |
\\ / 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) 2015-2022 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 .
\*---------------------------------------------------------------------------*/
#include "distributedTriSurfaceMesh.H"
#include "mapDistribute.H"
#include "Random.H"
#include "addToRunTimeSelectionTable.H"
#include "triangleFuncs.H"
#include "matchPoints.H"
#include "globalIndex.H"
#include "Time.H"
#include "IFstream.H"
#include "decompositionMethod.H"
#include "geomDecomp.H"
#include "vectorList.H"
#include "bitSet.H"
#include "PatchTools.H"
#include "OBJstream.H"
#include "labelBits.H"
#include "profiling.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(distributedTriSurfaceMesh, 0);
addToRunTimeSelectionTable
(
searchableSurface,
distributedTriSurfaceMesh,
dict
);
//- Combine operator for volume types
class volumeCombineOp
{
public:
void operator()(volumeType& x, const volumeType& y) const
{
if (x == volumeType::MIXED || y == volumeType::MIXED)
{
FatalErrorInFunction << "Illegal volume type "
<< volumeType::names[x]
<< "," << volumeType::names[y] << exit(FatalError);
}
else
{
switch (x)
{
case volumeType::UNKNOWN:
{
if (y == volumeType::INSIDE || y == volumeType::OUTSIDE)
{
x = y;
}
}
break;
case volumeType::INSIDE:
{
if (y == volumeType::OUTSIDE)
{
FatalErrorInFunction << "Conflicting volume types "
<< volumeType::names[x] << ","
<< volumeType::names[y] << exit(FatalError);
}
}
break;
case volumeType::OUTSIDE:
{
if (y == volumeType::INSIDE)
{
FatalErrorInFunction << "Conflicting volume types "
<< volumeType::names[x] << ","
<< volumeType::names[y] << exit(FatalError);
}
}
break;
case volumeType::MIXED:
break;
}
}
}
};
//typedef Tuple2, volumeType> NearType;
//
////- Combine operator for volume types
//struct NearTypeCombineOp
//{
// //const auto& this_;
//
// void operator()(NearType& nearX, const NearType& nearY) const
// {
// const volumeType& x = nearX.second();
// const volumeType& y = nearY.second();
//
// if (x == volumeType::MIXED || y == volumeType::MIXED)
// {
// FatalErrorInFunction << "Illegal volume type "
// << volumeType::names[x]
// << "," << volumeType::names[y]
// << " nearX:" << nearX << " nearY:" << nearY
// << exit(FatalError);
// }
// else
// {
// switch (x)
// {
// case volumeType::UNKNOWN:
// {
// if (y == volumeType::INSIDE
// || y == volumeType::OUTSIDE)
// {
// nearX = nearY;
// }
// }
// break;
// case volumeType::INSIDE:
// {
// if (y == volumeType::OUTSIDE)
// {
// FatalErrorInFunction
// << "Conflicting volume types "
// << volumeType::names[x] << ","
// << volumeType::names[y]
// << " nearX:" << nearX << " nearY:" << nearY
// << exit(FatalError);
// }
// }
// break;
// case volumeType::OUTSIDE:
// {
// if (y == volumeType::INSIDE)
// {
// FatalErrorInFunction
// << "Conflicting volume types "
// << volumeType::names[x] << ","
// << volumeType::names[y]
// << " nearX:" << nearX << " nearY:" << nearY
// << exit(FatalError);
// }
// }
// break;
// case volumeType::MIXED:
// break;
// }
// }
// }
//};
//- Combine operator for nearest
typedef Tuple2 nearestAndDist;
const nearestAndDist nearestZero
(
nearestAndDist
(
pointIndexHit(),
-GREAT
)
);
class nearestEqOp
{
public:
void operator()(nearestAndDist& x, const nearestAndDist& y) const
{
if (x.first().hit())
{
if (y.first().hit() && y.second() < x.second())
{
x = y;
}
}
else if (y.first().hit())
{
x = y;
}
}
};
}
const Foam::Enum
<
Foam::distributedTriSurfaceMesh::distributionType
>
Foam::distributedTriSurfaceMesh::distributionTypeNames_
({
{ distributionType::FOLLOW, "follow" },
{ distributionType::INDEPENDENT, "independent" },
{ distributionType::DISTRIBUTED, "distributed" },
{ distributionType::FROZEN, "frozen" }
});
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::word Foam::distributedTriSurfaceMesh::findLocalInstance
(
const IOobject& io
)
{
// Modified findInstance which also looks in parent directory
word instance
(
io.time().findInstance
(
io.local(),
word::null,
IOobject::READ_IF_PRESENT
)
);
if (instance.size())
{
return instance;
}
// Replicate findInstance operation but now on parent directory
// Search in parent directory
fileName parentDir =
io.rootPath()/io.time().globalCaseName()
/io.instance()/io.db().dbDir()/io.local()/io.name();
if (fileHandler().isDir(parentDir))
{
return io.instance();
}
instantList ts = io.time().times();
label instanceI;
const scalar startValue = io.time().timeOutputValue();
for (instanceI = ts.size()-1; instanceI >= 0; --instanceI)
{
if (ts[instanceI].value() <= startValue)
{
break;
}
}
// continue searching from here
for (; instanceI >= 0; --instanceI)
{
// Shortcut: if actual directory is the timeName we've already tested it
if (ts[instanceI].name() == io.instance())
{
continue;
}
fileName parentDir =
io.rootPath()/io.time().globalCaseName()
/ts[instanceI].name()/io.db().dbDir()/io.local()/io.name();
if (fileHandler().isDir(parentDir))
{
return ts[instanceI].name();
}
}
// times() usually already includes the constant() so would have been
// checked above. Re-test if
// - times() is empty. Sometimes this can happen (e.g. decomposePar with
// collated)
// - times()[0] is not constant
if (!ts.size() || ts[0].name() != io.time().constant())
{
// Note. This needs to be a hard-coded constant, rather than the
// constant function of the time, because the latter points to
// the case constant directory in parallel cases
fileName parentDir =
io.rootPath()/io.time().globalCaseName()
/io.time().constant()/io.db().dbDir()/io.local()/io.name();
if (fileHandler().isDir(parentDir))
{
return io.time().constant();
}
}
FatalErrorInFunction
<< "Cannot find directory " << io.local() << " in times " << ts
<< exit(FatalError);
return word::null;
}
// Read my additional data from the dictionary
bool Foam::distributedTriSurfaceMesh::read()
{
// Get bb of all domains.
procBb_.resize_nocopy(Pstream::nProcs());
if (dict_.empty())
{
// Did not find the distributed version; assume master has loaded the
// triSurfaceMesh version. Make up some settings.
const boundBox& localBb = triSurfaceMesh::bounds();
procBb_[Pstream::myProcNo()] =
treeBoundBoxList(1, treeBoundBox(localBb));
dict_.add("bounds", procBb_[Pstream::myProcNo()]);
// Wanted distribution type
distType_ = DISTRIBUTED; //INDEPENDENT;
dict_.add("distributionType", distributionTypeNames_[distType_]);
// Merge distance
mergeDist_ = SMALL;
dict_.add("mergeDistance", mergeDist_);
// Force underlying triSurfaceMesh to calculate volume type
// (is topological walk; does not construct tree)
surfaceClosed_ = triSurfaceMesh::hasVolumeType();
Pstream::broadcast(surfaceClosed_);
dict_.add("closed", surfaceClosed_);
// Delay calculating outside vol type since constructs tree. Is ok
// after distributing since then local surfaces much smaller
//outsideVolType_ = volumeType::UNKNOWN;
//if (surfaceClosed_)
//{
// point outsidePt(localBb.max()+localBb.centre());
// List outsideVolTypes;
// triSurfaceMesh::getVolumeType
// (
// pointField(1, outsidePt),
// outsideVolTypes
// );
// outsideVolType_ = outsideVolTypes[0];
//}
//dict_.add("outsideVolumeType", volumeType::names[outsideVolType_]);
}
else
{
dict_.readEntry("bounds", procBb_[Pstream::myProcNo()]);
// Wanted distribution type
distType_ = distributionTypeNames_.get("distributionType", dict_);
// Merge distance
dict_.readEntry("mergeDistance", mergeDist_);
// Distribution type
surfaceClosed_ = dict_.getOrDefault("closed", false);
outsideVolType_ = volumeType::names.getOrDefault
(
"outsideVolumeType",
dict_,
volumeType::UNKNOWN
);
}
Pstream::allGatherList(procBb_);
return true;
}
// Is segment fully local?
bool Foam::distributedTriSurfaceMesh::isLocal
(
const List& myBbs,
const point& start,
const point& end
)
{
forAll(myBbs, bbi)
{
if (myBbs[bbi].contains(start) && myBbs[bbi].contains(end))
{
return true;
}
}
return false;
}
//void Foam::distributedTriSurfaceMesh::splitSegment
//(
// const label segmenti,
// const point& start,
// const point& end,
// const treeBoundBox& bb,
//
// DynamicList& allSegments,
// DynamicList