meshTools: Added patchToPatch class for patch mapping

This commit is contained in:
Will Bainbridge
2022-04-12 14:56:46 +01:00
parent 96199075a6
commit 94679fa88d
18 changed files with 5598 additions and 0 deletions

View File

@ -256,6 +256,12 @@ $(AMIOverlapPatches)/cyclicRepeatAMIPolyPatch/cyclicRepeatAMIPolyPatch.C
$(AMIOverlapPatches)/cyclicRepeatAMIPointPatch/cyclicRepeatAMIPointPatch.C $(AMIOverlapPatches)/cyclicRepeatAMIPointPatch/cyclicRepeatAMIPointPatch.C
$(AMIOverlapPatches)/cyclicRepeatAMIPointPatchField/cyclicRepeatAMIPointPatchFields.C $(AMIOverlapPatches)/cyclicRepeatAMIPointPatchField/cyclicRepeatAMIPointPatchFields.C
patchToPatch/patchToPatch/patchToPatch.C
patchToPatch/patchToPatch/patchToPatchParallelOps.C
patchToPatch/nearest/nearestPatchToPatch.C
patchToPatch/inverseDistance/inverseDistancePatchToPatch.C
patchToPatch/intersection/intersectionPatchToPatch.C
mappedPatches/mappedPolyPatch/mappedPatchBase.C mappedPatches/mappedPolyPatch/mappedPatchBase.C
mappedPatches/mappedPolyPatch/mappedPolyPatch.C mappedPatches/mappedPolyPatch/mappedPolyPatch.C
mappedPatches/mappedPolyPatch/mappedWallPolyPatch.C mappedPatches/mappedPolyPatch/mappedWallPolyPatch.C

View File

@ -0,0 +1,235 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
\\/ 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 "PrimitiveOldTimePatch.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::PrimitiveOldTimePatch
(
const FaceList& faces,
const Field<PointType>& points,
const Field<PointType>& points0
)
:
PrimitivePatch<FaceList, PointField>(faces, points),
points0_(points0),
patch0Ptr_(new patch0Type(faces, points0_)),
localPoints0Ptr_(nullptr)
{}
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::PrimitiveOldTimePatch
(
const PrimitivePatch<FaceList, PointField>& patch,
const Field<PointType>& points0
)
:
PrimitivePatch<FaceList, PointField>(patch),
points0_(points0),
patch0Ptr_(new patch0Type(patch, points0_)),
localPoints0Ptr_(nullptr)
{}
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::PrimitiveOldTimePatch
(
const FaceList& faces,
const Field<PointType>& points
)
:
PrimitivePatch<FaceList, PointField>(faces, points),
points0_(NullObjectRef<Field<PointType>>()),
patch0Ptr_(nullptr),
localPoints0Ptr_(nullptr)
{}
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::PrimitiveOldTimePatch
(
const PrimitivePatch<FaceList, PointField>& patch
)
:
PrimitivePatch<FaceList, PointField>(patch),
points0_(NullObjectRef<Field<PointType>>()),
patch0Ptr_(nullptr),
localPoints0Ptr_(nullptr)
{}
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::PrimitiveOldTimePatch
(
const PrimitiveOldTimePatch<FaceList, PointField>& patch
)
:
PrimitivePatch<FaceList, PointField>(patch),
points0_(patch.points0_),
patch0Ptr_(patch.patch0Ptr_, false),
localPoints0Ptr_(nullptr)
{}
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::PrimitiveOldTimePatch
(
PrimitiveOldTimePatch<FaceList, PointField>&& patch
)
:
PrimitivePatch<FaceList, PointField>(move(patch)),
points0_(move(patch.points0_)),
patch0Ptr_(patch.patch0Ptr_),
localPoints0Ptr_(nullptr)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template<class FaceList, class PointField>
Foam::PrimitiveOldTimePatch<FaceList, PointField>::~PrimitiveOldTimePatch()
{
clearOut();
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
template<class FaceList, class PointField>
const Foam::Field
<
typename Foam::PrimitiveOldTimePatch<FaceList, PointField>::PointType
>& Foam::PrimitiveOldTimePatch<FaceList, PointField>::localPoints0() const
{
// !!! Cannot just call patch0Ptr_->localPoints() as this would generate
// topology in patch0Ptr_() that is already available in the base class.
// For now, we just duplicate the implementation in PrimitivePatch.
if (!localPoints0Ptr_)
{
const labelList& meshPts = this->meshPoints();
localPoints0Ptr_ = new Field<PointType>(meshPts.size());
Field<PointType>& locPts = *localPoints0Ptr_;
forAll(meshPts, pointi)
{
locPts[pointi] = points0_[meshPts[pointi]];
}
}
// But, it would be preferable to add a method to PrimitivePatch which
// calculates the local points given a list of points different to those
// that are stored. Then the implementations could be shared and we could
// do this:
/*
if (!localPoints0Ptr_)
{
localPoints0Ptr_ = this->calcLocalPoints(points0_);
}
*/
return *localPoints0Ptr_;
}
template<class FaceList, class PointField>
const Foam::Field
<
typename Foam::PrimitiveOldTimePatch<FaceList, PointField>::PointType
>& Foam::PrimitiveOldTimePatch<FaceList, PointField>::faceCentres0() const
{
return patch0Ptr_->faceCentres();
}
template<class FaceList, class PointField>
const Foam::Field
<
typename Foam::PrimitiveOldTimePatch<FaceList, PointField>::PointType
>& Foam::PrimitiveOldTimePatch<FaceList, PointField>::faceAreas0() const
{
return patch0Ptr_->faceAreas();
}
template<class FaceList, class PointField>
const Foam::Field
<
typename Foam::PrimitiveOldTimePatch<FaceList, PointField>::PointType
>& Foam::PrimitiveOldTimePatch<FaceList, PointField>::faceNormals0() const
{
return patch0Ptr_->faceNormals();
}
template<class FaceList, class PointField>
const Foam::Field
<
typename Foam::PrimitiveOldTimePatch<FaceList, PointField>::PointType
>& Foam::PrimitiveOldTimePatch<FaceList, PointField>::pointNormals0() const
{
// !!! See comments in localPoints0. This isn't needed for now.
NotImplemented;
return NullObjectRef<Field<PointType>>();
}
template<class FaceList, class PointField>
void Foam::PrimitiveOldTimePatch<FaceList, PointField>::clearOut()
{
PrimitivePatch<FaceList, PointField>::clearOut();
if (has0()) patch0Ptr_->clearOut();
deleteDemandDrivenData(localPoints0Ptr_);
}
template<class FaceList, class PointField>
void Foam::PrimitiveOldTimePatch<FaceList, PointField>::clearGeom()
{
PrimitivePatch<FaceList, PointField>::clearGeom();
if (has0()) patch0Ptr_->clearGeom();
deleteDemandDrivenData(localPoints0Ptr_);
}
template<class FaceList, class PointField>
void Foam::PrimitiveOldTimePatch<FaceList, PointField>::movePoints0
(
const Field<PointType>&
)
{
if (has0()) patch0Ptr_->clearGeom();
}
// ************************************************************************* //

View File

@ -0,0 +1,230 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
\\/ 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::PrimitiveOldTimePatch
Description
SourceFiles
PrimitiveOldTimePatch.C
\*---------------------------------------------------------------------------*/
#ifndef PrimitiveOldTimePatch_H
#define PrimitiveOldTimePatch_H
#include "PrimitivePatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Trait to determine what face list should be used for the old-time patch
template<class Container>
struct UFaceList;
template<class Face>
struct UFaceList<UList<Face>> { typedef UList<Face> type; };
template<class Face>
struct UFaceList<List<Face>> : public UFaceList<UList<Face>> {};
template<class Face>
struct UFaceList<SubList<Face>> : public UFaceList<UList<Face>> {};
template<class Face>
struct UFaceList<UIndirectList<Face>> { typedef UIndirectList<Face> type; };
template<class Face>
struct UFaceList<IndirectList<Face>> : public UFaceList<UIndirectList<Face>> {};
/*---------------------------------------------------------------------------*\
Class PrimitiveOldTimePatch Declaration
\*---------------------------------------------------------------------------*/
template<class FaceList, class PointField>
class PrimitiveOldTimePatch
:
public PrimitivePatch<FaceList, PointField>
{
public:
// Public Typedefs
using typename PrimitivePatch<FaceList, PointField>::FaceListType;
using typename PrimitivePatch<FaceList, PointField>::FaceType;
using typename PrimitivePatch<FaceList, PointField>::PointFieldType;
using typename PrimitivePatch<FaceList, PointField>::PointType;
private:
// Private Typedefs
typedef
PrimitivePatch
<
typename UFaceList<FaceListType>::type,
const PointFieldType&
>
patch0Type;
// Private Data
//- Reference to global list of old-time points
PointField points0_;
//- Engine for calculating old-time geometry. Note: Methods that
// generate topology should not be called here. The base patch should
// have all the necessary topology available. The calculation of some
// geometric quantities requires topological data to be available. In
// these cases, special steps need to be taken here to make sure that
// the old-time patch object does not generate duplicate topology.
autoPtr<patch0Type> patch0Ptr_;
//- Points local to patch
mutable Field<PointType>* localPoints0Ptr_;
public:
// Constructors
//- Construct from components
PrimitiveOldTimePatch
(
const FaceList& faces,
const Field<PointType>& points,
const Field<PointType>& points0
);
//- Construct from patch and old-time points
PrimitiveOldTimePatch
(
const PrimitivePatch<FaceList, PointField>& patch,
const Field<PointType>& points0
);
//- Construct from components without old-time points
PrimitiveOldTimePatch
(
const FaceList& faces,
const Field<PointType>& points
);
//- Construct from patch without old-time points
PrimitiveOldTimePatch
(
const PrimitivePatch<FaceList, PointField>& patch
);
//- Copy constructor
PrimitiveOldTimePatch(const PrimitiveOldTimePatch& patch);
//- Move constructor
PrimitiveOldTimePatch(PrimitiveOldTimePatch&& patch);
//- Construct and return a clone
autoPtr<PrimitiveOldTimePatch<FaceList, PointField>> clone() const
{
return autoPtr<PrimitiveOldTimePatch<FaceList, PointField>>
(
new PrimitiveOldTimePatch<FaceList, PointField>(*this)
);
}
//- Destructor
virtual ~PrimitiveOldTimePatch();
// Member Functions
// Access
//- Return whether or not old-time geometry is available
bool has0() const
{
return patch0Ptr_.valid();
}
//- Return reference to old-time global points
const Field<PointType>& points0() const
{
return points0_;
}
// Geometry
//- Return pointField of old-time points in patch
const Field<PointType>& localPoints0() const;
//- Return old-time face centres for patch
const Field<PointType>& faceCentres0() const;
//- Return old-time face areas for patch
const Field<PointType>& faceAreas0() const;
//- Return old-time face normals for patch
const Field<PointType>& faceNormals0() const;
//- Return old-time point normals for patch
const Field<PointType>& pointNormals0() const;
// Edit
//- ...
void clearOut();
//- ...
void clearGeom();
//- Correct patch after moving points
virtual void movePoints0(const Field<PointType>&);
// Member Operators
//- Disallow default bitwise assignment
void operator=(const PrimitiveOldTimePatch&) = delete;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "PrimitiveOldTimePatch.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
\\/ 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/>.
Typedef
Foam::primitiveOldTimePatch
Description
Addressing for a faceList slice.
\*---------------------------------------------------------------------------*/
#ifndef primitiveOldTimePatch_H
#define primitiveOldTimePatch_H
#include "PrimitiveOldTimePatch.H"
#include "face.H"
#include "SubList.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
typedef
PrimitiveOldTimePatch<SubList<face>, const pointField&>
primitiveOldTimePatch;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,53 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
\\/ 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/>.
Typedef
Foam::uindirectPrimitiveOldTimePatch
Description
Addressing for a faceList slice.
\*---------------------------------------------------------------------------*/
#ifndef uindirectPrimitiveOldTimePatch_H
#define uindirectPrimitiveOldTimePatch_H
#include "PrimitiveOldTimePatch.H"
#include "face.H"
#include "UIndirectList.H"
#include "pointField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
typedef
PrimitiveOldTimePatch<UIndirectList<face>, const pointField&>
uindirectPrimitiveOldTimePatch;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,937 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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 "intersectionPatchToPatch.H"
#include "triIntersect.H"
#include "vtkWritePolyData.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
defineTypeNameAndDebug(intersection, 0);
addToRunTimeSelectionTable(patchToPatch, intersection, bool);
int intersection::debugSrcFacei =
debug::debugSwitch((intersection::typeName + "SrcFace").c_str(), -1);
int intersection::debugTgtFacei =
debug::debugSwitch((intersection::typeName + "TgtFace").c_str(), -1);
}
}
// * * * * * * * * * * * Private Static Member Functions * * * * * * * * * * //
template<class Type>
Foam::FixedList<Type, 3>
Foam::patchToPatches::intersection::triPointValues
(
const triFace& t,
const UList<Type>& values
)
{
FixedList<Type, 3> result;
forAll(t, i)
{
result[i] = values[t[i]];
}
return result;
}
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
Foam::treeBoundBox Foam::patchToPatches::intersection::srcBoxStatic
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
)
{
static DynamicList<point> ps;
ps.clear();
const scalar l = sqrt(mag(srcFace.area(srcPoints)));
forAll(srcFace, srcFacePointi)
{
const label srcPointi = srcFace[srcFacePointi];
const point& p = srcPoints[srcPointi];
const vector& n = srcPointNormals[srcPointi];
ps.append(p - l/2*n);
ps.append(p + l/2*n);
}
return treeBoundBox(ps);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::treeBoundBox Foam::patchToPatches::intersection::srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const
{
return srcBoxStatic(srcFace, srcPoints, srcPointNormals);
}
bool Foam::patchToPatches::intersection::intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
)
{
// Quick rejection based on bound box
const treeBoundBox srcFaceBox =
srcBox
(
srcPatch.localFaces()[srcFacei],
srcPatch.localPoints(),
srcPointNormals
);
const treeBoundBox tgtFaceBox(tgtPatch.points(), tgtPatch[tgtFacei]);
if (!srcFaceBox.overlaps(tgtFaceBox)) return false;
// Construct face triangulations on demand
if (srcTriPoints_[srcFacei].empty())
{
triEngine_.triangulate
(
UIndirectList<point>
(
srcPatch.localPoints(),
srcPatch.localFaces()[srcFacei]
)
);
srcTriPoints_[srcFacei] =
triEngine_.triPoints(srcPatch.localFaces()[srcFacei]);
srcTriFaceEdges_[srcFacei] = triEngine_.triEdges();
}
if (tgtTriPoints_[tgtFacei].empty())
{
triEngine_.triangulate
(
UIndirectList<point>
(
tgtPatch.localPoints(),
tgtPatch.localFaces()[tgtFacei]
)
);
tgtTriPoints_[tgtFacei] =
triEngine_.triPoints(tgtPatch.localFaces()[tgtFacei]);
tgtTriFaceEdges_[tgtFacei] = triEngine_.triEdges();
}
// Construct and initialise workspace
bool srcCouples = false;
couple srcCouple;
srcFaceEdgePart_.resize(srcPatch[srcFacei].size());
forAll(srcFaceEdgePart_, srcFaceEdgei)
{
const edge e =
srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
const vector eC = e.centre(srcPatch.localPoints());
srcFaceEdgePart_[srcFaceEdgei] = part(Zero, eC);
}
bool tgtCouples = false;
couple tgtCouple;
tgtFaceEdgePart_.resize(tgtPatch[tgtFacei].size());
forAll(tgtFaceEdgePart_, tgtFaceEdgei)
{
const edge e =
tgtPatch.localFaces()[tgtFacei].faceEdge(tgtFaceEdgei);
const vector eC = e.centre(tgtPatch.localPoints());
tgtFaceEdgePart_[tgtFaceEdgei] = part(Zero, eC);
}
part errorPart(Zero, srcPatch.faceCentres()[srcFacei]);
// Cache the face area magnitudes
const scalar srcMagA = mag(srcPatch.faceAreas()[srcFacei]);
const scalar tgtMagA = mag(tgtPatch.faceAreas()[tgtFacei]);
// Determine whether or not to debug this tri intersection
const bool debugTriIntersect =
(debugSrcFacei != -1 || debugTgtFacei != -1)
&& (debugSrcFacei == -1 || debugSrcFacei == srcFacei)
&& (debugTgtFacei == -1 || debugTgtFacei == tgtFacei);
// Loop the face triangles and compute the intersections
bool anyCouples = false;
forAll(srcTriPoints_[srcFacei], srcFaceTrii)
{
const triFace& srcT = srcTriPoints_[srcFacei][srcFaceTrii];
const FixedList<point, 3> srcPs =
triPointValues(srcT, srcPatch.localPoints());
const FixedList<vector, 3> srcNs =
triPointValues(srcT, srcPointNormals);
forAll(tgtTriPoints_[tgtFacei], tgtFaceTrii)
{
const triFace tgtT =
reverse()
? tgtTriPoints_[tgtFacei][tgtFaceTrii].reverseFace()
: tgtTriPoints_[tgtFacei][tgtFaceTrii];
const FixedList<point, 3> tgtPs =
triPointValues(tgtT, tgtPatch.localPoints());
// Do tri-intersection
ictSrcPoints_.clear();
ictSrcPointNormals_.clear();
ictTgtPoints_.clear();
ictPointLocations_.clear();
triIntersect::intersectTris
(
srcPs,
srcNs,
{false, false, false},
{-1, -1, -1},
tgtPs,
{false, false, false},
{-1, -1, -1},
ictSrcPoints_,
ictSrcPointNormals_,
ictTgtPoints_,
ictPointLocations_,
debugTriIntersect,
debugTriIntersect
? word
(
typeName
+ "_srcFace=" + Foam::name(srcFacei)
+ "_tgtFace=" + Foam::name(tgtFacei)
+ "_intersection=" + Foam::name
(srcFaceTrii*tgtTriPoints_[tgtFacei].size() + tgtFaceTrii)
)
: word::null
);
// If there is no intersection then continue
if (ictPointLocations_.empty())
{
continue;
}
// Mark that there has been an intersection
anyCouples = true;
// Compute the intersection geometry
const part ictSrcPart(ictSrcPoints_);
const part ictTgtPart(ictTgtPoints_);
// If the intersection is below tolerance then continue
if
(
mag(ictSrcPart.area) < small*srcMagA
|| mag(ictTgtPart.area) < small*tgtMagA
)
{
continue;
}
// Mark that the source and target faces intersect
srcCouples = tgtCouples = true;
// Store the intersection geometry
srcCouple += ictSrcPart;
srcCouple.nbr += ictTgtPart;
if (reverse())
{
tgtCouple += ictTgtPart;
tgtCouple.nbr += ictSrcPart;
}
else
{
tgtCouple -= ictTgtPart;
tgtCouple.nbr -= ictSrcPart;
}
// Store the intersection polygons for debugging
const label debugSrcPoint0 = debugPoints_.size();
const label debugTgtPoint0 =
debugPoints_.size() + ictSrcPoints_.size();
if (debug)
{
debugPoints_.append(ictSrcPoints_);
debugPoints_.append(ictTgtPoints_);
debugFaces_.append
(
debugSrcPoint0 + identity(ictSrcPoints_.size())
);
debugFaceSrcFaces_.append(srcFacei);
debugFaceTgtFaces_.append(tgtFacei);
debugFaceSides_.append(1);
debugFaces_.append
(
debugTgtPoint0 + identity(ictTgtPoints_.size())
);
debugFaceSrcFaces_.append(srcFacei);
debugFaceTgtFaces_.append(tgtFacei);
debugFaceSides_.append(-1);
}
// Store edge and error areas
forAll(ictPointLocations_, i0)
{
const label i1 = ictPointLocations_.fcIndex(i0);
// Get the locations on each end of this edge of the
// intersection polygon
const triIntersect::location l0 = ictPointLocations_[i0];
const triIntersect::location l1 = ictPointLocations_[i1];
// Get the geometry for the projection of this edge
const part ictEdgePart
(
FixedList<point, 4>
({
ictSrcPoints_[i0],
ictSrcPoints_[i1],
ictTgtPoints_[i1],
ictTgtPoints_[i0]
})
);
// Store the "side" of the intersection that this edge
// corresponds to
label ictEdgeSide = -labelMax;
// If this edge corresponds to an edge of the source
// triangle
if
(
l0.isSrcNotTgtPoint()
|| l1.isSrcNotTgtPoint()
|| (
l0.isIntersection()
&& l1.isIntersection()
&& l0.srcEdgei() == l1.srcEdgei()
)
)
{
const label srcEi =
l0.isSrcPoint() ? l0.srcPointi()
: l1.isSrcPoint() ? (l1.srcPointi() + 2) % 3
: l0.srcEdgei();
const label srcFaceEdgei =
srcTriFaceEdges_[srcFacei][srcFaceTrii][srcEi];
if (srcFaceEdgei < srcPatch[srcFacei].size())
{
srcFaceEdgePart_[srcFaceEdgei] += ictEdgePart;
ictEdgeSide = 1;
}
else
{
errorPart += ictEdgePart;
ictEdgeSide = 0;
}
}
// If this edge corresponds to an edge of the target
// triangle
else if
(
l0.isTgtNotSrcPoint()
|| l1.isTgtNotSrcPoint()
|| (
l0.isIntersection()
&& l1.isIntersection()
&& l0.tgtEdgei() == l1.tgtEdgei()
)
)
{
const label tgtEi =
l0.isTgtPoint() ? (l0.tgtPointi() + 2) % 3
: l1.isTgtPoint() ? l1.tgtPointi()
: l0.tgtEdgei();
const label tgtFaceEdgei =
tgtTriFaceEdges_[tgtFacei][tgtFaceTrii]
[reverse() ? 2 - tgtEi : tgtEi];
if (tgtFaceEdgei < tgtPatch[tgtFacei].size())
{
if (reverse())
{
tgtFaceEdgePart_[tgtFaceEdgei] += ictEdgePart;
}
else
{
tgtFaceEdgePart_[tgtFaceEdgei] -= ictEdgePart;
}
ictEdgeSide = -1;
}
else
{
errorPart += ictEdgePart;
ictEdgeSide = 0;
}
}
// No other location combinations should be possible for an
// intersection without any shared points
else
{
FatalErrorInFunction
<< "Tri-intersection topology not recognised. "
<< "This is a bug." << exit(FatalError);
}
// Store the projected edge quadrilateral for debugging
if (debug)
{
debugFaces_.append
(
labelList
({
debugSrcPoint0 + i0,
debugSrcPoint0 + i1,
debugTgtPoint0 + i1,
debugTgtPoint0 + i0
})
);
debugFaceSrcFaces_.append(srcFacei);
debugFaceTgtFaces_.append(tgtFacei);
debugFaceSides_.append(ictEdgeSide);
}
}
}
}
// If the source face couples the target, then store the intersection
if (srcCouples)
{
srcLocalTgtFaces_[srcFacei].append(tgtFacei);
srcCouples_[srcFacei].append(srcCouple);
}
// If any intersection has occurred then store the edge and error parts
if (anyCouples)
{
forAll(srcFaceEdgeParts_[srcFacei], srcFaceEdgei)
{
srcFaceEdgeParts_[srcFacei][srcFaceEdgei] +=
srcFaceEdgePart_[srcFaceEdgei];
}
srcErrorParts_[srcFacei] -= sum(tgtFaceEdgePart_);
srcErrorParts_[srcFacei] += errorPart;
}
// If the target face couples the source, then store in the intersection
if (tgtCouples)
{
tgtLocalSrcFaces_[tgtFacei].append(srcFacei);
tgtCouples_[tgtFacei].append(tgtCouple);
}
return anyCouples;
}
void Foam::patchToPatches::intersection::initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
)
{
patchToPatch::initialise
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch
);
srcCouples_.resize(srcPatch.size());
forAll(srcLocalTgtFaces_, i)
{
srcCouples_[i].clear();
}
srcEdgeParts_.resize(srcPatch.nEdges());
forAll(srcEdgeParts_, srcEdgei)
{
const edge& e = srcPatch.edges()[srcEdgei];
const point c = e.centre(srcPatch.localPoints());
srcEdgeParts_[srcEdgei] = part(Zero, c);
}
srcErrorParts_.resize(srcPatch.size());
forAll(srcErrorParts_, srcFacei)
{
srcErrorParts_[srcFacei] =
part(Zero, srcPatch.faceCentres()[srcFacei]);
}
tgtCouples_.resize(tgtPatch.size());
forAll(tgtLocalSrcFaces_, i)
{
tgtCouples_[i].clear();
}
srcTriPoints_ = List<triFaceList>(srcPatch.size());
srcTriFaceEdges_ = List<List<FixedList<label, 3>>>(srcPatch.size());
tgtTriPoints_ = List<triFaceList>(tgtPatch.size());
tgtTriFaceEdges_ = List<List<FixedList<label, 3>>>(tgtPatch.size());
srcFaceEdgeParts_.resize(srcPatch.size());
forAll(srcFaceEdgeParts_, srcFacei)
{
srcFaceEdgeParts_[srcFacei].resize(srcPatch[srcFacei].size());
forAll(srcFaceEdgeParts_[srcFacei], srcFaceEdgei)
{
const label srcEdgei =
srcPatch.faceEdges()[srcFacei][srcFaceEdgei];
srcFaceEdgeParts_[srcFacei][srcFaceEdgei] = srcEdgeParts_[srcEdgei];
}
}
if (debug)
{
debugPoints_.clear();
debugFaces_.clear();
debugFaceSrcFaces_.clear();
debugFaceTgtFaces_.clear();
debugFaceSides_.clear();
}
}
void Foam::patchToPatches::intersection::rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
)
{
patchToPatch::rDistributeTgt(tgtPatch, tgtMap);
rDistributeListList(tgtPatch.size(), tgtMap, tgtCouples_);
}
Foam::label Foam::patchToPatches::intersection::finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
)
{
const label nCouples =
patchToPatch::finalise
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch,
tgtToSrc
);
// Convert face-edge-parts to edge-parts
labelList srcEdgeNParts(srcEdgeParts_.size(), 0);
forAll(srcEdgeParts_, srcEdgei)
{
const edge& e = srcPatch.edges()[srcEdgei];
srcEdgeParts_[srcEdgei] = part();
forAll(srcPatch.edgeFaces()[srcEdgei], i)
{
const label srcFacei = srcPatch.edgeFaces()[srcEdgei][i];
const label srcFaceEdgei =
findIndex(srcPatch.faceEdges()[srcFacei], srcEdgei);
const edge fe =
srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
if (edge::compare(e, fe) > 0)
{
srcEdgeParts_[srcEdgei] +=
srcFaceEdgeParts_[srcFacei][srcFaceEdgei];
}
else
{
srcEdgeParts_[srcEdgei] -=
srcFaceEdgeParts_[srcFacei][srcFaceEdgei];
}
srcEdgeNParts[srcEdgei] ++;
}
}
forAll(srcEdgeParts_, srcEdgei)
{
srcEdgeParts_[srcEdgei].area /= srcEdgeNParts[srcEdgei];
}
// Add the difference between the face-edge-part and the edge-part into the
// face-error-parts
forAll(srcEdgeParts_, srcEdgei)
{
const edge& e = srcPatch.edges()[srcEdgei];
forAll(srcPatch.edgeFaces()[srcEdgei], i)
{
const label srcFacei = srcPatch.edgeFaces()[srcEdgei][i];
const label srcFaceEdgei =
findIndex(srcPatch.faceEdges()[srcFacei], srcEdgei);
const edge fe =
srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
if (edge::compare(e, fe) > 0)
{
srcErrorParts_[srcFacei] -= srcEdgeParts_[srcEdgei];
}
else
{
srcErrorParts_[srcFacei] += srcEdgeParts_[srcEdgei];
}
srcErrorParts_[srcFacei] +=
srcFaceEdgeParts_[srcFacei][srcFaceEdgei];
}
}
// Transform the target couples back to the target side
if (!isNull(tgtToSrc))
{
forAll(tgtCouples_, tgtFacei)
{
forAll(tgtCouples_[tgtFacei], i)
{
couple& c = tgtCouples_[tgtFacei][i];
c.area = tgtToSrc.invTransform(c.area);
c.centre = tgtToSrc.invTransformPosition(c.centre);
c.nbr.area = tgtToSrc.invTransform(c.nbr.area);
c.nbr.centre = tgtToSrc.invTransformPosition(c.nbr.centre);
}
}
}
// Clear the triangulation workspace
srcTriPoints_.clear();
srcTriFaceEdges_.clear();
tgtTriPoints_.clear();
tgtTriFaceEdges_.clear();
// Clear face-edge-parts
srcFaceEdgePart_.clear();
tgtFaceEdgePart_.clear();
srcFaceEdgeParts_.clear();
// Checking and reporting
if (nCouples != 0)
{
scalar srcArea = 0, srcCoupleArea = 0;
scalarField srcCoverage(srcPatch.size());
scalarField srcOpenness(srcPatch.size());
scalarField srcError(srcPatch.size());
scalarField srcDepth(srcPatch.size());
scalarField srcAngle(srcPatch.size());
forAll(srcPatch, srcFacei)
{
const vector& a = srcPatch.faceAreas()[srcFacei];
const scalar magA = mag(a);
const point& c = srcPatch.faceCentres()[srcFacei];
couple Cpl(part(Zero, c), part(Zero, c));
forAll(srcCouples_[srcFacei], srcTgtFacei)
{
const couple& cpl = srcCouples_[srcFacei][srcTgtFacei];
Cpl += cpl;
Cpl.nbr += cpl.nbr;
}
const scalar magCA = mag(Cpl.area);
srcArea += magA;
srcCoupleArea += magCA;
srcCoverage[srcFacei] = magCA/magA;
vector projectionA = Zero;
scalar projectionV = 0;
forAll(srcCouples_[srcFacei], srcTgtFacei)
{
const couple& cpl = srcCouples_[srcFacei][srcTgtFacei];
projectionA += cpl.nbr.area;
projectionV +=
- (cpl.area/3 & (cpl.centre - Cpl.centre))
+ (cpl.nbr.area/3 & (cpl.nbr.centre - Cpl.centre));
}
forAll(srcPatch.faceEdges()[srcFacei], srcFaceEdgei)
{
const label srcEdgei =
srcPatch.faceEdges()[srcFacei][srcFaceEdgei];
const edge& e = srcPatch.edges()[srcEdgei];
const edge fe =
srcPatch.localFaces()[srcFacei].faceEdge(srcFaceEdgei);
const scalar sign = edge::compare(e, fe);
projectionA += sign*srcEdgeParts_[srcEdgei].area;
projectionV +=
sign*srcEdgeParts_[srcEdgei].area/3
& (srcEdgeParts_[srcEdgei].centre - Cpl.centre);
}
projectionA += srcErrorParts_[srcFacei].area;
projectionV +=
srcErrorParts_[srcFacei].area/3
& (srcErrorParts_[srcFacei].centre - Cpl.centre);
const vector aHat = normalised(a);
const vector aOppHat = normalised(a - Cpl.area + Cpl.nbr.area);
srcAngle[srcFacei] =
radToDeg(acos(min(max(aHat & aOppHat, -1), +1)));
srcOpenness[srcFacei] = mag(projectionA - Cpl.area)/magA;
srcError[srcFacei] = mag(srcErrorParts_[srcFacei].area)/magA;
srcDepth[srcFacei] = mag(projectionV)/pow3(sqrt(magA));
}
reduce(srcArea, sumOp<scalar>());
reduce(srcCoupleArea, sumOp<scalar>());
scalar tgtArea = 0, tgtCoupleArea = 0;
scalarField tgtCoverage(tgtPatch.size());
forAll(tgtPatch, tgtFacei)
{
const scalar magA = mag(tgtPatch.faceAreas()[tgtFacei]);
vector aCouple = Zero;
forAll(tgtCouples_[tgtFacei], tgtSrcFacei)
{
aCouple += tgtCouples_[tgtFacei][tgtSrcFacei].area;
}
const scalar magACouple = mag(aCouple);
tgtArea += magA;
tgtCoupleArea += magACouple;
tgtCoverage[tgtFacei] = magACouple/magA;
}
reduce(tgtArea, sumOp<scalar>());
reduce(tgtCoupleArea, sumOp<scalar>());
Info<< indent << "Source min/average/max coverage = "
<< gMin(srcCoverage) << '/' << srcCoupleArea/srcArea << '/'
<< gMax(srcCoverage) << endl
<< indent << "Target min/average/max coverage = "
<< gMin(tgtCoverage) << '/' << tgtCoupleArea/tgtArea << '/'
<< gMax(tgtCoverage) << endl
<< indent << "Source average openness/error/depth/angle = "
<< gAverage(srcOpenness) << '/' << gAverage(srcError) << '/'
<< gAverage(srcDepth) << '/' << gAverage(srcAngle) << endl
<< indent << "Source max openness/error/depth/angle = "
<< gMax(srcOpenness) << '/' << gMax(srcError) << '/'
<< gMax(srcDepth) << '/' << gMax(srcAngle) << endl;
if (debug)
{
word name = patchToPatch::typeName + '_' + typeName;
if (Pstream::parRun())
{
name += "_proc" + Foam::name(Pstream::myProcNo());
}
Info<< indent << "Writing intersected faces to "
<< name + ".vtk" << endl;
vtkWritePolyData::write
(
name + ".vtk",
name,
false,
debugPoints_,
labelList(),
labelListList(),
debugFaces_,
"srcFace", false, Field<label>(debugFaceSrcFaces_),
"tgtFace", false, Field<label>(debugFaceTgtFaces_),
"side", false, Field<label>(debugFaceSides_)
);
debugPoints_.clear();
debugFaces_.clear();
debugFaceSrcFaces_.clear();
debugFaceTgtFaces_.clear();
debugFaceSides_.clear();
Info<< indent << "Writing source patch to "
<< name + "_srcPatch.vtk" << endl;
vtkWritePolyData::write
(
name + "_srcPatch" + ".vtk",
name + "_srcPatch",
false,
srcPatch.localPoints(),
labelList(),
labelListList(),
srcPatch.localFaces(),
"coverage", false, srcCoverage,
"openness", false, srcOpenness,
"error", false, srcError,
"depth", false, srcDepth,
"angle", false, srcAngle
);
Info<< indent << "Writing target patch to "
<< name + "_tgtPatch.vtk" << endl;
vtkWritePolyData::write
(
name + "_tgtPatch" + ".vtk",
name + "_tgtPatch",
false,
tgtPatch.localPoints(),
labelList(),
labelListList(),
tgtPatch.localFaces(),
"coverage", false, tgtCoverage
);
}
}
return nCouples;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::patchToPatches::intersection::intersection(const bool reverse)
:
patchToPatch(reverse),
srcCouples_(),
srcEdgeParts_(),
srcErrorParts_(),
tgtCouples_(),
triEngine_(),
srcTriPoints_(),
srcTriFaceEdges_(),
tgtTriPoints_(),
tgtTriFaceEdges_(),
ictSrcPoints_(),
ictSrcPointNormals_(),
ictTgtPoints_(),
ictPointLocations_(),
srcFaceEdgePart_(),
tgtFaceEdgePart_(),
srcFaceEdgeParts_(),
debugPoints_(),
debugFaces_(),
debugFaceSrcFaces_(),
debugFaceTgtFaces_(),
debugFaceSides_()
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::patchToPatches::intersection::~intersection()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::intersection::srcWeights
(
const primitivePatch& srcPatch
) const
{
List<DynamicList<scalar>> result(srcCouples_.size());
forAll(srcCouples_, srcFacei)
{
result[srcFacei].resize(srcCouples_[srcFacei].size());
const scalar magA = mag(srcPatch.faceAreas()[srcFacei]);
forAll(srcCouples_[srcFacei], i)
{
result[srcFacei][i] = mag(srcCouples_[srcFacei][i].area)/magA;
}
}
return result;
}
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::intersection::tgtWeights
(
const primitivePatch& tgtPatch
) const
{
List<DynamicList<scalar>> result(tgtCouples_.size());
forAll(tgtCouples_, tgtFacei)
{
result[tgtFacei].resize(tgtCouples_[tgtFacei].size());
const scalar magA = mag(tgtPatch.faceAreas()[tgtFacei]);
forAll(tgtCouples_[tgtFacei], i)
{
result[tgtFacei][i] = mag(tgtCouples_[tgtFacei][i].area)/magA;
}
}
return result;
}
// ************************************************************************* //

View File

@ -0,0 +1,424 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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::patchToPatches::intersection
Description
Class to generate patchToPatch coupling geometry. A full geometric
intersection is done between a face and those opposite, and coupling
geometry is calculated accordingly.
SourceFiles
intersection.C
\*---------------------------------------------------------------------------*/
#ifndef intersectionPatchToPatch_H
#define intersectionPatchToPatch_H
#include "patchToPatch.H"
#include "polygonTriangulate.H"
#include "triFaceList.H"
#include "triIntersectLocation.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
/*---------------------------------------------------------------------------*\
Class intersection Declaration
\*---------------------------------------------------------------------------*/
class intersection
:
public patchToPatch
{
public:
// Public Structures
//- Structure to store the geometry associated with part of a patch
// face
struct part
{
//- The area of this part
vector area;
//- The centre of this part
point centre;
//- Default construct
part()
:
area(Zero),
centre(point::uniform(NaN))
{}
//- Default construct
part(const zero&)
:
part()
{}
//- Construct from an area and a centre
part(const vector& a, const point& c)
:
area(a),
centre(c)
{}
//- Construct from a polygon
template<class PointField>
part(const PointField& ps)
:
area(face::area(ps)),
centre(face::centre(ps))
{}
//- Negate this part
part operator-() const
{
return part(- area, centre);
}
//- Add another part to this one
void operator+=(const part& p)
{
const scalar magArea = mag(area);
const scalar magPArea = mag(p.area);
area = area + p.area;
centre =
magArea == 0 ? p.centre
: magPArea == 0 ? centre
: (magArea*centre + magPArea*p.centre)/(magArea + magPArea);
}
//- Subtract another part from this one
void operator-=(const part& p)
{
this->operator+=(-p);
}
//- Equality comparison
friend bool operator==(const part& a, const part& b)
{
return a.area == b.area && a.centre == b.centre;
}
//- Inequality comparison
friend bool operator!=(const part& a, const part& b)
{
return !(a == b);
}
//- Output stream operator
friend Ostream& operator<<(Ostream& os, const part& p)
{
return os << p.area << p.centre;
}
//- Input stream operator
friend Istream& operator>>(Istream& is, part& p)
{
return is >> p.area >> p.centre;
}
};
//- Structure to store the geometry associated with the coupling
// between parts of two patch faces
struct couple
:
public part
{
//- The neighbour part
part nbr;
//- Default construct
couple()
:
part(),
nbr()
{}
//- Construct from a coupled pair of parts
couple(const part& p, const part& nbrP)
:
part(p),
nbr(nbrP)
{}
//- Equality comparison
friend bool operator==(const couple& a, const couple& b)
{
return
static_cast<const part&>(a) == static_cast<const part&>(b)
&& a.nbr == b.nbr;
}
//- Inequality comparison
friend bool operator!=(const couple& a, const couple& b)
{
return !(a == b);
}
//- Output stream operator
friend Ostream& operator<<(Ostream& os, const couple& c)
{
return os << static_cast<const part&>(c) << c.nbr;
}
//- Input stream operator
friend Istream& operator>>(Istream& is, couple& c)
{
return is >> static_cast<part&>(c) >> c.nbr;
}
};
private:
// Private Member Data
// Geometry
//- The coupling geometry for for each source face
List<DynamicList<couple>> srcCouples_;
//- The non-coupled geometry associated with each source edge
List<part> srcEdgeParts_;
//- The non-coupled geometry associated with mismatch in each
// source face's couplings
List<part> srcErrorParts_;
//- The coupling geometry for for each target face
List<DynamicList<couple>> tgtCouples_;
//- Triangulation engine
mutable polygonTriangulate triEngine_;
// Workspace
//- Source face triangulation points
mutable List<triFaceList> srcTriPoints_;
//- Source face triangulation edges
mutable List<List<FixedList<label, 3>>> srcTriFaceEdges_;
//- Target face triangulation points
mutable List<triFaceList> tgtTriPoints_;
//- Target face triangulation edges
mutable List<List<FixedList<label, 3>>> tgtTriFaceEdges_;
//- Source intersection points
mutable DynamicList<point> ictSrcPoints_;
//- Source intersection point normals
mutable DynamicList<vector> ictSrcPointNormals_;
//- Target intersection points
mutable DynamicList<point> ictTgtPoints_;
//- Intersection locations
mutable DynamicList<triIntersect::location> ictPointLocations_;
//- Source face edge parts
DynamicList<part> srcFaceEdgePart_;
//- Target face edge parts
DynamicList<part> tgtFaceEdgePart_;
//- Source face edge parts
List<List<part>> srcFaceEdgeParts_;
// Debugging
//- Intersection points
mutable DynamicList<point> debugPoints_;
//- Intersection faces
mutable DynamicList<labelList> debugFaces_;
//- The source face associated with each intersection face
mutable DynamicList<label> debugFaceSrcFaces_;
//- The target face associated with each intersection face
mutable DynamicList<label> debugFaceTgtFaces_;
//- The side of the intersection each face is on; 1 is the source
// side, -1 is the target side, and 0 is a face that spans the
// intersection volume; e.g., an edge or error face.
mutable DynamicList<label> debugFaceSides_;
// Private Static Member Functions
//- Return the values at the points of a tri face
template<class Type>
static FixedList<Type, 3> triPointValues
(
const triFace& t,
const UList<Type>& values
);
// Private Member Functions
//- Get the bound box for a source face
virtual treeBoundBox srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const;
//- Intersect two faces
virtual bool intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
);
//- Initialise the workspace
virtual void initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
);
//- Send data that resulted from an intersection between the source
// patch and a distributed source-local-target patch back to the
// original target processes.
virtual void rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
);
//- Finalise the intersection
virtual label finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
);
public:
//- Runtime type information
TypeName("intersection");
// Static Data Members
//- Extra debugging for intersections between specific faces. Named
// "intersectionSrcFace" and "intersectionTgtFace" respectively.
static int debugSrcFacei, debugTgtFacei;
// Static Member Functions
//- Get the bound box for a source face
static treeBoundBox srcBoxStatic
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
);
// Constructors
//- Construct from components
intersection(const bool reverse);
//- Destructor
~intersection();
// Member Functions
//- For each source face, the source and target areas for each
// target coupling
inline const List<DynamicList<couple>>& srcCouples() const;
//- For each source edge, the non-coupled geometry associated
// with its projection
inline const List<part>& srcEdgeParts() const;
//- For each source face, the area associated with mismatch
// across the coupling
inline const List<part>& srcErrorParts() const;
//- For each target face, the target and source areas for each
// source coupling
inline const List<DynamicList<couple>>& tgtCouples() const;
//- For each source face, the coupled target weights
virtual tmpNrc<List<DynamicList<scalar>>> srcWeights
(
const primitivePatch& srcPatch
) const;
//- For each target face, the coupled source weights
virtual tmpNrc<List<DynamicList<scalar>>> tgtWeights
(
const primitivePatch& tgtPatch
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace patchToPatches
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "intersectionPatchToPatchI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,60 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ 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 "intersectionPatchToPatch.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline const
Foam::List<Foam::DynamicList<Foam::patchToPatches::intersection::couple>>&
Foam::patchToPatches::intersection::srcCouples() const
{
return srcCouples_;
}
inline const Foam::List<Foam::patchToPatches::intersection::part>&
Foam::patchToPatches::intersection::srcEdgeParts() const
{
return srcEdgeParts_;
}
inline const Foam::List<Foam::patchToPatches::intersection::part>&
Foam::patchToPatches::intersection::srcErrorParts() const
{
return srcErrorParts_;
}
inline const
Foam::List<Foam::DynamicList<Foam::patchToPatches::intersection::couple>>&
Foam::patchToPatches::intersection::tgtCouples() const
{
return tgtCouples_;
}
// ************************************************************************* //

View File

@ -0,0 +1,284 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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 "inverseDistancePatchToPatch.H"
#include "mathematicalConstants.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
defineTypeNameAndDebug(inverseDistance, 0);
addToRunTimeSelectionTable(patchToPatch, inverseDistance, bool);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::treeBoundBox Foam::patchToPatches::inverseDistance::srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const
{
const treeBoundBox bb(srcPoints, srcFace);
const point c = bb.midpoint();
const scalar l = bb.maxDim();
return treeBoundBox(c - l*vector::one, c + l*vector::one);
}
bool Foam::patchToPatches::inverseDistance::inside
(
const face& f,
const pointField& ps,
const point& p,
const vector& r
) const
{
using namespace constant::mathematical;
const tensor T = tensor::I - sqr(r);
scalar angle = 0;
forAll(f, i)
{
const vector& a = T & (ps[f[i]] - p);
const vector& b = T & (ps[f[f.fcIndex(i)]] - p);
const scalar magAB = sqrt(magSqr(a)*magSqr(b));
angle -= sign(r & (a ^ b))*acos((a & b)/magAB);
}
return pi < angle && angle < 3*pi;
}
bool Foam::patchToPatches::inverseDistance::intersectFaces
(
const primitivePatch& patch,
const primitivePatch& otherPatch,
const label facei,
const label otherFacei,
DynamicList<label>& faceOtherFaces,
DynamicList<scalar>& faceWeights
) const
{
const face& f = otherPatch[otherFacei];
const pointField& ps = otherPatch.points();
const point& p = patch.faceCentres()[facei];
const vector& r = patch.faceNormals()[facei];
bool intersectsOther = inside(f, ps, p, r);
if (!intersectsOther)
{
forAll(otherPatch.faceFaces()[otherFacei], otherFaceFacei)
{
const label otherFacej =
otherPatch.faceFaces()[otherFacei][otherFaceFacei];
const face& g = otherPatch[otherFacej];
if (inside(g, ps, p, r))
{
intersectsOther = true;
break;
}
}
}
if (intersectsOther)
{
faceOtherFaces.append(otherFacei);
faceWeights.append
(
1/max(mag(p - otherPatch.faceCentres()[otherFacei]), vSmall)
);
}
return intersectsOther;
}
bool Foam::patchToPatches::inverseDistance::intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
)
{
const bool srcCouples =
intersectFaces
(
srcPatch,
tgtPatch,
srcFacei,
tgtFacei,
srcLocalTgtFaces_[srcFacei],
srcWeights_[srcFacei]
);
const bool tgtCouples =
intersectFaces
(
tgtPatch,
srcPatch,
tgtFacei,
srcFacei,
tgtLocalSrcFaces_[tgtFacei],
tgtWeights_[tgtFacei]
);
return srcCouples || tgtCouples;
}
void Foam::patchToPatches::inverseDistance::initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
)
{
patchToPatch::initialise
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch
);
srcWeights_.resize(srcPatch.size());
tgtWeights_.resize(tgtPatch.size());
}
void Foam::patchToPatches::inverseDistance::rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
)
{
patchToPatch::rDistributeTgt(tgtPatch, tgtMap);
rDistributeListList(tgtPatch.size(), tgtMap, tgtWeights_);
}
Foam::label Foam::patchToPatches::inverseDistance::finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
)
{
const label nCouples =
patchToPatch::finalise
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch,
tgtToSrc
);
forAll(srcWeights_, srcFacei)
{
const scalar w = sum(srcWeights_[srcFacei]);
forAll(srcWeights_[srcFacei], i)
{
srcWeights_[srcFacei][i] /= max(w, vSmall);
}
}
forAll(tgtWeights_, tgtFacei)
{
const scalar w = sum(tgtWeights_[tgtFacei]);
forAll(tgtWeights_[tgtFacei], i)
{
tgtWeights_[tgtFacei][i] /= max(w, vSmall);
}
}
return nCouples;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::patchToPatches::inverseDistance::inverseDistance(const bool reverse)
:
patchToPatch(reverse),
srcWeights_(),
tgtWeights_()
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::patchToPatches::inverseDistance::~inverseDistance()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::inverseDistance::srcWeights
(
const primitivePatch& srcPatch
) const
{
return srcWeights_;
}
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::inverseDistance::tgtWeights
(
const primitivePatch& tgtPatch
) const
{
return tgtWeights_;
}
// ************************************************************************* //

View File

@ -0,0 +1,178 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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::patchToPatches::inverseDistance
Description
Class to generate patchToPatch coupling geometry. Couples a face to the
opposite face onto which its centre-normal ray projects, plus the immediate
neighbours to that opposite face. The proportion of contribution from the
different faces is calculated using inverse distance weighting.
SourceFiles
inverseDistance.C
\*---------------------------------------------------------------------------*/
#ifndef inverseDistancePatchToPatch_H
#define inverseDistancePatchToPatch_H
#include "patchToPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
/*---------------------------------------------------------------------------*\
Class inverseDistance Declaration
\*---------------------------------------------------------------------------*/
class inverseDistance
:
public patchToPatch
{
// Private Member Data
//- For each source face, the coupled target weights
List<DynamicList<scalar>> srcWeights_;
//- For each target face, the coupled source weights
List<DynamicList<scalar>> tgtWeights_;
// Private Member Functions
//- Get the bound box for a source face
virtual treeBoundBox srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const;
//- Return whether or not the face contains a point
bool inside
(
const face& f,
const pointField& ps,
const point& p,
const vector& r
) const;
//- Intersect two faces
virtual bool intersectFaces
(
const primitivePatch& patch,
const primitivePatch& otherPatch,
const label facei,
const label otherFacei,
DynamicList<label>& faceOtherFaces,
DynamicList<scalar>& faceWeights
) const;
//- Intersect two faces
virtual bool intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
);
//- Initialisation
virtual void initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
);
//- Send data that resulted from an intersection between the source
// patch and a distributed source-local-target patch back to the
// original target processes.
virtual void rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
);
//- Finalise the intersection
virtual label finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
);
public:
//- Runtime type information
TypeName("inverseDistance");
// Constructors
//- Construct from components
inverseDistance(const bool reverse);
//- Destructor
~inverseDistance();
// Member Functions
//- For each source face, the coupled target weights
virtual tmpNrc<List<DynamicList<scalar>>> srcWeights
(
const primitivePatch& srcPatch
) const;
//- For each target face, the coupled source weights
virtual tmpNrc<List<DynamicList<scalar>>> tgtWeights
(
const primitivePatch& tgtPatch
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace patchToPatches
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,303 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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 "nearestPatchToPatch.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
defineTypeNameAndDebug(nearest, 0);
addToRunTimeSelectionTable(patchToPatch, nearest, bool);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::treeBoundBox Foam::patchToPatches::nearest::srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const
{
const treeBoundBox bb(srcPoints, srcFace);
const point c = bb.midpoint();
const scalar l = bb.maxDim();
return treeBoundBox(c - l*vector::one, c + l*vector::one);
}
bool Foam::patchToPatches::nearest::intersectFaces
(
const primitivePatch& patch,
const primitivePatch& otherPatch,
const label facei,
const label otherFacei,
DynamicList<label>& faceOtherFaces,
scalar& faceDistance
) const
{
auto closest = [&patch,&otherPatch]
(
const label facei,
const label otherFacei
)
{
const point& c = patch.faceCentres()[facei];
const point& otherC = otherPatch.faceCentres()[otherFacei];
const scalar distSqr = magSqr(c - otherC);
forAll(otherPatch.faceEdges()[otherFacei], otherFaceEdgei)
{
const label otherEdgei =
otherPatch.faceEdges()[otherFacei][otherFaceEdgei];
point otherNbrC;
if (otherPatch.edgeFaces()[otherEdgei].size() == 2)
{
const label facej =
otherPatch.edgeFaces()[otherEdgei]
[otherPatch.edgeFaces()[otherEdgei][0] == otherFacei];
otherNbrC = otherPatch.faceCentres()[facej];
}
else
{
const edge& e = otherPatch.edges()[otherEdgei];
const point& p = otherPatch.localPoints()[e[0]];
const vector dp = e.vec(otherPatch.localPoints());
const vector n = otherPatch.faceNormals()[otherFacei] ^ dp;
otherNbrC = p + ((tensor::I - 2*sqr(n)) & (otherC - p));
}
if (magSqr(c - otherNbrC) < distSqr)
{
return false;
}
}
return true;
};
if (closest(facei, otherFacei))
{
const point& c = patch.faceCentres()[facei];
const point& otherC = otherPatch.faceCentres()[otherFacei];
const scalar distSqr = magSqr(c - otherC);
if (faceOtherFaces.empty() || faceDistance > distSqr)
{
faceOtherFaces.clear();
faceOtherFaces.append(otherFacei);
faceDistance = distSqr;
}
return true;
}
const labelList& otherFaceFaces = otherPatch.faceFaces()[otherFacei];
forAll(otherFaceFaces, otherFaceFacei)
{
if (closest(facei, otherFaceFaces[otherFaceFacei]))
{
return true;
}
}
return false;
}
bool Foam::patchToPatches::nearest::intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
)
{
const bool srcCouples =
intersectFaces
(
srcPatch,
tgtPatch,
srcFacei,
tgtFacei,
srcLocalTgtFaces_[srcFacei],
srcDistances_[srcFacei]
);
const bool tgtCouples =
intersectFaces
(
tgtPatch,
srcPatch,
tgtFacei,
srcFacei,
tgtLocalSrcFaces_[tgtFacei],
tgtDistances_[tgtFacei]
);
return srcCouples || tgtCouples;
}
void Foam::patchToPatches::nearest::initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
)
{
patchToPatch::initialise
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch
);
srcDistances_.resize(srcPatch.size());
srcDistances_ = vGreat;
tgtDistances_.resize(tgtPatch.size());
tgtDistances_ = vGreat;
}
void Foam::patchToPatches::nearest::rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
)
{
// Create a list-list of distances to match the addressing
List<List<scalar>> tgtDistances(tgtLocalSrcFaces_.size());
forAll(tgtLocalSrcFaces_, tgtFacei)
{
if (!tgtLocalSrcFaces_[tgtFacei].empty())
{
tgtDistances[tgtFacei].resize(1, tgtDistances_[tgtFacei]);
}
}
// Let the base class reverse distribute the addressing
patchToPatch::rDistributeTgt(tgtPatch, tgtMap);
// Reverse distribute the distances
rDistributeListList(tgtPatch.size(), tgtMap, tgtDistances);
// If there is more than one address, remove all but the closest
forAll(tgtLocalSrcFaces_, tgtFacei)
{
if (tgtLocalSrcFaces_[tgtFacei].size() > 1)
{
const label i = findMin(tgtDistances[tgtFacei]);
const label srcFacei = tgtLocalSrcFaces_[tgtFacei][i];
tgtLocalSrcFaces_[tgtFacei].resize(1);
tgtLocalSrcFaces_[tgtFacei][0] = srcFacei;
tgtDistances_[tgtFacei] = tgtDistances[tgtFacei][i];
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::patchToPatches::nearest::nearest(const bool reverse)
:
patchToPatch(reverse)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::patchToPatches::nearest::~nearest()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::nearest::srcWeights(const primitivePatch& srcPatch) const
{
tmpNrc<List<DynamicList<scalar>>> tResult
(
new List<DynamicList<scalar>>(srcLocalTgtFaces_.size())
);
List<DynamicList<scalar>>& result = tResult.ref();
forAll(srcLocalTgtFaces_, srcFacei)
{
if (!srcLocalTgtFaces_[srcFacei].empty())
{
result[srcFacei].resize(1, scalar(1));
}
}
return tResult;
}
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::nearest::tgtWeights(const primitivePatch& tgtPatch) const
{
tmpNrc<List<DynamicList<scalar>>> tResult
(
new List<DynamicList<scalar>>(tgtLocalSrcFaces_.size())
);
List<DynamicList<scalar>>& result = tResult.ref();
forAll(tgtLocalSrcFaces_, tgtFacei)
{
if (!tgtLocalSrcFaces_[tgtFacei].empty())
{
result[tgtFacei].resize(1, scalar(1));
}
}
return tResult;
}
// ************************************************************************* //

View File

@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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::patchToPatches::nearest
Description
Class to generate patchToPatch coupling geometry. Couples a face to the
single nearest opposite face only.
SourceFiles
nearest.C
\*---------------------------------------------------------------------------*/
#ifndef nearestPatchToPatch_H
#define nearestPatchToPatch_H
#include "patchToPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
/*---------------------------------------------------------------------------*\
Class nearest Declaration
\*---------------------------------------------------------------------------*/
class nearest
:
public patchToPatch
{
// Private Member Data
//- For each source face, the distance to its coupled target face
List<scalar> srcDistances_;
//- For each target face, the distance to its coupled source face
List<scalar> tgtDistances_;
// Private Member Functions
//- Get the bound box for a source face
virtual treeBoundBox srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const;
//- Intersect two faces
bool intersectFaces
(
const primitivePatch& patch,
const primitivePatch& otherPatch,
const label facei,
const label otherFacei,
DynamicList<label>& faceOtherFaces,
scalar& faceDistance
) const;
//- Intersect two faces
virtual bool intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
);
//- Initialisation
virtual void initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
);
//- Send data that resulted from an intersection between the source
// patch and a distributed source-local-target patch back to the
// original target processes.
virtual void rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
);
public:
//- Runtime type information
TypeName("nearest");
// Constructors
//- Construct from components
nearest(const bool reverse);
//- Destructor
~nearest();
// Member Functions
//- For each source face, the coupled target weights
virtual tmpNrc<List<DynamicList<scalar>>> srcWeights
(
const primitivePatch& srcPatch
) const;
//- For each target face, the coupled source weights
virtual tmpNrc<List<DynamicList<scalar>>> tgtWeights
(
const primitivePatch& tgtPatch
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace patchToPatches
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,485 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ 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::patchToPatch
Description
Class to generate coupling geometry between two primitive patches
SourceFiles
patchToPatch.C
patchToPatchParallelOps.C
\*---------------------------------------------------------------------------*/
#ifndef patchToPatch_H
#define patchToPatch_H
#include "distributionMap.H"
#include "primitivePatch.H"
#include "primitiveOldTimePatch.H"
#include "runTimeSelectionTables.H"
#include "treeBoundBox.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class patchToPatch Declaration
\*---------------------------------------------------------------------------*/
class patchToPatch
{
public:
// Public Structures
//- Structure to conveniently store processor and face indices
struct procFace
{
//- The processor index
label proci;
//- The face index
label facei;
//- Equality comparison
friend bool operator==(const procFace& a, const procFace& b)
{
return a.proci == b.proci && a.facei == b.facei;
}
//- Inequality comparison
friend bool operator!=(const procFace& a, const procFace& b)
{
return !(a == b);
}
//- Output stream operator
friend Ostream& operator<<(Ostream& os, const procFace& p)
{
return os << p.proci << token::SPACE << p.facei;
}
//- Input stream operator
friend Istream& operator>>(Istream& is, procFace& p)
{
return is >> p.proci >> p.facei;
}
};
protected:
// Private Data
//- Flag to indicate that the two patches are co-directional and
// that the orientation of one should therefore be reversed
const bool reverse_;
//- Index of the processor holding all faces of the patchToPatch, or -1
// if spread across multiple processors
label singleProcess_;
//- When running in parallel, a map from local source face index to
// source processor and face index
autoPtr<List<procFace>> localSrcProcFacesPtr_;
//- When running in parallel, a map from local target face index to
// target processor and face index
autoPtr<List<procFace>> localTgtProcFacesPtr_;
//- For each source face, the coupled local target faces
List<DynamicList<label>> srcLocalTgtFaces_;
//- For each target face, the coupled local source faces
List<DynamicList<label>> tgtLocalSrcFaces_;
// Private Member Functions
// Indexing
//- Transfer list-list b into list-list a
template<class SubListA, class SubListB>
static inline void transferListList
(
List<SubListA>& a,
List<SubListB>& b
);
//- Reverse distribute a list-list given the map
template<class Type>
static inline void rDistributeListList
(
const label size,
const distributionMap& map,
List<List<Type>>& data
);
//- Reverse distribute a dynamic list-list given the map
template<class Type>
static inline void rDistributeListList
(
const label size,
const distributionMap& map,
List<DynamicList<Type>>& data
);
//- Map local faces to proc faces
static List<List<procFace>> localFacesToProcFaces
(
const List<DynamicList<label>>& localFaces,
const List<procFace>& map = NullObjectRef<List<procFace>>()
);
//- Map proc faces to local faces
static List<DynamicList<label>> procFacesToLocalFaces
(
const List<List<procFace>>& procFaces,
const HashTable<label, procFace, Hash<procFace>>& map
);
// Searching
//- Get the bound box for a source face
virtual treeBoundBox srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const = 0;
//- Get the bound box for a source face
treeBoundBox srcBox
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const label srcFacei
) const;
//- Get the bound box for the source patch
treeBoundBox srcBox
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0
) const;
//- Get the bound box for a target face
treeBoundBox tgtBox
(
const primitiveOldTimePatch& tgtPatch,
const label tgtFacei
) const;
//- Get the bound box for the target patch
treeBoundBox tgtBox
(
const primitiveOldTimePatch& tgtPatch
) const;
// Intersection
//- Intersect two faces
virtual bool intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
) = 0;
//- Intersect two faces
bool findOrIntersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
);
//- Intersect a queue of source-target face pairs. Update completion
// lists and form a new queue of target-source face pairs.
label intersectPatchQueue
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const bool isSrc,
const DynamicList<labelPair>& queue,
labelList& faceComplete,
DynamicList<labelPair>& otherQueue,
const labelList& otherFaceComplete,
boolList& otherFaceQueued,
boolList& otherFaceVisited
);
//- Intersect the patches
void intersectPatches
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
);
// Parallel functionality
//- Determine whether or not the intersection of the given patches
// is on a single process. Set singleProcess_ to that process if
// so, and to -1 if not.
void calcSingleProcess
(
const primitiveOldTimePatch& srcPatch,
const primitiveOldTimePatch& tgtPatch
);
//- Determine which target faces need to be sent to the source.
// This is done before intersection. Bound boxes are used to
// estimate what faces will intersect.
labelListList tgtPatchSendFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
) const;
//- Determine which source faces need to be sent to the target.
// This is done after intersection, using the addressing generated
// by the intersection.
labelListList srcPatchSendFaces() const;
//- Create a distribution map from a list-list of faces to be sent
// (i.e., the result of calling one of the above methods).
distributionMap patchDistributionMap
(
labelListList&& sendFaces
) const;
//- Distribute a patch given its distribution map. Just generate
// local-proc-face addressing; not the distributed patch itself.
void distributePatch
(
const distributionMap& map,
List<procFace>& localProcFaces
) const;
//- Distribute a patch given its distribution map
PrimitiveOldTimePatch<faceList, pointField> distributePatch
(
const distributionMap& map,
const primitiveOldTimePatch& patch,
List<procFace>& localProcFaces
) const;
// Hooks
//- Initialisation
virtual void initialise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
);
//- Distribute the target patch so that enough is locally available
// for its intersection with the source patch can be computed.
// Happens before intersection. Bound boxes are used to determine
// what is needed where. Return the resulting local patch and the
// map from which it was calculated.
virtual
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
distributeTgt
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
distributionMap& tgtMap
);
//- Distribute the source patch so that everything the target
// intersects is locally available. Happens after intersection.
// The intersection addressing is used to determine what is needed
// where. Return the resulting local patch and the map from which
// it was calculated.
virtual
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
distributeSrc
(
const primitiveOldTimePatch& srcPatch,
distributionMap& srcMap
);
//- Send data that resulted from an intersection between the source
// patch and a distributed source-local-target patch back to the
// original target processes.
virtual void rDistributeTgt
(
const primitiveOldTimePatch& tgtPatch,
const distributionMap& tgtMap
);
//- Finalising
virtual label finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
);
public:
//- Runtime type information
TypeName("patchToPatch");
//- Declare runtime constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
patchToPatch,
bool,
(const bool reverse),
(reverse)
);
// Constructors
//- Construct from components
patchToPatch(const bool reverse);
//- Disallow default bitwise copy construction
patchToPatch(const patchToPatch&) = delete;
//- Destructor
virtual ~patchToPatch();
// Selector
//- Select from name
static autoPtr<patchToPatch> New
(
const word& patchToPatchType,
const bool reverse
);
// Member Functions
// Access
//- Flag to indicate that the two patches are co-directional and
// that the orientation of one should therefore be reversed
inline bool reverse() const;
//- Index of the processor holding all faces of the patchToPatch,
// or -1 if spread across multiple processors
inline label singleProcess() const;
//- Is this intersection on a single process?
inline bool isSingleProcess() const;
//- For each source face, the coupled target procs and faces
inline List<List<procFace>> srcTgtProcFaces() const;
//- For each target face, the coupled source procs and faces
inline List<List<procFace>> tgtSrcProcFaces() const;
//- For each source face, the coupled target weights
virtual tmpNrc<List<DynamicList<scalar>>> srcWeights
(
const primitivePatch& srcPatch
) const = 0;
//- For each target face, the coupled source weights
virtual tmpNrc<List<DynamicList<scalar>>> tgtWeights
(
const primitivePatch& tgtPatch
) const = 0;
// Manipulation
//- Update addressing and weights for the given patches
void update
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc = NullObjectRef<transformer>()
);
//- Update addressing and weights for the given patches
void update
(
const primitivePatch& srcPatch,
const vectorField& srcPointNormals,
const primitivePatch& tgtPatch,
const transformer& tgtToSrc = NullObjectRef<transformer>()
);
// Member Operators
//- Disallow default bitwise assignment
void operator=(const patchToPatch&) = delete;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "patchToPatchI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,125 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ 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 "patchToPatch.H"
// * * * * * * * * * * * Private Static Member Functions * * * * * * * * * * //
template<class SubListA, class SubListB>
inline void Foam::patchToPatch::transferListList
(
List<SubListA>& a,
List<SubListB>& b
)
{
a.resize(b.size());
forAll(a, i)
{
a[i].transfer(b[i]);
}
}
template<class Type>
inline void Foam::patchToPatch::rDistributeListList
(
const label size,
const distributionMap& map,
List<List<Type>>& data
)
{
distributionMapBase::distribute
(
Pstream::commsTypes::nonBlocking,
List<labelPair>(),
size,
map.constructMap(),
false,
map.subMap(),
false,
data,
ListAppendEqOp<Type>(),
flipOp(),
List<Type>()
);
}
template<class Type>
inline void Foam::patchToPatch::rDistributeListList
(
const label size,
const distributionMap& map,
List<DynamicList<Type>>& data
)
{
List<List<Type>> tData;
transferListList(tData, data);
rDistributeListList(size, map, tData);
transferListList(data, tData);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool Foam::patchToPatch::reverse() const
{
return reverse_;
}
inline Foam::label Foam::patchToPatch::singleProcess() const
{
return singleProcess_;
}
inline bool Foam::patchToPatch::isSingleProcess() const
{
return singleProcess_ != -1;
}
inline Foam::List<Foam::List<Foam::patchToPatch::procFace>>
Foam::patchToPatch::srcTgtProcFaces() const
{
return
isSingleProcess()
? localFacesToProcFaces(srcLocalTgtFaces_)
: localFacesToProcFaces(srcLocalTgtFaces_, localTgtProcFacesPtr_());
}
inline Foam::List<Foam::List<Foam::patchToPatch::procFace>>
Foam::patchToPatch::tgtSrcProcFaces() const
{
return
isSingleProcess()
? localFacesToProcFaces(tgtLocalSrcFaces_)
: localFacesToProcFaces(tgtLocalSrcFaces_, localSrcProcFacesPtr_());
}
// ************************************************************************* //

View File

@ -0,0 +1,469 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
\\/ 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 "patchToPatch.H"
#include "treeBoundBoxList.H"
#include "uindirectPrimitivePatch.H"
#include "uindirectPrimitiveOldTimePatch.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::patchToPatch::calcSingleProcess
(
const primitiveOldTimePatch& srcPatch,
const primitiveOldTimePatch& tgtPatch
)
{
singleProcess_ = 0;
if (Pstream::parRun())
{
boolList procHasFaces(Pstream::nProcs(), false);
if ((srcPatch.size() > 0) || (tgtPatch.size() > 0))
{
procHasFaces[Pstream::myProcNo()] = true;
}
Pstream::gatherList(procHasFaces);
Pstream::scatterList(procHasFaces);
const label nProcsHaveFaces = count(procHasFaces, true);
if (nProcsHaveFaces == 0)
{
singleProcess_ = 0;
}
if (nProcsHaveFaces == 1)
{
singleProcess_ = findIndex(procHasFaces, true);
}
if (nProcsHaveFaces > 1)
{
singleProcess_ = -1;
}
}
}
Foam::labelListList Foam::patchToPatch::tgtPatchSendFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch
) const
{
// Get the bound boxes for the source patch. Just a single box for now.
List<treeBoundBoxList> srcPatchProcBbs(Pstream::nProcs());
if (srcPatch.size())
{
srcPatchProcBbs[Pstream::myProcNo()] =
treeBoundBoxList
(
1,
srcBox(srcPatch, srcPointNormals, srcPointNormals0)
);
}
else
{
srcPatchProcBbs[Pstream::myProcNo()] = treeBoundBoxList();
}
// Distribute the boxes
Pstream::gatherList(srcPatchProcBbs);
Pstream::scatterList(srcPatchProcBbs);
// Send a target face to a process if it overlaps the source patch box
// for that process
List<DynamicList<label>> resultDyn(Pstream::nProcs());
forAll(tgtPatch, tgtFacei)
{
const treeBoundBox tgtFaceBb = tgtBox(tgtPatch, tgtFacei);
forAll(srcPatchProcBbs, proci)
{
forAll(srcPatchProcBbs[proci], bbi)
{
if (srcPatchProcBbs[proci][bbi].overlaps(tgtFaceBb))
{
resultDyn[proci].append(tgtFacei);
break;
}
}
}
}
// Transfer to non-dynamic storage
labelListList result(Pstream::nProcs());
forAll(result, proci)
{
result[proci].transfer(resultDyn[proci]);
}
return result;
}
Foam::labelListList Foam::patchToPatch::srcPatchSendFaces() const
{
// Send a source face to a proc if target face on that proc intersects it
List<labelHashSet> resultDyn(Pstream::nProcs());
forAll(tgtLocalSrcFaces_, tgtFacei)
{
const label tgtProci = localTgtProcFacesPtr_()[tgtFacei].proci;
forAll(tgtLocalSrcFaces_[tgtFacei], i)
{
const label srcFacei = tgtLocalSrcFaces_[tgtFacei][i];
resultDyn[tgtProci].insert(srcFacei);
}
}
// Transfer to non-dynamic storage
labelListList result(Pstream::nProcs());
forAll(result, proci)
{
result[proci] = resultDyn[proci].toc();
}
return result;
}
Foam::distributionMap Foam::patchToPatch::patchDistributionMap
(
labelListList&& sendFaces
) const
{
// Figure out how many target faces are to be received
labelList nReceiveFaces(Pstream::nProcs());
{
labelListList nSendFaces(Pstream::nProcs());
nSendFaces[Pstream::myProcNo()].setSize(Pstream::nProcs());
forAll(sendFaces, proci)
{
nSendFaces[Pstream::myProcNo()][proci] =
sendFaces[proci].size();
}
Pstream::gatherList(nSendFaces);
Pstream::scatterList(nSendFaces);
forAll(sendFaces, proci)
{
nReceiveFaces[proci] =
nSendFaces[proci][Pstream::myProcNo()];
}
}
// Determine order of receiving
labelListList receiveFaces(Pstream::nProcs());
// Local faces first
receiveFaces[Pstream::myProcNo()] =
identity(sendFaces[Pstream::myProcNo()].size());
// Remote faces next
label localFacei = receiveFaces[Pstream::myProcNo()].size();
forAll(receiveFaces, proci)
{
if (proci != Pstream::myProcNo())
{
const label n = nReceiveFaces[proci];
receiveFaces[proci].setSize(n);
for (label i = 0; i < n; i ++)
{
receiveFaces[proci][i] = localFacei ++;
}
}
}
// Construct and return the map
return
distributionMap
(
localFacei,
move(sendFaces),
move(receiveFaces)
);
}
void Foam::patchToPatch::distributePatch
(
const distributionMap& map,
List<procFace>& localProcFaces
) const
{
static const label thisProci = Pstream::myProcNo();
// Exchange per-processor data
List<labelList> procLocalFaceis(Pstream::nProcs());
{
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send
for (label proci = 0; proci < Pstream::nProcs(); proci++)
{
const labelList& sendFaces = map.subMap()[proci];
if (proci != thisProci && sendFaces.size())
{
UOPstream(proci, pBufs)() << sendFaces;
}
}
pBufs.finishedSends();
// Map local data
{
const labelList& sendFaces = map.subMap()[thisProci];
procLocalFaceis[thisProci] = sendFaces;
}
// Receive remote data
for (label proci = 0; proci < Pstream::nProcs(); proci++)
{
const labelList& receiveNewFaces = map.constructMap()[proci];
if (proci != thisProci && receiveNewFaces.size())
{
UIPstream(proci, pBufs)() >> procLocalFaceis[proci];
}
}
}
// Allocate
{
label nLocalFaces = 0;
forAll(procLocalFaceis, proci)
{
nLocalFaces += procLocalFaceis[proci].size();
}
localProcFaces.setSize(nLocalFaces);
}
// Renumber and flatten
label localTgtFacei = 0;
// Local data first
{
const labelList& fis = procLocalFaceis[thisProci];
forAll(fis, i)
{
localProcFaces[localTgtFacei] = {thisProci, fis[i]};
localTgtFacei ++;
}
}
// Remote data after
forAll(procLocalFaceis, proci)
{
if (proci != thisProci)
{
const labelList& fis = procLocalFaceis[proci];
forAll(fis, i)
{
localProcFaces[localTgtFacei] = {proci, fis[i]};
localTgtFacei ++;
}
}
}
}
Foam::PrimitiveOldTimePatch<Foam::faceList, Foam::pointField>
Foam::patchToPatch::distributePatch
(
const distributionMap& map,
const primitiveOldTimePatch& patch,
List<procFace>& localProcFaces
) const
{
static const label thisProci = Pstream::myProcNo();
// Exchange per-processor data
List<labelList> procLocalFaceis(Pstream::nProcs());
List<faceList> procLocalFaces(Pstream::nProcs());
List<pointField> procLocalPoints(Pstream::nProcs());
List<pointField> procLocalPoints0(Pstream::nProcs());
{
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
// Send
for (label proci = 0; proci < Pstream::nProcs(); proci++)
{
const labelList& sendTgtFaces = map.subMap()[proci];
if (proci != thisProci && sendTgtFaces.size())
{
uindirectPrimitiveOldTimePatch subPatch
(
UIndirectList<face>(patch, sendTgtFaces),
patch.points(),
patch.points0()
);
UOPstream(proci, pBufs)()
<< sendTgtFaces
<< subPatch.localFaces()
<< subPatch.localPoints()
<< (patch.has0() ? subPatch.localPoints0() : pointField());
}
}
pBufs.finishedSends();
// Map local data
{
const labelList& sendTgtFaces = map.subMap()[thisProci];
uindirectPrimitiveOldTimePatch subPatch
(
UIndirectList<face>(patch, sendTgtFaces),
patch.points(),
patch.points0()
);
procLocalFaceis[thisProci] = sendTgtFaces;
procLocalFaces[thisProci] = subPatch.localFaces();
procLocalPoints[thisProci] = subPatch.localPoints();
if (patch.has0())
{
procLocalPoints0[thisProci] = subPatch.localPoints0();
}
}
// Receive remote data
for (label proci = 0; proci < Pstream::nProcs(); proci++)
{
const labelList& receiveNewTgtFaces = map.constructMap()[proci];
if (proci != thisProci && receiveNewTgtFaces.size())
{
UIPstream(proci, pBufs)()
>> procLocalFaceis[proci]
>> procLocalFaces[proci]
>> procLocalPoints[proci]
>> procLocalPoints0[proci];
}
}
}
// Allocate
faceList localTgtFaces;
pointField localTgtPoints;
pointField localTgtPoints0;
{
label nLocalFaces = 0, nLocalPoints = 0;
forAll(procLocalFaceis, proci)
{
nLocalFaces += procLocalFaces[proci].size();
nLocalPoints += procLocalPoints[proci].size();
}
localProcFaces.setSize(nLocalFaces);
localTgtFaces.setSize(nLocalFaces);
localTgtPoints.setSize(nLocalPoints);
if (patch.has0())
{
localTgtPoints0.setSize(nLocalPoints);
}
}
// Renumber and flatten
label localTgtFacei = 0, localTgtPointi = 0;
// Local data first
{
const labelList& fis = procLocalFaceis[thisProci];
const faceList& fs = procLocalFaces[thisProci];
forAll(fis, i)
{
localProcFaces[localTgtFacei] = {thisProci, fis[i]};
localTgtFaces[localTgtFacei] = face(fs[i] + localTgtPointi);
localTgtFacei ++;
}
const pointField& ps = procLocalPoints[thisProci];
const pointField& ps0 = procLocalPoints0[thisProci];
forAll(ps, i)
{
localTgtPoints[localTgtPointi] = ps[i];
if (patch.has0())
{
localTgtPoints0[localTgtPointi] = ps0[i];
}
localTgtPointi ++;
}
}
// Remote data after
forAll(procLocalFaces, proci)
{
if (proci != thisProci)
{
const labelList& fis = procLocalFaceis[proci];
const faceList& fs = procLocalFaces[proci];
forAll(fis, i)
{
localProcFaces[localTgtFacei] = {proci, fis[i]};
localTgtFaces[localTgtFacei] = face(fs[i] + localTgtPointi);
localTgtFacei ++;
}
const pointField& ps = procLocalPoints[proci];
const pointField& ps0 = procLocalPoints0[proci];
forAll(ps, i)
{
localTgtPoints[localTgtPointi] = ps[i];
if (patch.has0())
{
localTgtPoints0[localTgtPointi] = ps0[i];
}
localTgtPointi ++;
}
}
}
return
patch.has0()
? PrimitiveOldTimePatch<faceList, pointField>
(
localTgtFaces,
localTgtPoints,
localTgtPoints0
)
: PrimitiveOldTimePatch<faceList, pointField>
(
localTgtFaces,
localTgtPoints
);
}
// ************************************************************************* //

View File

@ -0,0 +1,332 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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 "raysPatchToPatch.H"
#include "intersectionPatchToPatch.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
defineTypeNameAndDebug(rays, 0);
addToRunTimeSelectionTable(patchToPatch, rays, bool);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::treeBoundBox Foam::patchToPatches::rays::srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const
{
return intersection::srcBoxStatic(srcFace, srcPoints, srcPointNormals);
}
bool Foam::patchToPatches::rays::intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
)
{
const treeBoundBox srcFaceBox =
patchToPatch::srcBox
(
srcPatch,
srcPointNormals,
srcPointNormals0,
srcFacei
);
const treeBoundBox tgtFaceBox =
patchToPatch::tgtBox(tgtPatch, tgtFacei);
if (srcFaceBox.overlaps(tgtFaceBox))
{
srcLocalTgtFaces_[srcFacei].append(tgtFacei);
tgtLocalSrcFaces_[tgtFacei].append(srcFacei);
return true;
}
else
{
return false;
}
}
Foam::tmpNrc<Foam::PrimitiveOldTimePatch<Foam::faceList, Foam::pointField>>
Foam::patchToPatches::rays::distributeTgt
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
distributionMap& tgtMap
)
{
// Intercept generation of the local patch. Store it. Return a const
// reference tmp instead of a pointer.
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>> localTgtPatchPtr =
patchToPatch::distributeTgt
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch,
tgtMap
);
localTgtPatchPtr_.reset(localTgtPatchPtr.ptr());
return
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
(
localTgtPatchPtr_()
);
}
Foam::tmpNrc<Foam::PrimitiveOldTimePatch<Foam::faceList, Foam::pointField>>
Foam::patchToPatches::rays::distributeSrc
(
const primitiveOldTimePatch& srcPatch,
distributionMap& srcMap
)
{
// Intercept generation of the local patch. Store it. Return a const
// reference tmp instead of a pointer.
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>> localSrcPatchPtr =
patchToPatch::distributeSrc(srcPatch, srcMap);
localSrcPatchPtr_.reset(localSrcPatchPtr.ptr());
return
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
(
localSrcPatchPtr_()
);
}
Foam::label Foam::patchToPatches::rays::finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
)
{
const label nCouples =
patchToPatch::finalise
(
srcPatch,
srcPointNormals,
srcPointNormals0,
tgtPatch,
tgtToSrc
);
// Transform the source-local target patch back to the target
if (!isSingleProcess() && !isNull(tgtToSrc))
{
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>
localTgtPatchPtr(localTgtPatchPtr_.ptr());
localTgtPatchPtr_.set
(
new PrimitiveOldTimePatch<faceList, pointField>
(
localTgtPatchPtr(),
tgtToSrc.invTransformPosition(localTgtPatchPtr().points()),
isNull(localTgtPatchPtr().points0())
? NullObjectRef<pointField>()
: tgtToSrc.invTransformPosition(localTgtPatchPtr().points0())()
)
);
}
return nCouples;
}
Foam::patchToPatch::procFace Foam::patchToPatches::rays::ray
(
const primitiveOldTimePatch& outPatch,
const autoPtr<PrimitiveOldTimePatch<faceList, pointField>>&
localOutPatchPtr,
const autoPtr<List<procFace>>& localOutProcFacesPtr,
const List<DynamicList<label>>& inLocalOutFaces,
const scalar fraction,
const label inFacei,
const point& inP,
const vector& inN,
point& outP
) const
{
forAll(inLocalOutFaces[inFacei], i)
{
const label localOutFacei = inLocalOutFaces[inFacei][i];
const face& outF =
isSingleProcess()
? outPatch[localOutFacei]
: localOutPatchPtr()[localOutFacei];
const pointField& outPoints =
isSingleProcess()
? outPatch.points()
: localOutPatchPtr().points();
const pointField& outPoints0 =
isSingleProcess()
? outPatch.points0()
: localOutPatchPtr().points0();
const pointField outPoly
(
(1 - fraction)*outF.points(outPoints0)
+ fraction*outF.points(outPoints)
);
const pointHit ray =
face(identity(outPoly.size()))
.ray(inP, inN, outPoly, Foam::intersection::algorithm::visible);
if (ray.hit())
{
outP = ray.rawPoint();
return
isSingleProcess()
? procFace({Pstream::myProcNo(), localOutFacei})
: localOutProcFacesPtr()[localOutFacei];
}
}
return procFace({-1, -1});
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::patchToPatches::rays::rays
(
const bool reverse
)
:
patchToPatch(reverse)
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::patchToPatches::rays::~rays()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::rays::srcWeights(const primitivePatch& srcPatch) const
{
NotImplemented;
return tmpNrc<List<DynamicList<scalar>>>(nullptr);
}
Foam::tmpNrc<Foam::List<Foam::DynamicList<Foam::scalar>>>
Foam::patchToPatches::rays::tgtWeights(const primitivePatch& tgtPatch) const
{
NotImplemented;
return tmpNrc<List<DynamicList<scalar>>>(nullptr);
}
Foam::patchToPatch::procFace Foam::patchToPatches::rays::srcToTgtRay
(
const primitiveOldTimePatch& tgtPatch,
const scalar fraction,
const label srcFacei,
const vector& srcP,
const vector& srcN,
point& tgtP
) const
{
return
ray
(
tgtPatch,
localTgtPatchPtr_,
localTgtProcFacesPtr_,
srcLocalTgtFaces_,
fraction,
srcFacei,
srcP,
srcN,
tgtP
);
}
Foam::patchToPatch::procFace Foam::patchToPatches::rays::tgtToSrcRay
(
const primitiveOldTimePatch& srcPatch,
const scalar fraction,
const label tgtFacei,
const vector& tgtP,
const vector& tgtN,
point& srcP
) const
{
return
ray
(
srcPatch,
localSrcPatchPtr_,
localSrcProcFacesPtr_,
tgtLocalSrcFaces_,
fraction,
tgtFacei,
tgtP,
tgtN,
srcP
);
}
// ************************************************************************* //

View File

@ -0,0 +1,204 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2021-2022 OpenFOAM Foundation
\\/ 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::patchToPatches::intersection
Description
Class to generate patchToPatch coupling geometry. Coupling is determined by
means of comparing the bound boxes generated by the intersection method.
This generates an outer "envelope" of possible intersections that can be
used for ray shooting and Lagrangian transfer.
SourceFiles
rays.C
\*---------------------------------------------------------------------------*/
#ifndef raysPatchToPatch_H
#define raysPatchToPatch_H
#include "patchToPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace patchToPatches
{
/*---------------------------------------------------------------------------*\
Class rays Declaration
\*---------------------------------------------------------------------------*/
class rays
:
public patchToPatch
{
// Private Data
// Parallel
//- Cache of the part of the source patch local to the target
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>
localSrcPatchPtr_;
//- Cache of the part of the target patch local to the source
autoPtr<PrimitiveOldTimePatch<faceList, pointField>>
localTgtPatchPtr_;
// Private Member Functions
//- Get the bound box for a source face
virtual treeBoundBox srcBox
(
const face& srcFace,
const pointField& srcPoints,
const vectorField& srcPointNormals
) const;
//- Intersect two faces
virtual bool intersectFaces
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const label srcFacei,
const label tgtFacei
);
//- Distribute the target patch so that enough is locally available
// for its intersection with the source patch can be computed
virtual
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
distributeTgt
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
distributionMap& tgtMap
);
//- Distribute the source patch so that everything the target
// intersects is locally available. Happens after intersection.
virtual
tmpNrc<PrimitiveOldTimePatch<faceList, pointField>>
distributeSrc
(
const primitiveOldTimePatch& srcPatch,
distributionMap& srcMap
);
//- Finalising
virtual label finalise
(
const primitiveOldTimePatch& srcPatch,
const vectorField& srcPointNormals,
const vectorField& srcPointNormals0,
const primitiveOldTimePatch& tgtPatch,
const transformer& tgtToSrc
);
//- Compute a ray intersection
procFace ray
(
const primitiveOldTimePatch& outPatch,
const autoPtr<PrimitiveOldTimePatch<faceList, pointField>>&
localOutPatchPtr,
const autoPtr<List<procFace>>& localOutProcFacesPtr,
const List<DynamicList<label>>& inLocalOutFacesPtr,
const scalar fraction,
const label inFacei,
const point& inP,
const vector& inN,
point& outP
) const;
public:
//- Runtime type information
TypeName("rays");
// Constructors
//- Construct from components
rays(const bool reverse);
//- Destructor
~rays();
// Member Functions
//- For each source face, the coupled target weights
virtual tmpNrc<List<DynamicList<scalar>>> srcWeights
(
const primitivePatch& srcPatch
) const;
//- For each target face, the coupled source weights
virtual tmpNrc<List<DynamicList<scalar>>> tgtWeights
(
const primitivePatch& tgtPatch
) const;
//- Compute a ray intersection from the source side to the target
procFace srcToTgtRay
(
const primitiveOldTimePatch& tgtPatch,
const scalar fraction,
const label srcFacei,
const vector& srcP,
const vector& srcN,
point& tgtP
) const;
//- Compute a ray intersection from the target side to the source
procFace tgtToSrcRay
(
const primitiveOldTimePatch& srcPatch,
const scalar fraction,
const label tgtFacei,
const vector& tgtP,
const vector& tgtN,
point& srcP
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace patchToPatches
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //