diff --git a/applications/solvers/incompressible/pimpleFoam/pEqn.H b/applications/solvers/incompressible/pimpleFoam/pEqn.H index e3c61fe37da88f90ab2907b813b55dd81eed85ad..8f49f635992f9dcfaf68f1a22ddf78870ad7ccdb 100644 --- a/applications/solvers/incompressible/pimpleFoam/pEqn.H +++ b/applications/solvers/incompressible/pimpleFoam/pEqn.H @@ -1,11 +1,11 @@ volScalarField rAU(1.0/UEqn.A()); volVectorField HbyA(constrainHbyA(rAU*UEqn.H(), U, p)); -surfaceScalarField phiHbyA -( - "phiHbyA", - fvc::flux(HbyA) - + MRF.zeroFilter(fvc::interpolate(rAU)*fvc::ddtCorr(U, phi, Uf)) -); +surfaceScalarField phiHbyA("phiHbyA", fvc::flux(HbyA)); + +if (pimple.ddtCorr()) +{ + phiHbyA += MRF.zeroFilter(fvc::interpolate(rAU)*fvc::ddtCorr(U, phi, Uf)); +} MRF.makeRelative(phiHbyA); diff --git a/applications/utilities/preProcessing/mapFieldsPar/mapFieldsPar.C b/applications/utilities/preProcessing/mapFieldsPar/mapFieldsPar.C index 6c3f66c121d524c7b670dc7283069b1cf924d637..7c6435f1e424cba6338ecc46f94ce734bc2aae68 100644 --- a/applications/utilities/preProcessing/mapFieldsPar/mapFieldsPar.C +++ b/applications/utilities/preProcessing/mapFieldsPar/mapFieldsPar.C @@ -252,11 +252,7 @@ int main(int argc, char *argv[]) meshToMesh::interpolationMethod method = meshToMesh::interpolationMethodNames_[mapMethod]; - patchMapMethod = - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - meshToMesh::interpolationMethodAMI(method) - ]; + patchMapMethod = meshToMesh::interpolationMethodAMI(method); } word procMapMethod = diff --git a/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C b/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C index 80232d4498e081d7e3098538278b994bf3426bc5..e5818171d53ac6f85da1ceb6399a5e40ab79df99 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C +++ b/src/OpenFOAM/meshes/polyMesh/polyMeshUpdate.C @@ -45,6 +45,7 @@ void Foam::polyMesh::updateMesh(const mapPolyMesh& mpm) << "Updating addressing and (optional) pointMesh/pointFields" << endl; // Update boundaryMesh (note that patches themselves already ok) +// boundary_.updateMesh(mpm); boundary_.updateMesh(); // Update zones diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C index 3e915b3e7e6938eb96cbbd47ae49c16b44365b25..6db7dc22fcb8cb648992b24ff9cbfe31edaeb668 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C +++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C @@ -63,6 +63,7 @@ void Foam::polyPatch::movePoints(PstreamBuffers&, const pointField& p) primitivePatch::movePoints(p); } + void Foam::polyPatch::updateMesh(PstreamBuffers&) { primitivePatch::clearGeom(); diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H index 08bbf0c732aa34cc498a86359be0b314378086c6..f7f01abb091986e668a1cf66b95ff9fa121ad05b 100644 --- a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H +++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H @@ -55,6 +55,7 @@ namespace Foam // Forward declarations class polyBoundaryMesh; class polyPatch; +class polyTopoChange; class PstreamBuffers; Ostream& operator<<(Ostream&, const polyPatch&); @@ -419,6 +420,19 @@ public: labelList& rotation ) const; + //- For dynamic mesh cases - return true if this patch will change the + //- topology + virtual bool changeTopology() const + { + return false; + } + + //- Collect topology changes in a polyTopoChange object + virtual bool setTopology(polyTopoChange&) + { + return false; + } + // Member operators diff --git a/src/dynamicFaMesh/interfaceTrackingFvMesh/interfaceTrackingFvMesh.C b/src/dynamicFaMesh/interfaceTrackingFvMesh/interfaceTrackingFvMesh.C index 3a13ad4c5e3a939589eeb3f7e37363191e44205b..51d558a1fb9ae57423cead0c32bf0344fc4632d3 100644 --- a/src/dynamicFaMesh/interfaceTrackingFvMesh/interfaceTrackingFvMesh.C +++ b/src/dynamicFaMesh/interfaceTrackingFvMesh/interfaceTrackingFvMesh.C @@ -47,6 +47,7 @@ License #include "gravityMeshObject.H" #include "turbulentTransportModel.H" #include "demandDrivenData.H" +#include "unitConversion.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // diff --git a/src/dynamicFvMesh/Make/files b/src/dynamicFvMesh/Make/files index b8432c07c905108747f9b94eb4cffefd26d1e0bd..794af6f3d0dd9754f6371c669da5e3c10da2b07d 100644 --- a/src/dynamicFvMesh/Make/files +++ b/src/dynamicFvMesh/Make/files @@ -10,4 +10,9 @@ dynamicMotionSolverListFvMesh/dynamicMotionSolverListFvMesh.C simplifiedDynamicFvMesh/simplifiedDynamicFvMeshes.C simplifiedDynamicFvMesh/simplifiedDynamicFvMesh.C + + +dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.C + + LIB = $(FOAM_LIBBIN)/libdynamicFvMesh diff --git a/src/dynamicFvMesh/dynamicMotionSolverFvMesh/dynamicMotionSolverFvMesh.C b/src/dynamicFvMesh/dynamicMotionSolverFvMesh/dynamicMotionSolverFvMesh.C index ba1d636969a1aeb010e0e0712c4a0a6ffc5cad1d..5b7a90cddc85ae66857042fc5c54bb5347372998 100644 --- a/src/dynamicFvMesh/dynamicMotionSolverFvMesh/dynamicMotionSolverFvMesh.C +++ b/src/dynamicFvMesh/dynamicMotionSolverFvMesh/dynamicMotionSolverFvMesh.C @@ -92,6 +92,9 @@ const Foam::motionSolver& Foam::dynamicMotionSolverFvMesh::motion() const bool Foam::dynamicMotionSolverFvMesh::update() { + // Scan through AMI patches and update + + fvMesh::movePoints(motionPtr_->newPoints()); volVectorField* Uptr = getObjectPtr<volVectorField>("U"); diff --git a/src/dynamicFvMesh/dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.C b/src/dynamicFvMesh/dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.C new file mode 100644 index 0000000000000000000000000000000000000000..e431a39536d6a900d3cae632a116fea67eeb0235 --- /dev/null +++ b/src/dynamicFvMesh/dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.C @@ -0,0 +1,223 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2019-2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "dynamicMotionSolverFvMeshAMI.H" +#include "addToRunTimeSelectionTable.H" +#include "motionSolver.H" +#include "volFields.H" +#include "surfaceFields.H" +#include "cyclicAMIPolyPatch.H" +#include "polyTopoChange.H" +#include "MeshObject.H" +#include "lduMesh.H" +#include "surfaceInterpolate.H" + +#include "processorFvPatch.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(dynamicMotionSolverFvMeshAMI, 0); + addToRunTimeSelectionTable + ( + dynamicFvMesh, + dynamicMotionSolverFvMeshAMI, + IOobject + ); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::dynamicMotionSolverFvMeshAMI::dynamicMotionSolverFvMeshAMI +( + const IOobject& io +) +: + dynamicFvMesh(io), + motionPtr_(motionSolver::New(*this)) +{} + + +Foam::dynamicMotionSolverFvMeshAMI::dynamicMotionSolverFvMeshAMI +( + const IOobject& io, + pointField&& points, + faceList&& faces, + labelList&& allOwner, + labelList&& allNeighbour, + const bool syncPar +) +: + dynamicFvMesh + ( + io, + std::move(points), + std::move(faces), + std::move(allOwner), + std::move(allNeighbour), + syncPar + ), + motionPtr_(motionSolver::New(*this)) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::motionSolver& Foam::dynamicMotionSolverFvMeshAMI::motion() const +{ + return *motionPtr_; +} + + +bool Foam::dynamicMotionSolverFvMeshAMI::update() +{ + // Mesh not moved/changed yet + moving(false); + topoChanging(false); + + if (debug) + { + for (const fvPatch& fvp : boundary()) + { + if (!isA<processorFvPatch>(fvp)) + { + Info<< "1 --- patch:" << fvp.patch().name() + << " area:" << gSum(fvp.magSf()) << endl; + } + } + } + + pointField newPoints(motionPtr_->curPoints()); + + polyBoundaryMesh& pbm = const_cast<polyBoundaryMesh&>(boundaryMesh()); + + // Scan all patches and see if we want to apply a mesh topology update + bool changeRequired = false; + for (polyPatch& pp : pbm) + { + DebugInfo + << "pre-topology change: patch " << pp.name() + << " size:" << returnReduce(pp.size(), sumOp<label>()) + << " mag(faceAreas):" << gSum(mag(pp.faceAreas())) << endl; + + //changeRequired = pp.changeTopology(newPoints) || changeRequired; + changeRequired = pp.changeTopology() || changeRequired; + } + + reduce(changeRequired, orOp<bool>()); + + if (changeRequired) + { + polyTopoChange polyTopo(*this); + + // Set new point positions in polyTopo object + polyTopo.movePoints(newPoints); + + // Accumulate the patch-based mesh changes on the current mesh + // Note: + // - updates the AMIs using the new points + // - creates a topo change object that removes old added faces and + // adds the new faces + for (polyPatch& pp : pbm) + { + pp.setTopology(polyTopo); + } + + // Update geometry + // Note + // - changeMesh leads to polyMesh::resetPrimitives which will also + // trigger polyBoundaryMesh::updateMesh (init and update) and + // ::calcGeometry (with topoChanging = false) + // - BUT: mesh still corresponds to original (non-extended mesh) so + // we want to bypass these calls... + // - after changes topoChanging = true + autoPtr<mapPolyMesh> map = + polyTopo.changeMesh + ( + *this, + true // We will be calling movePoints after this update + ); + + // Apply topology change - update fv geometry and map fields + // - polyMesh::updateMesh + // - fires initUpdateMesh and updateMesh in AMI BCs - called before + // mapFields + // - AMI addressing must be up-to-date - used by, e.g. FaceCellWave + // - will trigger (again) polyBoundaryMesh::updateMesh (init and update) + updateMesh(map()); + + // Move points and update derived properties + // Note: + // - resets face areas based on raw point locations! + // - polyBoundaryMesh::updateMesh (init and update) + // Note: + // - processorPolyPatches will trigger calculation of faceCentres + // (and therefore cell volumes), so need to update faceAreas in + // initMovePoints since proc patches will be evaluated later than + // AMI patches + if (map().hasMotionPoints()) + { + movePoints(map().preMotionPoints()); + } + } + else + { + fvMesh::movePoints(newPoints); + } + + volVectorField* Uptr = getObjectPtr<volVectorField>("U"); + + if (Uptr) + { + Uptr->correctBoundaryConditions(); + + surfaceVectorField* UfPtr = getObjectPtr<surfaceVectorField>("Uf"); + if (UfPtr) + { + *UfPtr = fvc::interpolate(*Uptr); + } + } + + if (debug) + { + for (const fvPatch& fvp : boundary()) + { + if (!isA<processorFvPatch>(fvp)) + { + Info<< "2 --- patch:" << fvp.patch().name() + << " area:" << gSum(fvp.magSf()) << endl; + } + } + } + + return true; +} + + +// ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.H b/src/dynamicFvMesh/dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.H new file mode 100644 index 0000000000000000000000000000000000000000..e21f5623ed7df6416380459ef8b6470b6ebb42f0 --- /dev/null +++ b/src/dynamicFvMesh/dynamicMotionSolverFvMeshAMI/dynamicMotionSolverFvMeshAMI.H @@ -0,0 +1,121 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2011-2017 OpenFOAM Foundation + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::dynamicMotionSolverFvMeshAMI + +Description + The dynamicMotionSolverFvMeshAMI + +SourceFiles + dynamicMotionSolverFvMeshAMI.C + +\*---------------------------------------------------------------------------*/ + +#ifndef dynamicMotionSolverFvMeshAMI_H +#define dynamicMotionSolverFvMeshAMI_H + +#include "dynamicFvMesh.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +class motionSolver; + +/*---------------------------------------------------------------------------*\ + Class dynamicMotionSolverFvMeshAMI Declaration +\*---------------------------------------------------------------------------*/ + +class dynamicMotionSolverFvMeshAMI +: + public dynamicFvMesh +{ + // Private data + + autoPtr<motionSolver> motionPtr_; + + + // Private Member Functions + + //- No copy construct + dynamicMotionSolverFvMeshAMI + ( + const dynamicMotionSolverFvMeshAMI& + ) = delete; + + //- No copy assignment + void operator=(const dynamicMotionSolverFvMeshAMI&) = delete; + + +public: + + //- Runtime type information + TypeName("dynamicMotionSolverFvMeshAMI"); + + + // Constructors + + //- Construct from IOobject + dynamicMotionSolverFvMeshAMI(const IOobject& io); + + //- Construct from components without boundary. + // Boundary is added using addFvPatches() member function + dynamicMotionSolverFvMeshAMI + ( + const IOobject& io, + pointField&& points, + faceList&& faces, + labelList&& allOwner, + labelList&& allNeighbour, + const bool syncPar = true + ); + + + //- Destructor + virtual ~dynamicMotionSolverFvMeshAMI() = default; + + + // Member Functions + + //- Return the motionSolver + const motionSolver& motion() const; + + //- Update the mesh for both mesh motion and topology change + virtual bool update(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/finiteVolume/Make/options b/src/finiteVolume/Make/options index 851f94b6b3910365ebdd5ad09a66903da978f118..ea11ab0d45a46d24a226464a14238a684ff6278a 100644 --- a/src/finiteVolume/Make/options +++ b/src/finiteVolume/Make/options @@ -1,7 +1,8 @@ EXE_INC = \ -I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/surfMesh/lnInclude \ - -I$(LIB_SRC)/meshTools/lnInclude + -I$(LIB_SRC)/meshTools/lnInclude \ + -I$(LIB_SRC)/dynamicMesh/lnInclude LIB_LIBS = \ -lOpenFOAM \ diff --git a/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.C b/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.C index e49d3c75fc13b924e2819aa22c30482eddb072a8..aa4d3d6bcbbffde7e378dec00b8b0f7622602e1d 100644 --- a/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.C +++ b/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.C @@ -52,6 +52,7 @@ bool Foam::pimpleControl::read() pimpleDict.getOrDefault("turbOnFinalIterOnly", true); finalOnLastPimpleIterOnly_ = pimpleDict.getOrDefault("finalOnLastPimpleIterOnly", false); + ddtCorr_ = pimpleDict.getOrDefault("ddtCorr", true); return true; } @@ -155,8 +156,9 @@ Foam::pimpleControl::pimpleControl corrPISO_(0), SIMPLErho_(false), turbOnFinalIterOnly_(true), - converged_(false), - finalOnLastPimpleIterOnly_(false) + finalOnLastPimpleIterOnly_(false), + ddtCorr_(true), + converged_(false) { read(); diff --git a/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.H b/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.H index 1433215df84c5ca1712f0da4472e8db8f7d8e61c..017f4675b534d89695b009796886f2edfb344918 100644 --- a/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.H +++ b/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControl.H @@ -85,19 +85,22 @@ protected: label corrPISO_; //- Flag to indicate whether to update density in SIMPLE - // rather than PISO mode + //- rather than PISO mode bool SIMPLErho_; //- Flag to indicate whether to only solve turbulence on final iter bool turbOnFinalIterOnly_; - //- Converged flag - bool converged_; - //- Flag to indicate wheter the final solver is used only on the - // final pimple iter + //- final pimple iter bool finalOnLastPimpleIterOnly_; + //- Flag to indicate that ddtCorr should be applied; default = yes + bool ddtCorr_; + + //- Converged flag + bool converged_; + // Protected Member Functions @@ -181,6 +184,9 @@ public: //- Return true to solve for turbulence inline bool turbCorr(); + + //- Return true to apply ddtCorr + inline bool ddtCorr() const; }; diff --git a/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControlI.H b/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControlI.H index 344db63f93e197fd5e835b4dbf66a885e3471491..b0fd30e6fd13267e506b0fd534c05d848ba73196 100644 --- a/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControlI.H +++ b/src/finiteVolume/cfdTools/general/solutionControl/pimpleControl/pimpleControlI.H @@ -143,4 +143,10 @@ inline bool Foam::pimpleControl::turbCorr() } +inline bool Foam::pimpleControl::ddtCorr() const +{ + return ddtCorr_; +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.C b/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.C index beb923b8990b14762f9d25957689e994c524bad9..96415c00e56adaaa1645d264230e02b901037a02 100644 --- a/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.C +++ b/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.C @@ -226,10 +226,9 @@ void Foam::cyclicACMIFvPatchField<Type>::updateInterfaceMatrix { const cyclicACMIPolyPatch& cpp = cyclicACMIPatch_.cyclicACMIPatch(); - // note: only applying coupled contribution + // Note: only applying coupled contribution - const labelUList& nbrFaceCellsCoupled = - cpp.neighbPatch().faceCells(); + const labelUList& nbrFaceCellsCoupled = cpp.neighbPatch().faceCells(); solveScalarField pnf(psiInternal, nbrFaceCellsCoupled); @@ -254,7 +253,7 @@ void Foam::cyclicACMIFvPatchField<Type>::updateInterfaceMatrix { const cyclicACMIPolyPatch& cpp = cyclicACMIPatch_.cyclicACMIPatch(); - // note: only applying coupled contribution + // Note: only applying coupled contribution const labelUList& nbrFaceCellsCoupled = cpp.neighbPatch().faceCells(); @@ -277,7 +276,7 @@ void Foam::cyclicACMIFvPatchField<Type>::manipulateMatrix { const scalarField& mask = cyclicACMIPatch_.cyclicACMIPatch().mask(); - // nothing to be done by the AMI, but re-direct to non-overlap patch + // Nothing to be done by the AMI, but re-direct to non-overlap patch // with non-overlap patch weights const fvPatchField<Type>& npf = nonOverlapPatchField(); diff --git a/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.H b/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.H index eae2dd49dad5656f8de4b2d6690f9dc8dad0f3b1..db093b3940174646b4663dd5a93f52491f220d18 100644 --- a/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.H +++ b/src/finiteVolume/fields/fvPatchFields/constraint/cyclicACMI/cyclicACMIFvPatchField.H @@ -173,7 +173,7 @@ public: //- Return true if this patch field fixes a value // Needed to check if a level has to be specified while solving - // Poissons equations + // Poisson equations virtual bool fixesValue() const { const scalarField& mask = diff --git a/src/finiteVolume/fvMesh/fvMesh.C b/src/finiteVolume/fvMesh/fvMesh.C index 9aff27408a42320329b01ab30f83d41d4349f1d5..e02ae63dccb3177dc8a6766dc2b9f2187453afe9 100644 --- a/src/finiteVolume/fvMesh/fvMesh.C +++ b/src/finiteVolume/fvMesh/fvMesh.C @@ -726,6 +726,8 @@ void Foam::fvMesh::mapFields(const mapPolyMesh& meshMap) Foam::tmp<Foam::scalarField> Foam::fvMesh::movePoints(const pointField& p) { + DebugInFunction << endl; + // Grab old time volumes if the time has been incremented // This will update V0, V00 if (curTimeIndex_ < time().timeIndex()) @@ -733,6 +735,14 @@ Foam::tmp<Foam::scalarField> Foam::fvMesh::movePoints(const pointField& p) storeOldVol(V()); } + + // Move the polyMesh and set the mesh motion fluxes to the swept-volumes + + scalar rDeltaT = 1.0/time().deltaTValue(); + + tmp<scalarField> tsweptVols = polyMesh::movePoints(p); + scalarField& sweptVols = tsweptVols.ref(); + if (!phiPtr_) { // Create mesh motion flux @@ -761,14 +771,6 @@ Foam::tmp<Foam::scalarField> Foam::fvMesh::movePoints(const pointField& p) } surfaceScalarField& phi = *phiPtr_; - - // Move the polyMesh and set the mesh motion fluxes to the swept-volumes - - scalar rDeltaT = 1.0/time().deltaTValue(); - - tmp<scalarField> tsweptVols = polyMesh::movePoints(p); - scalarField& sweptVols = tsweptVols.ref(); - phi.primitiveFieldRef() = scalarField::subField(sweptVols, nInternalFaces()); phi.primitiveFieldRef() *= rDeltaT; @@ -776,7 +778,6 @@ Foam::tmp<Foam::scalarField> Foam::fvMesh::movePoints(const pointField& p) const fvPatchList& patches = boundary(); surfaceScalarField::Boundary& phibf = phi.boundaryFieldRef(); - forAll(patches, patchi) { phibf[patchi] = patches[patchi].patchSlice(sweptVols); @@ -805,6 +806,8 @@ Foam::tmp<Foam::scalarField> Foam::fvMesh::movePoints(const pointField& p) void Foam::fvMesh::updateMesh(const mapPolyMesh& mpm) { + DebugInFunction << endl; + // Update polyMesh. This needs to keep volume existent! polyMesh::updateMesh(mpm); diff --git a/src/finiteVolume/fvMesh/fvMesh.H b/src/finiteVolume/fvMesh/fvMesh.H index 53e57c7f683590c72fa7f0cd51eda9a89fbb46c9..0e35ef9f9d2a4da19d29e39bfedc28a33c41f9fb 100644 --- a/src/finiteVolume/fvMesh/fvMesh.H +++ b/src/finiteVolume/fvMesh/fvMesh.H @@ -91,6 +91,8 @@ class fvMesh public fvSolution, public data { +protected: + // Private data //- Boundary mesh diff --git a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.C b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.C index c4427d54849224973829e37955bd6144034c7c95..a66ae7d06b98271b7e39a4d4c45ba5f61e995801 100644 --- a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.C +++ b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.C @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2016 OpenFOAM Foundation + Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,9 +27,10 @@ License \*---------------------------------------------------------------------------*/ #include "cyclicACMIFvPatch.H" -#include "addToRunTimeSelectionTable.H" #include "fvMesh.H" #include "transform.H" +#include "surfaceFields.H" +#include "addToRunTimeSelectionTable.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -41,45 +43,14 @@ namespace Foam // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * // -void Foam::cyclicACMIFvPatch::updateAreas() const +void Foam::cyclicACMIFvPatch::resetPatchAreas(const fvPatch& fvp) const { - if (cyclicACMIPolyPatch_.updated()) - { - if (debug) - { - Pout<< "cyclicACMIFvPatch::updateAreas() : updating fv areas for " - << name() << " and " << this->nonOverlapPatch().name() - << endl; - } + const_cast<vectorField&>(fvp.Sf()) = fvp.patch().faceAreas(); + const_cast<vectorField&>(fvp.Cf()) = fvp.patch().faceCentres(); + const_cast<scalarField&>(fvp.magSf()) = mag(fvp.patch().faceAreas()); - // owner couple - const_cast<vectorField&>(Sf()) = patch().faceAreas(); - const_cast<scalarField&>(magSf()) = mag(patch().faceAreas()); - - // owner non-overlapping - const fvPatch& nonOverlapPatch = this->nonOverlapPatch(); - const_cast<vectorField&>(nonOverlapPatch.Sf()) = - nonOverlapPatch.patch().faceAreas(); - const_cast<scalarField&>(nonOverlapPatch.magSf()) = - mag(nonOverlapPatch.patch().faceAreas()); - - // neighbour couple - const cyclicACMIFvPatch& nbrACMI = neighbPatch(); - const_cast<vectorField&>(nbrACMI.Sf()) = - nbrACMI.patch().faceAreas(); - const_cast<scalarField&>(nbrACMI.magSf()) = - mag(nbrACMI.patch().faceAreas()); - - // neighbour non-overlapping - const fvPatch& nbrNonOverlapPatch = nbrACMI.nonOverlapPatch(); - const_cast<vectorField&>(nbrNonOverlapPatch.Sf()) = - nbrNonOverlapPatch.patch().faceAreas(); - const_cast<scalarField&>(nbrNonOverlapPatch.magSf()) = - mag(nbrNonOverlapPatch.patch().faceAreas()); - - // set the updated flag - cyclicACMIPolyPatch_.setUpdated(false); - } + DebugPout + << fvp.patch().name() << " area:" << sum(fvp.magSf()) << endl; } @@ -100,13 +71,13 @@ void Foam::cyclicACMIFvPatch::makeWeights(scalarField& w) const ) ); - scalar tol = cyclicACMIPolyPatch::tolerance(); + const scalar tol = cyclicACMIPolyPatch::tolerance(); forAll(deltas, facei) { - scalar di = deltas[facei]; - scalar dni = nbrDeltas[facei]; + scalar di = mag(deltas[facei]); + scalar dni = mag(nbrDeltas[facei]); if (dni < tol) { @@ -147,8 +118,7 @@ Foam::tmp<Foam::vectorField> Foam::cyclicACMIFvPatch::delta() const vectorField nbrPatchD(interpolate(nbrPatch.coupledFvPatch::delta())); - - tmp<vectorField> tpdv(new vectorField(patchD.size())); + auto tpdv = tmp<vectorField>::New(patchD.size()); vectorField& pdv = tpdv.ref(); // do the transformation if necessary @@ -201,4 +171,100 @@ Foam::tmp<Foam::labelField> Foam::cyclicACMIFvPatch::internalFieldTransfer } +void Foam::cyclicACMIFvPatch::movePoints() +{ + if (!cyclicACMIPolyPatch_.owner()) + { + return; + } + + // Set the patch face areas to be consistent with the changes made at the + // polyPatch level + + const fvPatch& nonOverlapPatch = this->nonOverlapPatch(); + const cyclicACMIFvPatch& nbrACMI = neighbPatch(); + const fvPatch& nbrNonOverlapPatch = nbrACMI.nonOverlapPatch(); + + resetPatchAreas(*this); + resetPatchAreas(nonOverlapPatch); + resetPatchAreas(nbrACMI); + resetPatchAreas(nbrNonOverlapPatch); + + // Scale the mesh flux + + const labelListList& newSrcAddr = AMI().srcAddress(); + const labelListList& newTgtAddr = AMI().tgtAddress(); + + const fvMesh& mesh = boundaryMesh().mesh(); + surfaceScalarField& meshPhi = const_cast<fvMesh&>(mesh).setPhi(); + surfaceScalarField::Boundary& meshPhiBf = meshPhi.boundaryFieldRef(); + + // Note: phip and phiNonOverlapp will be different sizes if new faces + // have been added + scalarField& phip = meshPhiBf[cyclicACMIPolyPatch_.index()]; + scalarField& phiNonOverlapp = + meshPhiBf[nonOverlapPatch.patch().index()]; + + const auto& localFaces = cyclicACMIPolyPatch_.localFaces(); + const auto& localPoints = cyclicACMIPolyPatch_.localPoints(); + + forAll(phip, facei) + { + if (newSrcAddr[facei].empty()) + { + // AMI patch with no connection to other coupled faces + phip[facei] = 0.0; + } + else + { + // Scale the mesh flux according to the area fraction + const face& fAMI = localFaces[facei]; + + // Note: using raw point locations to calculate the geometric + // area - faces areas are currently scaled (decoupled from + // mesh points) + const scalar geomArea = fAMI.mag(localPoints); + phip[facei] *= magSf()[facei]/geomArea; + } + } + + forAll(phiNonOverlapp, facei) + { + const scalar w = 1.0 - cyclicACMIPolyPatch_.srcMask()[facei]; + phiNonOverlapp[facei] *= w; + } + + scalarField& nbrPhip = meshPhiBf[nbrACMI.patch().index()]; + scalarField& nbrPhiNonOverlapp = + meshPhiBf[nbrNonOverlapPatch.patch().index()]; + + const auto& nbrLocalFaces = nbrACMI.patch().localFaces(); + const auto& nbrLocalPoints = nbrACMI.patch().localPoints(); + + forAll(nbrPhip, facei) + { + if (newTgtAddr[facei].empty()) + { + nbrPhip[facei] = 0.0; + } + else + { + const face& fAMI = nbrLocalFaces[facei]; + + // Note: using raw point locations to calculate the geometric + // area - faces areas are currently scaled (decoupled from + // mesh points) + const scalar geomArea = fAMI.mag(nbrLocalPoints); + nbrPhip[facei] *= nbrACMI.magSf()[facei]/geomArea; + } + } + + forAll(nbrPhiNonOverlapp, facei) + { + const scalar w = 1.0 - cyclicACMIPolyPatch_.tgtMask()[facei]; + nbrPhiNonOverlapp[facei] *= w; + } +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.H b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.H index 037df53fe3797d7dffdef2af16cafdfc6a325603..c3aed02df707219e3826b30a8ee8c8ae7b140df4 100644 --- a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.H +++ b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicACMI/cyclicACMIFvPatch.H @@ -65,12 +65,15 @@ protected: // Protected Member functions - //- Update the patch areas after AMI update - void updateAreas() const; + //- Helper function to reset the FV patch areas from the primitive patch + void resetPatchAreas(const fvPatch& fvp) const; //- Make patch weighting factors void makeWeights(scalarField&) const; + //- Correct patches after moving points + virtual void movePoints(); + public: @@ -134,12 +137,7 @@ public: //- Return a reference to the AMI interpolator virtual const AMIPatchToPatchInterpolation& AMI() const { - const AMIPatchToPatchInterpolation& AMI = - cyclicACMIPolyPatch_.AMI(); - - updateAreas(); - - return AMI; + return cyclicACMIPolyPatch_.AMI(); } //- Are the cyclic planes parallel @@ -169,8 +167,8 @@ public: } //- Return true if this patch is coupled. This is equivalent - // to the coupledPolyPatch::coupled() if parallel running or - // both sides present, false otherwise + //- to the coupledPolyPatch::coupled() if parallel running or + //- both sides present, false otherwise virtual bool coupled() const; //- Return delta (P to N) vectors across coupled patch @@ -183,8 +181,6 @@ public: const Field<Type>& fld ) const { - updateAreas(); - return cyclicACMIPolyPatch_.cyclicAMIPolyPatch::interpolate ( @@ -192,7 +188,7 @@ public: ); } - //- Interpolate (make sure to have uptodate areas) + //- Interpolate (make sure to have up-to-date areas) template<class Type> tmp<Field<Type>> interpolate ( @@ -206,7 +202,7 @@ public: // Interface transfer functions //- Return the values of the given internal data adjacent to - // the interface as a field + //- the interface as a field virtual tmp<labelField> interfaceInternalField ( const labelUList& internalData diff --git a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C index 356c61db10f7e9ed761916ed54bb4cbbb417b6bc..73398e753e08eb40f3cc967b726250606a8084a5 100644 --- a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C +++ b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.C @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation + Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +30,7 @@ License #include "addToRunTimeSelectionTable.H" #include "fvMesh.H" #include "transform.H" +#include "surfaceFields.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -82,8 +84,9 @@ void Foam::cyclicAMIFvPatch::makeWeights(scalarField& w) const forAll(deltas, facei) { - scalar di = deltas[facei]; - scalar dni = nbrDeltas[facei]; + // Note use of mag + scalar di = mag(deltas[facei]); + scalar dni = mag(nbrDeltas[facei]); w[facei] = dni/(di + dni); } @@ -96,6 +99,26 @@ void Foam::cyclicAMIFvPatch::makeWeights(scalarField& w) const } +void Foam::cyclicAMIFvPatch::makeDeltaCoeffs(scalarField& coeffs) const +{ + // Apply correction to default coeffs +} + + +void Foam::cyclicAMIFvPatch::makeNonOrthoDeltaCoeffs(scalarField& coeffs) const +{ + // Apply correction to default coeffs + //coeffs = Zero; +} + + +void Foam::cyclicAMIFvPatch::makeNonOrthoCorrVectors(vectorField& vecs) const +{ + // Apply correction to default vectors + //vecs = Zero; +} + + Foam::tmp<Foam::vectorField> Foam::cyclicAMIFvPatch::delta() const { const cyclicAMIFvPatch& nbrPatch = neighbFvPatch(); @@ -121,7 +144,7 @@ Foam::tmp<Foam::vectorField> Foam::cyclicAMIFvPatch::delta() const const vectorField& nbrPatchD = tnbrPatchD(); - tmp<vectorField> tpdv(new vectorField(patchD.size())); + auto tpdv = tmp<vectorField>::New(patchD.size()); vectorField& pdv = tpdv.ref(); // do the transformation if necessary @@ -174,4 +197,75 @@ Foam::tmp<Foam::labelField> Foam::cyclicAMIFvPatch::internalFieldTransfer } +void Foam::cyclicAMIFvPatch::movePoints() +{ + if (!owner() || !cyclicAMIPolyPatch_.createAMIFaces()) + { + // Only manipulating patch face areas and mesh motion flux if the AMI + // creates additional faces + return; + } + + // Update face data based on values set by the AMI manipulations + const_cast<vectorField&>(Sf()) = cyclicAMIPolyPatch_.faceAreas(); + const_cast<vectorField&>(Cf()) = cyclicAMIPolyPatch_.faceCentres(); + const_cast<scalarField&>(magSf()) = mag(Sf()); + + const cyclicAMIFvPatch& nbr = neighbPatch(); + const_cast<vectorField&>(nbr.Sf()) = nbr.cyclicAMIPatch().faceAreas(); + const_cast<vectorField&>(nbr.Cf()) = nbr.cyclicAMIPatch().faceCentres(); + const_cast<scalarField&>(nbr.magSf()) = mag(nbr.Sf()); + + + // Set consitent mesh motion flux + // TODO: currently maps src mesh flux to tgt - update to + // src = src + mapped(tgt) and tgt = tgt + mapped(src)? + + const fvMesh& mesh = boundaryMesh().mesh(); + surfaceScalarField& meshPhi = const_cast<fvMesh&>(mesh).setPhi(); + surfaceScalarField::Boundary& meshPhiBf = meshPhi.boundaryFieldRef(); + + if (cyclicAMIPolyPatch_.owner()) + { + scalarField& phip = meshPhiBf[patch().index()]; + forAll(phip, facei) + { + const face& f = cyclicAMIPolyPatch_.localFaces()[facei]; + + // Note: using raw point locations to calculate the geometric + // area - faces areas are currently scaled by the AMI weights + // (decoupled from mesh points) + const scalar geomArea = f.mag(cyclicAMIPolyPatch_.localPoints()); + + const scalar scaledArea = magSf()[facei]; + phip[facei] *= scaledArea/geomArea; + } + + scalarField srcMeshPhi(phip); + if (Pstream::parRun()) + { + AMI().srcMap().distribute(srcMeshPhi); + } + + const labelListList& tgtToSrcAddr = AMI().tgtAddress(); + scalarField& nbrPhip = meshPhiBf[nbr.index()]; + + forAll(tgtToSrcAddr, tgtFacei) + { + // Note: now have 1-to-1 mapping so tgtToSrcAddr[tgtFacei] is size 1 + const label srcFacei = tgtToSrcAddr[tgtFacei][0]; + nbrPhip[tgtFacei] = -srcMeshPhi[srcFacei]; + } + + DebugInfo + << "patch:" << patch().name() + << " sum(area):" << gSum(magSf()) + << " min(mag(faceAreas):" << gMin(magSf()) + << " sum(meshPhi):" << gSum(phip) << nl + << " sum(nbrMeshPhi):" << gSum(nbrPhip) << nl + << endl; + } +} + + // ************************************************************************* // diff --git a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.H b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.H index 2b643895982dbf9bedab765a25894d67dc8a79e4..1c3b46ab574592ac1a30dd22373de263d1532422 100644 --- a/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.H +++ b/src/finiteVolume/fvMesh/fvPatches/constraint/cyclicAMI/cyclicAMIFvPatch.H @@ -68,6 +68,18 @@ protected: //- Make patch weighting factors void makeWeights(scalarField&) const; + //- Correct patch deltaCoeffs + virtual void makeDeltaCoeffs(scalarField&) const; + + //- Correct patch non-ortho deltaCoeffs + virtual void makeNonOrthoDeltaCoeffs(scalarField&) const; + + //- Correct patch non-ortho correction vectors + virtual void makeNonOrthoCorrVectors(vectorField&) const; + + //- Correct patches after moving points + virtual void movePoints(); + public: @@ -156,8 +168,8 @@ public: } //- Return true if this patch is coupled. This is equivalent - // to the coupledPolyPatch::coupled() if parallel running or - // both sides present, false otherwise + //- to the coupledPolyPatch::coupled() if parallel running or + //- both sides present, false otherwise virtual bool coupled() const; //- Return delta (P to N) vectors across coupled patch @@ -187,7 +199,7 @@ public: // Interface transfer functions //- Return the values of the given internal data adjacent to - // the interface as a field + //- the interface as a field virtual tmp<labelField> interfaceInternalField ( const labelUList& internalData diff --git a/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.C b/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.C index 2b0b8ee5cba6e28b171382559c7eb6c205e1c5b4..b100323976d3f15a0bafe2adc491f0e7b06a119a 100644 --- a/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.C +++ b/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.C @@ -167,6 +167,18 @@ void Foam::fvPatch::makeWeights(scalarField& w) const } +void Foam::fvPatch::makeDeltaCoeffs(scalarField& w) const +{} + + +void Foam::fvPatch::makeNonOrthoDeltaCoeffs(scalarField& w) const +{} + + +void Foam::fvPatch::makeNonOrthoCorrVectors(vectorField& w) const +{} + + void Foam::fvPatch::initMovePoints() {} diff --git a/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.H b/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.H index 7f1e99775f9beda654b35a3285f5812bcdf4b442..3a04adfb38f06e0dec75600fbe38a75b4d2082a9 100644 --- a/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.H +++ b/src/finiteVolume/fvMesh/fvPatches/fvPatch/fvPatch.H @@ -81,6 +81,15 @@ protected: //- Make patch weighting factors virtual void makeWeights(scalarField&) const; + //- Correct patch deltaCoeffs + virtual void makeDeltaCoeffs(scalarField&) const; + + //- Correct patch non-ortho deltaCoeffs + virtual void makeNonOrthoDeltaCoeffs(scalarField&) const; + + //- Correct patch non-ortho correction vectors + virtual void makeNonOrthoCorrVectors(vectorField&) const; + //- Initialise the patches for moving points virtual void initMovePoints(); diff --git a/src/finiteVolume/interpolation/surfaceInterpolation/surfaceInterpolation/surfaceInterpolation.C b/src/finiteVolume/interpolation/surfaceInterpolation/surfaceInterpolation/surfaceInterpolation.C index 2b31e5c66bded5a82ef8aef4f05d36121a1e54ff..7642933971866680ca7687b0ba82604db92cf956 100644 --- a/src/finiteVolume/interpolation/surfaceInterpolation/surfaceInterpolation/surfaceInterpolation.C +++ b/src/finiteVolume/interpolation/surfaceInterpolation/surfaceInterpolation/surfaceInterpolation.C @@ -172,7 +172,6 @@ void Foam::surfaceInterpolation::makeWeights() const // ... and reference to the internal field of the weighting factors scalarField& w = weights.primitiveFieldRef(); - forAll(owner, facei) { // Note: mag in the dot-product. @@ -247,7 +246,11 @@ void Foam::surfaceInterpolation::makeDeltaCoeffs() const forAll(deltaCoeffsBf, patchi) { - deltaCoeffsBf[patchi] = 1.0/mag(mesh_.boundary()[patchi].delta()); + const fvPatch& p = mesh_.boundary()[patchi]; + deltaCoeffsBf[patchi] = 1.0/mag(p.delta()); + + // Optionally correct + p.makeDeltaCoeffs(deltaCoeffsBf[patchi]); } } @@ -330,6 +333,9 @@ void Foam::surfaceInterpolation::makeNonOrthDeltaCoeffs() const patchDeltaCoeffs[patchFacei] = 1.0/max(unitArea & delta, 0.05*mag(delta)); } + + // Optionally correct + p.makeNonOrthoDeltaCoeffs(patchDeltaCoeffs); } } @@ -386,6 +392,8 @@ void Foam::surfaceInterpolation::makeNonOrthCorrectionVectors() const { fvsPatchVectorField& patchCorrVecs = corrVecsBf[patchi]; + const fvPatch& p = patchCorrVecs.patch(); + if (!patchCorrVecs.coupled()) { patchCorrVecs = Zero; @@ -395,8 +403,6 @@ void Foam::surfaceInterpolation::makeNonOrthCorrectionVectors() const const fvsPatchScalarField& patchNonOrthDeltaCoeffs = NonOrthDeltaCoeffs.boundaryField()[patchi]; - const fvPatch& p = patchCorrVecs.patch(); - const vectorField patchDeltas(mesh_.boundary()[patchi].delta()); forAll(p, patchFacei) @@ -411,6 +417,9 @@ void Foam::surfaceInterpolation::makeNonOrthCorrectionVectors() const unitArea - delta*patchNonOrthDeltaCoeffs[patchFacei]; } } + + // Optionally correct + p.makeNonOrthoCorrVectors(patchCorrVecs); } if (debug) diff --git a/src/functionObjects/field/mapFields/mapFields.C b/src/functionObjects/field/mapFields/mapFields.C index 66fa2370379f46ab1f23db806b93330c2ed7f876..02170a93c84b1ab56f38ed32262f150198c764a8 100644 --- a/src/functionObjects/field/mapFields/mapFields.C +++ b/src/functionObjects/field/mapFields/mapFields.C @@ -86,11 +86,7 @@ void Foam::functionObjects::mapFields::createInterpolation ); // Lookup corresponding AMI method - word patchMapMethodName = - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - meshToMesh::interpolationMethodAMI(mapMethod) - ]; + word patchMapMethodName = meshToMesh::interpolationMethodAMI(mapMethod); // Optionally override if (dict.readIfPresent("patchMapMethod", patchMapMethodName)) diff --git a/src/lagrangian/basic/particle/particle.C b/src/lagrangian/basic/particle/particle.C index 42138a46b11dabb3090c740b13d1c4a5ef0c3d2e..6588607fbb283331e8d2bac294543a6a665ecb7b 100644 --- a/src/lagrangian/basic/particle/particle.C +++ b/src/lagrangian/basic/particle/particle.C @@ -31,6 +31,7 @@ License #include "treeDataCell.H" #include "cubicEqn.H" #include "registerSwitch.H" +#include "indexedOctree.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C index b7c297829447d505c46765b0afa9119056d508fa..f01f8570da98bf03348f4edf895e0affa672234c 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2018 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,78 +27,104 @@ License \*---------------------------------------------------------------------------*/ #include "AMIInterpolation.H" -#include "AMIMethod.H" #include "meshTools.H" #include "mapDistribute.H" #include "flipOp.H" #include "profiling.H" +#include "triPointRef.H" +#include "OFstream.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -const Foam::Enum -< - typename Foam::AMIInterpolation<SourcePatch, TargetPatch>:: - interpolationMethod -> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolationMethodNames_ -({ - { interpolationMethod::imDirect, "directAMI" }, - { interpolationMethod::imMapNearest, "mapNearestAMI" }, - { interpolationMethod::imFaceAreaWeight, "faceAreaWeightAMI" }, - { interpolationMethod::imPartialFaceAreaWeight, "partialFaceAreaWeightAMI" } -}); - -template<class SourcePatch, class TargetPatch> -bool Foam::AMIInterpolation<SourcePatch, TargetPatch>::cacheIntersections_ = - false; - -template<class SourcePatch, class TargetPatch> -template<class Patch> -Foam::tmp<Foam::scalarField> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::patchMagSf +namespace Foam +{ + defineTypeNameAndDebug(AMIInterpolation, 0); + defineRunTimeSelectionTable(AMIInterpolation, dict); + defineRunTimeSelectionTable(AMIInterpolation, component); +} + +bool Foam::AMIInterpolation::cacheIntersections_ = false; + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +Foam::autoPtr<Foam::indexedOctree<Foam::AMIInterpolation::treeType>> +Foam::AMIInterpolation::createTree ( - const Patch& patch, - const faceAreaIntersect::triangulationMode triMode -) + const primitivePatch& patch +) const { - tmp<scalarField> tResult(new scalarField(patch.size(), Zero)); - scalarField& result = tResult.ref(); + treeBoundBox bb(patch.points(), patch.meshPoints()); + bb.inflate(0.01); + + return autoPtr<indexedOctree<treeType>>::New + ( + treeType + ( + false, + patch, + indexedOctree<treeType>::perturbTol() + ), + bb, // overall search domain + 8, // maxLevel + 10, // leaf size + 3.0 // duplicity + ); +} - const pointField& patchPoints = patch.localPoints(); - faceList patchFaceTris; +Foam::label Foam::AMIInterpolation::calcDistribution +( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch +) const +{ + label proci = 0; - forAll(result, patchFacei) + if (Pstream::parRun()) { - faceAreaIntersect::triangulate - ( - patch.localFaces()[patchFacei], - patchPoints, - triMode, - patchFaceTris - ); + labelList facesPresentOnProc(Pstream::nProcs(), Zero); + if ((srcPatch.size() > 0) || (tgtPatch.size() > 0)) + { + facesPresentOnProc[Pstream::myProcNo()] = 1; + } + else + { + facesPresentOnProc[Pstream::myProcNo()] = 0; + } + + Pstream::gatherList(facesPresentOnProc); + Pstream::scatterList(facesPresentOnProc); + + label nHaveFaces = sum(facesPresentOnProc); - forAll(patchFaceTris, i) + if (nHaveFaces > 1) { - result[patchFacei] += - triPointRef - ( - patchPoints[patchFaceTris[i][0]], - patchPoints[patchFaceTris[i][1]], - patchPoints[patchFaceTris[i][2]] - ).mag(); + proci = -1; + if (debug) + { + InfoInFunction + << "AMI split across multiple processors" << endl; + } + } + else if (nHaveFaces == 1) + { + proci = facesPresentOnProc.find(1); + if (debug) + { + InfoInFunction + << "AMI local to processor" << proci << endl; + } } } - return tResult; -} + // Either not parallel or no faces on any processor + return proci; +} -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::projectPointsToSurface +void Foam::AMIInterpolation::projectPointsToSurface ( const searchableSurface& surf, pointField& pts @@ -138,8 +164,7 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::projectPointsToSurface } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights +void Foam::AMIInterpolation::normaliseWeights ( const scalarList& patchAreas, const word& patchName, @@ -167,7 +192,6 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights scalar s = sum(w); scalar t = s/denom; - if (conformal) { denom = s; @@ -179,10 +203,9 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights } wghtSum[facei] = t; - if (t < lowWeightTol) { - nLowWeight++; + ++nLowWeight; } } else @@ -191,7 +214,6 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights } } - if (output) { const label nFace = returnReduce(wght.size(), sumOp<label>()); @@ -220,8 +242,7 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::agglomerate +void Foam::AMIInterpolation::agglomerate ( const autoPtr<mapDistribute>& targetMapPtr, const scalarList& fineSrcMagSf, @@ -264,7 +285,6 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::agglomerate } } - // Agglomerate weights and indices if (targetMapPtr.valid()) { @@ -298,7 +318,7 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::agglomerate // the slots are equal to face indices. // A mapDistribute has: // - a subMap : these are face indices - // - a constructMap : these are from 'transferred-date' to slots + // - a constructMap : these are from 'transferred-data' to slots labelListList tgtSubMap(Pstream::nProcs()); @@ -492,10 +512,10 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::agglomerate forAll(elems, i) { - label elemi = elems[i]; - label coarseElemi = targetRestrictAddressing[elemi]; + const label elemi = elems[i]; + const label coarseElemi = targetRestrictAddressing[elemi]; - label index = newElems.find(coarseElemi); + const label index = newElems.find(coarseElemi); if (index == -1) { newElems.append(coarseElemi); @@ -524,235 +544,87 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::agglomerate } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::constructFromSurface -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const autoPtr<searchableSurface>& surfPtr -) -{ - if (surfPtr.valid()) - { - // Create new patches for source and target - pointField srcPoints = srcPatch.points(); - SourcePatch srcPatch0 - ( - SubList<face> - ( - srcPatch, - srcPatch.size(), - 0 - ), - srcPoints - ); - - if (debug) - { - OFstream os("amiSrcPoints.obj"); - for (const point& pt : srcPoints) - { - meshTools::writeOBJ(os, pt); - } - } - - pointField tgtPoints = tgtPatch.points(); - TargetPatch tgtPatch0 - ( - SubList<face> - ( - tgtPatch, - tgtPatch.size(), - 0 - ), - tgtPoints - ); - - if (debug) - { - OFstream os("amiTgtPoints.obj"); - for (const point& pt : tgtPoints) - { - meshTools::writeOBJ(os, pt); - } - } - - - // Map source and target patches onto projection surface - projectPointsToSurface(surfPtr(), srcPoints); - projectPointsToSurface(surfPtr(), tgtPoints); - - - // Calculate AMI interpolation - update(srcPatch0, tgtPatch0); - } - else - { - update(srcPatch, tgtPatch); - } -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::AMIInterpolation +Foam::AMIInterpolation::AMIInterpolation ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool requireMatch, - const interpolationMethod& method, - const scalar lowWeightCorrection, + const dictionary& dict, const bool reverseTarget ) : - methodName_(interpolationMethodNames_[method]), - reverseTarget_(reverseTarget), - requireMatch_(requireMatch), + requireMatch_(dict.getOrDefault("requireMatch", true)), + reverseTarget_(dict.getOrDefault("reverseTarget", reverseTarget)), + lowWeightCorrection_(dict.getOrDefault<scalar>("lowWeightCorrection", -1)), singlePatchProc_(-999), - lowWeightCorrection_(lowWeightCorrection), srcMagSf_(), srcAddress_(), srcWeights_(), srcWeightsSum_(), - tgtMagSf_(), - tgtAddress_(), - tgtWeights_(), - tgtWeightsSum_(), - triMode_(triMode), + srcCentroids_(), srcMapPtr_(nullptr), - tgtMapPtr_(nullptr) -{ - update(srcPatch, tgtPatch); -} - - -template<class SourcePatch, class TargetPatch> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::AMIInterpolation -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool requireMatch, - const word& methodName, - const scalar lowWeightCorrection, - const bool reverseTarget -) -: - methodName_(methodName), - reverseTarget_(reverseTarget), - requireMatch_(requireMatch), - singlePatchProc_(-999), - lowWeightCorrection_(lowWeightCorrection), - srcMagSf_(), - srcAddress_(), - srcWeights_(), - srcWeightsSum_(), tgtMagSf_(), tgtAddress_(), tgtWeights_(), tgtWeightsSum_(), - triMode_(triMode), - srcMapPtr_(nullptr), - tgtMapPtr_(nullptr) -{ - update(srcPatch, tgtPatch); -} + tgtCentroids_(), + tgtMapPtr_(nullptr), + upToDate_(false) +{} -template<class SourcePatch, class TargetPatch> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::AMIInterpolation +Foam::AMIInterpolation::AMIInterpolation ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const autoPtr<searchableSurface>& surfPtr, - const faceAreaIntersect::triangulationMode& triMode, const bool requireMatch, - const interpolationMethod& method, - const scalar lowWeightCorrection, - const bool reverseTarget + const bool reverseTarget, + const scalar lowWeightCorrection ) : - methodName_(interpolationMethodNames_[method]), - reverseTarget_(reverseTarget), requireMatch_(requireMatch), - singlePatchProc_(-999), - lowWeightCorrection_(lowWeightCorrection), - srcMagSf_(), - srcAddress_(), - srcWeights_(), - srcWeightsSum_(), - tgtMagSf_(), - tgtAddress_(), - tgtWeights_(), - tgtWeightsSum_(), - triMode_(triMode), - srcMapPtr_(nullptr), - tgtMapPtr_(nullptr) -{ - constructFromSurface(srcPatch, tgtPatch, surfPtr); -} - - -template<class SourcePatch, class TargetPatch> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::AMIInterpolation -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const autoPtr<searchableSurface>& surfPtr, - const faceAreaIntersect::triangulationMode& triMode, - const bool requireMatch, - const word& methodName, - const scalar lowWeightCorrection, - const bool reverseTarget -) -: - methodName_(methodName), reverseTarget_(reverseTarget), - requireMatch_(requireMatch), - singlePatchProc_(-999), lowWeightCorrection_(lowWeightCorrection), + singlePatchProc_(-999), srcMagSf_(), srcAddress_(), srcWeights_(), srcWeightsSum_(), + srcCentroids_(), + srcPatchPts_(), + srcMapPtr_(nullptr), tgtMagSf_(), tgtAddress_(), tgtWeights_(), tgtWeightsSum_(), - triMode_(triMode), - srcMapPtr_(nullptr), - tgtMapPtr_(nullptr) -{ - constructFromSurface(srcPatch, tgtPatch, surfPtr); -} + tgtCentroids_(), + tgtPatchPts_(), + tgtMapPtr_(nullptr), + upToDate_(false) +{} -template<class SourcePatch, class TargetPatch> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::AMIInterpolation +Foam::AMIInterpolation::AMIInterpolation ( - const AMIInterpolation<SourcePatch, TargetPatch>& fineAMI, + const AMIInterpolation& fineAMI, const labelList& sourceRestrictAddressing, const labelList& targetRestrictAddressing ) : - methodName_(fineAMI.methodName_), - reverseTarget_(fineAMI.reverseTarget_), requireMatch_(fineAMI.requireMatch_), - singlePatchProc_(fineAMI.singlePatchProc_), + reverseTarget_(fineAMI.reverseTarget_), lowWeightCorrection_(-1.0), + singlePatchProc_(fineAMI.singlePatchProc_), srcMagSf_(), srcAddress_(), srcWeights_(), srcWeightsSum_(), + srcPatchPts_(), + srcMapPtr_(nullptr), tgtMagSf_(), tgtAddress_(), tgtWeights_(), tgtWeightsSum_(), - triMode_(fineAMI.triMode_), - srcMapPtr_(nullptr), - tgtMapPtr_(nullptr) + tgtPatchPts_(), + tgtMapPtr_(nullptr), + upToDate_(false) { label sourceCoarseSize = ( @@ -834,23 +706,67 @@ Foam::AMIInterpolation<SourcePatch, TargetPatch>::AMIInterpolation } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::~AMIInterpolation() +Foam::AMIInterpolation::AMIInterpolation(const AMIInterpolation& ami) +: + requireMatch_(ami.requireMatch_), + reverseTarget_(ami.reverseTarget_), + lowWeightCorrection_(ami.lowWeightCorrection_), + singlePatchProc_(ami.singlePatchProc_), + srcMagSf_(ami.srcMagSf_), + srcAddress_(ami.srcAddress_), + srcWeights_(ami.srcWeights_), + srcWeightsSum_(ami.srcWeightsSum_), + srcCentroids_(ami.srcCentroids_), + srcMapPtr_(nullptr), + tgtMagSf_(ami.tgtMagSf_), + tgtAddress_(ami.tgtAddress_), + tgtWeights_(ami.tgtWeights_), + tgtWeightsSum_(ami.tgtWeightsSum_), + tgtCentroids_(ami.tgtCentroids_), + tgtMapPtr_(nullptr), + upToDate_(false) {} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::update +bool Foam::AMIInterpolation::calculate ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr ) { - addProfiling(ami, "AMIInterpolation::update"); + if (upToDate_) + { + return false; + } + + addProfiling(ami, "AMIInterpolation::calculate"); + + if (surfPtr) + { + srcPatchPts_ = srcPatch.points(); + projectPointsToSurface(surfPtr(), srcPatchPts_); + tsrcPatch0_ = tmpNrc<primitivePatch>::New + ( + SubList<face>(srcPatch), + srcPatchPts_ + ); + + tgtPatchPts_ = tgtPatch.points(); + projectPointsToSurface(surfPtr(), tgtPatchPts_); + ttgtPatch0_ = tmpNrc<primitivePatch>::New + ( + SubList<face>(tgtPatch), + tgtPatchPts_ + ); + } + else + { + tsrcPatch0_.cref(srcPatch); + ttgtPatch0_.cref(tgtPatch); + } label srcTotalSize = returnReduce(srcPatch.size(), sumOp<label>()); label tgtTotalSize = returnReduce(tgtPatch.size(), sumOp<label>()); @@ -860,7 +776,7 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::update DebugInfo<< "AMI: no source faces present - no addressing constructed" << endl; - return; + return false; } Info<< indent @@ -869,219 +785,70 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::update << tgtTotalSize << " target faces" << endl; - // Calculate if patches present on multiple processors singlePatchProc_ = calcDistribution(srcPatch, tgtPatch); - if (singlePatchProc_ == -1) + if (debug) { - // Convert local addressing to global addressing - globalIndex globalSrcFaces(srcPatch.size()); - globalIndex globalTgtFaces(tgtPatch.size()); - - // Create processor map of overlapping faces. This map gets - // (possibly remote) faces from the tgtPatch such that they (together) - // cover all of the srcPatch - autoPtr<mapDistribute> mapPtr = calcProcMap(srcPatch, tgtPatch); - const mapDistribute& map = mapPtr(); - - // Create new target patch that fully encompasses source patch - - // Faces and points - faceList newTgtFaces; - pointField newTgtPoints; - - // Original faces from tgtPatch (in globalIndexing since might be - // remote) - labelList tgtFaceIDs; - distributeAndMergePatches - ( - map, - tgtPatch, - globalTgtFaces, - newTgtFaces, - newTgtPoints, - tgtFaceIDs - ); - - const TargetPatch - newTgtPatch - ( - SubList<face> - ( - newTgtFaces, - newTgtFaces.size() - ), - newTgtPoints - ); - - // Calculate AMI interpolation - autoPtr<AMIMethod<SourcePatch, TargetPatch>> AMIPtr - ( - AMIMethod<SourcePatch, TargetPatch>::New - ( - methodName_, - srcPatch, - newTgtPatch, - triMode_, - reverseTarget_, - requireMatch_ && (lowWeightCorrection_ < 0) - ) - ); - - AMIPtr->calculate - ( - srcAddress_, - srcWeights_, - tgtAddress_, - tgtWeights_ - ); - - - // Note: using patch face areas calculated by the AMI method - // - TODO: move into the calculate or normalise method? - AMIPtr->setMagSf(tgtPatch, map, srcMagSf_, tgtMagSf_); - - - // Now - // ~~~ - // srcAddress_ : per srcPatch face a list of the newTgtPatch (not - // tgtPatch) faces it overlaps - // tgtAddress_ : per newTgtPatch (not tgtPatch) face a list of the - // srcPatch faces it overlaps - - if (debug) - { - writeFaceConnectivity(srcPatch, newTgtPatch, srcAddress_); - } - - - // Rework newTgtPatch indices into globalIndices of tgtPatch - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - - for (labelList& addressing : srcAddress_) - { - for (label& addr : addressing) - { - addr = tgtFaceIDs[addr]; - } - } - - for (labelList& addressing : tgtAddress_) - { - globalSrcFaces.inplaceToGlobal(addressing); - } + Info<< "AMIInterpolation:" << nl + << " singlePatchProc:" << singlePatchProc_ << nl + << endl; + } - // Send data back to originating procs. Note that contributions - // from different processors get added (ListOps::appendEqOp) + return true; +} - mapDistributeBase::distribute - ( - Pstream::commsTypes::nonBlocking, - List<labelPair>(), - tgtPatch.size(), - map.constructMap(), - false, // has flip - map.subMap(), - false, // has flip - tgtAddress_, - ListOps::appendEqOp<label>(), - flipOp(), // flip operation - labelList() - ); - mapDistributeBase::distribute - ( - Pstream::commsTypes::nonBlocking, - List<labelPair>(), - tgtPatch.size(), - map.constructMap(), - false, - map.subMap(), - false, - tgtWeights_, - ListOps::appendEqOp<scalar>(), - flipOp(), - scalarList() - ); +void Foam::AMIInterpolation::reset +( + autoPtr<mapDistribute>&& srcToTgtMap, + autoPtr<mapDistribute>&& tgtToSrcMap, + labelListList&& srcAddress, + scalarListList&& srcWeights, + labelListList&& tgtAddress, + scalarListList&& tgtWeights +) +{ + DebugInFunction<< endl; - // weights normalisation - AMIPtr->normaliseWeights(true, *this); + srcAddress_.transfer(srcAddress); + srcWeights_.transfer(srcWeights); + tgtAddress_.transfer(tgtAddress); + tgtWeights_.transfer(tgtWeights); - // Cache maps and reset addresses - List<Map<label>> cMap; - srcMapPtr_.reset(new mapDistribute(globalSrcFaces, tgtAddress_, cMap)); - tgtMapPtr_.reset(new mapDistribute(globalTgtFaces, srcAddress_, cMap)); - } - else + // Reset the sums of the weights + srcWeightsSum_.setSize(srcWeights_.size()); + forAll(srcWeights_, facei) { - // Calculate AMI interpolation - autoPtr<AMIMethod<SourcePatch, TargetPatch>> AMIPtr - ( - AMIMethod<SourcePatch, TargetPatch>::New - ( - methodName_, - srcPatch, - tgtPatch, - triMode_, - reverseTarget_, - requireMatch_ && (lowWeightCorrection_ < 0) - ) - ); - - AMIPtr->calculate - ( - srcAddress_, - srcWeights_, - tgtAddress_, - tgtWeights_ - ); - - srcMagSf_.transfer(AMIPtr->srcMagSf()); - tgtMagSf_.transfer(AMIPtr->tgtMagSf()); - - AMIPtr->normaliseWeights(true, *this); + srcWeightsSum_[facei] = sum(srcWeights_[facei]); } - if (debug) + tgtWeightsSum_.setSize(tgtWeights_.size()); + forAll(tgtWeights_, facei) { - Info<< "AMIInterpolation : Constructed addressing and weights" << nl - << " triMode :" - << faceAreaIntersect::triangulationModeNames_[triMode_] << nl - << " singlePatchProc:" << singlePatchProc_ << nl - << " srcMagSf :" << gSum(srcMagSf_) << nl - << " tgtMagSf :" << gSum(tgtMagSf_) << nl - << endl; + tgtWeightsSum_[facei] = sum(tgtWeights_[facei]); } + + srcMapPtr_ = srcToTgtMap; + tgtMapPtr_ = tgtToSrcMap; + + upToDate_ = true; } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::append +void Foam::AMIInterpolation::append ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch ) { addProfiling(ami, "AMIInterpolation::append"); // Create a new interpolation - autoPtr<AMIInterpolation<SourcePatch, TargetPatch>> newPtr - ( - new AMIInterpolation<SourcePatch, TargetPatch> - ( - srcPatch, - tgtPatch, - triMode_, - requireMatch_, - methodName_, - lowWeightCorrection_, - reverseTarget_ - ) - ); + auto newPtr = clone(); + newPtr->calculate(srcPatch, tgtPatch); // If parallel then combine the mapDistribution and re-index - if (singlePatchProc_ == -1) + if (distributed()) { labelListList& srcSubMap = srcMapPtr_->subMap(); labelListList& srcConstructMap = srcMapPtr_->constructMap(); @@ -1140,8 +907,7 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::append { forAll(tgtAddress_[tgti], tgtj) { - tgtAddress_[tgti][tgtj] = - mapMap[tgtAddress_[tgti][tgtj]]; + tgtAddress_[tgti][tgtj] = mapMap[tgtAddress_[tgti][tgtj]]; } } @@ -1248,8 +1014,7 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::append } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights +void Foam::AMIInterpolation::normaliseWeights ( const bool conformal, const bool output @@ -1281,327 +1046,10 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::normaliseWeights } -template<class SourcePatch, class TargetPatch> -template<class Type, class CombineOp> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToTarget -( - const UList<Type>& fld, - const CombineOp& cop, - List<Type>& result, - const UList<Type>& defaultValues -) const -{ - addProfiling(ami, "AMIInterpolation::interpolateToTarget"); - - if (fld.size() != srcAddress_.size()) - { - FatalErrorInFunction - << "Supplied field size is not equal to source patch size" << nl - << " source patch = " << srcAddress_.size() << nl - << " target patch = " << tgtAddress_.size() << nl - << " supplied field = " << fld.size() - << abort(FatalError); - } - - if (lowWeightCorrection_ > 0) - { - if (defaultValues.size() != tgtAddress_.size()) - { - FatalErrorInFunction - << "Employing default values when sum of weights falls below " - << lowWeightCorrection_ - << " but supplied default field size is not equal to target " - << "patch size" << nl - << " default values = " << defaultValues.size() << nl - << " target patch = " << tgtAddress_.size() << nl - << abort(FatalError); - } - } - - result.setSize(tgtAddress_.size()); - - if (singlePatchProc_ == -1) - { - const mapDistribute& map = srcMapPtr_(); - - List<Type> work(fld); - map.distribute(work); - - forAll(result, facei) - { - if (tgtWeightsSum_[facei] < lowWeightCorrection_) - { - result[facei] = defaultValues[facei]; - } - else - { - const labelList& faces = tgtAddress_[facei]; - const scalarList& weights = tgtWeights_[facei]; - - forAll(faces, i) - { - cop(result[facei], facei, work[faces[i]], weights[i]); - } - } - } - } - else - { - forAll(result, facei) - { - if (tgtWeightsSum_[facei] < lowWeightCorrection_) - { - result[facei] = defaultValues[facei]; - } - else - { - const labelList& faces = tgtAddress_[facei]; - const scalarList& weights = tgtWeights_[facei]; - - forAll(faces, i) - { - cop(result[facei], facei, fld[faces[i]], weights[i]); - } - } - } - } -} - - -template<class SourcePatch, class TargetPatch> -template<class Type, class CombineOp> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToSource -( - const UList<Type>& fld, - const CombineOp& cop, - List<Type>& result, - const UList<Type>& defaultValues -) const -{ - addProfiling(ami, "AMIInterpolation::interpolateToSource"); - - if (fld.size() != tgtAddress_.size()) - { - FatalErrorInFunction - << "Supplied field size is not equal to target patch size" << nl - << " source patch = " << srcAddress_.size() << nl - << " target patch = " << tgtAddress_.size() << nl - << " supplied field = " << fld.size() - << abort(FatalError); - } - - if (lowWeightCorrection_ > 0) - { - if (defaultValues.size() != srcAddress_.size()) - { - FatalErrorInFunction - << "Employing default values when sum of weights falls below " - << lowWeightCorrection_ - << " but supplied default field size is not equal to target " - << "patch size" << nl - << " default values = " << defaultValues.size() << nl - << " source patch = " << srcAddress_.size() << nl - << abort(FatalError); - } - } - - result.setSize(srcAddress_.size()); - - if (singlePatchProc_ == -1) - { - const mapDistribute& map = tgtMapPtr_(); - - List<Type> work(fld); - map.distribute(work); - - forAll(result, facei) - { - if (srcWeightsSum_[facei] < lowWeightCorrection_) - { - result[facei] = defaultValues[facei]; - } - else - { - const labelList& faces = srcAddress_[facei]; - const scalarList& weights = srcWeights_[facei]; - - forAll(faces, i) - { - cop(result[facei], facei, work[faces[i]], weights[i]); - } - } - } - } - else - { - forAll(result, facei) - { - if (srcWeightsSum_[facei] < lowWeightCorrection_) - { - result[facei] = defaultValues[facei]; - } - else - { - const labelList& faces = srcAddress_[facei]; - const scalarList& weights = srcWeights_[facei]; - - forAll(faces, i) - { - cop(result[facei], facei, fld[faces[i]], weights[i]); - } - } - } - } -} - - -template<class SourcePatch, class TargetPatch> -template<class Type, class CombineOp> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToSource +Foam::label Foam::AMIInterpolation::srcPointFace ( - const Field<Type>& fld, - const CombineOp& cop, - const UList<Type>& defaultValues -) const -{ - tmp<Field<Type>> tresult - ( - new Field<Type> - ( - srcAddress_.size(), - Zero - ) - ); - - interpolateToSource - ( - fld, - multiplyWeightedOp<Type, CombineOp>(cop), - tresult.ref(), - defaultValues - ); - - return tresult; -} - - -template<class SourcePatch, class TargetPatch> -template<class Type, class CombineOp> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToSource -( - const tmp<Field<Type>>& tFld, - const CombineOp& cop, - const UList<Type>& defaultValues -) const -{ - return interpolateToSource(tFld(), cop, defaultValues); -} - - -template<class SourcePatch, class TargetPatch> -template<class Type, class CombineOp> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToTarget -( - const Field<Type>& fld, - const CombineOp& cop, - const UList<Type>& defaultValues -) const -{ - tmp<Field<Type>> tresult - ( - new Field<Type> - ( - tgtAddress_.size(), - Zero - ) - ); - - interpolateToTarget - ( - fld, - multiplyWeightedOp<Type, CombineOp>(cop), - tresult.ref(), - defaultValues - ); - - return tresult; -} - - -template<class SourcePatch, class TargetPatch> -template<class Type, class CombineOp> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToTarget -( - const tmp<Field<Type>>& tFld, - const CombineOp& cop, - const UList<Type>& defaultValues -) const -{ - return interpolateToTarget(tFld(), cop, defaultValues); -} - - -template<class SourcePatch, class TargetPatch> -template<class Type> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToSource -( - const Field<Type>& fld, - const UList<Type>& defaultValues -) const -{ - return interpolateToSource(fld, plusEqOp<Type>(), defaultValues); -} - - -template<class SourcePatch, class TargetPatch> -template<class Type> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToSource -( - const tmp<Field<Type>>& tFld, - const UList<Type>& defaultValues -) const -{ - return interpolateToSource(tFld(), plusEqOp<Type>(), defaultValues); -} - - -template<class SourcePatch, class TargetPatch> -template<class Type> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToTarget -( - const Field<Type>& fld, - const UList<Type>& defaultValues -) const -{ - return interpolateToTarget(fld, plusEqOp<Type>(), defaultValues); -} - - -template<class SourcePatch, class TargetPatch> -template<class Type> -Foam::tmp<Foam::Field<Type>> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::interpolateToTarget -( - const tmp<Field<Type>>& tFld, - const UList<Type>& defaultValues -) const -{ - return interpolateToTarget(tFld(), plusEqOp<Type>(), defaultValues); -} - - -template<class SourcePatch, class TargetPatch> -Foam::label Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcPointFace -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, const vector& n, const label tgtFacei, point& tgtPoint @@ -1645,11 +1093,10 @@ const } -template<class SourcePatch, class TargetPatch> -Foam::label Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtPointFace +Foam::label Foam::AMIInterpolation::tgtPointFace ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, const vector& n, const label srcFacei, point& srcPoint @@ -1693,11 +1140,73 @@ const } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::writeFaceConnectivity +bool Foam::AMIInterpolation::checkSymmetricWeights(const bool log) const +{ + if (Pstream::parRun() && (singlePatchProc_ == -1)) + { + Log << "Checks only valid for serial running (currently)" << endl; + + return true; + } + + bool symmetricSrc = true; + + Log << " Checking for missing src face in tgt lists" << nl; + + forAll(srcAddress_, srcFacei) + { + const labelList& tgtIds = srcAddress_[srcFacei]; + for (const label tgtFacei : tgtIds) + { + if (!tgtAddress_[tgtFacei].found(srcFacei)) + { + symmetricSrc = false; + + Log << " srcFacei:" << srcFacei + << " not found in tgtToSrc list for tgtFacei:" + << tgtFacei << nl; + } + } + } + + if (symmetricSrc) + { + Log << " - symmetric" << endl; + } + + bool symmetricTgt = true; + + Log << " Checking for missing tgt face in src lists" << nl; + + forAll(tgtAddress_, tgtFacei) + { + const labelList& srcIds = tgtAddress_[tgtFacei]; + for (const label srcFacei : srcIds) + { + if (!srcAddress_[srcFacei].found(tgtFacei)) + { + symmetricTgt = false; + + Log << " tgtFacei:" << tgtFacei + << " not found in srcToTgt list for srcFacei:" + << srcFacei << nl; + } + } + } + + if (symmetricTgt) + { + Log << " - symmetric" << endl; + } + + return symmetricSrc && symmetricTgt; +} + + +void Foam::AMIInterpolation::writeFaceConnectivity ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, const labelListList& srcAddress ) const @@ -1726,4 +1235,20 @@ const } +void Foam::AMIInterpolation::write(Ostream& os) const +{ + os.writeEntry("AMIMethod", type()); + + if (reverseTarget_) + { + os.writeEntry("flipNormals", reverseTarget_); + } + + if (lowWeightCorrection_ > 0) + { + os.writeEntry("lowWeightCorrection", lowWeightCorrection_); + } +} + + // ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.H index fcf418ff6bf2b67087a6c2cfbcfed0ca3c3fd8fb..8ce226bbb4f392b1fcf3bb66491c069a0548397b 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.H +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolation.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2016-2018 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -61,76 +61,53 @@ SourceFiles #include "globalIndex.H" #include "ops.H" #include "Enum.H" +#include "pointList.H" +#include "indexedOctree.H" +#include "treeDataPrimitivePatch.H" + +#include "runTimeSelectionTables.H" + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -/*---------------------------------------------------------------------------*\ - Class AMIInterpolationName Declaration -\*---------------------------------------------------------------------------*/ - -TemplateName(AMIInterpolation); - - /*---------------------------------------------------------------------------*\ Class AMIInterpolation Declaration \*---------------------------------------------------------------------------*/ -template<class SourcePatch, class TargetPatch> class AMIInterpolation -: - public AMIInterpolationName { public: // Public data types - //- Enumeration specifying interpolation method - enum interpolationMethod - { - imDirect, - imMapNearest, - imFaceAreaWeight, - imPartialFaceAreaWeight - }; - - static const Enum<interpolationMethod> interpolationMethodNames_; - static bool cacheIntersections_; - //- Calculate the patch face magnitudes for the given tri-mode - template<class Patch> - static tmp<scalarField> patchMagSf - ( - const Patch& patch, - const faceAreaIntersect::triangulationMode triMode - ); +protected: -private: + //- Local typedef to octree tree-type + typedef treeDataPrimitivePatch<primitivePatch> treeType; - // Private data + // Protected data - //- Interpolation method - const word methodName_; + //- Flag to indicate that the two patches must be matched/an overlap + //- exists between them + bool requireMatch_; //- Flag to indicate that the two patches are co-directional and //- that the orientation of the target patch should be reversed const bool reverseTarget_; - //- Flag to indicate that the two patches must be matched/an overlap - //- exists between them - const bool requireMatch_; + //- Threshold weight below which interpolation is deactivated + scalar lowWeightCorrection_; //- Index of processor that holds all of both sides. -1 in all other //- cases label singlePatchProc_; - //- Threshold weight below which interpolation is deactivated - scalar lowWeightCorrection_; - // Source patch @@ -146,6 +123,19 @@ private: //- Sum of weights of target faces per source face scalarField srcWeightsSum_; + //- Centroid of target faces per source face + pointListList srcCentroids_; + + //- Source patch points if input points are manipulated, e.g. + //- projected + pointField srcPatchPts_; + + //- Source patch using manipulated input points + tmpNrc<primitivePatch> tsrcPatch0_; + + //- Source map pointer - parallel running only + autoPtr<mapDistribute> srcMapPtr_; + // Target patch @@ -161,71 +151,44 @@ private: //- Sum of weights of source faces per target face scalarField tgtWeightsSum_; + //- Centroid of source faces per target face + pointListList tgtCentroids_; - //- Face triangulation mode - const faceAreaIntersect::triangulationMode triMode_; + //- Target patch points if input points are manipulated, e.g. + //- projected + pointField tgtPatchPts_; - //- Source map pointer - parallel running only - autoPtr<mapDistribute> srcMapPtr_; + //- Target patch using manipulated input points + tmpNrc<primitivePatch> ttgtPatch0_; - //- Target map pointer - parallel running only - autoPtr<mapDistribute> tgtMapPtr_; + //- Target map pointer - parallel running only + autoPtr<mapDistribute> tgtMapPtr_; + //- Up-to-date flag + bool upToDate_; - // Private Member Functions - //- No copy construct - AMIInterpolation(const AMIInterpolation&) = delete; + // Protected Member Functions //- No copy assignment void operator=(const AMIInterpolation&) = delete; - // Parallel functionality - - //- Calculate if patches are on multiple processors - label calcDistribution - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch - ) const; - - label calcOverlappingProcs - ( - const List<treeBoundBoxList>& procBb, - const treeBoundBox& bb, - boolList& overlaps - ) const; - - void distributePatches - ( - const mapDistribute& map, - const TargetPatch& pp, - const globalIndex& gi, - List<faceList>& faces, - List<pointField>& points, - List<labelList>& tgtFaceIDs - ) const; + // Initialisation - void distributeAndMergePatches + //- Reset the octree for the patch face search + autoPtr<indexedOctree<treeType>> createTree ( - const mapDistribute& map, - const TargetPatch& tgtPatch, - const globalIndex& gi, - faceList& tgtFaces, - pointField& tgtPoints, - labelList& tgtFaceIDs + const primitivePatch& patch ) const; - autoPtr<mapDistribute> calcProcMap + //- Calculate if patches are on multiple processors + label calcDistribution ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch ) const; - - // Initialisation - //- Project points to surface void projectPointsToSurface ( @@ -234,6 +197,15 @@ private: ) const; + // Access + + //- Return the orginal src patch with optionally updated points + inline const primitivePatch& srcPatch0() const; + + //- Return the orginal tgt patch with optionally updated points + inline const primitivePatch& tgtPatch0() const; + + // Evaluation //- Normalise the (area) weights - suppresses numerical error in @@ -273,96 +245,127 @@ private: autoPtr<mapDistribute>& tgtMap ); - void constructFromSurface - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const autoPtr<searchableSurface>& surfPtr - ); public: - // Constructors + //- Runtime type information + TypeName("AMIInterpolation"); - //- Construct from components - AMIInterpolation + // Selection tables + + //- Selection table for dictionary construction + declareRunTimeSelectionTable ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool requireMatch = true, - const interpolationMethod& method = imFaceAreaWeight, - const scalar lowWeightCorrection = -1, + autoPtr, + AMIInterpolation, + dict, + ( + const dictionary& dict, + const bool reverseTarget + ), + ( + dict, + reverseTarget + ) + ); + + //- Selection table for component-wise construction + declareRunTimeSelectionTable + ( + autoPtr, + AMIInterpolation, + component, + ( + const bool requireMatch, + const bool reverseTarget, + const scalar lowWeightCorrection + ), + ( + requireMatch, + reverseTarget, + lowWeightCorrection + ) + ); + + //- Selector for dictionary + static autoPtr<AMIInterpolation> New + ( + const word& modelName, + const dictionary& dict, const bool reverseTarget = false ); - //- Construct from components - AMIInterpolation + //- Selector for components + static autoPtr<AMIInterpolation> New ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, + const word& modelName, const bool requireMatch = true, - const word& methodName = - interpolationMethodNames_[imFaceAreaWeight], - const scalar lowWeightCorrection = -1, - const bool reverseTarget = false + const bool reverseTarget = false, + const scalar lowWeightCorrection = -1 ); - //- Construct from components, with projection surface + + // Constructors + + //- Construct from dictionary AMIInterpolation ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const autoPtr<searchableSurface>& surf, - const faceAreaIntersect::triangulationMode& triMode, - const bool requireMatch = true, - const interpolationMethod& method = imFaceAreaWeight, - const scalar lowWeightCorrection = -1, + const dictionary& dict, const bool reverseTarget = false ); - //- Construct from components, with projection surface + //- Construct from components AMIInterpolation ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const autoPtr<searchableSurface>& surf, - const faceAreaIntersect::triangulationMode& triMode, const bool requireMatch = true, - const word& methodName = - interpolationMethodNames_[imFaceAreaWeight], - const scalar lowWeightCorrection = -1, - const bool reverseTarget = false + const bool reverseTarget = false, + const scalar lowWeightCorrection = -1 ); //- Construct from agglomeration of AMIInterpolation. Agglomeration - // passed in as new coarse size and addressing from fine from coarse + //- passed in as new coarse size and addressing from fine from coarse AMIInterpolation ( - const AMIInterpolation<SourcePatch, TargetPatch>& fineAMI, + const AMIInterpolation& fineAMI, const labelList& sourceRestrictAddressing, const labelList& neighbourRestrictAddressing ); + //- Construct as copy + AMIInterpolation(const AMIInterpolation& ami); - //- Destructor - ~AMIInterpolation(); + //- Construct and return a clone + virtual autoPtr<AMIInterpolation> clone() const + { + return autoPtr<AMIInterpolation>::New(*this); + } - // Typedef to SourcePatch type this AMIInterpolation is instantiated on - typedef SourcePatch sourcePatchType; - // Typedef to TargetPatch type this AMIInterpolation is instantiated on - typedef TargetPatch targetPatchType; + //- Destructor + virtual ~AMIInterpolation() = default; // Member Functions // Access - //- Set to -1, or the processor holding all faces (both sides) of - //- the AMI - inline label singlePatchProc() const; + //- Access to the up-to-date flag + inline bool upToDate() const; + + //- Access to the up-to-date flag + inline bool& upToDate(); + + //- Access to the distributed flag + inline bool distributed() const; + + //- Access to the requireMatch flag + inline bool requireMatch() const; + + //- Access to the requireMatch flag + inline bool setRequireMatch(const bool flag); + + //- Access to the reverseTarget flag + inline bool reverseTarget() const; //- Threshold weight below which interpolation is deactivated inline scalar lowWeightCorrection() const; @@ -370,6 +373,10 @@ public: //- Return true if employing a 'lowWeightCorrection' inline bool applyLowWeightCorrection() const; + //- Set to -1, or the processor holding all faces (both sides) of + //- the AMI + inline label singlePatchProc() const; + // Source patch @@ -399,6 +406,12 @@ public: //- patch weights (i.e. the sum before normalisation) inline scalarField& srcWeightsSum(); + //- Return const access to source patch face centroids + inline const pointListList& srcCentroids() const; + + //- Return access to source patch face centroids + inline pointListList& srcCentroids(); + //- Source map pointer - valid only if singlePatchProc = -1 //- This gets source data into a form to be consumed by //- tgtAddress, tgtWeights @@ -441,18 +454,30 @@ public: // Manipulation - //- Update addressing and weights - void update + //- Update addressing, weights and (optional) centroids + virtual bool calculate + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr = nullptr + ); + + //- Set the maps, addresses and weights from an external source + void reset ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch + autoPtr<mapDistribute>&& srcToTgtMap, + autoPtr<mapDistribute>&& tgtToSrcMap, + labelListList&& srcAddress, + scalarListList&& srcWeights, + labelListList&& tgtAddress, + scalarListList&& tgtWeights ); //- Append additional addressing and weights void append ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch ); //- Normalise the weights @@ -560,8 +585,8 @@ public: //- Return source patch face index of point on target patch face label srcPointFace ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, const vector& n, const label tgtFacei, point& tgtPoint @@ -571,8 +596,8 @@ public: //- Return target patch face index of point on source patch face label tgtPointFace ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, const vector& n, const label srcFacei, point& srcPoint @@ -582,13 +607,23 @@ public: // Checks + //- Check if src addresses are present in tgt addresses and + //- viceversa + bool checkSymmetricWeights(const bool log) const; + //- Write face connectivity as OBJ file void writeFaceConnectivity ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, const labelListList& srcAddress ) const; + + + // I-O + + //- Write + virtual void write(Ostream& os) const; }; @@ -603,8 +638,7 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #ifdef NoRepository - #include "AMIInterpolation.C" - #include "AMIInterpolationParallelOps.C" + #include "AMIInterpolationTemplates.C" #endif // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationI.H index 9cd5e51ff1dce34480e328ddd6cd7532e31c5fff..22823a23ec6d8d57f334b1731d8dba53d92506f9 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationI.H +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationI.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,170 +26,203 @@ License \*---------------------------------------------------------------------------*/ -template<class SourcePatch, class TargetPatch> -inline Foam::label -Foam::AMIInterpolation<SourcePatch, TargetPatch>::singlePatchProc() const +inline const Foam::primitivePatch& Foam::AMIInterpolation::srcPatch0() const { - return singlePatchProc_; + if (!tsrcPatch0_.valid()) + { + FatalErrorInFunction + << "tsrcPatch0Ptr_ not set" + << abort(FatalError); + } + + return tsrcPatch0_(); +} + + +inline const Foam::primitivePatch& Foam::AMIInterpolation::tgtPatch0() const +{ + + if (!ttgtPatch0_.valid()) + { + FatalErrorInFunction + << "ttgtPatch0Ptr_ not set" + << abort(FatalError); + } + + return ttgtPatch0_(); +} + + +inline bool Foam::AMIInterpolation::upToDate() const +{ + return upToDate_; } -template<class SourcePatch, class TargetPatch> -inline Foam::scalar -Foam::AMIInterpolation<SourcePatch, TargetPatch>::lowWeightCorrection() const +inline bool& Foam::AMIInterpolation::upToDate() +{ + return upToDate_; +} + + +inline bool Foam::AMIInterpolation::distributed() const +{ + return singlePatchProc_ == -1; +} + + +inline bool Foam::AMIInterpolation::requireMatch() const +{ + return requireMatch_ && lowWeightCorrection_ < 0; +} + + +inline bool Foam::AMIInterpolation::setRequireMatch(const bool flag) +{ + requireMatch_ = flag; + return requireMatch_; +} + + +inline bool Foam::AMIInterpolation::reverseTarget() const +{ + return reverseTarget_; +} + + +inline Foam::scalar Foam::AMIInterpolation::lowWeightCorrection() const { return lowWeightCorrection_; } -template<class SourcePatch, class TargetPatch> -inline bool -Foam::AMIInterpolation<SourcePatch, TargetPatch>:: -applyLowWeightCorrection() const +inline bool Foam::AMIInterpolation::applyLowWeightCorrection() const { return lowWeightCorrection_ > 0; } -template<class SourcePatch, class TargetPatch> -inline const Foam::List<Foam::scalar>& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcMagSf() const +inline Foam::label Foam::AMIInterpolation::singlePatchProc() const +{ + return singlePatchProc_; +} + + +inline const Foam::List<Foam::scalar>& Foam::AMIInterpolation::srcMagSf() const { return srcMagSf_; } -template<class SourcePatch, class TargetPatch> -inline Foam::List<Foam::scalar>& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcMagSf() +inline Foam::List<Foam::scalar>& Foam::AMIInterpolation::srcMagSf() { return srcMagSf_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::labelListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcAddress() const +inline const Foam::labelListList& Foam::AMIInterpolation::srcAddress() const { return srcAddress_; } -template<class SourcePatch, class TargetPatch> -inline Foam::labelListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcAddress() +inline Foam::labelListList& Foam::AMIInterpolation::srcAddress() { return srcAddress_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::scalarListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcWeights() const +inline const Foam::scalarListList& Foam::AMIInterpolation::srcWeights() const { return srcWeights_; } -template<class SourcePatch, class TargetPatch> -inline Foam::scalarListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcWeights() +inline Foam::scalarListList& Foam::AMIInterpolation::srcWeights() { return srcWeights_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::scalarField& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcWeightsSum() const +inline const Foam::scalarField& Foam::AMIInterpolation::srcWeightsSum() const { return srcWeightsSum_; } -template<class SourcePatch, class TargetPatch> -inline Foam::scalarField& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcWeightsSum() +inline Foam::scalarField& Foam::AMIInterpolation::srcWeightsSum() { return srcWeightsSum_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::mapDistribute& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::srcMap() const +inline const Foam::pointListList& Foam::AMIInterpolation::srcCentroids() const +{ + return srcCentroids_; +} + + +inline Foam::pointListList& Foam::AMIInterpolation::srcCentroids() +{ + return srcCentroids_; +} + + +inline const Foam::mapDistribute& Foam::AMIInterpolation::srcMap() const { return *srcMapPtr_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::List<Foam::scalar>& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtMagSf() const +inline const Foam::List<Foam::scalar>& Foam::AMIInterpolation::tgtMagSf() const { return tgtMagSf_; } -template<class SourcePatch, class TargetPatch> -inline Foam::List<Foam::scalar>& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtMagSf() +inline Foam::List<Foam::scalar>& Foam::AMIInterpolation::tgtMagSf() { return tgtMagSf_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::labelListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtAddress() const +inline const Foam::labelListList& Foam::AMIInterpolation::tgtAddress() const { return tgtAddress_; } -template<class SourcePatch, class TargetPatch> -inline Foam::labelListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtAddress() +inline Foam::labelListList& Foam::AMIInterpolation::tgtAddress() { return tgtAddress_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::scalarListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtWeights() const +inline const Foam::scalarListList& Foam::AMIInterpolation::tgtWeights() const { return tgtWeights_; } -template<class SourcePatch, class TargetPatch> -inline Foam::scalarListList& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtWeights() +inline Foam::scalarListList& Foam::AMIInterpolation::tgtWeights() { return tgtWeights_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::scalarField& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtWeightsSum() const +inline const Foam::scalarField& Foam::AMIInterpolation::tgtWeightsSum() const { return tgtWeightsSum_; } -template<class SourcePatch, class TargetPatch> -inline Foam::scalarField& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtWeightsSum() +inline Foam::scalarField& Foam::AMIInterpolation::tgtWeightsSum() { return tgtWeightsSum_; } -template<class SourcePatch, class TargetPatch> -inline const Foam::mapDistribute& -Foam::AMIInterpolation<SourcePatch, TargetPatch>::tgtMap() const +inline const Foam::mapDistribute& Foam::AMIInterpolation::tgtMap() const { return *tgtMapPtr_; } diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationName.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationName.C deleted file mode 100644 index b09ca433fbef4a6a4f8da8d4083a7bb8ec255750..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationName.C +++ /dev/null @@ -1,38 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2011-2012 OpenFOAM Foundation -------------------------------------------------------------------------------- -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 "AMIInterpolation.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ -defineTypeNameAndDebug(AMIInterpolationName, 0); -} - - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethodNew.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationNew.C similarity index 59% rename from src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethodNew.C rename to src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationNew.C index 5ed107dc23e47de7f3d35a44d06c9d8e44e8eb37..6bc4ba2c2e673869b8afae534ea2ecd5a212a9d2 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethodNew.C +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationNew.C @@ -5,8 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2019 OpenCFD Ltd. + Copyright (C) 2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,46 +25,66 @@ License \*---------------------------------------------------------------------------*/ +#include "AMIInterpolation.H" + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -Foam::autoPtr<Foam::AMIMethod<SourcePatch, TargetPatch>> -Foam::AMIMethod<SourcePatch, TargetPatch>::New +Foam::autoPtr<Foam::AMIInterpolation> Foam::AMIInterpolation::New ( - const word& methodName, - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, + const word& modelName, + const dictionary& dict, + const bool reverseTarget +) +{ + DebugInfo << "Selecting model " << modelName << endl; + + auto cstrIter = dictConstructorTablePtr_->cfind(modelName); + + if (!cstrIter.found()) + { + FatalErrorInLookup + ( + typeName, + modelName, + *dictConstructorTablePtr_ + ) << exit(FatalError); + } + + return autoPtr<AMIInterpolation>(cstrIter()(dict, reverseTarget)); +} + + +Foam::autoPtr<Foam::AMIInterpolation> Foam::AMIInterpolation::New +( + const word& modelName, + const bool requireMatch, const bool reverseTarget, - const bool requireMatch + const scalar lowWeightCorrection ) { - DebugInfo << "Selecting AMIMethod " << methodName << endl; + DebugInfo << "Selecting model " << modelName << endl; - auto cstrIter = componentsConstructorTablePtr_->cfind(methodName); + auto cstrIter = componentConstructorTablePtr_->cfind(modelName); if (!cstrIter.found()) { FatalErrorInLookup ( - "AMIMethod", - methodName, - *componentsConstructorTablePtr_ + typeName, + modelName, + *componentConstructorTablePtr_ ) << exit(FatalError); } - return autoPtr<AMIMethod<SourcePatch, TargetPatch>> + return autoPtr<AMIInterpolation> ( cstrIter() ( - srcPatch, - tgtPatch, - triMode, + requireMatch, reverseTarget, - requireMatch + lowWeightCorrection ) ); } - // ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationTemplates.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..418bf48cc863fe6a977cdd81b54a4ab92f7ec37c --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationTemplates.C @@ -0,0 +1,318 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2011-2017 OpenFOAM Foundation + Copyright (C) 2015-2018 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "profiling.H" +#include "mapDistribute.H" + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +template<class Type, class CombineOp> +void Foam::AMIInterpolation::interpolateToTarget +( + const UList<Type>& fld, + const CombineOp& cop, + List<Type>& result, + const UList<Type>& defaultValues +) const +{ + addProfiling(ami, "AMIInterpolation::interpolateToTarget"); + + if (fld.size() != srcAddress_.size()) + { + FatalErrorInFunction + << "Supplied field size is not equal to source patch size" << nl + << " source patch = " << srcAddress_.size() << nl + << " target patch = " << tgtAddress_.size() << nl + << " supplied field = " << fld.size() + << abort(FatalError); + } + + if (lowWeightCorrection_ > 0) + { + if (defaultValues.size() != tgtAddress_.size()) + { + FatalErrorInFunction + << "Employing default values when sum of weights falls below " + << lowWeightCorrection_ + << " but supplied default field size is not equal to target " + << "patch size" << nl + << " default values = " << defaultValues.size() << nl + << " target patch = " << tgtAddress_.size() << nl + << abort(FatalError); + } + } + + result.setSize(tgtAddress_.size()); + + if (distributed()) + { + const mapDistribute& map = srcMapPtr_(); + + List<Type> work(fld); + map.distribute(work); + + forAll(result, facei) + { + if (tgtWeightsSum_[facei] < lowWeightCorrection_) + { + result[facei] = defaultValues[facei]; + } + else + { + const labelList& faces = tgtAddress_[facei]; + const scalarList& weights = tgtWeights_[facei]; + + forAll(faces, i) + { + cop(result[facei], facei, work[faces[i]], weights[i]); + } + } + } + } + else + { + forAll(result, facei) + { + if (tgtWeightsSum_[facei] < lowWeightCorrection_) + { + result[facei] = defaultValues[facei]; + } + else + { + const labelList& faces = tgtAddress_[facei]; + const scalarList& weights = tgtWeights_[facei]; + + forAll(faces, i) + { + cop(result[facei], facei, fld[faces[i]], weights[i]); + } + } + } + } +} + + +template<class Type, class CombineOp> +void Foam::AMIInterpolation::interpolateToSource +( + const UList<Type>& fld, + const CombineOp& cop, + List<Type>& result, + const UList<Type>& defaultValues +) const +{ + addProfiling(ami, "AMIInterpolation::interpolateToSource"); + + if (fld.size() != tgtAddress_.size()) + { + FatalErrorInFunction + << "Supplied field size is not equal to target patch size" << nl + << " source patch = " << srcAddress_.size() << nl + << " target patch = " << tgtAddress_.size() << nl + << " supplied field = " << fld.size() + << abort(FatalError); + } + + if (lowWeightCorrection_ > 0) + { + if (defaultValues.size() != srcAddress_.size()) + { + FatalErrorInFunction + << "Employing default values when sum of weights falls below " + << lowWeightCorrection_ + << " but supplied default field size is not equal to source " + << "patch size" << nl + << " default values = " << defaultValues.size() << nl + << " source patch = " << srcAddress_.size() << nl + << abort(FatalError); + } + } + + result.setSize(srcAddress_.size()); + + if (distributed()) + { + const mapDistribute& map = tgtMapPtr_(); + + List<Type> work(fld); + map.distribute(work); + + forAll(result, facei) + { + if (srcWeightsSum_[facei] < lowWeightCorrection_) + { + result[facei] = defaultValues[facei]; + } + else + { + const labelList& faces = srcAddress_[facei]; + const scalarList& weights = srcWeights_[facei]; + + forAll(faces, i) + { + cop(result[facei], facei, work[faces[i]], weights[i]); + } + } + } + } + else + { + forAll(result, facei) + { + if (srcWeightsSum_[facei] < lowWeightCorrection_) + { + result[facei] = defaultValues[facei]; + } + else + { + const labelList& faces = srcAddress_[facei]; + const scalarList& weights = srcWeights_[facei]; + + forAll(faces, i) + { + cop(result[facei], facei, fld[faces[i]], weights[i]); + } + } + } + } +} + + +template<class Type, class CombineOp> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource +( + const Field<Type>& fld, + const CombineOp& cop, + const UList<Type>& defaultValues +) const +{ + auto tresult = tmp<Field<Type>>::New(srcAddress_.size(), Zero); + + interpolateToSource + ( + fld, + multiplyWeightedOp<Type, CombineOp>(cop), + tresult.ref(), + defaultValues + ); + + return tresult; +} + + +template<class Type, class CombineOp> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource +( + const tmp<Field<Type>>& tFld, + const CombineOp& cop, + const UList<Type>& defaultValues +) const +{ + return interpolateToSource(tFld(), cop, defaultValues); +} + + +template<class Type, class CombineOp> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget +( + const Field<Type>& fld, + const CombineOp& cop, + const UList<Type>& defaultValues +) const +{ + auto tresult = tmp<Field<Type>>::New(tgtAddress_.size(), Zero); + + interpolateToTarget + ( + fld, + multiplyWeightedOp<Type, CombineOp>(cop), + tresult.ref(), + defaultValues + ); + + return tresult; +} + + +template<class Type, class CombineOp> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget +( + const tmp<Field<Type>>& tFld, + const CombineOp& cop, + const UList<Type>& defaultValues +) const +{ + return interpolateToTarget(tFld(), cop, defaultValues); +} + + +template<class Type> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource +( + const Field<Type>& fld, + const UList<Type>& defaultValues +) const +{ + return interpolateToSource(fld, plusEqOp<Type>(), defaultValues); +} + + +template<class Type> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToSource +( + const tmp<Field<Type>>& tFld, + const UList<Type>& defaultValues +) const +{ + return interpolateToSource(tFld(), plusEqOp<Type>(), defaultValues); +} + + +template<class Type> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget +( + const Field<Type>& fld, + const UList<Type>& defaultValues +) const +{ + return interpolateToTarget(fld, plusEqOp<Type>(), defaultValues); +} + + +template<class Type> +Foam::tmp<Foam::Field<Type>> Foam::AMIInterpolation::interpolateToTarget +( + const tmp<Field<Type>>& tFld, + const UList<Type>& defaultValues +) const +{ + return interpolateToTarget(tFld(), plusEqOp<Type>(), defaultValues); +} + + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.H deleted file mode 100644 index bf569aad560a8e392ed97e9277573397b55bead0..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.H +++ /dev/null @@ -1,321 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2016-2018 OpenCFD Ltd. -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - -Class - Foam::AMIMethod - -Description - Base class for Arbitrary Mesh Interface (AMI) methods - -SourceFiles - AMIMethod.C - -\*---------------------------------------------------------------------------*/ - -#ifndef AMIMethod_H -#define AMIMethod_H - -#include "className.H" -#include "DynamicList.H" -#include "faceAreaIntersect.H" -#include "indexedOctree.H" -#include "treeDataPrimitivePatch.H" -#include "treeBoundBoxList.H" -#include "runTimeSelectionTables.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -template<class SourcePatch, class TargetPatch> class AMIInterpolation; - -/*---------------------------------------------------------------------------*\ - Class AMIMethod Declaration -\*---------------------------------------------------------------------------*/ - -template<class SourcePatch, class TargetPatch> -class AMIMethod -{ - -private: - - // Private Member Functions - - //- No copy construct - AMIMethod(const AMIMethod&) = delete; - - //- No copy assignment - void operator=(const AMIMethod&) = delete; - - -protected: - - //- Local typedef to octree tree-type - typedef treeDataPrimitivePatch<TargetPatch> treeType; - - - // Protected data - - //- Reference to source patch - const SourcePatch& srcPatch_; - - //- Reference to target patch - const TargetPatch& tgtPatch_; - - //- Flag to indicate that the two patches are co-directional and - //- that the orientation of the target patch should be reversed - const bool reverseTarget_; - - //- Flag to indicate that the two patches must be matched/an overlap - //- exists between them - const bool requireMatch_; - - //- Source face areas - List<scalar> srcMagSf_; - - //- Target face areas - List<scalar> tgtMagSf_; - - //- Labels of faces that are not overlapped by any target faces - //- (should be empty for correct functioning) - labelList srcNonOverlap_; - - //- Octree used to find face seeds - autoPtr<indexedOctree<treeType>> treePtr_; - - //- Face triangulation mode - const faceAreaIntersect::triangulationMode triMode_; - - - // Protected Member Functions - - // Helper functions - - //- Check AMI patch coupling - void checkPatches() const; - - //- Initialise and return true if all ok - bool initialise - ( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label& srcFacei, - label& tgtFacei - ); - - //- Write triangle intersection to OBJ file - void writeIntersectionOBJ - ( - const scalar area, - const face& f1, - const face& f2, - const pointField& f1Points, - const pointField& f2Points - ) const; - - - // Common AMI method functions - - //- Reset the octree for the target patch face search - void resetTree(); - - //- Find face on target patch that overlaps source face - label findTargetFace(const label srcFacei) const; - - //- Add faces neighbouring facei to the ID list - void appendNbrFaces - ( - const label facei, - const TargetPatch& patch, - const DynamicList<label>& visitedFaces, - DynamicList<label>& faceIDs - ) const; - - //- Helper function to decompose a patch - template<class PatchType> - void triangulatePatch - ( - const PatchType& patch, - List<DynamicList<face>>& tris, - List<scalar>& magSf - ) const; - - -public: - - //- Runtime type information - TypeName("AMIMethod"); - - //- Declare runtime constructor selection table - declareRunTimeSelectionTable - ( - autoPtr, - AMIMethod, - components, - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch - ), - ( - srcPatch, - tgtPatch, - triMode, - reverseTarget, - requireMatch - ) - ); - - //- Construct from components - AMIMethod - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch - ); - - //- Selector - static autoPtr<AMIMethod> New - ( - const word& methodName, - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch - ); - - - //- Destructor - virtual ~AMIMethod() = default; - - - // Member Functions - - // Access - - //- Labels of faces that are not overlapped by any target faces - // Note: this should be empty for correct functioning - inline const labelList& srcNonOverlap() const; - - //- Flag to indicate that interpolation patches are conformal - virtual bool conformal() const; - - //- Return const access to source patch face areas - inline const List<scalar>& srcMagSf() const; - - //- Return access to source patch face areas - inline List<scalar>& srcMagSf(); - - //- Return const access to target patch face areas - inline const List<scalar>& tgtMagSf() const; - - //- Return access to target patch face areas - inline List<scalar>& tgtMagSf(); - - - // Manipulation - - //- Update addressing and weights - virtual void calculate - ( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei = -1, - label tgtFacei = -1 - ) = 0; - - //- Set the face areas for parallel runs - virtual void setMagSf - ( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf - ) const = 0; - - //- Normalise the weight. Can optionally subset addressing - //- (e.g. for mapNearest) - virtual void normaliseWeights - ( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter - ) = 0; -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#define makeAMIMethod(AMIType) \ - \ - typedef AMIMethod<AMIType::sourcePatchType,AMIType::targetPatchType> \ - AMIMethod##AMIType; \ - \ - defineNamedTemplateTypeNameAndDebug(AMIMethod##AMIType, 0); \ - defineTemplateRunTimeSelectionTable(AMIMethod##AMIType, components); - - -#define makeAMIMethodType(AMIType, Method) \ - \ - typedef Method<AMIType::sourcePatchType,AMIType::targetPatchType> \ - Method##AMIType; \ - \ - defineNamedTemplateTypeNameAndDebug(Method##AMIType, 0); \ - \ - AMIMethod<AMIType::sourcePatchType,AMIType::targetPatchType>:: \ - addcomponentsConstructorToTable<Method##AMIType> \ - add##Method##AMIType##ConstructorToTable_; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#include "AMIMethodI.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#ifdef NoRepository - #include "AMIMethod.C" - #include "AMIMethodNew.C" -#endif - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethodI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethodI.H deleted file mode 100644 index caea348e2df5fad06cea4bee21328e7bad7df2d2..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethodI.H +++ /dev/null @@ -1,68 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013 OpenFOAM Foundation -------------------------------------------------------------------------------- -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/>. - -\*---------------------------------------------------------------------------*/ - -template<class SourcePatch, class TargetPatch> -inline const Foam::List<Foam::scalar>& -Foam::AMIMethod<SourcePatch, TargetPatch>::srcMagSf() const -{ - return srcMagSf_; -} - - -template<class SourcePatch, class TargetPatch> -inline Foam::List<Foam::scalar>& -Foam::AMIMethod<SourcePatch, TargetPatch>::srcMagSf() -{ - return srcMagSf_; -} - - -template<class SourcePatch, class TargetPatch> -inline const Foam::List<Foam::scalar>& -Foam::AMIMethod<SourcePatch, TargetPatch>::tgtMagSf() const -{ - return tgtMagSf_; -} - - -template<class SourcePatch, class TargetPatch> -inline Foam::List<Foam::scalar>& -Foam::AMIMethod<SourcePatch, TargetPatch>::tgtMagSf() -{ - return tgtMagSf_; -} - - -template<class SourcePatch, class TargetPatch> -inline const Foam::labelList& -Foam::AMIMethod<SourcePatch, TargetPatch>::srcNonOverlap() const -{ - return srcNonOverlap_; -} - - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/directAMI/directAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/directAMI/directAMI.C deleted file mode 100644 index 894b33fe0f63d5f0292d48e3a46495ca7ced0d30..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/directAMI/directAMI.C +++ /dev/null @@ -1,343 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation -------------------------------------------------------------------------------- -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 "directAMI.H" - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::directAMI<SourcePatch, TargetPatch>::appendToDirectSeeds -( - labelList& mapFlag, - labelList& srcTgtSeed, - DynamicList<label>& srcSeeds, - DynamicList<label>& nonOverlapFaces, - label& srcFacei, - label& tgtFacei -) const -{ - const labelList& srcNbr = this->srcPatch_.faceFaces()[srcFacei]; - const labelList& tgtNbr = this->tgtPatch_.faceFaces()[tgtFacei]; - - const pointField& srcPoints = this->srcPatch_.points(); - const pointField& tgtPoints = this->tgtPatch_.points(); - - const vectorField& srcCf = this->srcPatch_.faceCentres(); - - for (const label srcI : srcNbr) - { - if ((mapFlag[srcI] == 0) && (srcTgtSeed[srcI] == -1)) - { - // first attempt: match by comparing face centres - const face& srcF = this->srcPatch_[srcI]; - const point& srcC = srcCf[srcI]; - - scalar tol = GREAT; - forAll(srcF, fpI) - { - const point& p = srcPoints[srcF[fpI]]; - scalar d2 = magSqr(p - srcC); - if (d2 < tol) - { - tol = d2; - } - } - tol = max(SMALL, 0.0001*sqrt(tol)); - - bool found = false; - for (const label tgtI : tgtNbr) - { - const face& tgtF = this->tgtPatch_[tgtI]; - const point tgtC = tgtF.centre(tgtPoints); - - if (mag(srcC - tgtC) < tol) - { - // new match - append to lists - found = true; - - srcTgtSeed[srcI] = tgtI; - srcSeeds.append(srcI); - - break; - } - } - - // second attempt: match by shooting a ray into the tgt face - if (!found) - { - const vector srcN = srcF.areaNormal(srcPoints); - - for (const label tgtI : tgtNbr) - { - const face& tgtF = this->tgtPatch_[tgtI]; - pointHit ray = tgtF.ray(srcCf[srcI], srcN, tgtPoints); - - if (ray.hit()) - { - // new match - append to lists - found = true; - - srcTgtSeed[srcI] = tgtI; - srcSeeds.append(srcI); - - break; - } - } - } - - // no match available for source face srcI - if (!found) - { - mapFlag[srcI] = -1; - nonOverlapFaces.append(srcI); - - if (debug) - { - Pout<< "source face not found: id=" << srcI - << " centre=" << srcCf[srcI] - << " normal=" << srcF.areaNormal(srcPoints) - << " points=" << srcF.points(srcPoints) - << endl; - - Pout<< "target neighbours:" << nl; - for (const label tgtI : tgtNbr) - { - const face& tgtF = this->tgtPatch_[tgtI]; - - Pout<< "face id: " << tgtI - << " centre=" << tgtF.centre(tgtPoints) - << " normal=" << tgtF.areaNormal(tgtPoints) - << " points=" << tgtF.points(tgtPoints) - << endl; - } - } - } - } - } - - if (srcSeeds.size()) - { - srcFacei = srcSeeds.remove(); - tgtFacei = srcTgtSeed[srcFacei]; - } - else - { - srcFacei = -1; - tgtFacei = -1; - } -} - - -template<class SourcePatch, class TargetPatch> -void Foam::directAMI<SourcePatch, TargetPatch>::restartAdvancingFront -( - labelList& mapFlag, - DynamicList<label>& nonOverlapFaces, - label& srcFacei, - label& tgtFacei -) const -{ - forAll(mapFlag, facei) - { - if (mapFlag[facei] == 0) - { - tgtFacei = this->findTargetFace(facei); - - if (tgtFacei < 0) - { - mapFlag[facei] = -1; - nonOverlapFaces.append(facei); - } - else - { - srcFacei = facei; - break; - } - } - } -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::directAMI<SourcePatch, TargetPatch>::directAMI -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch -) -: - AMIMethod<SourcePatch, TargetPatch> - ( - srcPatch, - tgtPatch, - triMode, - reverseTarget, - requireMatch - ) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::directAMI<SourcePatch, TargetPatch>::~directAMI() -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::directAMI<SourcePatch, TargetPatch>::calculate -( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei, - label tgtFacei -) -{ - bool ok = - this->initialise - ( - srcAddress, - srcWeights, - tgtAddress, - tgtWeights, - srcFacei, - tgtFacei - ); - - if (!ok) - { - return; - } - - - // temporary storage for addressing and weights - List<DynamicList<label>> srcAddr(this->srcPatch_.size()); - List<DynamicList<label>> tgtAddr(this->tgtPatch_.size()); - - - // construct weights and addressing - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // list of faces currently visited for srcFacei to avoid multiple hits - DynamicList<label> srcSeeds(10); - - // list to keep track of tgt faces used to seed src faces - labelList srcTgtSeed(srcAddr.size(), -1); - srcTgtSeed[srcFacei] = tgtFacei; - - // list to keep track of whether src face can be mapped - // 1 = mapped, 0 = untested, -1 = cannot map - labelList mapFlag(srcAddr.size(), Zero); - - label nTested = 0; - DynamicList<label> nonOverlapFaces; - do - { - srcAddr[srcFacei].append(tgtFacei); - tgtAddr[tgtFacei].append(srcFacei); - - mapFlag[srcFacei] = 1; - - nTested++; - - // Do advancing front starting from srcFacei, tgtFacei - appendToDirectSeeds - ( - mapFlag, - srcTgtSeed, - srcSeeds, - nonOverlapFaces, - srcFacei, - tgtFacei - ); - - if (srcFacei < 0 && nTested < this->srcPatch_.size()) - { - restartAdvancingFront(mapFlag, nonOverlapFaces, srcFacei, tgtFacei); - } - - } while (srcFacei >= 0); - - if (nonOverlapFaces.size() != 0) - { - Pout<< " AMI: " << nonOverlapFaces.size() - << " non-overlap faces identified" - << endl; - - this->srcNonOverlap_.transfer(nonOverlapFaces); - } - - // transfer data to persistent storage - forAll(srcAddr, i) - { - scalar magSf = this->srcMagSf_[i]; - srcAddress[i].transfer(srcAddr[i]); - srcWeights[i] = scalarList(1, magSf); - } - forAll(tgtAddr, i) - { - scalar magSf = this->tgtMagSf_[i]; - tgtAddress[i].transfer(tgtAddr[i]); - tgtWeights[i] = scalarList(1, magSf); - } -} - - -template<class SourcePatch, class TargetPatch> -void Foam::directAMI<SourcePatch, TargetPatch>::setMagSf -( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf -) const -{ - srcMagSf = std::move(this->srcMagSf_); - tgtMagSf = scalarList(tgtPatch.size(), 1.0); -} - - -template<class SourcePatch, class TargetPatch> -void Foam::directAMI<SourcePatch, TargetPatch>::normaliseWeights -( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter -) -{ - inter.normaliseWeights(this->conformal(), verbose); -} - - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/directAMI/directAMI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/directAMI/directAMI.H deleted file mode 100644 index a451cad7da2c5e5c3bb4a15ea42b31eab12245be..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/directAMI/directAMI.H +++ /dev/null @@ -1,172 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation -------------------------------------------------------------------------------- -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::directAMI - -Description - Direct mapped Arbitrary Mesh Interface (AMI) method - -SourceFiles - directAMI.C - -\*---------------------------------------------------------------------------*/ - -#ifndef directAMI_H -#define directAMI_H - -#include "AMIMethod.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -/*---------------------------------------------------------------------------*\ - Class directAMI Declaration -\*---------------------------------------------------------------------------*/ - -template<class SourcePatch, class TargetPatch> -class directAMI -: - public AMIMethod<SourcePatch, TargetPatch> -{ - -private: - - // Private Member Functions - - //- No copy construct - directAMI(const directAMI&) = delete; - - //- No copy assignment - void operator=(const directAMI&) = delete; - - // Marching front - - //- Append to list of src face seed indices - void appendToDirectSeeds - ( - labelList& mapFlag, - labelList& srcTgtSeed, - DynamicList<label>& srcSeeds, - DynamicList<label>& nonOverlapFaces, - label& srcFacei, - label& tgtFacei - ) const; - - //- Restart the advancing front - typically happens for - // disconnected regions - void restartAdvancingFront - ( - labelList& mapFlag, - DynamicList<label>& nonOverlapFaces, - label& srcFacei, - label& tgtFacei - ) const; - - - // Evaluation - - //- Area of intersection between source and target faces - scalar interArea - ( - const label srcFacei, - const label tgtFacei - ) const; - - -public: - - //- Runtime type information - TypeName("directAMI"); - - - // Constructors - - //- Construct from components - directAMI - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget = false, - const bool requireMatch = true - ); - - - //- Destructor - virtual ~directAMI(); - - - // Member Functions - - // Manipulation - - //- Update addressing and weights - virtual void calculate - ( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei = -1, - label tgtFacei = -1 - ); - - //- Set the face areas for parallel runs - virtual void setMagSf - ( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf - ) const; - - //- Normalise the weight. Can optionally subset addressing - // (e.g. for mapNearest) - virtual void normaliseWeights - ( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter - ); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#ifdef NoRepository - #include "directAMI.C" -#endif - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/faceAreaWeightAMI/faceAreaWeightAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/faceAreaWeightAMI/faceAreaWeightAMI.C deleted file mode 100644 index 3cbe9cd65f8cedcbb26730f9722640790cef792d..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/faceAreaWeightAMI/faceAreaWeightAMI.C +++ /dev/null @@ -1,693 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2018 OpenCFD Ltd. -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - -\*---------------------------------------------------------------------------*/ - -#include "faceAreaWeightAMI.H" -#include "profiling.H" - -// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::calcAddressing -( - List<DynamicList<label>>& srcAddr, - List<DynamicList<scalar>>& srcWght, - List<DynamicList<label>>& tgtAddr, - List<DynamicList<scalar>>& tgtWght, - label srcFacei, - label tgtFacei -) -{ - addProfiling(ami, "faceAreaWeightAMI::calcAddressing"); - - // construct weights and addressing - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - label nFacesRemaining = srcAddr.size(); - - // list of tgt face neighbour faces - DynamicList<label> nbrFaces(10); - - // list of faces currently visited for srcFacei to avoid multiple hits - DynamicList<label> visitedFaces(10); - - // list to keep track of tgt faces used to seed src faces - labelList seedFaces(nFacesRemaining, -1); - seedFaces[srcFacei] = tgtFacei; - - // list to keep track of whether src face can be mapped - boolList mapFlag(nFacesRemaining, true); - - // reset starting seed - label startSeedi = 0; - - DynamicList<label> nonOverlapFaces; - do - { - // Do advancing front starting from srcFacei,tgtFacei - bool faceProcessed = processSourceFace - ( - srcFacei, - tgtFacei, - - nbrFaces, - visitedFaces, - - srcAddr, - srcWght, - tgtAddr, - tgtWght - ); - - mapFlag[srcFacei] = false; - - nFacesRemaining--; - - if (!faceProcessed) - { - nonOverlapFaces.append(srcFacei); - } - - // choose new src face from current src face neighbour - if (nFacesRemaining > 0) - { - setNextFaces - ( - startSeedi, - srcFacei, - tgtFacei, - mapFlag, - seedFaces, - visitedFaces - ); - } - } while (nFacesRemaining > 0); - - this->srcNonOverlap_.transfer(nonOverlapFaces); -} - - -template<class SourcePatch, class TargetPatch> -bool Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::processSourceFace -( - const label srcFacei, - const label tgtStartFacei, - - // list of tgt face neighbour faces - DynamicList<label>& nbrFaces, - // list of faces currently visited for srcFacei to avoid multiple hits - DynamicList<label>& visitedFaces, - - // temporary storage for addressing and weights - List<DynamicList<label>>& srcAddr, - List<DynamicList<scalar>>& srcWght, - List<DynamicList<label>>& tgtAddr, - List<DynamicList<scalar>>& tgtWght -) -{ - addProfiling(ami, "faceAreaWeightAMI::processSourceFace"); - - if (tgtStartFacei == -1) - { - return false; - } - - nbrFaces.clear(); - visitedFaces.clear(); - - // append initial target face and neighbours - nbrFaces.append(tgtStartFacei); - this->appendNbrFaces - ( - tgtStartFacei, - this->tgtPatch_, - visitedFaces, - nbrFaces - ); - - bool faceProcessed = false; - - label maxNeighbourFaces = nbrFaces.size(); - - do - { - // process new target face - label tgtFacei = nbrFaces.remove(); - visitedFaces.append(tgtFacei); - scalar area = interArea(srcFacei, tgtFacei); - - // store when intersection fractional area > tolerance - if (area/this->srcMagSf_[srcFacei] > faceAreaIntersect::tolerance()) - { - srcAddr[srcFacei].append(tgtFacei); - srcWght[srcFacei].append(area); - - tgtAddr[tgtFacei].append(srcFacei); - tgtWght[tgtFacei].append(area); - - this->appendNbrFaces - ( - tgtFacei, - this->tgtPatch_, - visitedFaces, - nbrFaces - ); - - faceProcessed = true; - - maxNeighbourFaces = max(maxNeighbourFaces, nbrFaces.size()); - } - - } while (nbrFaces.size() > 0); - - if (debug > 1) - { - DebugVar(maxNeighbourFaces); - } - - return faceProcessed; -} - - -template<class SourcePatch, class TargetPatch> -void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::setNextFaces -( - label& startSeedi, - label& srcFacei, - label& tgtFacei, - const boolList& mapFlag, - labelList& seedFaces, - const DynamicList<label>& visitedFaces, - bool errorOnNotFound -) const -{ - addProfiling(ami, "faceAreaWeightAMI::setNextFaces"); - - const labelList& srcNbrFaces = this->srcPatch_.faceFaces()[srcFacei]; - - // initialise tgtFacei - tgtFacei = -1; - - // set possible seeds for later use - bool valuesSet = false; - for (label faceS: srcNbrFaces) - { - if (mapFlag[faceS] && seedFaces[faceS] == -1) - { - for (label faceT : visitedFaces) - { - const scalar threshold = - this->srcMagSf_[faceS]*faceAreaIntersect::tolerance(); - - // store when intersection fractional area > tolerance - // Check that faces have enough overlap for robust walking - if (overlaps(faceS, faceT, threshold)) - { - seedFaces[faceS] = faceT; - - if (!valuesSet) - { - srcFacei = faceS; - tgtFacei = faceT; - valuesSet = true; - } - } - } - } - } - - // set next src and tgt faces if not set above - if (valuesSet) - { - return; - } - else - { - // try to use existing seed - bool foundNextSeed = false; - for (label facei = startSeedi; facei < mapFlag.size(); ++facei) - { - if (mapFlag[facei]) - { - if (!foundNextSeed) - { - startSeedi = facei; - foundNextSeed = true; - } - - if (seedFaces[facei] != -1) - { - srcFacei = facei; - tgtFacei = seedFaces[facei]; - - return; - } - } - } - - // perform new search to find match - if (debug) - { - Pout<< "Advancing front stalled: searching for new " - << "target face" << endl; - } - - foundNextSeed = false; - for (label facei = startSeedi; facei < mapFlag.size(); ++facei) - { - if (mapFlag[facei]) - { - if (!foundNextSeed) - { - startSeedi = facei + 1; - foundNextSeed = true; - } - - srcFacei = facei; - tgtFacei = this->findTargetFace(srcFacei); - - if (tgtFacei >= 0) - { - return; - } - } - } - - if (errorOnNotFound) - { - FatalErrorInFunction - << "Unable to set source and target faces" << abort(FatalError); - } - } -} - - -template<class SourcePatch, class TargetPatch> -Foam::scalar Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::interArea -( - const label srcFacei, - const label tgtFacei -) const -{ - addProfiling(ami, "faceAreaWeightAMI::interArea"); - - scalar area = 0; - - const pointField& srcPoints = this->srcPatch_.points(); - const pointField& tgtPoints = this->tgtPatch_.points(); - - // references to candidate faces - const face& src = this->srcPatch_[srcFacei]; - const face& tgt = this->tgtPatch_[tgtFacei]; - - // quick reject if either face has zero area - if - ( - (this->srcMagSf_[srcFacei] < ROOTVSMALL) - || (this->tgtMagSf_[tgtFacei] < ROOTVSMALL) - ) - { - return area; - } - - // create intersection object - faceAreaIntersect inter - ( - srcPoints, - tgtPoints, - this->srcTris_[srcFacei], - this->tgtTris_[tgtFacei], - this->reverseTarget_, - AMIInterpolation<SourcePatch, TargetPatch>::cacheIntersections_ - ); - - // crude resultant norm - vector n(-this->srcPatch_.faceNormals()[srcFacei]); - if (this->reverseTarget_) - { - n -= this->tgtPatch_.faceNormals()[tgtFacei]; - } - else - { - n += this->tgtPatch_.faceNormals()[tgtFacei]; - } - scalar magN = mag(n); - - if (magN > ROOTVSMALL) - { - area = inter.calc(src, tgt, n/magN); - } - else - { - WarningInFunction - << "Invalid normal for source face " << srcFacei - << " points " << UIndirectList<point>(srcPoints, src) - << " target face " << tgtFacei - << " points " << UIndirectList<point>(tgtPoints, tgt) - << endl; - } - - - if ((debug > 1) && (area > 0)) - { - this->writeIntersectionOBJ(area, src, tgt, srcPoints, tgtPoints); - } - - return area; -} - - -template<class SourcePatch, class TargetPatch> -bool Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::overlaps -( - const label srcFacei, - const label tgtFacei, - const scalar threshold -) const -{ - const pointField& srcPoints = this->srcPatch_.points(); - const pointField& tgtPoints = this->tgtPatch_.points(); - - // references to candidate faces - const face& src = this->srcPatch_[srcFacei]; - const face& tgt = this->tgtPatch_[tgtFacei]; - - // quick reject if either face has zero area - if - ( - (this->srcMagSf_[srcFacei] < ROOTVSMALL) - || (this->tgtMagSf_[tgtFacei] < ROOTVSMALL) - ) - { - return false; - } - - faceAreaIntersect inter - ( - srcPoints, - tgtPoints, - this->srcTris_[srcFacei], - this->tgtTris_[tgtFacei], - this->reverseTarget_, - AMIInterpolation<SourcePatch, TargetPatch>::cacheIntersections_ - ); - - // crude resultant norm - vector n(-this->srcPatch_.faceNormals()[srcFacei]); - if (this->reverseTarget_) - { - n -= this->tgtPatch_.faceNormals()[tgtFacei]; - } - else - { - n += this->tgtPatch_.faceNormals()[tgtFacei]; - } - scalar magN = mag(n); - - if (magN > ROOTVSMALL) - { - return inter.overlaps(src, tgt, n/magN, threshold); - } - else - { - WarningInFunction - << "Invalid normal for source face " << srcFacei - << " points " << UIndirectList<point>(srcPoints, src) - << " target face " << tgtFacei - << " points " << UIndirectList<point>(tgtPoints, tgt) - << endl; - } - - return false; -} - - -template<class SourcePatch, class TargetPatch> -void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>:: -restartUncoveredSourceFace -( - List<DynamicList<label>>& srcAddr, - List<DynamicList<scalar>>& srcWght, - List<DynamicList<label>>& tgtAddr, - List<DynamicList<scalar>>& tgtWght -) -{ - addProfiling(ami, "faceAreaWeightAMI::restartUncoveredSourceFace"); - - // Collect all src faces with a low weight - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - labelHashSet lowWeightFaces(100); - forAll(srcWght, srcFacei) - { - scalar s = sum(srcWght[srcFacei]); - scalar t = s/this->srcMagSf_[srcFacei]; - - if (t < 0.5) - { - lowWeightFaces.insert(srcFacei); - } - } - - if (debug) - { - Pout<< "faceAreaWeightAMI: restarting search on " - << lowWeightFaces.size() << " faces since sum of weights < 0.5" - << endl; - } - - if (lowWeightFaces.size() > 0) - { - // Erase all the lowWeight source faces from the target - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - DynamicList<label> okSrcFaces(10); - DynamicList<scalar> okSrcWeights(10); - forAll(tgtAddr, tgtFacei) - { - okSrcFaces.clear(); - okSrcWeights.clear(); - DynamicList<label>& srcFaces = tgtAddr[tgtFacei]; - DynamicList<scalar>& srcWeights = tgtWght[tgtFacei]; - forAll(srcFaces, i) - { - if (!lowWeightFaces.found(srcFaces[i])) - { - okSrcFaces.append(srcFaces[i]); - okSrcWeights.append(srcWeights[i]); - } - } - if (okSrcFaces.size() < srcFaces.size()) - { - srcFaces.transfer(okSrcFaces); - srcWeights.transfer(okSrcWeights); - } - } - - - - // Restart search from best hit - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // list of tgt face neighbour faces - DynamicList<label> nbrFaces(10); - - // list of faces currently visited for srcFacei to avoid multiple hits - DynamicList<label> visitedFaces(10); - - for (const label srcFacei : lowWeightFaces) - { - const label tgtFacei = this->findTargetFace(srcFacei); - if (tgtFacei != -1) - { - //bool faceProcessed = - processSourceFace - ( - srcFacei, - tgtFacei, - - nbrFaces, - visitedFaces, - - srcAddr, - srcWght, - tgtAddr, - tgtWght - ); - // ? Check faceProcessed to see if restarting has worked. - } - } - } -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::faceAreaWeightAMI -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch, - const bool restartUncoveredSourceFace -) -: - AMIMethod<SourcePatch, TargetPatch> - ( - srcPatch, - tgtPatch, - triMode, - reverseTarget, - requireMatch - ), - restartUncoveredSourceFace_(restartUncoveredSourceFace), - srcTris_(), - tgtTris_() -{ - this->triangulatePatch(srcPatch, srcTris_, this->srcMagSf_); - this->triangulatePatch(tgtPatch, tgtTris_, this->tgtMagSf_); -} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::~faceAreaWeightAMI() -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::calculate -( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei, - label tgtFacei -) -{ - addProfiling(ami, "faceAreaWeightAMI::calculate"); - - bool ok = - this->initialise - ( - srcAddress, - srcWeights, - tgtAddress, - tgtWeights, - srcFacei, - tgtFacei - ); - - if (!ok) - { - return; - } - - // temporary storage for addressing and weights - List<DynamicList<label>> srcAddr(this->srcPatch_.size()); - List<DynamicList<scalar>> srcWght(srcAddr.size()); - List<DynamicList<label>> tgtAddr(this->tgtPatch_.size()); - List<DynamicList<scalar>> tgtWght(tgtAddr.size()); - - calcAddressing - ( - srcAddr, - srcWght, - tgtAddr, - tgtWght, - srcFacei, - tgtFacei - ); - - if (debug && !this->srcNonOverlap_.empty()) - { - Pout<< " AMI: " << this->srcNonOverlap_.size() - << " non-overlap faces identified" - << endl; - } - - - // Check for badly covered faces - if (restartUncoveredSourceFace_) - { - restartUncoveredSourceFace - ( - srcAddr, - srcWght, - tgtAddr, - tgtWght - ); - } - - - // transfer data to persistent storage - forAll(srcAddr, i) - { - srcAddress[i].transfer(srcAddr[i]); - srcWeights[i].transfer(srcWght[i]); - } - forAll(tgtAddr, i) - { - tgtAddress[i].transfer(tgtAddr[i]); - tgtWeights[i].transfer(tgtWght[i]); - } -} - - -template<class SourcePatch, class TargetPatch> -void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::setMagSf -( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf -) const -{ - srcMagSf = std::move(this->srcMagSf_); - tgtMagSf = std::move(this->tgtMagSf_); - map.reverseDistribute(tgtPatch.size(), tgtMagSf); -} - - -template<class SourcePatch, class TargetPatch> -void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::normaliseWeights -( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter -) -{ - inter.normaliseWeights(this->conformal(), verbose); -} - - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/mapNearestAMI/mapNearestAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/mapNearestAMI/mapNearestAMI.C deleted file mode 100644 index 5bfaa347ca68747b5ae725a9fe2c8f63b7761a61..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/mapNearestAMI/mapNearestAMI.C +++ /dev/null @@ -1,444 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - -\*---------------------------------------------------------------------------*/ - -#include "mapNearestAMI.H" - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::mapNearestAMI<SourcePatch, TargetPatch>::findNearestFace -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const label& srcFacei, - label& tgtFacei -) const -{ - const vectorField& srcCf = srcPatch.faceCentres(); - const vectorField& tgtCf = tgtPatch.faceCentres(); - - const vector srcP = srcCf[srcFacei]; - - DynamicList<label> tgtFaces(10); - tgtFaces.append(tgtFacei); - - DynamicList<label> visitedFaces(10); - - scalar d = GREAT; - - do - { - label tgtI = tgtFaces.remove(); - visitedFaces.append(tgtI); - - scalar dTest = magSqr(tgtCf[tgtI] - srcP); - if (dTest < d) - { - tgtFacei = tgtI; - d = dTest; - - this->appendNbrFaces - ( - tgtFacei, - tgtPatch, - visitedFaces, - tgtFaces - ); - } - - } while (tgtFaces.size() > 0); -} - - -template<class SourcePatch, class TargetPatch> -void Foam::mapNearestAMI<SourcePatch, TargetPatch>::setNextNearestFaces -( - boolList& mapFlag, - label& startSeedI, - label& srcFacei, - label& tgtFacei -) const -{ - const labelList& srcNbr = this->srcPatch_.faceFaces()[srcFacei]; - - srcFacei = -1; - - for (const label facei : srcNbr) - { - if (mapFlag[facei]) - { - srcFacei = facei; - startSeedI = facei + 1; - - return; - } - } - - forAll(mapFlag, facei) - { - if (mapFlag[facei]) - { - srcFacei = facei; - tgtFacei = this->findTargetFace(facei); - - if (tgtFacei == -1) - { - const vectorField& srcCf = this->srcPatch_.faceCentres(); - - FatalErrorInFunction - << "Unable to find target face for source face " - << srcFacei << " with face centre " << srcCf[srcFacei] - << abort(FatalError); - } - - break; - } - } -} - - -template<class SourcePatch, class TargetPatch> -Foam::label Foam::mapNearestAMI<SourcePatch, TargetPatch>::findMappedSrcFace -( - const label tgtFacei, - const List<DynamicList<label>>& tgtToSrc -) const -{ - DynamicList<label> testFaces(10); - DynamicList<label> visitedFaces(10); - - testFaces.append(tgtFacei); - - do - { - // search target tgtFacei neighbours for match with source face - label tgtI = testFaces.remove(); - - if (!visitedFaces.found(tgtI)) - { - visitedFaces.append(tgtI); - - if (tgtToSrc[tgtI].size()) - { - return tgtToSrc[tgtI][0]; - } - else - { - const labelList& nbrFaces = this->tgtPatch_.faceFaces()[tgtI]; - - for (const label nbrFacei : nbrFaces) - { - if (!visitedFaces.found(nbrFacei)) - { - testFaces.append(nbrFacei); - } - } - } - } - } while (testFaces.size()); - - // did not find any match - should not be possible to get here! - return -1; -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::mapNearestAMI<SourcePatch, TargetPatch>::mapNearestAMI -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch -) -: - AMIMethod<SourcePatch, TargetPatch> - ( - srcPatch, - tgtPatch, - triMode, - reverseTarget, - requireMatch - ) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::mapNearestAMI<SourcePatch, TargetPatch>::~mapNearestAMI() -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::mapNearestAMI<SourcePatch, TargetPatch>::calculate -( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei, - label tgtFacei -) -{ - bool ok = - this->initialise - ( - srcAddress, - srcWeights, - tgtAddress, - tgtWeights, - srcFacei, - tgtFacei - ); - - if (!ok) - { - return; - } - - - // temporary storage for addressing and weights - List<DynamicList<label>> srcAddr(this->srcPatch_.size()); - List<DynamicList<label>> tgtAddr(this->tgtPatch_.size()); - - - // construct weights and addressing - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - // list to keep track of whether src face can be mapped - boolList mapFlag(srcAddr.size(), true); - - // reset starting seed - label startSeedI = 0; - - DynamicList<label> nonOverlapFaces; - do - { - findNearestFace(this->srcPatch_, this->tgtPatch_, srcFacei, tgtFacei); - - srcAddr[srcFacei].append(tgtFacei); - tgtAddr[tgtFacei].append(srcFacei); - - mapFlag[srcFacei] = false; - - // Do advancing front starting from srcFacei, tgtFacei - setNextNearestFaces - ( - mapFlag, - startSeedI, - srcFacei, - tgtFacei - ); - } while (srcFacei >= 0); - - - // for the case of multiple source faces per target face, select the - // nearest source face only and discard the others - const vectorField& srcCf = this->srcPatch_.faceCentres(); - const vectorField& tgtCf = this->tgtPatch_.faceCentres(); - - forAll(tgtAddr, targetFacei) - { - if (tgtAddr[targetFacei].size() > 1) - { - const vector& tgtC = tgtCf[tgtFacei]; - - DynamicList<label>& srcFaces = tgtAddr[targetFacei]; - - label srcFacei = srcFaces[0]; - scalar d = magSqr(tgtC - srcCf[srcFacei]); - - for (label i = 1; i < srcFaces.size(); ++i) - { - label srcI = srcFaces[i]; - scalar dNew = magSqr(tgtC - srcCf[srcI]); - if (dNew < d) - { - d = dNew; - srcFacei = srcI; - } - } - - srcFaces.clear(); - srcFaces.append(srcFacei); - } - } - - // If there are more target faces than source faces, some target faces - // might not yet be mapped - forAll(tgtAddr, tgtFacei) - { - if (tgtAddr[tgtFacei].empty()) - { - label srcFacei = findMappedSrcFace(tgtFacei, tgtAddr); - - if (srcFacei >= 0) - { - // note - reversed search from src->tgt to tgt->src - findNearestFace - ( - this->tgtPatch_, - this->srcPatch_, - tgtFacei, - srcFacei - ); - - tgtAddr[tgtFacei].append(srcFacei); - } - } - } - - - // transfer data to persistent storage - const pointField& srcFc = this->srcPatch_.faceCentres(); - const pointField& tgtFc = this->tgtPatch_.faceCentres(); - - forAll(srcAddr, srcI) - { - srcAddress[srcI].transfer(srcAddr[srcI]); - - const labelList& addr = srcAddress[srcI]; - srcWeights[srcI].setSize(addr.size()); - const point& srcPt = srcFc[srcI]; - forAll(addr, i) - { - srcWeights[srcI][i] = magSqr(srcPt-tgtFc[addr[i]]); - } - } - forAll(tgtAddr, tgtI) - { - tgtAddress[tgtI].transfer(tgtAddr[tgtI]); - - const labelList& addr = tgtAddress[tgtI]; - tgtWeights[tgtI].setSize(addr.size()); - const point& tgtPt = tgtFc[tgtI]; - forAll(addr, i) - { - tgtWeights[tgtI][i] = magSqr(tgtPt-srcFc[addr[i]]); - } - } -} - - -template<class SourcePatch, class TargetPatch> -void Foam::mapNearestAMI<SourcePatch, TargetPatch>::setMagSf -( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf -) const -{ - srcMagSf = std::move(this->srcMagSf_); - tgtMagSf = scalarList(tgtPatch.size(), 1.0); -} - - -template<class SourcePatch, class TargetPatch> -void Foam::mapNearestAMI<SourcePatch, TargetPatch>::normaliseWeights -( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter -) -{ - { - labelListList& srcAddress = inter.srcAddress(); - scalarListList& srcWeights = inter.srcWeights(); - - forAll(srcAddress, srcI) - { - labelList& addr = srcAddress[srcI]; - scalarList& wghts = srcWeights[srcI]; - - // Choose one with smallest weight (since calculate above returns - // distance) - if (addr.size()) - { - label minFaceI = addr[0]; - scalar minWeight = wghts[0]; - - for (label i = 0; i < addr.size(); ++i) - { - if (wghts[i] < minWeight) - { - minWeight = wghts[i]; - minFaceI = addr[i]; - } - } - - wghts.setSize(1); - wghts[0] = this->srcMagSf_[srcI]; - addr.setSize(1); - addr[0] = minFaceI; - } - } - } - - { - labelListList& tgtAddress = inter.tgtAddress(); - scalarListList& tgtWeights = inter.tgtWeights(); - - forAll(tgtAddress, tgtI) - { - labelList& addr = tgtAddress[tgtI]; - scalarList& wghts = tgtWeights[tgtI]; - - // Choose one with smallest weight (since calculate above returns - // distance) - if (addr.size()) - { - label minFaceI = addr[0]; - scalar minWeight = wghts[0]; - - forAll(addr, i) - { - if (wghts[i] < minWeight) - { - minWeight = wghts[i]; - minFaceI = addr[i]; - } - } - - wghts.setSize(1); - wghts[0] = inter.tgtMagSf()[tgtI]; - addr.setSize(1); - addr[0] = minFaceI; - } - } - } - - inter.normaliseWeights(this->conformal(), verbose); -} - - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/mapNearestAMI/mapNearestAMI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/mapNearestAMI/mapNearestAMI.H deleted file mode 100644 index b59e0682d3bcc5f21b8d301e561c64371e9b7b25..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/mapNearestAMI/mapNearestAMI.H +++ /dev/null @@ -1,177 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - -Class - Foam::mapNearestAMI - -Description - Nearest-mapping Arbitrary Mesh Interface (AMI) method - -SourceFiles - mapNearestAMI.C - -\*---------------------------------------------------------------------------*/ - -#ifndef mapNearestAMI_H -#define mapNearestAMI_H - -#include "AMIMethod.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -/*---------------------------------------------------------------------------*\ - Class mapNearestAMI Declaration -\*---------------------------------------------------------------------------*/ - -template<class SourcePatch, class TargetPatch> -class mapNearestAMI -: - public AMIMethod<SourcePatch, TargetPatch> -{ - -private: - - // Private Member Functions - - //- No copy construct - mapNearestAMI(const mapNearestAMI&) = delete; - - //- No copy assignment - void operator=(const mapNearestAMI&) = delete; - - // Marching front - - //- Find nearest target face for source face srcFacei - void findNearestFace - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const label& srcFacei, - label& tgtFacei - ) const; - - //- Determine next source-target face pair - void setNextNearestFaces - ( - boolList& mapFlag, - label& startSeedI, - label& srcFacei, - label& tgtFacei - ) const; - - //- Find mapped source face - label findMappedSrcFace - ( - const label tgtFacei, - const List<DynamicList<label>>& tgtToSrc - ) const; - - - // Evaluation - - //- Area of intersection between source and target faces - scalar interArea - ( - const label srcFacei, - const label tgtFacei - ) const; - - -public: - - //- Runtime type information - TypeName("mapNearestAMI"); - - - // Constructors - - //- Construct from components - mapNearestAMI - ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget = false, - const bool requireMatch = true - ); - - - //- Destructor - virtual ~mapNearestAMI(); - - - // Member Functions - - // Manipulation - - //- Update addressing and weights - virtual void calculate - ( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei = -1, - label tgtFacei = -1 - ); - - //- Set the face areas for parallel runs - virtual void setMagSf - ( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf - ) const; - - //- Normalise the weight. Can optionally subset addressing - //- (e.g. for mapNearest) - virtual void normaliseWeights - ( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter - ); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#ifdef NoRepository - #include "mapNearestAMI.C" -#endif - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C deleted file mode 100644 index 78275e0111c64cf05b958dcfeee5f80f35aea498..0000000000000000000000000000000000000000 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C +++ /dev/null @@ -1,183 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013-2016 OpenFOAM Foundation -------------------------------------------------------------------------------- -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 "partialFaceAreaWeightAMI.H" - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -void Foam::partialFaceAreaWeightAMI<SourcePatch, TargetPatch>::setNextFaces -( - label& startSeedi, - label& srcFacei, - label& tgtFacei, - const boolList& mapFlag, - labelList& seedFaces, - const DynamicList<label>& visitedFaces, - const bool errorOnNotFound -) const -{ - faceAreaWeightAMI<SourcePatch, TargetPatch>::setNextFaces - ( - startSeedi, - srcFacei, - tgtFacei, - mapFlag, - seedFaces, - visitedFaces, - false // no error on not found - ); -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::partialFaceAreaWeightAMI<SourcePatch, TargetPatch>:: -partialFaceAreaWeightAMI -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, - const bool reverseTarget, - const bool requireMatch -) -: - faceAreaWeightAMI<SourcePatch, TargetPatch> - ( - srcPatch, - tgtPatch, - triMode, - reverseTarget, - requireMatch - ) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -Foam::partialFaceAreaWeightAMI<SourcePatch, TargetPatch>:: -~partialFaceAreaWeightAMI() -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -template<class SourcePatch, class TargetPatch> -bool Foam::partialFaceAreaWeightAMI<SourcePatch, TargetPatch>::conformal() const -{ - return false; -} - - -template<class SourcePatch, class TargetPatch> -void Foam::partialFaceAreaWeightAMI<SourcePatch, TargetPatch>::calculate -( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei, - label tgtFacei -) -{ - bool ok = - this->initialise - ( - srcAddress, - srcWeights, - tgtAddress, - tgtWeights, - srcFacei, - tgtFacei - ); - - if (!ok) - { - return; - } - - // temporary storage for addressing and weights - List<DynamicList<label>> srcAddr(this->srcPatch_.size()); - List<DynamicList<scalar>> srcWght(srcAddr.size()); - List<DynamicList<label>> tgtAddr(this->tgtPatch_.size()); - List<DynamicList<scalar>> tgtWght(tgtAddr.size()); - - faceAreaWeightAMI<SourcePatch, TargetPatch>::calcAddressing - ( - srcAddr, - srcWght, - tgtAddr, - tgtWght, - srcFacei, - tgtFacei - ); - - // transfer data to persistent storage - forAll(srcAddr, i) - { - srcAddress[i].transfer(srcAddr[i]); - srcWeights[i].transfer(srcWght[i]); - } - forAll(tgtAddr, i) - { - tgtAddress[i].transfer(tgtAddr[i]); - tgtWeights[i].transfer(tgtWght[i]); - } -} - - -template<class SourcePatch, class TargetPatch> -void Foam::partialFaceAreaWeightAMI<SourcePatch, TargetPatch>::setMagSf -( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf -) const -{ - srcMagSf = std::move(this->srcMagSf_); - - scalarList newTgtMagSf(std::move(this->tgtMagSf_)); - map.reverseDistribute(tgtPatch.size(), newTgtMagSf); - - // Assign default sizes. Override selected values with - // calculated values. This is to support ACMI - // where some of the target faces are never used (so never get sent - // over and hence never assigned to) - tgtMagSf = tgtPatch.magFaceAreas(); - - for (const labelList& smap : map.subMap()) - { - UIndirectList<scalar>(tgtMagSf, smap) = - UIndirectList<scalar>(newTgtMagSf, smap); - } -} - - -// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.H b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.H index c11f82dc3a0f5295149eebd85bfa8e5f8bd7c062..43a8a3e5cc5023531d6d1a1078dbf3e7994cadd7 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.H +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.H @@ -30,14 +30,12 @@ License #define AMIPatchToPatchInterpolation_H #include "AMIInterpolation.H" -#include "primitivePatch.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { - typedef AMIInterpolation<primitivePatch, primitivePatch> - AMIPatchToPatchInterpolation; + typedef AMIInterpolation AMIPatchToPatchInterpolation; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.C b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C similarity index 52% rename from src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.C rename to src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C index 3b1f06d405cf74a363d3ae5066bb522fe4500b7b..dc41c132ea60a990f89c16e796022146944c596d 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/AMIMethod/AMIMethod.C +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2015-2018 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,20 +26,31 @@ License \*---------------------------------------------------------------------------*/ -#include "AMIMethod.H" +#include "advancingFrontAMI.H" #include "meshTools.H" #include "mapDistribute.H" #include "unitConversion.H" +#include "findNearestMaskedOp.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(advancingFrontAMI, 0); +} + // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -void Foam::AMIMethod<SourcePatch, TargetPatch>::checkPatches() const +void Foam::advancingFrontAMI::checkPatches() const { - if (debug && (!srcPatch_.size() || !tgtPatch_.size())) + const auto& src = srcPatch(); + const auto& tgt = tgtPatch(); + + if (debug && (!src.size() || !tgt.size())) { Pout<< "AMI: Patches not on processor: Source faces = " - << srcPatch_.size() << ", target faces = " << tgtPatch_.size() + << src.size() << ", target faces = " << tgt.size() << endl; } @@ -48,9 +59,9 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::checkPatches() const { const scalar maxBoundsError = 0.05; - // check bounds of source and target - boundBox bbSrc(srcPatch_.points(), srcPatch_.meshPoints(), true); - boundBox bbTgt(tgtPatch_.points(), tgtPatch_.meshPoints(), true); + // Check bounds of source and target + boundBox bbSrc(src.points(), src.meshPoints(), true); + boundBox bbTgt(tgt.points(), tgt.meshPoints(), true); boundBox bbTgtInf(bbTgt); bbTgtInf.inflate(maxBoundsError); @@ -70,49 +81,69 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::checkPatches() const } -template<class SourcePatch, class TargetPatch> -bool Foam::AMIMethod<SourcePatch, TargetPatch>::initialise -( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label& srcFacei, - label& tgtFacei -) +void Foam::advancingFrontAMI::createExtendedTgtPatch() { - checkPatches(); + // Create processor map of extended cells. This map gets (possibly + // remote) cells from the src mesh such that they (together) cover + // all of tgt + extendedTgtMapPtr_.reset(calcProcMap(srcPatch0(), tgtPatch0())); + const mapDistribute& map = extendedTgtMapPtr_(); + + // Original faces from tgtPatch + // Note: in globalIndexing since might be remote + globalIndex globalTgtFaces(tgtPatch0().size()); + distributeAndMergePatches + ( + map, + tgtPatch0(), + globalTgtFaces, + extendedTgtFaces_, + extendedTgtPoints_, + extendedTgtFaceIDs_ + ); + + // Create a representation of the tgt patch that is extended to overlap + // the src patch + extendedTgtPatchPtr_.reset + ( + autoPtr<primitivePatch>::New + ( + SubList<face>(extendedTgtFaces_), + extendedTgtPoints_ + ) + ); +} + + +bool Foam::advancingFrontAMI::initialiseWalk(label& srcFacei, label& tgtFacei) +{ + const auto& src = this->srcPatch(); + const auto& tgt = this->tgtPatch(); - // set initial sizes for weights and addressing - must be done even if - // returns false below - srcAddress.setSize(srcPatch_.size()); - srcWeights.setSize(srcPatch_.size()); - tgtAddress.setSize(tgtPatch_.size()); - tgtWeights.setSize(tgtPatch_.size()); + bool foundFace = false; - // check that patch sizes are valid - if (!srcPatch_.size()) + // Check that patch sizes are valid + if (!src.size()) { - return false; + return foundFace; } - else if (!tgtPatch_.size()) + else if (!tgt.size()) { WarningInFunction - << srcPatch_.size() << " source faces but no target faces" << endl; + << src.size() << " source faces but no target faces" << endl; - return false; + return foundFace; } - // reset the octree - resetTree(); + // Reset the octree + treePtr_.reset(createTree(tgt)); - // find initial face match using brute force/octree search + // Find initial face match using brute force/octree search if ((srcFacei == -1) || (tgtFacei == -1)) { srcFacei = 0; tgtFacei = 0; - bool foundFace = false; - forAll(srcPatch_, facei) + forAll(src, facei) { tgtFacei = findTargetFace(facei); if (tgtFacei >= 0) @@ -132,7 +163,7 @@ bool Foam::AMIMethod<SourcePatch, TargetPatch>::initialise << abort(FatalError); } - return false; + return foundFace; } } @@ -145,8 +176,7 @@ bool Foam::AMIMethod<SourcePatch, TargetPatch>::initialise } -template<class SourcePatch, class TargetPatch> -void Foam::AMIMethod<SourcePatch, TargetPatch>::writeIntersectionOBJ +void Foam::advancingFrontAMI::writeIntersectionOBJ ( const scalar area, const face& f1, @@ -197,51 +227,29 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::writeIntersectionOBJ } -template<class SourcePatch, class TargetPatch> -void Foam::AMIMethod<SourcePatch, TargetPatch>::resetTree() +Foam::label Foam::advancingFrontAMI::findTargetFace +( + const label srcFacei, + const UList<label>& excludeFaces, + const label srcFacePti +) const { - // Clear the old octree - treePtr_.clear(); + const auto& src = srcPatch(); - treeBoundBox bb(tgtPatch_.points(), tgtPatch_.meshPoints()); - bb.inflate(0.01); + label targetFacei = -1; - if (!treePtr_.valid()) - { - treePtr_.reset - ( - new indexedOctree<treeType> - ( - treeType - ( - false, - tgtPatch_, - indexedOctree<treeType>::perturbTol() - ), - bb, // overall search domain - 8, // maxLevel - 10, // leaf size - 3.0 // duplicity - ) - ); - } -} + const pointField& srcPts = src.points(); + const face& srcFace = src[srcFacei]; + findNearestMaskedOp<primitivePatch> fnOp(*treePtr_, excludeFaces); -template<class SourcePatch, class TargetPatch> -Foam::label Foam::AMIMethod<SourcePatch, TargetPatch>::findTargetFace -( - const label srcFacei -) const -{ - label targetFacei = -1; + const boundBox bb(srcPts, srcFace, false); - const pointField& srcPts = srcPatch_.points(); - const face& srcFace = srcPatch_[srcFacei]; - const point srcPt = srcFace.centre(srcPts); - const scalar srcFaceArea = srcMagSf_[srcFacei]; + const point srcPt = + srcFacePti == -1 ? bb.centre() : srcPts[srcFace[srcFacePti]]; - pointIndexHit sample = treePtr_->findNearest(srcPt, 10.0*srcFaceArea); + const pointIndexHit sample = + treePtr_->findNearest(srcPt, magSqr(bb.max() - bb.centre()), fnOp); if (sample.hit()) { @@ -259,11 +267,10 @@ Foam::label Foam::AMIMethod<SourcePatch, TargetPatch>::findTargetFace } -template<class SourcePatch, class TargetPatch> -void Foam::AMIMethod<SourcePatch, TargetPatch>::appendNbrFaces +void Foam::advancingFrontAMI::appendNbrFaces ( const label facei, - const TargetPatch& patch, + const primitivePatch& patch, const DynamicList<label>& visitedFaces, DynamicList<label>& faceIDs ) const @@ -272,33 +279,11 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::appendNbrFaces const labelList& nbrFaces = patch.faceFaces()[facei]; - // filter out faces already visited from face neighbours + // Filter out faces already visited from face neighbours for (const label nbrFacei : nbrFaces) { - bool valid = true; - for (const label visitedFacei : visitedFaces) - { - if (nbrFacei == visitedFacei) - { - valid = false; - break; - } - } - - if (valid) - { - for (const label testFacei : faceIDs) - { - if (nbrFacei == testFacei) - { - valid = false; - break; - } - } - } - - // prevent addition of face if it is not on the same plane-ish - if (valid) + // Prevent addition of face if it is not on the same plane-ish + if (!visitedFaces.found(nbrFacei) && !faceIDs.found(nbrFacei)) { const vector& n1 = patch.faceNormals()[facei]; const vector& n2 = patch.faceNormals()[nbrFacei]; @@ -314,11 +299,9 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::appendNbrFaces } -template<class SourcePatch, class TargetPatch> -template<class PatchType> -void Foam::AMIMethod<SourcePatch, TargetPatch>::triangulatePatch +void Foam::advancingFrontAMI::triangulatePatch ( - const PatchType& patch, + const primitivePatch& patch, List<DynamicList<face>>& tris, List<scalar>& magSf ) const @@ -330,6 +313,8 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::triangulatePatch // Using methods that index into existing points forAll(patch, facei) { + tris[facei].clear(); + switch (triMode_) { case faceAreaIntersect::tmFan: @@ -362,34 +347,114 @@ void Foam::AMIMethod<SourcePatch, TargetPatch>::triangulatePatch // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -Foam::AMIMethod<SourcePatch, TargetPatch>::AMIMethod +Foam::advancingFrontAMI::advancingFrontAMI ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, + const dictionary& dict, + const bool reverseTarget +) +: + AMIInterpolation(dict, reverseTarget), + srcTris_(), + tgtTris_(), + extendedTgtPatchPtr_(nullptr), + extendedTgtFaces_(), + extendedTgtPoints_(), + extendedTgtFaceIDs_(), + extendedTgtMapPtr_(nullptr), + srcNonOverlap_(), + triMode_ + ( + faceAreaIntersect::triangulationModeNames_.getOrDefault + ( + "triMode", + dict, + faceAreaIntersect::tmMesh + ) + ) +{} + + +Foam::advancingFrontAMI::advancingFrontAMI +( + const bool requireMatch, const bool reverseTarget, - const bool requireMatch + const scalar lowWeightCorrection, + const faceAreaIntersect::triangulationMode triMode ) : - srcPatch_(srcPatch), - tgtPatch_(tgtPatch), - reverseTarget_(reverseTarget), - requireMatch_(requireMatch), - srcMagSf_(srcPatch.size(), 1.0), - tgtMagSf_(tgtPatch.size(), 1.0), + AMIInterpolation(requireMatch, reverseTarget, lowWeightCorrection), + srcTris_(), + tgtTris_(), + extendedTgtPatchPtr_(nullptr), + extendedTgtFaces_(), + extendedTgtPoints_(), + extendedTgtFaceIDs_(), + extendedTgtMapPtr_(nullptr), srcNonOverlap_(), triMode_(triMode) -{ - // Note: setting srcMagSf and tgtMagSf to 1 by default for 1-to-1 methods - // - others will need to overwrite as necessary -} +{} + + +Foam::advancingFrontAMI::advancingFrontAMI(const advancingFrontAMI& ami) +: + AMIInterpolation(ami), + srcTris_(), + tgtTris_(), + extendedTgtPatchPtr_(nullptr), + extendedTgtFaces_(), + extendedTgtPoints_(), + extendedTgtFaceIDs_(), + extendedTgtMapPtr_(nullptr), + srcNonOverlap_(), + triMode_(ami.triMode_) +{} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -bool Foam::AMIMethod<SourcePatch, TargetPatch>::conformal() const +bool Foam::advancingFrontAMI::calculate +( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr +) +{ + if (AMIInterpolation::calculate(srcPatch, tgtPatch, surfPtr)) + { + // Create a representation of the target patch that covers the source patch + if (distributed()) + { + createExtendedTgtPatch(); + } + + const auto& src = this->srcPatch(); + const auto& tgt = this->tgtPatch(); + + // Initialise area magnitudes + srcMagSf_.setSize(src.size(), 1.0); + tgtMagSf_.setSize(tgt.size(), 1.0); + + // Source and target patch triangulations + triangulatePatch(src, srcTris_, srcMagSf_); + triangulatePatch(tgt, tgtTris_, tgtMagSf_); + + checkPatches(); + + // Set initial sizes for weights and addressing - must be done even if + // returns false below + srcAddress_.setSize(src.size()); + srcWeights_.setSize(src.size()); + tgtAddress_.setSize(tgt.size()); + tgtWeights_.setSize(tgt.size()); + + return true; + } + + return false; +} + + +bool Foam::advancingFrontAMI::conformal() const { return true; } diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.H new file mode 100644 index 0000000000000000000000000000000000000000..84031daa733f3e53df6d86d6bdaca30a458ee3db --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.H @@ -0,0 +1,271 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2013-2016 OpenFOAM Foundation + Copyright (C) 2016-2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::advancingFrontAMI + +Description + Base class for Arbitrary Mesh Interface (AMI) methods + +SourceFiles + advancingFrontAMI.C + +\*---------------------------------------------------------------------------*/ + +#ifndef advancingFrontAMI_H +#define advancingFrontAMI_H + +#include "className.H" +#include "DynamicList.H" +#include "faceAreaIntersect.H" +#include "pointList.H" +#include "AMIInterpolation.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class advancingFrontAMI Declaration +\*---------------------------------------------------------------------------*/ + +class advancingFrontAMI +: + public AMIInterpolation +{ + +private: + + // Private Member Functions + + //- No copy assignment + void operator=(const advancingFrontAMI&) = delete; + + + // Parallel operations + + label calcOverlappingProcs + ( + const List<treeBoundBoxList>& procBb, + const treeBoundBox& bb, + boolList& overlaps + ) const; + + void distributePatches + ( + const mapDistribute& map, + const primitivePatch& pp, + const globalIndex& gi, + List<faceList>& faces, + List<pointField>& points, + List<labelList>& tgtFaceIDs + ) const; + + void distributeAndMergePatches + ( + const mapDistribute& map, + const primitivePatch& tgtPatch, + const globalIndex& gi, + faceList& tgtFaces, + pointField& tgtPoints, + labelList& tgtFaceIDs + ) const; + + autoPtr<mapDistribute> calcProcMap + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch + ) const; + + +protected: + + // Protected data + + //- Storage for src-side triangle decomposition + List<DynamicList<face>> srcTris_; + + //- Storage for tgt-side triangle decomposition + List<DynamicList<face>> tgtTris_; + + //- Demand-driven extended target mesh (distributed parallel usage) + autoPtr<primitivePatch> extendedTgtPatchPtr_; + + //- Extended patch faces + faceList extendedTgtFaces_; + + //- Extended patch points + pointField extendedTgtPoints_; + + //- Extended patch face IDs + labelList extendedTgtFaceIDs_; + + //- Extended patch map + autoPtr<mapDistribute> extendedTgtMapPtr_; + + //- Labels of faces that are not overlapped by any target faces + //- (should be empty for correct functioning for fully covered AMIs) + labelList srcNonOverlap_; + + //- Octree used to find face seeds + autoPtr<indexedOctree<treeType>> treePtr_; + + //- Face triangulation mode + const faceAreaIntersect::triangulationMode triMode_; + + + // Protected Member Functions + + // Helper functions + + //- Create a map that extends tgtPatch so that it covers srcPatch + void createExtendedTgtPatch(); + + //- Check AMI patch coupling + void checkPatches() const; + + virtual bool calculate + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr = nullptr + ); + + //- Initialise walk and return true if all ok + bool initialiseWalk + ( + label& srcFacei, + label& tgtFacei + ); + + //- Write triangle intersection to OBJ file + void writeIntersectionOBJ + ( + const scalar area, + const face& f1, + const face& f2, + const pointField& f1Points, + const pointField& f2Points + ) const; + + + // Common AMI method functions + + label findTargetFace + ( + const label srcFacei, + const UList<label>& excludeFaces = UList<label>::null(), + const label srcFacePti = -1 + ) const; + + //- Add faces neighbouring facei to the ID list + void appendNbrFaces + ( + const label facei, + const primitivePatch& patch, + const DynamicList<label>& visitedFaces, + DynamicList<label>& faceIDs + ) const; + + //- Helper function to decompose a patch + void triangulatePatch + ( + const primitivePatch& patch, + List<DynamicList<face>>& tris, + List<scalar>& magSf + ) const; + + +public: + + //- Runtime type information + TypeName("advancingFrontAMI"); + + // Constructors + + //- Construct from components + advancingFrontAMI + ( + const dictionary& dict, + const bool reverseTarget + ); + + //- Construct from components + advancingFrontAMI + ( + const bool requireMatch = true, + const bool reverseTarget = false, + const scalar lowWeightCorrection = -1, + const faceAreaIntersect::triangulationMode triMode = + faceAreaIntersect::tmMesh + ); + + //- Construct as copy + advancingFrontAMI(const advancingFrontAMI& ami); + + //- Construct and return a clone + virtual autoPtr<AMIInterpolation> clone() const + { + return autoPtr<AMIInterpolation>(new advancingFrontAMI(*this)); + } + + + //- Destructor + virtual ~advancingFrontAMI() = default; + + + // Member Functions + + //- Return const access to the source patch + inline const primitivePatch& srcPatch() const; + + //- Return const access to the target patch + inline const primitivePatch& tgtPatch() const; + + //- Labels of faces that are not overlapped by any target faces + // Note: this should be empty for correct functioning + inline const labelList& srcNonOverlap() const; + + //- Flag to indicate that interpolation patches are conformal, i.e. + //- should fully cover each other + virtual bool conformal() const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "advancingFrontAMII.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.C b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMII.H similarity index 63% rename from src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.C rename to src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMII.H index 3ea1622bed68b5104889157962713e26dfe5c318..e0441345383976a94c5f1b2ddf26ff89b6ef8ab2 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIPatchToPatchInterpolation.C +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMII.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2013 OpenFOAM Foundation + Copyright (C) 2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -25,23 +25,40 @@ License \*---------------------------------------------------------------------------*/ -#include "AMIPatchToPatchInterpolation.H" -#include "AMIMethod.H" -#include "directAMI.H" -#include "mapNearestAMI.H" -#include "faceAreaWeightAMI.H" -#include "partialFaceAreaWeightAMI.H" +inline const Foam::primitivePatch& Foam::advancingFrontAMI::srcPatch() const +{ + if (!tsrcPatch0_.valid()) + { + FatalErrorInFunction + << "tsrcPatch0_ not allocated" + << abort(FatalError); + } + + return tsrcPatch0_(); +} -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -namespace Foam +inline const Foam::primitivePatch& Foam::advancingFrontAMI::tgtPatch() const { - makeAMIMethod(AMIPatchToPatchInterpolation); + if (extendedTgtPatchPtr_) + { + return extendedTgtPatchPtr_(); + } + + if (!ttgtPatch0_.valid()) + { + FatalErrorInFunction + << "srcPatch0Ptr not allocated" + << abort(FatalError); + } - makeAMIMethodType(AMIPatchToPatchInterpolation, directAMI); - makeAMIMethodType(AMIPatchToPatchInterpolation, mapNearestAMI); - makeAMIMethodType(AMIPatchToPatchInterpolation, faceAreaWeightAMI); - makeAMIMethodType(AMIPatchToPatchInterpolation, partialFaceAreaWeightAMI); + return ttgtPatch0_(); +} + + +inline const Foam::labelList& Foam::advancingFrontAMI::srcNonOverlap() const +{ + return srcNonOverlap_; } diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationParallelOps.C b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMIParallelOps.C similarity index 84% rename from src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationParallelOps.C rename to src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMIParallelOps.C index ad3a9ec83ad7d43af7c87deaea3155f2eccc4bc3..e67d9e6e400cde827065477af3a849195c9e272e 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIInterpolationParallelOps.C +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/advancingFrontAMI/advancingFrontAMIParallelOps.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2020 OpenCFD Ltd. + Copyright (C) 2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,62 +26,14 @@ License \*---------------------------------------------------------------------------*/ -#include "AMIInterpolation.H" +#include "advancingFrontAMI.H" #include "mergePoints.H" #include "mapDistribute.H" #include "AABBTree.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -template<class SourcePatch, class TargetPatch> -Foam::label Foam::AMIInterpolation<SourcePatch, TargetPatch>::calcDistribution -( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch -) const -{ - label proci = 0; - - if (Pstream::parRun()) - { - labelList facesPresentOnProc(Pstream::nProcs(), Zero); - if ((srcPatch.size() > 0) || (tgtPatch.size() > 0)) - { - facesPresentOnProc[Pstream::myProcNo()] = 1; - } - else - { - facesPresentOnProc[Pstream::myProcNo()] = 0; - } - - Pstream::gatherList(facesPresentOnProc); - Pstream::scatterList(facesPresentOnProc); - - label nHaveFaces = sum(facesPresentOnProc); - - if (nHaveFaces > 1) - { - proci = -1; - DebugInFunction - << "AMI split across multiple processors" << endl; - } - else if (nHaveFaces == 1) - { - proci = facesPresentOnProc.find(1); - DebugInFunction - << "AMI local to processor" << proci << endl; - } - } - - - // Either not parallel or no faces on any processor - return proci; -} - - -template<class SourcePatch, class TargetPatch> -Foam::label -Foam::AMIInterpolation<SourcePatch, TargetPatch>::calcOverlappingProcs +Foam::label Foam::advancingFrontAMI::calcOverlappingProcs ( const List<treeBoundBoxList>& procBb, const treeBoundBox& bb, @@ -102,7 +54,7 @@ Foam::AMIInterpolation<SourcePatch, TargetPatch>::calcOverlappingProcs if (tbb.overlaps(bb)) { overlaps[proci] = true; - nOverlaps++; + ++nOverlaps; break; } } @@ -112,11 +64,10 @@ Foam::AMIInterpolation<SourcePatch, TargetPatch>::calcOverlappingProcs } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>::distributePatches +void Foam::advancingFrontAMI::distributePatches ( const mapDistribute& map, - const TargetPatch& pp, + const primitivePatch& pp, const globalIndex& gi, List<faceList>& faces, List<pointField>& points, @@ -197,12 +148,10 @@ void Foam::AMIInterpolation<SourcePatch, TargetPatch>::distributePatches } -template<class SourcePatch, class TargetPatch> -void Foam::AMIInterpolation<SourcePatch, TargetPatch>:: -distributeAndMergePatches +void Foam::advancingFrontAMI::distributeAndMergePatches ( const mapDistribute& map, - const TargetPatch& tgtPatch, + const primitivePatch& tgtPatch, const globalIndex& gi, faceList& tgtFaces, pointField& tgtPoints, @@ -311,12 +260,10 @@ distributeAndMergePatches } -template<class SourcePatch, class TargetPatch> -Foam::autoPtr<Foam::mapDistribute> -Foam::AMIInterpolation<SourcePatch, TargetPatch>::calcProcMap +Foam::autoPtr<Foam::mapDistribute> Foam::advancingFrontAMI::calcProcMap ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch ) const { // Get decomposition of patch diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.C new file mode 100644 index 0000000000000000000000000000000000000000..2be76626bdf415b70290fe4d9f7989a207e40794 --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.C @@ -0,0 +1,801 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2013-2016 OpenFOAM Foundation + Copyright (C) 2018-2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "faceAreaWeightAMI.H" +#include "profiling.H" +#include "OBJstream.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(faceAreaWeightAMI, 0); + addToRunTimeSelectionTable(AMIInterpolation, faceAreaWeightAMI, dict); + addToRunTimeSelectionTable(AMIInterpolation, faceAreaWeightAMI, component); +} + +// * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * // + +/* + if (debug) + { + static label nAMI = 0; + + // Write out triangulated surfaces as OBJ files + OBJstream srcTriObj("srcTris_" + Foam::name(nAMI) + ".obj"); + const pointField& srcPts = src.points(); + forAll(srcTris_, facei) + { + const DynamicList<face>& faces = srcTris_[facei]; + for (const face& f : faces) + { + srcTriObj.write + ( + triPointRef(srcPts[f[0]], srcPts[f[1]], srcPts[f[2]]) + ); + } + } + + OBJstream tgtTriObj("tgtTris_" + Foam::name(nAMI) + ".obj"); + const pointField& tgtPts = tgt.points(); + forAll(tgtTris_, facei) + { + const DynamicList<face>& faces = tgtTris_[facei]; + for (const face& f : faces) + { + tgtTriObj.write + ( + triPointRef(tgtPts[f[0]], tgtPts[f[1]], tgtPts[f[2]]) + ); + } + } + + ++nAMI; + } +*/ + + +void Foam::faceAreaWeightAMI::calcAddressing +( + List<DynamicList<label>>& srcAddr, + List<DynamicList<scalar>>& srcWght, + List<DynamicList<point>>& srcCtr, + List<DynamicList<label>>& tgtAddr, + List<DynamicList<scalar>>& tgtWght, + label srcFacei, + label tgtFacei +) +{ + addProfiling(ami, "faceAreaWeightAMI::calcAddressing"); + + // Construct weights and addressing + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + label nFacesRemaining = srcAddr.size(); + + // List of tgt face neighbour faces + DynamicList<label> nbrFaces(10); + + // List of faces currently visited for srcFacei to avoid multiple hits + DynamicList<label> visitedFaces(10); + + // List to keep track of tgt faces used to seed src faces + labelList seedFaces(nFacesRemaining, -1); + seedFaces[srcFacei] = tgtFacei; + + // List to keep track of whether src face can be mapped + bitSet mapFlag(nFacesRemaining, true); + + // Reset starting seed + label startSeedi = 0; + + bool continueWalk = true; + DynamicList<label> nonOverlapFaces; + do + { + nbrFaces.clear(); + visitedFaces.clear(); + + // Do advancing front starting from srcFacei,tgtFacei + bool faceProcessed = processSourceFace + ( + srcFacei, + tgtFacei, + + nbrFaces, + visitedFaces, + + srcAddr, + srcWght, + srcCtr, + tgtAddr, + tgtWght + ); + + mapFlag.unset(srcFacei); + + if (!faceProcessed) + { + nonOverlapFaces.append(srcFacei); + } + + // Choose new src face from current src face neighbour + continueWalk = setNextFaces + ( + startSeedi, + srcFacei, + tgtFacei, + mapFlag, + seedFaces, + visitedFaces, + requireMatch_ && (lowWeightCorrection_ < 0) + // pass in nonOverlapFaces for failed tree search? + ); + } while (continueWalk); + + srcNonOverlap_.transfer(nonOverlapFaces); +} + + +bool Foam::faceAreaWeightAMI::processSourceFace +( + const label srcFacei, + const label tgtStartFacei, + + // list of tgt face neighbour faces + DynamicList<label>& nbrFaces, + // list of faces currently visited for srcFacei to avoid multiple hits + DynamicList<label>& visitedFaces, + + // temporary storage for addressing, weights and centroid + List<DynamicList<label>>& srcAddr, + List<DynamicList<scalar>>& srcWght, + List<DynamicList<point>>& srcCtr, + List<DynamicList<label>>& tgtAddr, + List<DynamicList<scalar>>& tgtWght +) +{ + addProfiling(ami, "faceAreaWeightAMI::processSourceFace"); + + if (tgtStartFacei == -1) + { + return false; + } + + const auto& tgtPatch = this->tgtPatch(); + + // append initial target face and neighbours + nbrFaces.append(tgtStartFacei); + appendNbrFaces(tgtStartFacei, tgtPatch, visitedFaces, nbrFaces); + + bool faceProcessed = false; + + label maxNeighbourFaces = nbrFaces.size(); + + do + { + // process new target face + label tgtFacei = nbrFaces.remove(); + visitedFaces.append(tgtFacei); + + scalar interArea = 0; + vector interCentroid(Zero); + calcInterArea(srcFacei, tgtFacei, interArea, interCentroid); + + // store when intersection fractional area > tolerance + if (interArea/srcMagSf_[srcFacei] > faceAreaIntersect::tolerance()) + { + srcAddr[srcFacei].append(tgtFacei); + srcWght[srcFacei].append(interArea); + srcCtr[srcFacei].append(interCentroid); + + tgtAddr[tgtFacei].append(srcFacei); + tgtWght[tgtFacei].append(interArea); + + appendNbrFaces(tgtFacei, tgtPatch, visitedFaces, nbrFaces); + + faceProcessed = true; + + maxNeighbourFaces = max(maxNeighbourFaces, nbrFaces.size()); + } + + } while (nbrFaces.size() > 0); + + if (debug > 1) + { + DebugVar(maxNeighbourFaces); + } + + return faceProcessed; +} + + +bool Foam::faceAreaWeightAMI::setNextFaces +( + label& startSeedi, + label& srcFacei, + label& tgtFacei, + const bitSet& mapFlag, + labelList& seedFaces, + const DynamicList<label>& visitedFaces, + const bool errorOnNotFound +) const +{ + addProfiling(ami, "faceAreaWeightAMI::setNextFaces"); + + if (mapFlag.count() == 0) + { + // No more faces to map + return false; + } + + const labelList& srcNbrFaces = this->srcPatch().faceFaces()[srcFacei]; + + // Initialise tgtFacei + tgtFacei = -1; + + // Set possible seeds for later use + bool valuesSet = false; + for (label faceS: srcNbrFaces) + { + if (mapFlag.test(faceS) && seedFaces[faceS] == -1) + { + for (label faceT : visitedFaces) + { + const scalar threshold = + srcMagSf_[faceS]*faceAreaIntersect::tolerance(); + + // Store when intersection fractional area > threshold + if (overlaps(faceS, faceT, threshold)) + { + seedFaces[faceS] = faceT; + + if (!valuesSet) + { + srcFacei = faceS; + tgtFacei = faceT; + valuesSet = true; + } + } + } + } + } + + if (valuesSet) + { + return true; + } + + // Set next src and tgt faces if not set above + // - try to use existing seed + label facei = startSeedi; + if (!mapFlag.test(startSeedi)) + { + facei = mapFlag.find_next(facei); + } + const label startSeedi0 = facei; + + bool foundNextSeed = false; + while (facei != -1) + { + if (!foundNextSeed) + { + startSeedi = facei; + foundNextSeed = true; + } + + if (seedFaces[facei] != -1) + { + srcFacei = facei; + tgtFacei = seedFaces[facei]; + + return true; + } + + facei = mapFlag.find_next(facei); + } + + // Perform new search to find match + if (debug) + { + Pout<< "Advancing front stalled: searching for new " + << "target face" << endl; + } + + facei = startSeedi0; + while (facei != -1) + { + srcFacei = facei; + tgtFacei = findTargetFace(srcFacei, visitedFaces); + + if (tgtFacei >= 0) + { + return true; + } + + facei = mapFlag.find_next(facei); + } + + if (errorOnNotFound) + { + FatalErrorInFunction + << "Unable to set target face for source face " << srcFacei + << abort(FatalError); + } + + return false; +} + + +void Foam::faceAreaWeightAMI::calcInterArea +( + const label srcFacei, + const label tgtFacei, + scalar& area, + vector& centroid +) const +{ + addProfiling(ami, "faceAreaWeightAMI::interArea"); + + // Quick reject if either face has zero area + if + ( + (srcMagSf_[srcFacei] < ROOTVSMALL) + || (tgtMagSf_[tgtFacei] < ROOTVSMALL) + ) + { + return; + } + + const auto& srcPatch = this->srcPatch(); + const auto& tgtPatch = this->tgtPatch(); + + const pointField& srcPoints = srcPatch.points(); + const pointField& tgtPoints = tgtPatch.points(); + + // Create intersection object + faceAreaIntersect inter + ( + srcPoints, + tgtPoints, + srcTris_[srcFacei], + tgtTris_[tgtFacei], + reverseTarget_, + AMIInterpolation::cacheIntersections_ + ); + + // Crude resultant norm + vector n(-srcPatch.faceNormals()[srcFacei]); + if (reverseTarget_) + { + n -= tgtPatch.faceNormals()[tgtFacei]; + } + else + { + n += tgtPatch.faceNormals()[tgtFacei]; + } + scalar magN = mag(n); + + const face& src = srcPatch[srcFacei]; + const face& tgt = tgtPatch[tgtFacei]; + + if (magN > ROOTVSMALL) + { + inter.calc(src, tgt, n/magN, area, centroid); + } + else + { + WarningInFunction + << "Invalid normal for source face " << srcFacei + << " points " << UIndirectList<point>(srcPoints, src) + << " target face " << tgtFacei + << " points " << UIndirectList<point>(tgtPoints, tgt) + << endl; + } + + if (AMIInterpolation::cacheIntersections_ && debug) + { + static OBJstream tris("intersectionTris.obj"); + const auto& triPts = inter.triangles(); + for (const auto& tp : triPts) + { + tris.write(triPointRef(tp[0], tp[1], tp[2]), false); + } + } + + if ((debug > 1) && (area > 0)) + { + writeIntersectionOBJ(area, src, tgt, srcPoints, tgtPoints); + } +} + + +bool Foam::faceAreaWeightAMI::overlaps +( + const label srcFacei, + const label tgtFacei, + const scalar threshold +) const +{ + // Quick reject if either face has zero area + if + ( + (srcMagSf_[srcFacei] < ROOTVSMALL) + || (tgtMagSf_[tgtFacei] < ROOTVSMALL) + ) + { + return false; + } + + const auto& srcPatch = this->srcPatch(); + const auto& tgtPatch = this->tgtPatch(); + + const pointField& srcPoints = srcPatch.points(); + const pointField& tgtPoints = tgtPatch.points(); + + faceAreaIntersect inter + ( + srcPoints, + tgtPoints, + srcTris_[srcFacei], + tgtTris_[tgtFacei], + reverseTarget_, + AMIInterpolation::cacheIntersections_ + ); + + // Crude resultant norm + vector n(-srcPatch.faceNormals()[srcFacei]); + if (reverseTarget_) + { + n -= tgtPatch.faceNormals()[tgtFacei]; + } + else + { + n += tgtPatch.faceNormals()[tgtFacei]; + } + scalar magN = mag(n); + + const face& src = srcPatch[srcFacei]; + const face& tgt = tgtPatch[tgtFacei]; + + if (magN > ROOTVSMALL) + { + return inter.overlaps(src, tgt, n/magN, threshold); + } + else + { + WarningInFunction + << "Invalid normal for source face " << srcFacei + << " points " << UIndirectList<point>(srcPoints, src) + << " target face " << tgtFacei + << " points " << UIndirectList<point>(tgtPoints, tgt) + << endl; + } + + return false; +} + + +void Foam::faceAreaWeightAMI::restartUncoveredSourceFace +( + List<DynamicList<label>>& srcAddr, + List<DynamicList<scalar>>& srcWght, + List<DynamicList<point>>& srcCtr, + List<DynamicList<label>>& tgtAddr, + List<DynamicList<scalar>>& tgtWght +) +{ + addProfiling(ami, "faceAreaWeightAMI::restartUncoveredSourceFace"); + + // Note: exclude faces in srcNonOverlap_ for ACMI? + + label nBelowMinWeight = 0; + const scalar minWeight = 0.95; + + // List of tgt face neighbour faces + DynamicList<label> nbrFaces(10); + + // List of faces currently visited for srcFacei to avoid multiple hits + DynamicList<label> visitedFaces(10); + + const auto& srcPatch = this->srcPatch(); + + forAll(srcWght, srcFacei) + { + const scalar s = sum(srcWght[srcFacei]); + const scalar t = s/srcMagSf_[srcFacei]; + + if (t < minWeight) + { + ++nBelowMinWeight; + + const face& f = srcPatch[srcFacei]; + + forAll(f, fpi) + { + const label tgtFacei = + findTargetFace(srcFacei, srcAddr[srcFacei], fpi); + + if (tgtFacei != -1) + { + nbrFaces.clear(); + visitedFaces = srcAddr[srcFacei]; + + (void)processSourceFace + ( + srcFacei, + tgtFacei, + + nbrFaces, + visitedFaces, + + srcAddr, + srcWght, + srcCtr, + tgtAddr, + tgtWght + ); + } + } + } + } + + if (debug && nBelowMinWeight) + { + WarningInFunction + << "Restarted search on " << nBelowMinWeight + << " faces since sum of weights < " << minWeight + << endl; + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::faceAreaWeightAMI::faceAreaWeightAMI +( + const dictionary& dict, + const bool reverseTarget +) +: + advancingFrontAMI(dict, reverseTarget), + restartUncoveredSourceFace_ + ( + dict.getOrDefault("restartUncoveredSourceFace", true) + ) +{} + + +Foam::faceAreaWeightAMI::faceAreaWeightAMI +( + const bool requireMatch, + const bool reverseTarget, + const scalar lowWeightCorrection, + const faceAreaIntersect::triangulationMode triMode, + const bool restartUncoveredSourceFace +) +: + advancingFrontAMI + ( + requireMatch, + reverseTarget, + lowWeightCorrection, + triMode + ), + restartUncoveredSourceFace_(restartUncoveredSourceFace) +{} + + +Foam::faceAreaWeightAMI::faceAreaWeightAMI(const faceAreaWeightAMI& ami) +: + advancingFrontAMI(ami), + restartUncoveredSourceFace_(ami.restartUncoveredSourceFace_) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::faceAreaWeightAMI::calculate +( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr +) +{ + if (upToDate_) + { + return false; + } + + addProfiling(ami, "faceAreaWeightAMI::calculate"); + + advancingFrontAMI::calculate(srcPatch, tgtPatch, surfPtr); + + label srcFacei = 0; + label tgtFacei = 0; + + bool ok = initialiseWalk(srcFacei, tgtFacei); + + srcCentroids_.setSize(srcAddress_.size()); + + const auto& src = this->srcPatch(); + const auto& tgt = this->tgtPatch(); // might be the extended patch! + + // Temporary storage for addressing and weights + List<DynamicList<label>> srcAddr(src.size()); + List<DynamicList<scalar>> srcWght(srcAddr.size()); + List<DynamicList<point>> srcCtr(srcAddr.size()); + List<DynamicList<label>> tgtAddr(tgt.size()); + List<DynamicList<scalar>> tgtWght(tgtAddr.size()); + + if (ok) + { + calcAddressing + ( + srcAddr, + srcWght, + srcCtr, + tgtAddr, + tgtWght, + srcFacei, + tgtFacei + ); + + if (debug && !srcNonOverlap_.empty()) + { + Pout<< " AMI: " << srcNonOverlap_.size() + << " non-overlap faces identified" + << endl; + } + + // Check for badly covered faces + if (restartUncoveredSourceFace_) // && requireMatch_??? + { + restartUncoveredSourceFace + ( + srcAddr, + srcWght, + srcCtr, + tgtAddr, + tgtWght + ); + } + } + + // Transfer data to persistent storage + forAll(srcAddr, i) + { + srcAddress_[i].transfer(srcAddr[i]); + srcWeights_[i].transfer(srcWght[i]); + srcCentroids_[i].transfer(srcCtr[i]); + } + + forAll(tgtAddr, i) + { + tgtAddress_[i].transfer(tgtAddr[i]); + tgtWeights_[i].transfer(tgtWght[i]); + } + + if (distributed()) + { + const primitivePatch& srcPatch0 = this->srcPatch0(); + const primitivePatch& tgtPatch0 = this->tgtPatch0(); + + // Create global indexing for each original patch + globalIndex globalSrcFaces(srcPatch0.size()); + globalIndex globalTgtFaces(tgtPatch0.size()); + + for (labelList& addressing : srcAddress_) + { + for (label& addr : addressing) + { + addr = extendedTgtFaceIDs_[addr]; + } + } + + for (labelList& addressing : tgtAddress_) + { + globalSrcFaces.inplaceToGlobal(addressing); + } + + // Send data back to originating procs. Note that contributions + // from different processors get added (ListOps::appendEqOp) + + mapDistributeBase::distribute + ( + Pstream::commsTypes::nonBlocking, + List<labelPair>(), + tgtPatch0.size(), + extendedTgtMapPtr_->constructMap(), + false, // has flip + extendedTgtMapPtr_->subMap(), + false, // has flip + tgtAddress_, + ListOps::appendEqOp<label>(), + flipOp(), // flip operation + labelList() + ); + + mapDistributeBase::distribute + ( + Pstream::commsTypes::nonBlocking, + List<labelPair>(), + tgtPatch0.size(), + extendedTgtMapPtr_->constructMap(), + false, + extendedTgtMapPtr_->subMap(), + false, + tgtWeights_, + ListOps::appendEqOp<scalar>(), + flipOp(), + scalarList() + ); + + // Note: using patch face areas calculated by the AMI method + extendedTgtMapPtr_->reverseDistribute(tgtPatch0.size(), tgtMagSf_); + + // Cache maps and reset addresses + List<Map<label>> cMapSrc; + srcMapPtr_.reset + ( + new mapDistribute(globalSrcFaces, tgtAddress_, cMapSrc) + ); + + List<Map<label>> cMapTgt; + tgtMapPtr_.reset + ( + new mapDistribute(globalTgtFaces, srcAddress_, cMapTgt) + ); + } + + // Convert the weights from areas to normalised values + normaliseWeights(conformal(), true); + + upToDate_ = true; + + return upToDate_; +} + + +void Foam::faceAreaWeightAMI::write(Ostream& os) const +{ + advancingFrontAMI::write(os); + + if (restartUncoveredSourceFace_) + { + os.writeEntry + ( + "restartUncoveredSourceFace", + restartUncoveredSourceFace_ + ); + } +} + + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/faceAreaWeightAMI/faceAreaWeightAMI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.H similarity index 70% rename from src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/faceAreaWeightAMI/faceAreaWeightAMI.H rename to src/meshTools/AMIInterpolation/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.H index 0c6dec88d6ce98d25f95c8efa330720eea418278..818d26ebea8aec4310209e3d46261a90384a3f4d 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/faceAreaWeightAMI/faceAreaWeightAMI.H +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.H @@ -38,7 +38,7 @@ SourceFiles #ifndef faceAreaWeightAMI_H #define faceAreaWeightAMI_H -#include "AMIMethod.H" +#include "advancingFrontAMI.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -49,10 +49,9 @@ namespace Foam Class faceAreaWeightAMI Declaration \*---------------------------------------------------------------------------*/ -template<class SourcePatch, class TargetPatch> class faceAreaWeightAMI : - public AMIMethod<SourcePatch, TargetPatch> + public advancingFrontAMI { private: @@ -61,30 +60,34 @@ private: //- Flag to restart uncovered source faces const bool restartUncoveredSourceFace_; - //- Storage for src-side triangle decomposition - List<DynamicList<face>> srcTris_; - - //- Storage for tgt-side triangle decomposition - List<DynamicList<face>> tgtTris_; protected: // Protected Member Functions - //- No copy construct - faceAreaWeightAMI(const faceAreaWeightAMI&) = delete; - //- No copy assignment void operator=(const faceAreaWeightAMI&) = delete; + //- Initialise the geometry + void initGeom + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const globalIndex& globalTgtFaces, + labelList& extendedTgtFaceIDs + ); + + // Marching front - //- Calculate addressing and weights using temporary storage + //- Calculate addressing, weights and centroids using temporary + //- storage virtual void calcAddressing ( List<DynamicList<label>>& srcAddress, List<DynamicList<scalar>>& srcWeights, + List<DynamicList<point>>& srcCentroids, List<DynamicList<label>>& tgtAddress, List<DynamicList<scalar>>& tgtWeights, label srcFacei, @@ -100,6 +103,7 @@ protected: DynamicList<label>& visitedFaces, List<DynamicList<label>>& srcAddr, List<DynamicList<scalar>>& srcWght, + List<DynamicList<point>>& srcCtr, List<DynamicList<label>>& tgtAddr, List<DynamicList<scalar>>& tgtWght ); @@ -109,30 +113,33 @@ protected: ( List<DynamicList<label>>& srcAddr, List<DynamicList<scalar>>& srcWght, + List<DynamicList<point>>& srcCtr, List<DynamicList<label>>& tgtAddr, List<DynamicList<scalar>>& tgtWght ); //- Set the source and target seed faces - virtual void setNextFaces + virtual bool setNextFaces ( label& startSeedi, label& srcFacei, label& tgtFacei, - const boolList& mapFlag, + const bitSet& mapFlag, labelList& seedFaces, const DynamicList<label>& visitedFaces, - bool errorOnNotFound = true + const bool errorOnNotFound = true ) const; // Evaluation //- Area of intersection between source and target faces - virtual scalar interArea + virtual void calcInterArea ( const label srcFacei, - const label tgtFacei + const label tgtFacei, + scalar& area, + vector& centroid ) const; //- Return true if faces overlap @@ -152,53 +159,50 @@ public: // Constructors + //- Construct from dictionary + faceAreaWeightAMI + ( + const dictionary& dict, + const bool reverseTarget = false + ); + //- Construct from components faceAreaWeightAMI ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, + const bool requireMatch, const bool reverseTarget = false, - const bool requireMatch = true, + const scalar lowWeightCorrection = -1, + const faceAreaIntersect::triangulationMode triMode = + faceAreaIntersect::tmMesh, const bool restartUncoveredSourceFace = true ); + //- Construct as copy + faceAreaWeightAMI(const faceAreaWeightAMI& ami); - //- Destructor - virtual ~faceAreaWeightAMI(); + //- Construct and return a clone + virtual autoPtr<AMIInterpolation> clone() const + { + return autoPtr<AMIInterpolation>(new faceAreaWeightAMI(*this)); + } - // Member Functions + //- Destructor + virtual ~faceAreaWeightAMI() = default; - // Manipulation - //- Update addressing and weights - virtual void calculate - ( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei = -1, - label tgtFacei = -1 - ); + // Member Functions - //- Set the face areas for parallel runs - virtual void setMagSf - ( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf - ) const; + //- Update addressing, weights and (optional) centroids + virtual bool calculate + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr = nullptr + ); - //- Normalise the weight. Can optionally subset addressing - //- (e.g. for mapNearest) - virtual void normaliseWeights - ( - const bool verbose, - AMIInterpolation<SourcePatch, TargetPatch>& inter - ); + //- Write + virtual void write(Ostream& os) const; }; @@ -208,12 +212,6 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#ifdef NoRepository - #include "faceAreaWeightAMI.C" -#endif - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/findNearestMaskedOp.H b/src/meshTools/AMIInterpolation/AMIInterpolation/findNearestMaskedOp.H new file mode 100644 index 0000000000000000000000000000000000000000..4bc2507cc998b85706a7b372031a32402704034f --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/findNearestMaskedOp.H @@ -0,0 +1,62 @@ +#include "indexedOctree.H" +#include "treeDataPrimitivePatch.H" + +namespace Foam +{ + +template<class PatchType> +class findNearestMaskedOp +{ + const indexedOctree<treeDataPrimitivePatch<PatchType>>& tree_; + const labelUList& excludeIndices_; + +public: + + findNearestMaskedOp + ( + const indexedOctree<treeDataPrimitivePatch<PatchType>>& tree, + const labelUList& excludeIndices + ) + : + tree_(tree), + excludeIndices_(excludeIndices) + {} + + void operator() + ( + const labelUList& indices, + const point& sample, + + scalar& nearestDistSqr, + label& minIndex, + point& nearestPoint + ) const + { + const treeDataPrimitivePatch<PatchType>& shape = tree_.shapes(); + const PatchType& patch = shape.patch(); + + const pointField& points = patch.points(); + + forAll(indices, i) + { + const label index = indices[i]; + + if (!excludeIndices_.found(index)) + { + const typename PatchType::FaceType& f = patch[index]; + + pointHit nearHit = f.nearestPoint(sample, points); + scalar distSqr = sqr(nearHit.distance()); + + if (distSqr < nearestDistSqr) + { + nearestDistSqr = distSqr; + minIndex = index; + nearestPoint = nearHit.rawPoint(); + } + } + } + } +}; + +} // End namespace Foam diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.C new file mode 100644 index 0000000000000000000000000000000000000000..9108ddbca89f3131065442b65e65c527ad2ffc65 --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.C @@ -0,0 +1,408 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "nearestFaceAMI.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(nearestFaceAMI, 0); + addToRunTimeSelectionTable(AMIInterpolation, nearestFaceAMI, dict); + addToRunTimeSelectionTable(AMIInterpolation, nearestFaceAMI, component); +} + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::autoPtr<Foam::mapDistribute> Foam::nearestFaceAMI::calcFaceMap +( + const List<nearestAndDist>& localInfo, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch +) const +{ + // Generate the list of processor bounding boxes for tgtPatch + List<boundBox> procBbs(Pstream::nProcs()); + procBbs[Pstream::myProcNo()] = + boundBox(tgtPatch.points(), tgtPatch.meshPoints(), true); + Pstream::gatherList(procBbs); + Pstream::scatterList(procBbs); + + // Identify which of my local src faces intersect with each processor + // tgtPatch bb within the current match's search distance + const pointField& srcCcs = srcPatch.faceCentres(); + List<DynamicList<label>> dynSendMap(Pstream::nProcs()); + + forAll(localInfo, srcFacei) + { + // Test local srcPatch face centres against remote processor tgtPatch bb + // using distance from initial pass + + const scalar r2 = localInfo[srcFacei].second(); + + forAll(procBbs, proci) + { + if (proci != Pstream::myProcNo()) + { + if (procBbs[proci].overlaps(srcCcs[srcFacei], r2)) + { + dynSendMap[proci].append(srcFacei); + } + } + } + } + + // Convert dynamicList to labelList + labelListList sendMap(Pstream::nProcs()); + forAll(sendMap, proci) + { + dynSendMap[proci].shrink(); + sendMap[proci].transfer(dynSendMap[proci]); + + if (debug) + { + Pout<< "send map - to proc " << proci << " sending " + << sendMap[proci].size() << " elements" << endl; + } + } + + return autoPtr<mapDistribute>::New(std::move(sendMap)); +} + + +Foam::autoPtr<Foam::mapDistribute> Foam::nearestFaceAMI::calcDistributed +( + const primitivePatch& src, + const primitivePatch& tgt, + labelListList& srcToTgtAddr, + scalarListList& srcToTgtWght +) const +{ + autoPtr<indexedOctree<treeType>> tgtTreePtr; + if (tgt.size()) + { + tgtTreePtr = this->createTree(tgt); + } + + // Create global indexing for tgtPatch + globalIndex globalTgtCells(tgt.size()); + + + // First pass + // ========== + // For each srcPatch face, determine local match on tgtPatch + + // Identify local nearest matches + pointField srcCcs(src.faceCentres()); + + List<nearestAndDist> localInfo(src.size()); + if (tgt.size()) + { + const auto& tgtTree = tgtTreePtr(); + + forAll(srcCcs, srcCelli) + { + const point& srcCc = srcCcs[srcCelli]; + + pointIndexHit& test = localInfo[srcCelli].first(); + test = tgtTree.findNearest(srcCc, GREAT); + + if (test.hit()) + { + // With a search radius2 of GREAT all cells should receive a hit + localInfo[srcCelli].second() = magSqr(srcCc - test.hitPoint()); + test.setIndex(globalTgtCells.toGlobal(test.index())); + } + } + } + else + { + // No local tgtPatch faces - initialise nearest distance for all + // srcPatch faces to GREAT so that they [should be] set by remote + // tgtPatch faces + for (auto& info : localInfo) + { + info.second() = GREAT; + } + } + + + // Second pass + // =========== + // Determine remote matches + + // Map returns labels of src patch faces to send to each proc + autoPtr<mapDistribute> mapPtr = calcFaceMap(localInfo, src, tgt); + mapDistribute& map = mapPtr(); + + List<nearestAndDist> remoteInfo(localInfo); + map.distribute(remoteInfo); + + // Note: re-using srcCcs + map.distribute(srcCcs); + + if (tgt.size()) + { + const auto& tgtTree = tgtTreePtr(); + + // Test remote srcPatch faces against local tgtPatch faces + nearestAndDist testInfo; + pointIndexHit& test = testInfo.first(); + forAll(remoteInfo, i) + { + test = tgtTree.findNearest(srcCcs[i], remoteInfo[i].second()); + if (test.hit()) + { + test.setIndex(globalTgtCells.toGlobal(test.index())); + testInfo.second() = magSqr(test.hitPoint() - srcCcs[i]); + nearestEqOp()(remoteInfo[i], testInfo); + } + } + } + + // Send back to originating processor. Choose best if sent to multiple + // processors. Note that afterwards all unused entries have the unique + // value nearestZero (distance < 0). This is used later on to see if + // the sample was sent to any processor. + const nearestAndDist nearestZero(pointIndexHit(), -GREAT); + mapDistributeBase::distribute + ( + Pstream::commsTypes::nonBlocking, + List<labelPair>(0), + src.size(), + map.constructMap(), + map.constructHasFlip(), + map.subMap(), + map.subHasFlip(), + remoteInfo, + nearestEqOp(), + noOp(), // no flipping + nearestZero + ); + + + // Third pass + // ========== + // Combine local and remote info and filter out any connections that are + // further away than threshold distance squared + + srcToTgtAddr.setSize(src.size()); + srcToTgtWght.setSize(src.size()); + forAll(srcToTgtAddr, srcFacei) + { + nearestEqOp()(localInfo[srcFacei], remoteInfo[srcFacei]); + if (localInfo[srcFacei].second() < maxDistance2_) + { + const label tgtFacei = localInfo[srcFacei].first().index(); + srcToTgtAddr[srcFacei] = labelList(1, tgtFacei); + srcToTgtWght[srcFacei] = scalarList(1, 1.0); + } + } + + List<Map<label>> cMap; + return autoPtr<mapDistribute>::New(globalTgtCells, srcToTgtAddr, cMap); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::nearestFaceAMI::nearestFaceAMI +( + const dictionary& dict, + const bool reverseTarget +) +: + AMIInterpolation(dict, reverseTarget), + maxDistance2_(dict.getOrDefault<scalar>("maxDistance2", GREAT)) +{} + + +Foam::nearestFaceAMI::nearestFaceAMI +( + const bool requireMatch, + const bool reverseTarget, + const scalar lowWeightCorrection +) +: + AMIInterpolation(requireMatch, reverseTarget, lowWeightCorrection), + maxDistance2_(GREAT) +{} + + +Foam::nearestFaceAMI::nearestFaceAMI(const nearestFaceAMI& ami) +: + AMIInterpolation(ami), + maxDistance2_(ami.maxDistance2_) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::nearestFaceAMI::calculate +( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr +) +{ + if (upToDate_) + { + return false; + } + + AMIInterpolation::calculate(srcPatch, tgtPatch, surfPtr); + + const auto& src = this->srcPatch0(); + const auto& tgt = this->tgtPatch0(); + + // Set face area magnitudes + srcMagSf_ = mag(src.faceAreas()); + tgtMagSf_ = mag(tgt.faceAreas()); + + // TODO: implement symmetric calculation controls; assume yes for now + bool symmetric_ = true; + + if (this->distributed()) + { + tgtMapPtr_ = + calcDistributed + ( + src, + tgt, + srcAddress_, + srcWeights_ + ); + + if (symmetric_) + { + srcMapPtr_ = + calcDistributed + ( + tgt, + src, + tgtAddress_, + tgtWeights_ + ); + } + } + else + { + srcAddress_.setSize(src.size()); + srcWeights_.setSize(src.size()); + + if (symmetric_) + { + tgtAddress_.setSize(tgt.size()); + tgtWeights_.setSize(tgt.size()); + } + + const pointField& srcCcs = src.faceCentres(); + const pointField& tgtCcs = tgt.faceCentres(); + + const auto tgtTreePtr = this->createTree(tgtPatch); + const auto& tgtTree = tgtTreePtr(); + + forAll(srcCcs, srcFacei) + { + const point& srcCc = srcCcs[srcFacei]; + const pointIndexHit hit = tgtTree.findNearest(srcCc, GREAT); + + if + ( + hit.hit() + && (magSqr(srcCc - tgtCcs[hit.index()]) < maxDistance2_) + ) + { + label tgtFacei = hit.index(); + srcAddress_[srcFacei] = labelList(1, tgtFacei); + srcWeights_[srcFacei] = scalarList(1, 1.0); + + if (symmetric_) + { + tgtAddress_[tgtFacei] = labelList(1, srcFacei); + tgtWeights_[tgtFacei] = scalarList(1, 1.0); + } + } + else + { + if (debug) + { + WarningInFunction + << "Unable to find target face for source face " + << srcFacei << endl; + } + } + } + + if (symmetric_) + { + const auto srcTreePtr = this->createTree(srcPatch); + const auto& srcTree = srcTreePtr(); + + // Check that all source cells have connections and populate any + // missing entries + forAll(tgtWeights_, tgtCelli) + { + if (tgtAddress_[tgtCelli].empty()) + { + const point& tgtCc = tgtCcs[tgtCelli]; + pointIndexHit hit = srcTree.findNearest(tgtCc, GREAT); + + if + ( + hit.hit() + && (magSqr(tgtCc - srcCcs[hit.index()]) < maxDistance2_) + ) + { + tgtAddress_[tgtCelli] = labelList(1, hit.index()); + tgtWeights_[tgtCelli] = scalarList(1, 1.0); + } + } + else + { + if (debug) + { + WarningInFunction + << "Unable to find source face for target face " + << tgtCelli << endl; + } + } + } + } + } + + srcWeightsSum_.setSize(srcWeights_.size(), 1); + tgtWeightsSum_.setSize(tgtWeights_.size(), 1); + + upToDate_ = true; + + return upToDate_; +} + + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.H new file mode 100644 index 0000000000000000000000000000000000000000..85938ecf4d817422cf1aee4646756949ccefd527 --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.H @@ -0,0 +1,169 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::nearestFaceAMI + +Description + Nearest-face Arbitrary Mesh Interface (AMI) method + +SourceFiles + nearestFaceAMI.C + +\*---------------------------------------------------------------------------*/ + +#ifndef nearestFaceAMI_H +#define nearestFaceAMI_H + +#include "AMIInterpolation.H" +#include "pointIndexHit.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class nearestFaceAMI Declaration +\*---------------------------------------------------------------------------*/ + +class nearestFaceAMI +: + public AMIInterpolation +{ +public: + + typedef Tuple2<pointIndexHit, scalar> nearestAndDist; + + //- Helper class for finding nearest + class nearestEqOp + { + + public: + + void operator()(nearestAndDist& x, const nearestAndDist& y) const + { + if (y.first().hit()) + { + if (!x.first().hit()) + { + x = y; + } + else if (y.second() < x.second()) + { + x = y; + } + } + } + }; + + +private: + + // Private Data + + //- Maximum squared distance + scalar maxDistance2_; + + + // Private Member Functions + + //- No copy assignment + void operator=(const nearestFaceAMI&) = delete; + + autoPtr<mapDistribute> calcFaceMap + ( + const List<nearestAndDist>& localInfo, + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch + ) const; + + autoPtr<mapDistribute> calcDistributed + ( + const primitivePatch& src, + const primitivePatch& tgt, + labelListList& srcToTgtAddr, + scalarListList& srcToTgtWght + ) const; + + +public: + + //- Runtime type information + TypeName("nearestFaceAMI"); + + + // Constructors + + //- Construct from dictionary + nearestFaceAMI + ( + const dictionary& dict, + const bool reverseTarget = false + ); + + //- Construct from components + nearestFaceAMI + ( + const bool requireMatch = true, + const bool reverseTarget = false, + const scalar lowWeightCorrection = -1 + ); + + //- Construct as copy + nearestFaceAMI(const nearestFaceAMI& ami); + + //- Construct and return a clone + virtual autoPtr<AMIInterpolation> clone() const + { + return autoPtr<AMIInterpolation>(new nearestFaceAMI(*this)); + } + + + //- Destructor + virtual ~nearestFaceAMI() = default; + + + // Member Functions + + //- Update addressing and weights + virtual bool calculate + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr = nullptr + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C b/src/meshTools/AMIInterpolation/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C new file mode 100644 index 0000000000000000000000000000000000000000..61b4197f2b0b5354f02bfa7c3dada538d4a46555 --- /dev/null +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C @@ -0,0 +1,159 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2013-2016 OpenFOAM Foundation + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "partialFaceAreaWeightAMI.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(partialFaceAreaWeightAMI, 0); + addToRunTimeSelectionTable + ( + AMIInterpolation, + partialFaceAreaWeightAMI, + dict + ); + addToRunTimeSelectionTable + ( + AMIInterpolation, + partialFaceAreaWeightAMI, + component + ); +} + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +bool Foam::partialFaceAreaWeightAMI::setNextFaces +( + label& startSeedi, + label& srcFacei, + label& tgtFacei, + const bitSet& mapFlag, + labelList& seedFaces, + const DynamicList<label>& visitedFaces, + const bool errorOnNotFound +) const +{ + return faceAreaWeightAMI::setNextFaces + ( + startSeedi, + srcFacei, + tgtFacei, + mapFlag, + seedFaces, + visitedFaces, + false // no error on not found + ); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::partialFaceAreaWeightAMI::partialFaceAreaWeightAMI +( + const dictionary& dict, + const bool reverseTarget +) +: + faceAreaWeightAMI(dict, reverseTarget) +{} + + +Foam::partialFaceAreaWeightAMI::partialFaceAreaWeightAMI +( + const bool requireMatch, + const bool reverseTarget, + const scalar lowWeightCorrection, + const faceAreaIntersect::triangulationMode triMode, + const bool restartUncoveredSourceFace +) +: + faceAreaWeightAMI + ( + requireMatch, + reverseTarget, + lowWeightCorrection, + triMode, + restartUncoveredSourceFace + ) +{} + + +Foam::partialFaceAreaWeightAMI::partialFaceAreaWeightAMI +( + const partialFaceAreaWeightAMI& ami +) +: + faceAreaWeightAMI(ami) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::partialFaceAreaWeightAMI::conformal() const +{ + return false; +} + + +bool Foam::partialFaceAreaWeightAMI::calculate +( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr +) +{ + if (faceAreaWeightAMI::calculate(srcPatch, tgtPatch, surfPtr)) + { + if (distributed()) + { + scalarList newTgtMagSf(std::move(tgtMagSf_)); + + // Assign default sizes. Override selected values with calculated + // values. This is to support ACMI where some of the target faces + // are never used (so never get sent over and hence never assigned + // to) + tgtMagSf_ = tgtPatch0().magFaceAreas(); + + for (const labelList& smap : this->extendedTgtMapPtr_->subMap()) + { + UIndirectList<scalar>(tgtMagSf_, smap) = + UIndirectList<scalar>(newTgtMagSf, smap); + } + } + + return true; + } + + return false; +} + + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.H b/src/meshTools/AMIInterpolation/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.H similarity index 59% rename from src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.H rename to src/meshTools/AMIInterpolation/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.H index becb1c69fb4f3e1cf08f68db6e40c8850c54f5a1..f03f8d155dd4281eb33555170e4b0b1328f48206 100644 --- a/src/meshTools/AMIInterpolation/AMIInterpolation/AMIMethod/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.H +++ b/src/meshTools/AMIInterpolation/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -49,35 +49,34 @@ namespace Foam Class partialFaceAreaWeightAMI Declaration \*---------------------------------------------------------------------------*/ -template<class SourcePatch, class TargetPatch> class partialFaceAreaWeightAMI : - public faceAreaWeightAMI<SourcePatch, TargetPatch> + public faceAreaWeightAMI { private: // Private Member Functions - //- No copy construct - partialFaceAreaWeightAMI(const partialFaceAreaWeightAMI&) = delete; - //- No copy assignment void operator=(const partialFaceAreaWeightAMI&) = delete; - // Marching front - //- Set the source and target seed faces - virtual void setNextFaces - ( - label& startSeedi, - label& srcFacei, - label& tgtFacei, - const boolList& mapFlag, - labelList& seedFaces, - const DynamicList<label>& visitedFaces, - bool errorOnNotFound = true - ) const; +protected: + + // Protected Member Functions + + //- Set the source and target seed faces + virtual bool setNextFaces + ( + label& startSeedi, + label& srcFacei, + label& tgtFacei, + const bitSet& mapFlag, + labelList& seedFaces, + const DynamicList<label>& visitedFaces, + const bool errorOnNotFound = true + ) const; public: @@ -88,50 +87,51 @@ public: // Constructors + //- Construct from dictionary + partialFaceAreaWeightAMI + ( + const dictionary& dict, + const bool reverseTarget = false + ); + //- Construct from components partialFaceAreaWeightAMI ( - const SourcePatch& srcPatch, - const TargetPatch& tgtPatch, - const faceAreaIntersect::triangulationMode& triMode, + const bool requireMatch = false, const bool reverseTarget = false, - const bool requireMatch = true + const scalar lowWeightCorrection = -1, + const faceAreaIntersect::triangulationMode triMode = + faceAreaIntersect::tmMesh, + const bool restartUncoveredSourceFace = true ); + //- Construct as copy + partialFaceAreaWeightAMI(const partialFaceAreaWeightAMI& ami); + + //- Construct and return a clone + virtual autoPtr<AMIInterpolation> clone() const + { + return + autoPtr<AMIInterpolation>(new partialFaceAreaWeightAMI(*this)); + } + //- Destructor - virtual ~partialFaceAreaWeightAMI(); + virtual ~partialFaceAreaWeightAMI() = default; // Member Functions - // Access - - //- Flag to indicate that interpolation patches are conformal - virtual bool conformal() const; - - - // Manipulation - - //- Update addressing and weights - virtual void calculate - ( - labelListList& srcAddress, - scalarListList& srcWeights, - labelListList& tgtAddress, - scalarListList& tgtWeights, - label srcFacei = -1, - label tgtFacei = -1 - ); - - //- Set the face areas for parallel runs - virtual void setMagSf - ( - const TargetPatch& tgtPatch, - const mapDistribute& map, - scalarList& srcMagSf, - scalarList& tgtMagSf - ) const; + //- Flag to indicate that interpolation patches are conformal + virtual bool conformal() const; + + //- Update addressing, weights and (optional) centroids + virtual bool calculate + ( + const primitivePatch& srcPatch, + const primitivePatch& tgtPatch, + const autoPtr<searchableSurface>& surfPtr = nullptr + ); }; @@ -141,12 +141,6 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#ifdef NoRepository - #include "partialFaceAreaWeightAMI.C" -#endif - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.C b/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.C index 97428ec0e3bf66b9772c21e025ec297a8d54455d..8976e57b586dc365a0b6dd4366d35a19fc567a82 100644 --- a/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.C +++ b/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.C @@ -219,13 +219,15 @@ void Foam::faceAreaIntersect::triSliceWithPlane } -Foam::scalar Foam::faceAreaIntersect::triangleIntersect +void Foam::faceAreaIntersect::triangleIntersect ( const triPoints& src, const point& tgt0, const point& tgt1, const point& tgt2, - const vector& n + const vector& n, + scalar& area, + vector& centroid ) const { // Work storage @@ -241,7 +243,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect const scalar srcArea(triArea(src)); if (srcArea < ROOTVSMALL) { - return 0.0; + return; } // Typical length scale @@ -255,7 +257,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect scalar s = mag(tgt1 - tgt0); if (s < ROOTVSMALL) { - return 0.0; + return; } // Note: outer product with n pre-scaled with edge length. This is @@ -268,7 +270,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect // Triangle either zero edge length (s == 0) or // perpendicular to face normal n. In either case zero // overlap area - return 0.0; + return; } else { @@ -279,7 +281,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect if (nWorkTris1 == 0) { - return 0.0; + return; } // Edge 1 @@ -290,7 +292,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect scalar s = mag(tgt2 - tgt1); if (s < ROOTVSMALL) { - return 0.0; + return; } const vector n1((tgt1 - tgt2)^(-s*n)); const scalar magSqrN1(magSqr(n1)); @@ -300,7 +302,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect // Triangle either zero edge length (s == 0) or // perpendicular to face normal n. In either case zero // overlap area - return 0.0; + return; } else { @@ -315,7 +317,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect if (nWorkTris2 == 0) { - return 0.0; + return; } } } @@ -328,7 +330,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect scalar s = mag(tgt2 - tgt0); if (s < ROOTVSMALL) { - return 0.0; + return; } const vector n2((tgt2 - tgt0)^(-s*n)); const scalar magSqrN2(magSqr(n2)); @@ -338,7 +340,7 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect // Triangle either zero edge length (s == 0) or // perpendicular to face normal n. In either case zero // overlap area - return 0.0; + return; } else { @@ -353,23 +355,25 @@ Foam::scalar Foam::faceAreaIntersect::triangleIntersect if (nWorkTris1 == 0) { - return 0.0; + return; } else { // Calculate area of sub-triangles - scalar area = 0.0; for (label i = 0; i < nWorkTris1; ++i) { - area += triArea(workTris1[i]); + // Area of intersection + const scalar currArea = triArea(workTris1[i]); + area += currArea; + + // Area-weighted centroid of intersection + centroid += currArea*triCentroid(workTris1[i]); if (cacheTriangulation_) { triangles_.append(workTris1[i]); } } - - return area; } } } @@ -443,12 +447,13 @@ void Foam::faceAreaIntersect::triangulate } - -Foam::scalar Foam::faceAreaIntersect::calc +void Foam::faceAreaIntersect::calc ( const face& faceA, const face& faceB, - const vector& n + const vector& n, + scalar& area, + vector& centroid ) const { if (cacheTriangulation_) @@ -456,8 +461,10 @@ Foam::scalar Foam::faceAreaIntersect::calc triangles_.clear(); } + area = 0.0; + centroid = vector::zero; + // Intersect triangles - scalar totalArea = 0.0; for (const face& triA : trisA_) { triPoints tpA = getTriPoints(pointsA_, triA, false); @@ -466,32 +473,38 @@ Foam::scalar Foam::faceAreaIntersect::calc { if (reverseB_) { - totalArea += - triangleIntersect - ( - tpA, - pointsB_[triB[0]], - pointsB_[triB[1]], - pointsB_[triB[2]], - n - ); + triangleIntersect + ( + tpA, + pointsB_[triB[0]], + pointsB_[triB[1]], + pointsB_[triB[2]], + n, + area, + centroid + ); } else { - totalArea += - triangleIntersect - ( - tpA, - pointsB_[triB[2]], - pointsB_[triB[1]], - pointsB_[triB[0]], - n - ); + triangleIntersect + ( + tpA, + pointsB_[triB[2]], + pointsB_[triB[1]], + pointsB_[triB[0]], + n, + area, + centroid + ); } } } - return totalArea; + // Area weighed centroid + if (area > 0) + { + centroid /= area; + } } @@ -503,8 +516,10 @@ bool Foam::faceAreaIntersect::overlaps const scalar threshold ) const { + scalar area = 0.0; + vector centroid(Zero); + // Intersect triangles - scalar totalArea = 0.0; for (const face& triA : trisA_) { const triPoints tpA = getTriPoints(pointsA_, triA, false); @@ -513,30 +528,32 @@ bool Foam::faceAreaIntersect::overlaps { if (reverseB_) { - totalArea += - triangleIntersect - ( - tpA, - pointsB_[triB[0]], - pointsB_[triB[1]], - pointsB_[triB[2]], - n - ); + triangleIntersect + ( + tpA, + pointsB_[triB[0]], + pointsB_[triB[1]], + pointsB_[triB[2]], + n, + area, + centroid + ); } else { - totalArea += - triangleIntersect - ( - tpA, - pointsB_[triB[2]], - pointsB_[triB[1]], - pointsB_[triB[0]], - n - ); + triangleIntersect + ( + tpA, + pointsB_[triB[2]], + pointsB_[triB[1]], + pointsB_[triB[0]], + n, + area, + centroid + ); } - if (totalArea > threshold) + if (area > threshold) { return true; } diff --git a/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.H b/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.H index f0ba9b3e92510c4ad9a11f1b8ed8116982b6b817..d79327de31ddc44d3b331a2e0dcbd2212af0f8e8 100644 --- a/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.H +++ b/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersect.H @@ -46,6 +46,7 @@ SourceFiles #include "face.H" #include "triPoints.H" #include "Enum.H" +#include "searchableSurface.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -97,6 +98,7 @@ private: // Static data members + //- Tolerance static scalar tol; @@ -132,6 +134,9 @@ private: //- Return triangle area inline scalar triArea(const triPoints& t) const; + //- Return triangle centre + inline vector triCentroid(const triPoints& t) const; + //- Slice triangle with plane and generate new cut sub-triangles void triSliceWithPlane ( @@ -143,13 +148,15 @@ private: ) const; //- Return area of intersection of triangles src and tgt - scalar triangleIntersect + void triangleIntersect ( const triPoints& src, const point& tgt0, const point& tgt1, const point& tgt2, - const vector& n + const vector& n, + scalar& area, + vector& centroid ) const; @@ -199,12 +206,15 @@ public: DynamicList<face>& faces ); - //- Return area of intersection of faceA with faceB - scalar calc + //- Return area of intersection of faceA with faceB and effective + //- face centre + void calc ( const face& faceA, const face& faceB, - const vector& n + const vector& n, + scalar& area, + vector& centroid ) const; //- Return area of intersection of faceA with faceB diff --git a/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersectI.H b/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersectI.H index 12113a594d6cc71da2ad12ad5c0a85b7417dc46b..836b87d76200a29f5ec519dfca87d7559d1a50ad 100644 --- a/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersectI.H +++ b/src/meshTools/AMIInterpolation/faceAreaIntersect/faceAreaIntersectI.H @@ -113,6 +113,15 @@ inline Foam::scalar Foam::faceAreaIntersect::triArea(const triPoints& t) const } +inline Foam::vector Foam::faceAreaIntersect::triCentroid +( + const triPoints& t +) const +{ + return (t[0] + t[1] + t[2])/3; +} + + // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // Foam::scalar& Foam::faceAreaIntersect::tolerance() diff --git a/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.C b/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.C index 3cd26ef2b82f8069e73f5bb0215a4719d4968ad4..4e994a6f236185043af6457fa7b607da60537c64 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.C +++ b/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2017-2018 OpenCFD Ltd. + Copyright (C) 2017-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -41,221 +41,234 @@ namespace Foam addToRunTimeSelectionTable(polyPatch, cyclicACMIPolyPatch, dictionary); } -const Foam::scalar Foam::cyclicACMIPolyPatch::tolerance_ = 1e-10; - // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -void Foam::cyclicACMIPolyPatch::resetAMI +void Foam::cyclicACMIPolyPatch::reportCoverage ( - const AMIPatchToPatchInterpolation::interpolationMethod& + const word& name, + const scalarField& weightSum ) const { - if (owner()) + label nUncovered = 0; + label nCovered = 0; + for (const scalar sum : weightSum) { - const polyPatch& nonOverlapPatch = this->nonOverlapPatch(); - - if (debug) + if (sum < tolerance_) { - Pout<< "cyclicACMIPolyPatch::resetAMI : recalculating weights" - << " for " << name() << " and " << nonOverlapPatch.name() - << endl; + ++nUncovered; } - - if (boundaryMesh().mesh().hasCellCentres()) + else if (sum > scalar(1) - tolerance_) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::resetAMI : clearing cellCentres" - << " for " << name() << " and " << nonOverlapPatch.name() - << endl; - } - - //WarningInFunction - // << "The mesh already has cellCentres calculated when" - // << " resetting ACMI " << name() << "." << endl - // << "This is a problem since ACMI adapts the face areas" - // << " (to close cells) so this has" << endl - // << "to be done before cell centre calculation." << endl - // << "This can happen if e.g. the cyclicACMI is after" - // << " any processor patches in the boundary." << endl; - const_cast<polyMesh&> - ( - boundaryMesh().mesh() - ).primitiveMesh::clearGeom(); + ++nCovered; } + } + reduce(nUncovered, sumOp<label>()); + reduce(nCovered, sumOp<label>()); + label nTotal = returnReduce(weightSum.size(), sumOp<label>()); + Info<< "ACMI: Patch " << name << " uncovered/blended/covered = " + << nUncovered << ", " << nTotal-nUncovered-nCovered + << ", " << nCovered << endl; +} - // Trigger re-building of faceAreas - (void)boundaryMesh().mesh().faceAreas(); +void Foam::cyclicACMIPolyPatch::resetAMI() const +{ + resetAMI(boundaryMesh().mesh().points()); +} - // Calculate the AMI using partial face-area-weighted. This leaves - // the weights as fractions of local areas (sum(weights) = 1 means - // face is fully covered) - cyclicAMIPolyPatch::resetAMI - ( - AMIPatchToPatchInterpolation::imPartialFaceAreaWeight - ); - AMIPatchToPatchInterpolation& AMI = - const_cast<AMIPatchToPatchInterpolation&>(this->AMI()); +void Foam::cyclicACMIPolyPatch::resetAMI(const UList<point>& points) const +{ + if (!owner()) + { + return; + } - // Output some stats. AMIInterpolation will have already output the - // average weights ("sum(weights) min:1 max:1 average:1") - { - const scalarField& wghtsSum = AMI.srcWeightsSum(); + const polyPatch& nonOverlapPatch = this->nonOverlapPatch(); - label nUncovered = 0; - label nCovered = 0; - forAll(wghtsSum, facei) - { - scalar sum = wghtsSum[facei]; - if (sum < tolerance_) - { - nUncovered++; - } - else if (sum > scalar(1)-tolerance_) - { - nCovered++; - } - } - reduce(nUncovered, sumOp<label>()); - reduce(nCovered, sumOp<label>()); - label nTotal = returnReduce(wghtsSum.size(), sumOp<label>()); + DebugPout + << "cyclicACMIPolyPatch::resetAMI : recalculating weights" + << " for " << name() << " and " << nonOverlapPatch.name() + << endl; - Info<< "ACMI: Patch source uncovered/blended/covered = " - << nUncovered << ", " << nTotal-nUncovered-nCovered - << ", " << nCovered << endl; - } - { - const scalarField& wghtsSum = AMI.tgtWeightsSum(); + const polyMesh& mesh = boundaryMesh().mesh(); - label nUncovered = 0; - label nCovered = 0; - forAll(wghtsSum, facei) - { - scalar sum = wghtsSum[facei]; - if (sum < tolerance_) - { - nUncovered++; - } - else if (sum > scalar(1)-tolerance_) - { - nCovered++; - } - } - reduce(nUncovered, sumOp<label>()); - reduce(nCovered, sumOp<label>()); - label nTotal = returnReduce(wghtsSum.size(), sumOp<label>()); + if (!createAMIFaces_ && mesh.hasCellCentres()) + { + DebugPout + << "cyclicACMIPolyPatch::resetAMI : clearing cellCentres" + << " for " << name() << " and " << nonOverlapPatch.name() + << endl; + + WarningInFunction + << "The mesh already has cellCentres calculated when" + << " resetting ACMI " << name() << "." << nl + << "This is a problem since ACMI adapts the face areas" + << " (to close cells) so this has" << nl + << "to be done before cell centre calculation." << nl + << "This can happen if e.g. the cyclicACMI is after" + << " any processor patches in the boundary." << endl; + const_cast<polyMesh&>(mesh).primitiveMesh::clearGeom(); + } - Info<< "ACMI: Patch target uncovered/blended/covered = " - << nUncovered << ", " << nTotal-nUncovered-nCovered - << ", " << nCovered << endl; - } - srcMask_ = - min(scalar(1) - tolerance_, max(tolerance_, AMI.srcWeightsSum())); + // Trigger re-building of faceAreas + (void)mesh.faceAreas(); - tgtMask_ = - min(scalar(1) - tolerance_, max(tolerance_, AMI.tgtWeightsSum())); + // Calculate the AMI using partial face-area-weighted. This leaves + // the weights as fractions of local areas (sum(weights) = 1 means + // face is fully covered) + cyclicAMIPolyPatch::resetAMI(points); - // Adapt owner side areas. Note that in uncoupled situations (e.g. - // decomposePar) srcMask, tgtMask can be zero size. - if (srcMask_.size()) - { - vectorField::subField Sf = faceAreas(); - vectorField::subField noSf = nonOverlapPatch.faceAreas(); + const AMIPatchToPatchInterpolation& AMI = this->AMI(); - forAll(Sf, facei) - { - Sf[facei] *= srcMask_[facei]; - noSf[facei] *= 1.0 - srcMask_[facei]; - } + // Output some statistics + reportCoverage("source", AMI.srcWeightsSum()); + reportCoverage("target", AMI.tgtWeightsSum()); + + // Set the mask fields + // Note: + // - assumes that the non-overlap patches are decomposed using the same + // decomposition as the coupled patches (per side) + srcMask_ = min(scalar(1), max(scalar(0), AMI.srcWeightsSum())); + tgtMask_ = min(scalar(1), max(scalar(0), AMI.tgtWeightsSum())); + + if (debug) + { + Pout<< "resetAMI" << endl; + { + const cyclicACMIPolyPatch& patch = *this; + Pout<< "patch:" << patch.name() << " size:" << patch.size() + << " non-overlap patch: " << patch.nonOverlapPatch().name() + << " size:" << patch.nonOverlapPatch().size() + << " mask size:" << patch.srcMask().size() << endl; } - // Adapt slave side areas - if (tgtMask_.size()) { - const cyclicACMIPolyPatch& cp = - refCast<const cyclicACMIPolyPatch>(this->neighbPatch()); - const polyPatch& pp = cp.nonOverlapPatch(); + const cyclicACMIPolyPatch& patch = this->neighbPatch(); + Pout<< "patch:" << patch.name() << " size:" << patch.size() + << " non-overlap patch: " << patch.nonOverlapPatch().name() + << " size:" << patch.nonOverlapPatch().size() + << " mask size:" << patch.neighbPatch().tgtMask().size() + << endl; + } + } +} - vectorField::subField Sf = cp.faceAreas(); - vectorField::subField noSf = pp.faceAreas(); - forAll(Sf, facei) - { - Sf[facei] *= tgtMask_[facei]; - noSf[facei] *= 1.0 - tgtMask_[facei]; - } +void Foam::cyclicACMIPolyPatch::scalePatchFaceAreas() +{ + if (!owner() || !canResetAMI()) + { + return; + } + + scalePatchFaceAreas(*this); + scalePatchFaceAreas(this->neighbPatch()); +} + + +void Foam::cyclicACMIPolyPatch::scalePatchFaceAreas +( + const cyclicACMIPolyPatch& acmipp +) +{ + // Primitive patch face areas have been cleared/reset based on the raw + // points - need to reset to avoid double-accounting of face areas + + const scalar maxTol = scalar(1) - tolerance_; + const scalarField& mask = acmipp.mask(); + + const polyPatch& nonOverlapPatch = acmipp.nonOverlapPatch(); + vectorField::subField noSf = nonOverlapPatch.faceAreas(); + + DebugPout + << "rescaling non-overlap patch areas for: " << nonOverlapPatch.name() + << endl; + + + if (mask.size() != noSf.size()) + { + WarningInFunction + << "Inconsistent sizes for patch: " << acmipp.name() + << " - not manipulating patches" << nl + << " - size: " << size() << nl + << " - non-overlap patch size: " << noSf.size() << nl + << " - mask size: " << mask.size() << nl + << "This is OK for decomposition but should be considered fatal " + << "at run-time" << endl; + + return; + } + + forAll(noSf, facei) + { + const scalar w = min(maxTol, max(tolerance_, mask[facei])); + noSf[facei] *= scalar(1) - w; + } + + if (!createAMIFaces_) + { + // Note: for topological update (createAMIFaces_ = true) + // AMI coupled patch face areas are updated as part of the topological + // updates, e.g. by the calls to cyclicAMIPolyPatch's setTopology and + // initMovePoints + DebugPout + << "scaling coupled patch areas for: " << acmipp.name() << endl; + + // Scale the coupled patch face areas + vectorField::subField Sf = acmipp.faceAreas(); + + forAll(Sf, facei) + { + Sf[facei] *= max(tolerance_, mask[facei]); } // Re-normalise the weights since the effect of overlap is already - // accounted for in the area. + // accounted for in the area + auto& weights = const_cast<scalarListList&>(acmipp.weights()); + auto& weightsSum = const_cast<scalarField&>(acmipp.weightsSum()); + forAll(weights, i) { - scalarListList& srcWeights = AMI.srcWeights(); - scalarField& srcWeightsSum = AMI.srcWeightsSum(); - forAll(srcWeights, i) + scalarList& wghts = weights[i]; + if (wghts.size()) { - scalarList& wghts = srcWeights[i]; - if (wghts.size()) - { - scalar& sum = srcWeightsSum[i]; + scalar& sum = weightsSum[i]; - forAll(wghts, j) - { - wghts[j] /= sum; - } - sum = 1.0; - } - } - } - { - scalarListList& tgtWeights = AMI.tgtWeights(); - scalarField& tgtWeightsSum = AMI.tgtWeightsSum(); - forAll(tgtWeights, i) - { - scalarList& wghts = tgtWeights[i]; - if (wghts.size()) + forAll(wghts, j) { - scalar& sum = tgtWeightsSum[i]; - forAll(wghts, j) - { - wghts[j] /= sum; - } - sum = 1.0; + wghts[j] /= sum; } + sum = 1.0; } } - - // Set the updated flag - updated_ = true; } } void Foam::cyclicACMIPolyPatch::initGeometry(PstreamBuffers& pBufs) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::initGeometry : " << name() << endl; - } + DebugPout << "cyclicACMIPolyPatch::initGeometry : " << name() << endl; // Note: calculates transformation and triggers face centre calculation cyclicAMIPolyPatch::initGeometry(pBufs); // Initialise the AMI early to make sure we adapt the face areas before the // cell centre calculation gets triggered. - resetAMI(); + if (!createAMIFaces_ && canResetAMI()) + { + resetAMI(); + } + + scalePatchFaceAreas(); } void Foam::cyclicACMIPolyPatch::calcGeometry(PstreamBuffers& pBufs) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::calcGeometry : " << name() << endl; - } + DebugPout << "cyclicACMIPolyPatch::calcGeometry : " << name() << endl; + cyclicAMIPolyPatch::calcGeometry(pBufs); } @@ -266,16 +279,13 @@ void Foam::cyclicACMIPolyPatch::initMovePoints const pointField& p ) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::initMovePoints : " << name() << endl; - } + DebugPout<< "cyclicACMIPolyPatch::initMovePoints : " << name() << endl; // Note: calculates transformation and triggers face centre calculation + // - Note: resetAMI called by cyclicAMIPolyPatch::initMovePoints cyclicAMIPolyPatch::initMovePoints(pBufs, p); - // Initialise the AMI early. See initGeometry. - resetAMI(); + scalePatchFaceAreas(); } @@ -285,40 +295,33 @@ void Foam::cyclicACMIPolyPatch::movePoints const pointField& p ) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::movePoints : " << name() << endl; - } + DebugPout << "cyclicACMIPolyPatch::movePoints : " << name() << endl; + + // When topology is changing, this will scale the duplicate AMI faces cyclicAMIPolyPatch::movePoints(pBufs, p); } void Foam::cyclicACMIPolyPatch::initUpdateMesh(PstreamBuffers& pBufs) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::initUpdateMesh : " << name() << endl; - } + DebugPout << "cyclicACMIPolyPatch::initUpdateMesh : " << name() << endl; + cyclicAMIPolyPatch::initUpdateMesh(pBufs); } void Foam::cyclicACMIPolyPatch::updateMesh(PstreamBuffers& pBufs) { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::updateMesh : " << name() << endl; - } + DebugPout << "cyclicACMIPolyPatch::updateMesh : " << name() << endl; + cyclicAMIPolyPatch::updateMesh(pBufs); } void Foam::cyclicACMIPolyPatch::clearGeom() { - if (debug) - { - Pout<< "cyclicACMIPolyPatch::clearGeom : " << name() << endl; - } + DebugPout << "cyclicACMIPolyPatch::clearGeom : " << name() << endl; + cyclicAMIPolyPatch::clearGeom(); } @@ -345,17 +348,27 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch const label index, const polyBoundaryMesh& bm, const word& patchType, - const transformType transform + const transformType transform, + const word& defaultAMIMethod ) : - cyclicAMIPolyPatch(name, size, start, index, bm, patchType, transform), + cyclicAMIPolyPatch + ( + name, + size, + start, + index, + bm, + patchType, + transform, + defaultAMIMethod + ), nonOverlapPatchName_(word::null), nonOverlapPatchID_(-1), srcMask_(), - tgtMask_(), - updated_(false) + tgtMask_() { - AMIRequireMatch_ = false; + AMIPtr_->setRequireMatch(false); // Non-overlapping patch might not be valid yet so cannot determine // associated patchID @@ -368,17 +381,17 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch const dictionary& dict, const label index, const polyBoundaryMesh& bm, - const word& patchType + const word& patchType, + const word& defaultAMIMethod ) : - cyclicAMIPolyPatch(name, dict, index, bm, patchType), - nonOverlapPatchName_(dict.lookup("nonOverlapPatch")), + cyclicAMIPolyPatch(name, dict, index, bm, patchType, defaultAMIMethod), + nonOverlapPatchName_(dict.get<word>("nonOverlapPatch")), nonOverlapPatchID_(-1), srcMask_(), - tgtMask_(), - updated_(false) + tgtMask_() { - AMIRequireMatch_ = false; + AMIPtr_->setRequireMatch(false); if (nonOverlapPatchName_ == name) { @@ -403,10 +416,9 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch nonOverlapPatchName_(pp.nonOverlapPatchName_), nonOverlapPatchID_(-1), srcMask_(), - tgtMask_(), - updated_(false) + tgtMask_() { - AMIRequireMatch_ = false; + AMIPtr_->setRequireMatch(false); // Non-overlapping patch might not be valid yet so cannot determine // associated patchID @@ -428,10 +440,9 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch nonOverlapPatchName_(nonOverlapPatchName), nonOverlapPatchID_(-1), srcMask_(), - tgtMask_(), - updated_(false) + tgtMask_() { - AMIRequireMatch_ = false; + AMIPtr_->setRequireMatch(false); if (nonOverlapPatchName_ == name()) { @@ -459,19 +470,12 @@ Foam::cyclicACMIPolyPatch::cyclicACMIPolyPatch nonOverlapPatchName_(pp.nonOverlapPatchName_), nonOverlapPatchID_(-1), srcMask_(), - tgtMask_(), - updated_(false) + tgtMask_() { - AMIRequireMatch_ = false; + AMIPtr_->setRequireMatch(false); } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::cyclicACMIPolyPatch::~cyclicACMIPolyPatch() -{} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // const Foam::cyclicACMIPolyPatch& Foam::cyclicACMIPolyPatch::neighbPatch() const diff --git a/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.H b/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.H index 5f2bd9dfad989c9a68b8e1d394ce0263c165fcca..51b0f40b5c3d2e92fcd1eb1a7476ceba05ee4e0b 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.H +++ b/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatch.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2016 OpenFOAM Foundation - Copyright (C) 2018 OpenCFD Ltd. + Copyright (C) 2018-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -41,6 +41,7 @@ SourceFiles #include "cyclicAMIPolyPatch.H" #include "AMIPatchToPatchInterpolation.H" #include "polyBoundaryMesh.H" +#include "partialFaceAreaWeightAMI.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -60,9 +61,6 @@ private: // Private data - //- Fraction of face area below which face is considered disconnected - static const scalar tolerance_; - //- Name of non-overlapping patch const word nonOverlapPatchName_; @@ -75,21 +73,31 @@ private: //- Mask/weighting for target patch mutable scalarField tgtMask_; - //- Flag to indicate that AMI has been updated - mutable bool updated_; - protected: // Protected Member Functions - //- Reset the AMI interpolator - virtual void resetAMI + //- Report coverage statics, e.g. number of uncovered/blended/covered + //- faces + void reportCoverage ( - const AMIPatchToPatchInterpolation::interpolationMethod& AMIMethod = - AMIPatchToPatchInterpolation::imFaceAreaWeight + const word& name, + const scalarField& weightSum ) const; + //- Reset the AMI interpolator, supply patch points + virtual void resetAMI(const UList<point>& points) const; + + //- Reset the AMI interpolator, use current patch points + virtual void resetAMI() const; + + //- Scale patch face areas to maintain physical area + virtual void scalePatchFaceAreas(); + + //- Scale patch face areas to maintain physical area + virtual void scalePatchFaceAreas(const cyclicACMIPolyPatch& acmipp); + //- Initialise the calculation of the patch geometry virtual void initGeometry(PstreamBuffers&); @@ -111,12 +119,6 @@ protected: //- Clear geometry virtual void clearGeom(); - //- Return the mask/weighting for the source patch - virtual const scalarField& srcMask() const; - - //- Return the mask/weighting for the target patch - virtual const scalarField& tgtMask() const; - public: @@ -135,7 +137,8 @@ public: const label index, const polyBoundaryMesh& bm, const word& patchType, - const transformType transform = UNKNOWN + const transformType transform = UNKNOWN, + const word& defaultAMIMethod = partialFaceAreaWeightAMI::typeName ); //- Construct from dictionary @@ -145,7 +148,8 @@ public: const dictionary& dict, const label index, const polyBoundaryMesh& bm, - const word& patchType + const word& patchType, + const word& defaultAMIMethod = partialFaceAreaWeightAMI::typeName ); //- Construct as copy, resetting the boundary mesh @@ -235,19 +239,13 @@ public: //- Destructor - virtual ~cyclicACMIPolyPatch(); + virtual ~cyclicACMIPolyPatch() = default; // Member Functions // Access - //- Reset the updated flag - inline void setUpdated(bool flag) const; - - //- Return access to the updated flag - inline bool updated() const; - //- Return a reference to the neighbour patch virtual const cyclicACMIPolyPatch& neighbPatch() const; @@ -263,9 +261,15 @@ public: //- Return a reference to the non-overlapping patch inline polyPatch& nonOverlapPatch(); - //- Mask field where 1 = overlap, 0 = no-overlap + //- Mask field where 1 = overlap(coupled), 0 = no-overlap inline const scalarField& mask() const; + //- Return the mask/weighting for the source patch + virtual const scalarField& srcMask() const; + + //- Return the mask/weighting for the target patch + virtual const scalarField& tgtMask() const; + //- Overlap tolerance inline static scalar tolerance(); diff --git a/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatchI.H b/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatchI.H index 42b41196673b4f316e4bcb331b14a4a93b3ea646..50f4022ed63e2ce5204ebda9f9b33b1f653218fa 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatchI.H +++ b/src/meshTools/AMIInterpolation/patches/cyclicACMI/cyclicACMIPolyPatch/cyclicACMIPolyPatchI.H @@ -27,18 +27,6 @@ License // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -inline void Foam::cyclicACMIPolyPatch::setUpdated(const bool flag) const -{ - updated_ = flag; -} - - -inline bool Foam::cyclicACMIPolyPatch::updated() const -{ - return updated_; -} - - inline const Foam::word& Foam::cyclicACMIPolyPatch::nonOverlapPatchName() const { return nonOverlapPatchName_; @@ -69,10 +57,8 @@ inline const Foam::scalarField& Foam::cyclicACMIPolyPatch::mask() const { return srcMask_; } - else - { - return neighbPatch().tgtMask(); - } + + return neighbPatch().tgtMask(); } diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C index 51f14ccb5ed67a11988c894ce82fe7259b128cdd..85f6170f7185e854219d3992f863303992ac0c42 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C +++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C @@ -27,13 +27,12 @@ License \*---------------------------------------------------------------------------*/ #include "cyclicAMIPolyPatch.H" -#include "transformField.H" #include "SubField.H" -#include "polyMesh.H" #include "Time.H" +#include "unitConversion.H" +#include "OFstream.H" +#include "meshTools.H" #include "addToRunTimeSelectionTable.H" -#include "faceAreaIntersect.H" -#include "ops.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -45,6 +44,7 @@ namespace Foam addToRunTimeSelectionTable(polyPatch, cyclicAMIPolyPatch, dictionary); } +const Foam::scalar Foam::cyclicAMIPolyPatch::tolerance_ = 1e-10; // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // @@ -61,14 +61,12 @@ Foam::vector Foam::cyclicAMIPolyPatch::findFaceNormalMaxRadius label facei = findMax(magRadSqr); - if (debug) - { - Info<< "findFaceMaxRadius(const pointField&) : patch: " << name() << nl - << " rotFace = " << facei << nl - << " point = " << faceCentres[facei] << nl - << " distance = " << Foam::sqrt(magRadSqr[facei]) - << endl; - } + DebugInFunction + << "Patch: " << name() << nl + << " rotFace = " << facei << nl + << " point = " << faceCentres[facei] << nl + << " distance = " << Foam::sqrt(magRadSqr[facei]) + << endl; return n[facei]; } @@ -290,82 +288,119 @@ void Foam::cyclicAMIPolyPatch::calcTransforms // * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * // -void Foam::cyclicAMIPolyPatch::resetAMI -( - const AMIPatchToPatchInterpolation::interpolationMethod& AMIMethod -) const +const Foam::autoPtr<Foam::searchableSurface>& +Foam::cyclicAMIPolyPatch::surfPtr() const { - if (owner()) - { - AMIPtr_.clear(); + const word surfType(surfDict_.getOrDefault<word>("type", "none")); - const polyPatch& nbr = neighbPatch(); - pointField nbrPoints - ( - neighbPatch().boundaryMesh().mesh().points(), - neighbPatch().meshPoints() - ); + if (!surfPtr_ && owner() && surfType != "none") + { + word surfName(surfDict_.getOrDefault("name", name())); - if (debug) - { - const Time& t = boundaryMesh().mesh().time(); - OFstream os(t.path()/name() + "_neighbourPatch-org.obj"); - meshTools::writeOBJ(os, neighbPatch().localFaces(), nbrPoints); - } + const polyMesh& mesh = boundaryMesh().mesh(); - // Transform neighbour patch to local system - transformPosition(nbrPoints); - primitivePatch nbrPatch0 - ( - SubList<face> + surfPtr_ = + searchableSurface::New ( - nbr.localFaces(), - nbr.size() - ), - nbrPoints - ); + surfType, + IOobject + ( + surfName, + mesh.time().constant(), + "triSurface", + mesh, + IOobject::MUST_READ, + IOobject::NO_WRITE + ), + surfDict_ + ); + } - if (debug) - { - const Time& t = boundaryMesh().mesh().time(); - OFstream osN(t.path()/name() + "_neighbourPatch-trans.obj"); - meshTools::writeOBJ(osN, nbrPatch0.localFaces(), nbrPoints); + return surfPtr_; +} - OFstream osO(t.path()/name() + "_ownerPatch.obj"); - meshTools::writeOBJ(osO, this->localFaces(), localPoints()); - } - // Construct/apply AMI interpolation to determine addressing and weights - AMIPtr_.reset - ( - new AMIPatchToPatchInterpolation - ( - *this, - nbrPatch0, - surfPtr(), - faceAreaIntersect::tmMesh, - AMIRequireMatch_, - AMIMethod, - AMILowWeightCorrection_, - AMIReverse_ - ) - ); +void Foam::cyclicAMIPolyPatch::resetAMI() const +{ + resetAMI(boundaryMesh().mesh().points()); +} + + +void Foam::cyclicAMIPolyPatch::resetAMI(const UList<point>& points) const +{ + DebugInFunction << endl; + + if (!owner()) + { + return; + } + + const cyclicAMIPolyPatch& nbr = neighbPatch(); + pointField srcPoints(localPoints()); + pointField nbrPoints(nbr.localPoints()); + + if (debug) + { + const Time& t = boundaryMesh().mesh().time(); + OFstream os(t.path()/name() + "_neighbourPatch-org.obj"); + meshTools::writeOBJ(os, neighbPatch().localFaces(), nbrPoints); + } + + label patchSize0 = size(); + label nbrPatchSize0 = nbr.size(); - if (debug) + if (createAMIFaces_) + { + // AMI is created based on the original patch faces (non-extended patch) + if (srcFaceIDs_.size()) + { + patchSize0 = srcFaceIDs_.size(); + } + if (tgtFaceIDs_.size()) { - Pout<< "cyclicAMIPolyPatch : " << name() - << " constructed AMI with " << nl - << " " << "srcAddress:" << AMIPtr_().srcAddress().size() - << nl - << " " << "tgAddress :" << AMIPtr_().tgtAddress().size() - << nl << endl; + nbrPatchSize0 = tgtFaceIDs_.size(); } } + + // Transform neighbour patch to local system + transformPosition(nbrPoints); + primitivePatch nbrPatch0 + ( + SubList<face>(nbr.localFaces(), nbrPatchSize0), + nbrPoints + ); + primitivePatch patch0 + ( + SubList<face>(localFaces(), patchSize0), + srcPoints + ); + + + if (debug) + { + const Time& t = boundaryMesh().mesh().time(); + OFstream osN(t.path()/name() + "_neighbourPatch-trans.obj"); + meshTools::writeOBJ(osN, nbrPatch0.localFaces(), nbrPoints); + + OFstream osO(t.path()/name() + "_ownerPatch.obj"); + meshTools::writeOBJ(osO, this->localFaces(), localPoints()); + } + + // Construct/apply AMI interpolation to determine addressing and weights + AMIPtr_->upToDate() = false; + AMIPtr_->calculate(patch0, nbrPatch0, surfPtr()); + + if (debug) + { + AMIPtr_->checkSymmetricWeights(true); + } } void Foam::cyclicAMIPolyPatch::calcTransforms() { + DebugInFunction << endl; + const cyclicAMIPolyPatch& half0 = *this; vectorField half0Areas(half0.size()); forAll(half0, facei) @@ -389,35 +424,35 @@ void Foam::cyclicAMIPolyPatch::calcTransforms() half1Areas ); - if (debug) - { - Pout<< "calcTransforms() : patch: " << name() << nl - << " forwardT = " << forwardT() << nl - << " reverseT = " << reverseT() << nl - << " separation = " << separation() << nl - << " collocated = " << collocated() << nl << endl; - } + DebugPout + << "calcTransforms() : patch: " << name() << nl + << " forwardT = " << forwardT() << nl + << " reverseT = " << reverseT() << nl + << " separation = " << separation() << nl + << " collocated = " << collocated() << nl << endl; } void Foam::cyclicAMIPolyPatch::initGeometry(PstreamBuffers& pBufs) { - // The AMI is no longer valid. Leave it up to demand-driven calculation - AMIPtr_.clear(); + DebugInFunction << endl; + + // Flag AMI as needing update + AMIPtr_->upToDate() = false; polyPatch::initGeometry(pBufs); // Early calculation of transforms so e.g. cyclicACMI can use them. // Note: also triggers primitiveMesh face centre. Note that cell // centres should -not- be calculated - // since e.g. cyclicACMI override face areas + // since e.g. cyclicACMI overrides face areas calcTransforms(); } void Foam::cyclicAMIPolyPatch::calcGeometry(PstreamBuffers& pBufs) { - // All geometry done inside initGeometry + DebugInFunction << endl; } @@ -427,14 +462,31 @@ void Foam::cyclicAMIPolyPatch::initMovePoints const pointField& p ) { - // The AMI is no longer valid. Leave it up to demand-driven calculation - AMIPtr_.clear(); - - polyPatch::initMovePoints(pBufs, p); + DebugInFunction << endl; // See below. Clear out any local geometry primitivePatch::movePoints(p); + // Note: processorPolyPatch::initMovePoints calls + // processorPolyPatch::initGeometry which will trigger calculation of + // patch faceCentres() and cell volumes... + + if (createAMIFaces_) + { + // Note: AMI should have been updated in setTopology + + // faceAreas() and faceCentres() have been reset and will be + // recalculated on-demand using the mesh points and no longer + // correspond to the scaled areas! + restoreScaledGeometry(); + + // deltas need to be recalculated to use new face centres! + } + else + { + AMIPtr_->upToDate() = false; + } + // Early calculation of transforms. See above. calcTransforms(); } @@ -446,30 +498,55 @@ void Foam::cyclicAMIPolyPatch::movePoints const pointField& p ) { - polyPatch::movePoints(pBufs, p); - - // All transformation tensors already done in initMovePoints + DebugInFunction << endl; + +// Note: not calling movePoints since this will undo our manipulations! +// polyPatch::movePoints(pBufs, p); +/* + polyPatch::movePoints + -> primitivePatch::movePoints + -> primitivePatch::clearGeom: + deleteDemandDrivenData(localPointsPtr_); + deleteDemandDrivenData(faceCentresPtr_); + deleteDemandDrivenData(faceAreasPtr_); + deleteDemandDrivenData(magFaceAreasPtr_); + deleteDemandDrivenData(faceNormalsPtr_); + deleteDemandDrivenData(pointNormalsPtr_); +*/ } void Foam::cyclicAMIPolyPatch::initUpdateMesh(PstreamBuffers& pBufs) { - // The AMI is no longer valid. Leave it up to demand-driven calculation - AMIPtr_.clear(); + DebugInFunction << endl; polyPatch::initUpdateMesh(pBufs); + + if (createAMIFaces_ && boundaryMesh().mesh().topoChanging() && owner()) + { + setAMIFaces(); + } } void Foam::cyclicAMIPolyPatch::updateMesh(PstreamBuffers& pBufs) { + DebugInFunction << endl; + + // Note: this clears out cellCentres(), faceCentres() and faceAreas() polyPatch::updateMesh(pBufs); } void Foam::cyclicAMIPolyPatch::clearGeom() { - AMIPtr_.clear(); + DebugInFunction << endl; + + if (!updatingAMI_) + { + AMIPtr_->upToDate() = false; + } + polyPatch::clearGeom(); } @@ -484,7 +561,8 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch const label index, const polyBoundaryMesh& bm, const word& patchType, - const transformType transform + const transformType transform, + const word& defaultAMIMethod ) : coupledPolyPatch(name, size, start, index, bm, patchType, transform), @@ -495,13 +573,16 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch rotationAngleDefined_(false), rotationAngle_(0.0), separationVector_(Zero), - AMIPtr_(nullptr), - AMIMethod_(AMIPatchToPatchInterpolation::imFaceAreaWeight), - AMIReverse_(false), - AMIRequireMatch_(true), - AMILowWeightCorrection_(-1.0), + AMIPtr_(AMIInterpolation::New(defaultAMIMethod)), + surfDict_(fileName("surface")), surfPtr_(nullptr), - surfDict_(fileName("surface")) + createAMIFaces_(false), + moveFaceCentres_(false), + updatingAMI_(true), + srcFaceIDs_(), + tgtFaceIDs_(), + faceAreas0_(), + faceCentres0_() { // Neighbour patch might not be valid yet so no transformation // calculation possible @@ -514,11 +595,12 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch const dictionary& dict, const label index, const polyBoundaryMesh& bm, - const word& patchType + const word& patchType, + const word& defaultAMIMethod ) : coupledPolyPatch(name, dict, index, bm, patchType), - nbrPatchName_(dict.getOrDefault<word>("neighbourPatch", "")), + nbrPatchName_(dict.getOrDefault<word>("neighbourPatch", word::null)), coupleGroup_(dict), nbrPatchID_(-1), rotationAxis_(Zero), @@ -526,26 +608,24 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch rotationAngleDefined_(false), rotationAngle_(0.0), separationVector_(Zero), - AMIPtr_(nullptr), - AMIMethod_ + AMIPtr_ ( - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - dict.getOrDefault - ( - "method", - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - AMIPatchToPatchInterpolation::imFaceAreaWeight - ] - ) - ] + AMIInterpolation::New + ( + dict.getOrDefault<word>("AMIMethod", defaultAMIMethod), + dict, + dict.getOrDefault("flipNormals", false) + ) ), - AMIReverse_(dict.getOrDefault("flipNormals", false)), - AMIRequireMatch_(true), - AMILowWeightCorrection_(dict.getOrDefault("lowWeightCorrection", -1.0)), + surfDict_(dict.subOrEmptyDict("surface")), surfPtr_(nullptr), - surfDict_(dict.subOrEmptyDict("surface")) + createAMIFaces_(dict.getOrDefault("createAMIFaces", false)), + moveFaceCentres_(false), + updatingAMI_(true), + srcFaceIDs_(), + tgtFaceIDs_(), + faceAreas0_(), + faceCentres0_() { if (nbrPatchName_ == word::null && !coupleGroup_.valid()) { @@ -605,6 +685,15 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch // Neighbour patch might not be valid yet so no transformation // calculation possible + + // If topology change, recover the sizes of the original patches and + // read additional controls + if (createAMIFaces_) + { + srcFaceIDs_.setSize(dict.get<label>("srcSize")); + tgtFaceIDs_.setSize(dict.get<label>("tgtSize")); + moveFaceCentres_ = dict.getOrDefault("moveFaceCentres", true); + } } @@ -623,13 +712,16 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch rotationAngleDefined_(pp.rotationAngleDefined_), rotationAngle_(pp.rotationAngle_), separationVector_(pp.separationVector_), - AMIPtr_(nullptr), - AMIMethod_(pp.AMIMethod_), - AMIReverse_(pp.AMIReverse_), - AMIRequireMatch_(pp.AMIRequireMatch_), - AMILowWeightCorrection_(pp.AMILowWeightCorrection_), + AMIPtr_(pp.AMIPtr_->clone()), + surfDict_(pp.surfDict_), surfPtr_(nullptr), - surfDict_(pp.surfDict_) + createAMIFaces_(pp.createAMIFaces_), + moveFaceCentres_(pp.moveFaceCentres_), + updatingAMI_(true), + srcFaceIDs_(), + tgtFaceIDs_(), + faceAreas0_(), + faceCentres0_() { // Neighbour patch might not be valid yet so no transformation // calculation possible @@ -655,13 +747,16 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch rotationAngleDefined_(pp.rotationAngleDefined_), rotationAngle_(pp.rotationAngle_), separationVector_(pp.separationVector_), - AMIPtr_(nullptr), - AMIMethod_(pp.AMIMethod_), - AMIReverse_(pp.AMIReverse_), - AMIRequireMatch_(pp.AMIRequireMatch_), - AMILowWeightCorrection_(pp.AMILowWeightCorrection_), + AMIPtr_(pp.AMIPtr_->clone()), + surfDict_(pp.surfDict_), surfPtr_(nullptr), - surfDict_(pp.surfDict_) + createAMIFaces_(pp.createAMIFaces_), + moveFaceCentres_(pp.moveFaceCentres_), + updatingAMI_(true), + srcFaceIDs_(), + tgtFaceIDs_(), + faceAreas0_(), + faceCentres0_() { if (nbrPatchName_ == name()) { @@ -694,19 +789,16 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch rotationAngleDefined_(pp.rotationAngleDefined_), rotationAngle_(pp.rotationAngle_), separationVector_(pp.separationVector_), - AMIPtr_(nullptr), - AMIMethod_(pp.AMIMethod_), - AMIReverse_(pp.AMIReverse_), - AMIRequireMatch_(pp.AMIRequireMatch_), - AMILowWeightCorrection_(pp.AMILowWeightCorrection_), + AMIPtr_(pp.AMIPtr_->clone()), + surfDict_(pp.surfDict_), surfPtr_(nullptr), - surfDict_(pp.surfDict_) -{} - - -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::cyclicAMIPolyPatch::~cyclicAMIPolyPatch() + createAMIFaces_(pp.createAMIFaces_), + moveFaceCentres_(pp.moveFaceCentres_), + updatingAMI_(true), + srcFaceIDs_(), + tgtFaceIDs_(), + faceAreas0_(), + faceCentres0_() {} @@ -761,38 +853,6 @@ const Foam::cyclicAMIPolyPatch& Foam::cyclicAMIPolyPatch::neighbPatch() const } -const Foam::autoPtr<Foam::searchableSurface>& -Foam::cyclicAMIPolyPatch::surfPtr() const -{ - const word surfType(surfDict_.getOrDefault<word>("type", "none")); - - if (!surfPtr_.valid() && owner() && surfType != "none") - { - word surfName(surfDict_.getOrDefault("name", name())); - - const polyMesh& mesh = boundaryMesh().mesh(); - - surfPtr_ = - searchableSurface::New - ( - surfType, - IOobject - ( - surfName, - mesh.time().constant(), - "triSurface", - mesh, - IOobject::MUST_READ, - IOobject::NO_WRITE - ), - surfDict_ - ); - } - - return surfPtr_; -} - - const Foam::AMIPatchToPatchInterpolation& Foam::cyclicAMIPolyPatch::AMI() const { if (!owner()) @@ -802,9 +862,9 @@ const Foam::AMIPatchToPatchInterpolation& Foam::cyclicAMIPolyPatch::AMI() const << abort(FatalError); } - if (!AMIPtr_.valid()) + if (!AMIPtr_->upToDate()) { - resetAMI(AMIMethod_); + resetAMI(); } return *AMIPtr_; @@ -1079,31 +1139,19 @@ void Foam::cyclicAMIPolyPatch::write(Ostream& os) const } } - if (AMIMethod_ != AMIPatchToPatchInterpolation::imFaceAreaWeight) - { - os.writeEntry - ( - "method", - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - AMIMethod_ - ] - ); - } - - if (AMIReverse_) - { - os.writeEntry("flipNormals", AMIReverse_); - } + AMIPtr_->write(os); - if (AMILowWeightCorrection_ > 0) + if (!surfDict_.empty()) { - os.writeEntry("lowWeightCorrection", AMILowWeightCorrection_); + surfDict_.writeEntry(surfDict_.dictName(), os); } - if (!surfDict_.empty()) + if (createAMIFaces_) { - surfDict_.writeEntry(surfDict_.dictName(), os); + os.writeEntry("createAMIFaces", createAMIFaces_); + os.writeEntry("srcSize", srcFaceIDs_.size()); + os.writeEntry("tgtSize", tgtFaceIDs_.size()); + os.writeEntry("moveFaceCentres", moveFaceCentres_); } } diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H index 25259ffacdfc8dff92aa2ae82363658b16f99f5e..2d0f0b393d8350f68c8fa0fd83aec84f46ea1aae 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H +++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation + Copyright (C) 2018-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +30,18 @@ Class Description Cyclic patch for Arbitrary Mesh Interface (AMI) + Includes provision for updating the patch topology to enforce a 1-to-1 + face match across the interface, based on the \c createAMIFaces flag. + + The manipulations are based on the reference: + + \verbatim + H.J. Aguerre, S. Márquez Damián, J.M. Gimenez, N.M.Nigro, Conservative + handling of arbitrary non-conformal interfaces using an efficient + supermesh, Journal of Computational Physics 335(15) 21-49. 2017. + https://doi.org/10.1016/j.jcp.2017.01.018. + \endverbatim + SourceFiles cyclicAMIPolyPatch.C @@ -41,6 +54,7 @@ SourceFiles #include "AMIPatchToPatchInterpolation.H" #include "polyBoundaryMesh.H" #include "coupleGroupIdentifier.H" +#include "faceAreaWeightAMI.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -110,33 +124,61 @@ protected: //- AMI interpolation class mutable autoPtr<AMIPatchToPatchInterpolation> AMIPtr_; - //- AMI method - const AMIPatchToPatchInterpolation::interpolationMethod AMIMethod_; + //- Dictionary used during projection surface construction + const dictionary surfDict_; - //- Flag to indicate that slave patch should be reversed for AMI - const bool AMIReverse_; + //- Projection surface + mutable autoPtr<searchableSurface> surfPtr_; - //- Flag to indicate that patches should match/overlap - bool AMIRequireMatch_; - //- Low weight correction threshold for AMI - const scalar AMILowWeightCorrection_; + // Change of topology as AMI is updated - //- Projection surface - mutable autoPtr<searchableSurface> surfPtr_; + //- Flag to indicate that new AMI faces will created + // Set by the call to changeTopology + mutable bool createAMIFaces_; - //- Dictionary used during projection surface construction - const dictionary surfDict_; + //- Move face centres (default = no) + bool moveFaceCentres_; + + mutable bool updatingAMI_; + + labelListList srcFaceIDs_; + + labelListList tgtFaceIDs_; + + //- Temporary storage for AMI face areas + mutable vectorField faceAreas0_; + + //- Temporary storage for AMI face centres + mutable vectorField faceCentres0_; // Protected Member Functions - //- Reset the AMI interpolator - virtual void resetAMI - ( - const AMIPatchToPatchInterpolation::interpolationMethod& AMIMethod = - AMIPatchToPatchInterpolation::imFaceAreaWeight - ) const; + // Topology change + + //- Collect faces to remove in the topoChange container + virtual bool removeAMIFaces(polyTopoChange& topoChange); + + //- Collect faces to add in the topoChange container + virtual bool addAMIFaces(polyTopoChange& topoChange); + + //- Set properties of newly inserted faces after topological changes + virtual void setAMIFaces(); + + //- Helper to re-apply the geometric scaling lost during mesh + //- updates + virtual void restoreScaledGeometry(); + + + //- Create and return pointer to the projection surface + const autoPtr<searchableSurface>& surfPtr() const; + + //- Reset the AMI interpolator, supply patch points + virtual void resetAMI(const UList<point>& points) const; + + //- Reset the AMI interpolator, use current patch points + virtual void resetAMI() const; //- Recalculate the transformation tensors virtual void calcTransforms(); @@ -180,7 +222,8 @@ public: const label index, const polyBoundaryMesh& bm, const word& patchType, - const transformType transform = UNKNOWN + const transformType transform = UNKNOWN, + const word& defaultAMIMethod = faceAreaWeightAMI::typeName ); //- Construct from dictionary @@ -190,7 +233,8 @@ public: const dictionary& dict, const label index, const polyBoundaryMesh& bm, - const word& patchType + const word& patchType, + const word& defaultAMIMethod = faceAreaWeightAMI::typeName ); //- Construct as copy, resetting the boundary mesh @@ -274,15 +318,34 @@ public: //- Destructor - virtual ~cyclicAMIPolyPatch(); + virtual ~cyclicAMIPolyPatch() = default; // Member Functions // Access + //- Tolerance used e.g. for area calculations/limits + static const scalar tolerance_; + + //- Flag to indicate whether the AMI can be reset + inline bool canResetAMI() const; + + //- Return access to the createAMIFaces flag + inline bool createAMIFaces() const; + + //- Return access to the updated flag + inline bool updatingAMI() const; + + //- Return true if this patch changes the mesh topology + // True when createAMIFaces is true + virtual bool changeTopology() const; + + //- Set topology changes in the polyTopoChange object + virtual bool setTopology(polyTopoChange& topoChange); + //- Is patch 'coupled'. Note that on AMI the geometry is not - // coupled but the fields are! + //- coupled but the fields are! virtual bool coupled() const { return false; @@ -300,15 +363,26 @@ public: //- Return a reference to the neighbour patch virtual const cyclicAMIPolyPatch& neighbPatch() const; - //- Return a reference to the projection surface - const autoPtr<searchableSurface>& surfPtr() const; - //- Return a reference to the AMI interpolator const AMIPatchToPatchInterpolation& AMI() const; + //- Helper function to return the weights + inline const scalarListList& weights() const; + + //- Helper function to return the weights sum + inline const scalarField& weightsSum() const; + //- Return true if applying the low weight correction bool applyLowWeightCorrection() const; + //- Return access to the initial face areas + // Used for topology change + inline vectorField& faceAreas0() const; + + //- Return access to the initial face centres + // Used for topology change + inline vectorField& faceCentres0() const; + // Transformations @@ -388,7 +462,7 @@ public: ); //- Initialize ordering for primitivePatch. Does not - // refer to *this (except for name() and type() etc.) + //- refer to *this (except for name() and type() etc.) virtual void initOrder ( PstreamBuffers&, @@ -409,7 +483,7 @@ public: ) const; //- Return face index on neighbour patch which shares point p - // following trajectory vector n + //- following trajectory vector n label pointFace ( const label facei, diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchI.H b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchI.H index ccc36fc3007d3fdc7f7768c85c61edc63250ba42..f4c640d7c95356ef10562c585c1f6ad7cb91a51c 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchI.H +++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchI.H @@ -6,6 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2013 OpenFOAM Foundation + Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,6 +28,24 @@ License // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +inline bool Foam::cyclicAMIPolyPatch::canResetAMI() const +{ + return Pstream::parRun() || !boundaryMesh().mesh().time().processorCase(); +} + + +inline bool Foam::cyclicAMIPolyPatch::createAMIFaces() const +{ + return createAMIFaces_; +} + + +inline bool Foam::cyclicAMIPolyPatch::updatingAMI() const +{ + return updatingAMI_; +} + + inline const Foam::word& Foam::cyclicAMIPolyPatch::neighbPatchName() const { if (nbrPatchName_.empty()) @@ -39,6 +58,38 @@ inline const Foam::word& Foam::cyclicAMIPolyPatch::neighbPatchName() const return nbrPatchName_; } +inline const Foam::scalarListList& Foam::cyclicAMIPolyPatch::weights() const +{ + if (owner()) + { + return AMI().srcWeights(); + } + + return neighbPatch().AMI().tgtWeights(); +} + + +inline const Foam::scalarField& Foam::cyclicAMIPolyPatch::weightsSum() const +{ + if (owner()) + { + return AMI().srcWeightsSum(); + } + + return neighbPatch().AMI().tgtWeightsSum(); +} + + +inline Foam::vectorField& Foam::cyclicAMIPolyPatch::faceAreas0() const +{ + return faceAreas0_; +} + + +inline Foam::vectorField& Foam::cyclicAMIPolyPatch::faceCentres0() const +{ + return faceCentres0_; +} inline const Foam::vector& Foam::cyclicAMIPolyPatch::rotationAxis() const { diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTopologyChange.C b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTopologyChange.C new file mode 100644 index 0000000000000000000000000000000000000000..a1c6634e2831b47a34adaefe0889cba00797afdf --- /dev/null +++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTopologyChange.C @@ -0,0 +1,678 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2019-2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "cyclicAMIPolyPatch.H" +#include "SubField.H" +#include "vectorList.H" +#include "polyTopoChange.H" + +// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * // + +void Foam::cyclicAMIPolyPatch::restoreScaledGeometry() +{ + DebugInFunction << endl; + + // Note: only used for topology update (createAMIFaces_ flag) + if (!createAMIFaces_) + { + FatalErrorInFunction + << "Attempted to perform topology update when createAMIFaces_ " + << "flag is set to false" + << abort(FatalError); + } + + if (boundaryMesh().mesh().hasCellVolumes()) + { + WarningInFunction + << "Mesh already has volumes set!" + << endl; + } + + vectorField::subField faceAreas = this->faceAreas(); + vectorField::subField faceCentres = this->faceCentres(); + + DebugInfo + << "Patch:" << name() << " before: sum(mag(faceAreas)):" + << gSum(mag(faceAreas)) << nl + << "Patch:" << name() << " before: sum(mag(faceAreas0)):" + << gSum(mag(faceAreas0_)) << endl; + + faceAreas = faceAreas0_; + if (moveFaceCentres_) + { + DebugInfo << "Moving face centres" << endl; + faceCentres = faceCentres0_; + } + + faceAreas0_.clear(); + faceCentres0_.clear(); + + DebugInfo + << "Patch:" << name() << " after: sum(mag(faceAreas)):" + << gSum(mag(faceAreas)) << nl + << "Patch:" << name() << " after: sum(mag(faceAreas0)):" + << gSum(mag(faceAreas0_)) << endl; +} + + +bool Foam::cyclicAMIPolyPatch::removeAMIFaces(polyTopoChange& topoChange) +{ + DebugInFunction << endl; + + // Note: only used for topology update (createAMIFaces_ flag) + if (!createAMIFaces_) + { + FatalErrorInFunction + << "Attempted to perform topology update when createAMIFaces_ " + << "flag is set to false" + << abort(FatalError); + } + + if (!owner()) + { + return false; + } + + bool changeRequired = false; + + // Remove any faces that we inserted to create the 1-to-1 match... + + const cyclicAMIPolyPatch& nbr = neighbPatch(); + + const label newSrcFaceStart = srcFaceIDs_.size(); + + if (newSrcFaceStart != 0) + { + for (label facei = newSrcFaceStart; facei < size(); ++facei) + { + changeRequired = true; + label meshFacei = start() + facei; + topoChange.removeFace(meshFacei, -1); + } + } + + const label newTgtFaceStart = tgtFaceIDs_.size(); + + if (newTgtFaceStart != 0) + { + for (label facei = newTgtFaceStart; facei < nbr.size(); ++facei) + { + changeRequired = true; + label meshFacei = nbr.start() + facei; + topoChange.removeFace(meshFacei, -1); + } + } + + srcFaceIDs_.clear(); + tgtFaceIDs_.clear(); + + return changeRequired; +} + + +bool Foam::cyclicAMIPolyPatch::addAMIFaces(polyTopoChange& topoChange) +{ + DebugInFunction << endl; + + // Note: only used for topology update (createAMIFaces_ flag = true) + if (!createAMIFaces_) + { + FatalErrorInFunction + << "Attempted to perform topology update when createAMIFaces_ " + << "flag is set to false" + << abort(FatalError); + } + + bool changedFaces = false; + const cyclicAMIPolyPatch& nbr = neighbPatch(); + + polyMesh& mesh = const_cast<polyMesh&>(boundaryMesh().mesh()); + const faceZoneMesh& faceZones = mesh.faceZones(); + + // First face address and weight are used to manipulate the + // original face - all other addresses and weights are used to + // create additional faces + const labelListList& srcToTgtAddr = AMI().srcAddress(); + const labelListList& tgtToSrcAddr = AMI().tgtAddress(); + + const label nSrcFace = srcToTgtAddr.size(); + const label nTgtFace = tgtToSrcAddr.size(); + + srcFaceIDs_.setSize(nSrcFace); + tgtFaceIDs_.setSize(nTgtFace); + + label nNewSrcFaces = 0; + forAll(srcToTgtAddr, srcFacei) + { + const labelList& tgtAddr = srcToTgtAddr[srcFacei]; + + // No tgt faces linked to srcFacei (ACMI) + if (tgtAddr.empty()) continue; + + srcFaceIDs_[srcFacei].setSize(tgtAddr.size()); + srcFaceIDs_[srcFacei][0] = srcFacei; + + const label meshFacei = start() + srcFacei; + for (label addri = 1; addri < tgtAddr.size(); ++addri) + { + changedFaces = true; + + // Note: new faces reuse originating face points + // - but areas are scaled by the weights (later) + + // New source face for each target face address + srcFaceIDs_[srcFacei][addri] = nNewSrcFaces + nSrcFace; + ++nNewSrcFaces; + (void)topoChange.addFace + ( + mesh.faces()[meshFacei], // modified face + mesh.faceOwner()[meshFacei], // owner + -1, // neighbour + -1, // master point + -1, // master edge + meshFacei, // master face + false, // face flip + index(), // patch for face + faceZones.whichZone(meshFacei), // zone for original face + false // face flip in zone + ); + } + } + + label nNewTgtFaces = 0; + forAll(tgtToSrcAddr, tgtFacei) + { + const labelList& srcAddr = tgtToSrcAddr[tgtFacei]; + + // No src faces linked to tgtFacei (ACMI) + if (srcAddr.empty()) continue; + + tgtFaceIDs_[tgtFacei].setSize(srcAddr.size()); + tgtFaceIDs_[tgtFacei][0] = tgtFacei; + + const label meshFacei = nbr.start() + tgtFacei; + for (label addri = 1; addri < srcAddr.size(); ++addri) + { + changedFaces = true; + + // Note: new faces reuse originating face points + // - but areas are scaled by the weights (later) + + // New target face for each source face address + tgtFaceIDs_[tgtFacei][addri] = nNewTgtFaces + nTgtFace; + ++nNewTgtFaces; + + (void)topoChange.addFace + ( + mesh.faces()[meshFacei], // modified face + mesh.faceOwner()[meshFacei], // owner + -1, // neighbour + -1, // master point + -1, // master edge + meshFacei, // master face + false, // face flip + nbr.index(), // patch for face + faceZones.whichZone(meshFacei), // zone for original face + false // face flip in zone + ); + } + } + + Info<< "AMI: Patch " << name() << " additional faces: " + << returnReduce(nNewSrcFaces, sumOp<label>()) << nl + << "AMI: Patch " << nbr.name() << " additional faces: " + << returnReduce(nNewTgtFaces, sumOp<label>()) + << endl; + + if (debug) + { + Pout<< "New faces - " << name() << ": " << nNewSrcFaces + << " " << nbr.name() << ": " << nNewTgtFaces << endl; + } + + return returnReduce(changedFaces, orOp<bool>()); +} + + +void Foam::cyclicAMIPolyPatch::setAMIFaces() +{ + // Create new mesh faces so that there is a 1-to-1 correspondence + // between faces on each side of the AMI + + // Note: only used for topology update (createAMIFaces_ flag) + if (!createAMIFaces_) + { + FatalErrorInFunction + << "Attempted to perform topology update when createAMIFaces_ " + << "flag is set to false" + << abort(FatalError); + } + + + DebugInFunction << endl; + + if (!owner()) + { + return; + } + + const cyclicAMIPolyPatch& nbr = neighbPatch(); + + vectorField& nbrFaceAreas0 = nbr.faceAreas0(); + vectorField& nbrFaceCentres0 = nbr.faceCentres0(); + + // Scale the new face areas and set the centroids + // Note: + // - storing local copies so that they can be re-applied after the call to + // movePoints that will reset any changes to the areas and centroids + // + // - For AMI, src and tgt patches should be the same + // - For ACMI they are likely to be different! + faceAreas0_ = faceAreas(); + faceCentres0_ = faceCentres(); + nbrFaceAreas0 = nbr.faceAreas(); + nbrFaceCentres0 = nbr.faceCentres(); + + // Original AMI info (based on the mesh state when the AMI was evaluated) + const labelListList& srcToTgtAddr0 = AMIPtr_->srcAddress(); + const labelListList& tgtToSrcAddr0 = AMIPtr_->tgtAddress(); + const pointListList& srcCtr0 = AMIPtr_->srcCentroids(); + const scalarListList& srcToTgtWght0 = AMIPtr_->srcWeights(); + + // New addressing on new mesh (extended by polyTopoChange) + labelListList srcToTgtAddr1(size(), labelList()); + labelListList tgtToSrcAddr1(nbr.size(), labelList()); + + // Need to calc new parallel maps (mesh has changed since AMI was computed) + autoPtr<mapDistribute> srcToTgtMap1; + autoPtr<mapDistribute> tgtToSrcMap1; + + if (AMIPtr_->singlePatchProc() == -1) + { + // Parallel running + + // Global index based on old patch sizes (when AMI was computed) + globalIndex globalSrcFaces0(srcToTgtAddr0.size()); + globalIndex globalTgtFaces0(tgtToSrcAddr0.size()); + + // Global index based on new patch sizes + globalIndex globalSrcFaces1(size()); + globalIndex globalTgtFaces1(nbr.size()); + + + // Gather source side info + // ======================= + + // Note: using new global index for addressing, and distributed using + // the old AMI map + labelListList newTgtGlobalFaces(tgtFaceIDs_); + forAll(newTgtGlobalFaces, tgtFacei) + { + globalTgtFaces1.inplaceToGlobal(newTgtGlobalFaces[tgtFacei]); + } + AMIPtr_->tgtMap().distribute(newTgtGlobalFaces); + + // Now have new tgt face indices for each src face + + labelList globalSrcFaceIDs(identity(srcToTgtAddr0.size())); + globalSrcFaces0.inplaceToGlobal(globalSrcFaceIDs); + AMIPtr_->srcMap().distribute(globalSrcFaceIDs); + // globalSrcFaceIDs now has remote data for each srcFacei0 known to the + // tgt patch + + List<List<point>> globalSrcCtrs0(srcCtr0); + AMIPtr_->srcMap().distribute(globalSrcCtrs0); + + labelList globalTgtFaceIDs(identity(tgtToSrcAddr0.size())); + globalTgtFaces0.inplaceToGlobal(globalTgtFaceIDs); + AMIPtr_->tgtMap().distribute(globalTgtFaceIDs); + // globalTgtFaceIDs now has remote data for each tgtFacei0 known to the + // src patch + + // For debug - send tgt face centres and compare against mapped src + // face centres + //List<List<point>> globalTgtCtrs0(tgtCtr0); + //AMIPtr_->tgtMap().distribute(globalTgtCtrs0); + + labelListList globalTgtToSrcAddr(tgtToSrcAddr0); + forAll(tgtToSrcAddr0, tgtFacei0) + { + forAll(tgtToSrcAddr0[tgtFacei0], addri) + { + const label globalSrcFacei = + globalSrcFaceIDs[tgtToSrcAddr0[tgtFacei0][addri]]; + globalTgtToSrcAddr[tgtFacei0][addri] = globalSrcFacei; + } + } + AMIPtr_->tgtMap().distribute(globalTgtToSrcAddr); + + labelListList globalSrcToTgtAddr(srcToTgtAddr0); + forAll(srcToTgtAddr0, srcFacei0) + { + forAll(srcToTgtAddr0[srcFacei0], addri) + { + const label globalTgtFacei = + globalTgtFaceIDs[srcToTgtAddr0[srcFacei0][addri]]; + globalSrcToTgtAddr[srcFacei0][addri] = globalTgtFacei; + } + } + AMIPtr_->srcMap().distribute(globalSrcToTgtAddr); + + label nError = 0; + forAll(srcToTgtAddr0, srcFacei0) + { + const labelList& newSrcFaces = srcFaceIDs_[srcFacei0]; + + forAll(newSrcFaces, i) + { + const label srcFacei1 = newSrcFaces[i]; + + // What index did srcFacei0 appear in tgtToSrc0 list? + // - if first index, all ok + // - else tgt face has been moved to according to tgtFaceIDs_ + const label tgtFacei0 = srcToTgtAddr0[srcFacei0][i]; + const label addri = + globalTgtToSrcAddr[tgtFacei0].find + ( + globalSrcFaceIDs[srcFacei0] + ); + + if (addri == -1) + { + ++nError; + continue; + + if (debug) + { + Pout<< "Unable to find global source face " + << globalSrcFaceIDs[srcFacei0] + << " in globalTgtToSrcAddr[" << tgtFacei0 << "]: " + << globalTgtToSrcAddr[tgtFacei0] + << endl; + } + } + + const label tgtFacei1 = newTgtGlobalFaces[tgtFacei0][addri]; + + // Sanity check to see that we've picked the correct face + // point tgtCtr0(globalTgtCtrs0[tgtFacei0][addri]); + // Pout<< "srcCtr:" << srcCtr0[srcFacei0][i] + // << " tgtCtr:" << tgtCtr0 << endl; + + srcToTgtAddr1[srcFacei1] = labelList(1, tgtFacei1); + faceAreas0_[srcFacei1] *= srcToTgtWght0[srcFacei0][i]; + faceCentres0_[srcFacei1] = srcCtr0[srcFacei0][i]; + } + } + + if (nError) + { + FatalErrorInFunction + << "Unable to find " << nError << " global source faces" + << abort(FatalError); + } + + + // Gather Target side info + // ======================= + + labelListList newSrcGlobalFaces(srcFaceIDs_); + forAll(newSrcGlobalFaces, srcFacei) + { + globalSrcFaces1.inplaceToGlobal(newSrcGlobalFaces[srcFacei]); + } + + AMIPtr_->srcMap().distribute(newSrcGlobalFaces); + + // Now have new src face indices for each tgt face + forAll(tgtToSrcAddr0, tgtFacei0) + { + const labelList& newTgtFaces = tgtFaceIDs_[tgtFacei0]; + forAll(newTgtFaces, i) + { + const label srcFacei0 = tgtToSrcAddr0[tgtFacei0][i]; + + const label addri = + globalSrcToTgtAddr[srcFacei0].find + ( + globalTgtFaceIDs[tgtFacei0] + ); + + if (addri == -1) + { + ++nError; + continue; + + if (debug) + { + Pout<< "Unable to find global target face " + << globalTgtFaceIDs[tgtFacei0] + << " in globalSrcToTgtAddr[" << srcFacei0 << "]: " + << globalSrcToTgtAddr[srcFacei0] + << endl; + } + } + + const label srcFacei1 = newSrcGlobalFaces[srcFacei0][addri]; + + // Sanity check to see that we've picked the correct face + point srcCtr0(globalSrcCtrs0[srcFacei0][addri]); + reverseTransformPosition(srcCtr0, srcFacei0); + + const label tgtFacei1 = newTgtFaces[i]; + tgtToSrcAddr1[tgtFacei1] = labelList(1, srcFacei1); + nbrFaceCentres0[tgtFacei1] = srcCtr0; + } + } + + if (nError) + { + FatalErrorInFunction + << "Unable to find " << nError << " global target faces" + << abort(FatalError); + } + + // Update the maps + { + List<Map<label>> cMap; + srcToTgtMap1.reset + ( + new mapDistribute(globalSrcFaces1, tgtToSrcAddr1, cMap) + ); + } + { + List<Map<label>> cMap; + tgtToSrcMap1.reset + ( + new mapDistribute(globalTgtFaces1, srcToTgtAddr1, cMap) + ); + } + + // Reset tgt patch areas using the new map + vectorList newSrcGlobalFaceAreas(faceAreas0_); + + srcToTgtMap1->distribute(newSrcGlobalFaceAreas); + forAll(nbrFaceAreas0, tgtFacei) + { + if (!tgtToSrcAddr1[tgtFacei].empty()) + { + const label srcFacei = tgtToSrcAddr1[tgtFacei][0]; + nbrFaceAreas0[tgtFacei] = -newSrcGlobalFaceAreas[srcFacei]; + } + } + } + else + { + label nError = 0; + forAll(srcToTgtAddr0, srcFacei0) + { + const labelList& srcFaceTgtAddr0 = srcToTgtAddr0[srcFacei0]; + const scalarList& srcFaceTgtWght0 = srcToTgtWght0[srcFacei0]; + const pointList& srcFaceTgtCtr0 = srcCtr0[srcFacei0]; + forAll(srcFaceTgtAddr0, addri) + { + const label srcFacei1 = srcFaceIDs_[srcFacei0][addri]; + + // Find which slot srcFacei0 appears in tgt->src addressing + const label tgtFacei0 = srcFaceTgtAddr0[addri]; + const label tgtAddri0 = + tgtToSrcAddr0[tgtFacei0].find(srcFacei0); + + if (tgtAddri0 == -1) + { + ++nError; + continue; + + if (debug) + { + Pout<< "Unable to find source face " << srcFacei0 + << " in tgtToSrcAddr0[" << tgtFacei0 << "]: " + << tgtToSrcAddr0[tgtFacei0] + << endl; + } + } + + const label tgtFacei1 = tgtFaceIDs_[tgtFacei0][tgtAddri0]; + + faceAreas0_[srcFacei1] *= srcFaceTgtWght0[addri]; + nbrFaceAreas0[tgtFacei1] = -faceAreas0_[srcFacei1]; + + point pt(srcFaceTgtCtr0[addri]); + faceCentres0_[srcFacei1] = pt; + reverseTransformPosition(pt, srcFacei0); + nbrFaceCentres0[tgtFacei1] = pt; + + // SANITY CHECK + // Info<< "srcPt:" << srcFaceCentres[srcFacei1] + // << " tgtPt:" << tgtFaceCentres[tgtFacei1] << endl; + + srcToTgtAddr1[srcFacei1] = labelList(1, tgtFacei1); + tgtToSrcAddr1[tgtFacei1] = labelList(1, srcFacei1); + } + } + + if (nError) + { + FatalErrorInFunction + << "Unable to find " << nError + << " source faces in tgtToSrcAddr0" + << abort(FatalError); + } + } + + scalarListList newSrcToTgtWeights(srcToTgtAddr1.size()); + forAll(srcToTgtAddr1, facei) + { + if (srcToTgtAddr1[facei].size()) + { + newSrcToTgtWeights[facei] = scalarList(1, scalar(1)); + } + else + { + // No connection - effect of face removed by setting area to a + // a small value + faceAreas0_[facei] *= tolerance_; + } + } + + scalarListList newTgtToSrcWeights(tgtToSrcAddr1.size()); + forAll(tgtToSrcAddr1, facei) + { + if (tgtToSrcAddr1[facei].size()) + { + newTgtToSrcWeights[facei] = scalarList(1, scalar(1)); + } + else + { + // No connection - effect of face removed by setting area to a + // a small value + nbrFaceAreas0[facei] *= tolerance_; + } + } + + // Reset the AMI addressing and weights to reflect the new 1-to-1 + // correspondence + AMIPtr_->reset + ( + std::move(srcToTgtMap1), + std::move(tgtToSrcMap1), + std::move(srcToTgtAddr1), + std::move(newSrcToTgtWeights), + std::move(tgtToSrcAddr1), + std::move(newTgtToSrcWeights) + ); + + // Need to set areas, e.g. for agglomeration to (re-)normalisation weights + AMIPtr_->srcMagSf() = mag(faceAreas0_); + AMIPtr_->tgtMagSf() = mag(nbrFaceAreas0); + + if (debug) + { + Pout<< "cyclicAMIPolyPatch : " << name() + << " constructed AMI with " << nl + << " " << "srcAddress:" << AMIPtr_().srcAddress().size() + << nl + << " " << "tgAddress :" << AMIPtr_().tgtAddress().size() + << nl << endl; + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::cyclicAMIPolyPatch::changeTopology() const +{ + DebugInFunction << endl; + + createAMIFaces_ = true; + + return true; +} + + +bool Foam::cyclicAMIPolyPatch::setTopology(polyTopoChange& topoChange) +{ + DebugInFunction << endl; + + if (createAMIFaces_ && owner()) + { + // Calculate the AMI using the new points + // Note: mesh still has old points + resetAMI(topoChange.points()); + + removeAMIFaces(topoChange); + + addAMIFaces(topoChange); + + return true; + } + + return false; +} + + +// ************************************************************************* // diff --git a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C index 28c6b98f6d48420a7e1bfe3bd21928ca86eeb78c..d8ade6e0cc2e1538157ee023229f0c64522e44f5 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C +++ b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C @@ -26,6 +26,7 @@ License \*---------------------------------------------------------------------------*/ #include "cyclicPeriodicAMIPolyPatch.H" +#include "partialFaceAreaWeightAMI.H" #include "addToRunTimeSelectionTable.H" // For debugging @@ -228,10 +229,7 @@ void Foam::cyclicPeriodicAMIPolyPatch::writeOBJ } -void Foam::cyclicPeriodicAMIPolyPatch::resetAMI -( - const AMIPatchToPatchInterpolation::interpolationMethod& AMIMethod -) const +void Foam::cyclicPeriodicAMIPolyPatch::resetAMI() const { if (owner()) { @@ -326,20 +324,8 @@ void Foam::cyclicPeriodicAMIPolyPatch::resetAMI ); // Construct a new AMI interpolation between the initial patch locations - AMIPtr_.reset - ( - new AMIPatchToPatchInterpolation - ( - thisPatch0, - nbrPatch0, - surfPtr(), - faceAreaIntersect::tmMesh, - false, - AMIPatchToPatchInterpolation::imPartialFaceAreaWeight, - AMILowWeightCorrection_, - AMIReverse_ - ) - ); + AMIPtr_->setRequireMatch(false); + AMIPtr_->calculate(thisPatch0, nbrPatch0, surfPtr()); // Number of geometry replications label iter(0); @@ -358,7 +344,6 @@ void Foam::cyclicPeriodicAMIPolyPatch::resetAMI // Weight sum averages scalar srcSum(gAverage(AMIPtr_->srcWeightsSum())); scalar tgtSum(gAverage(AMIPtr_->tgtWeightsSum())); - // Direction (or rather side of AMI : this or nbr patch) of // geometry replication bool direction = nTransforms_ >= 0; @@ -520,17 +505,13 @@ void Foam::cyclicPeriodicAMIPolyPatch::resetAMI << "The current matchTolerance : " << matchTolerance() << ", sum of owner weights : " << srcSum << ", sum of neighbour weights : " << tgtSum - << "." << nl + << "." << nl << "This is only acceptable during post-processing" << "; not during running. Improve your mesh or increase" << " the 'matchTolerance' setting in the patch specification." << endl; } - // Normalise the weights. Disable printing since weights are - // still areas. - AMIPtr_->normaliseWeights(true, false); - // Print some statistics const label nFace = returnReduce(size(), sumOp<label>()); @@ -577,7 +558,17 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch const transformType transform ) : - cyclicAMIPolyPatch(name, size, start, index, bm, patchType, transform), + cyclicAMIPolyPatch + ( + name, + size, + start, + index, + bm, + patchType, + transform, + partialFaceAreaWeightAMI::typeName + ), periodicPatchName_(word::null), periodicPatchID_(-1), nTransforms_(0), @@ -595,7 +586,15 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch const word& patchType ) : - cyclicAMIPolyPatch(name, dict, index, bm, patchType), + cyclicAMIPolyPatch + ( + name, + dict, + index, + bm, + patchType, + partialFaceAreaWeightAMI::typeName + ), periodicPatchName_(dict.lookup("periodicPatch")), periodicPatchID_(-1), nTransforms_(dict.getOrDefault<label>("nTransforms", 0)), diff --git a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H index 22fbc088455d3b3f30373dcd552e1c769d7e59bf..297c5c3189310d8ef90faf64244c4b0332005075 100644 --- a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H +++ b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H @@ -83,11 +83,7 @@ private: void writeOBJ(const primitivePatch& p, OBJstream& str) const; //- Reset the AMI interpolator - virtual void resetAMI - ( - const AMIPatchToPatchInterpolation::interpolationMethod& AMIMethod = - AMIPatchToPatchInterpolation::imFaceAreaWeight - ) const; + virtual void resetAMI() const; public: diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files index 22b12ee488cfd3e4ba2d8395e20ddb4ff3c4d0cd..e428fc63dcbdf3ce93c549d8e2c35b97e428872e 100644 --- a/src/meshTools/Make/files +++ b/src/meshTools/Make/files @@ -259,8 +259,13 @@ processorLOD/cellBox/cellBox.C processorLOD/faceBox/faceBox.C AMI=AMIInterpolation -$(AMI)/AMIInterpolation/AMIInterpolationName.C -$(AMI)/AMIInterpolation/AMIPatchToPatchInterpolation.C +$(AMI)/AMIInterpolation/AMIInterpolation.C +$(AMI)/AMIInterpolation/AMIInterpolationNew.C +$(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMI.C +$(AMI)/AMIInterpolation/advancingFrontAMI/advancingFrontAMIParallelOps.C +$(AMI)/AMIInterpolation/faceAreaWeightAMI/faceAreaWeightAMI.C +$(AMI)/AMIInterpolation/partialFaceAreaWeightAMI/partialFaceAreaWeightAMI.C +$(AMI)/AMIInterpolation/nearestFaceAMI/nearestFaceAMI.C $(AMI)/faceAreaIntersect/faceAreaIntersect.C $(AMI)/GAMG/interfaces/cyclicAMIGAMGInterface/cyclicAMIGAMGInterface.C $(AMI)/GAMG/interfaceFields/cyclicAMIGAMGInterfaceField/cyclicAMIGAMGInterfaceField.C @@ -271,6 +276,7 @@ AMICycPatches=$(AMI)/patches/cyclicAMI $(AMICycPatches)/cyclicAMILduInterfaceField/cyclicAMILduInterface.C $(AMICycPatches)/cyclicAMILduInterfaceField/cyclicAMILduInterfaceField.C $(AMICycPatches)/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C +$(AMICycPatches)/cyclicAMIPolyPatch/cyclicAMIPolyPatchTopologyChange.C $(AMICycPatches)/cyclicAMIPointPatch/cyclicAMIPointPatch.C $(AMICycPatches)/cyclicAMIPointPatchField/cyclicAMIPointPatchFields.C diff --git a/src/meshTools/Make/options b/src/meshTools/Make/options index 9ee5884e5908ccdb6b1ba3acf323b8c524ec996a..5b4f9ec84181988556c25393c12e10eb3e3b4531 100644 --- a/src/meshTools/Make/options +++ b/src/meshTools/Make/options @@ -1,6 +1,7 @@ EXE_INC = \ -I$(LIB_SRC)/fileFormats/lnInclude \ - -I$(LIB_SRC)/surfMesh/lnInclude + -I$(LIB_SRC)/surfMesh/lnInclude \ + -I$(LIB_SRC)/dynamicMesh/lnInclude LIB_LIBS = \ -lfileFormats \ diff --git a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.C b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.C index 8dac4e801c5cc156b8fb66c6617ed3241dd70da3..cef6859a6f9d70181524113f896a5bb342e86f47 100644 --- a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.C +++ b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.C @@ -45,6 +45,7 @@ License #include "syncTools.H" #include "treeDataCell.H" #include "DynamicField.H" +#include "faceAreaWeightAMI.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -791,14 +792,14 @@ const void Foam::mappedPatchBase::calcAMI() const { - if (AMIPtr_.valid()) + if (AMIPtr_->upToDate()) { - FatalErrorInFunction - << "AMI already calculated" << exit(FatalError); - } - - AMIPtr_.clear(); + DebugInFunction + << "AMI already up-to-date" + << endl; + return; + } const polyPatch& nbr = samplePolyPatch(); @@ -829,29 +830,13 @@ void Foam::mappedPatchBase::calcAMI() const } // Construct/apply AMI interpolation to determine addressing and weights - AMIPtr_.reset - ( - new AMIPatchToPatchInterpolation - ( - patch_, - nbrPatch0, - surfPtr(), - faceAreaIntersect::tmMesh, - true, - AMIPatchToPatchInterpolation::imFaceAreaWeight, - -1, - AMIReverse_ - ) - ); + AMIPtr_->calculate(patch_, nbrPatch0, surfPtr()); } // * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * // -Foam::mappedPatchBase::mappedPatchBase -( - const polyPatch& pp -) +Foam::mappedPatchBase::mappedPatchBase(const polyPatch& pp) : patch_(pp), sampleRegion_(patch_.boundaryMesh().mesh().name()), @@ -864,8 +849,8 @@ Foam::mappedPatchBase::mappedPatchBase distance_(0), sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(false), + AMIPtr_(new faceAreaWeightAMI(true, AMIReverse_)), surfPtr_(nullptr), surfDict_(fileName("surface")) {} @@ -891,8 +876,8 @@ Foam::mappedPatchBase::mappedPatchBase distance_(0), sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(false), + AMIPtr_(new faceAreaWeightAMI(true, AMIReverse_)), surfPtr_(nullptr), surfDict_(fileName("surface")) {} @@ -918,8 +903,8 @@ Foam::mappedPatchBase::mappedPatchBase distance_(0), sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(false), + AMIPtr_(new faceAreaWeightAMI(true, AMIReverse_)), surfPtr_(nullptr), surfDict_(fileName("surface")) {} @@ -945,8 +930,8 @@ Foam::mappedPatchBase::mappedPatchBase distance_(distance), sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(false), + AMIPtr_(new faceAreaWeightAMI(true, AMIReverse_)), surfPtr_(nullptr), surfDict_(fileName("surface")) {} @@ -969,8 +954,16 @@ Foam::mappedPatchBase::mappedPatchBase distance_(0), sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(dict.getOrDefault("flipNormals", false)), + AMIPtr_ + ( + AMIInterpolation::New + ( + dict.getOrDefault("AMIMethod", faceAreaWeightAMI::typeName), + dict, + AMIReverse_ + ) + ), surfPtr_(nullptr), surfDict_(dict.subOrEmptyDict("surface")) { @@ -1044,8 +1037,16 @@ Foam::mappedPatchBase::mappedPatchBase distance_(0), sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(dict.getOrDefault("flipNormals", false)), + AMIPtr_ + ( + AMIInterpolation::New + ( + dict.getOrDefault("AMIMethod", faceAreaWeightAMI::typeName), + dict, + AMIReverse_ + ) + ), surfPtr_(nullptr), surfDict_(dict.subOrEmptyDict("surface")) { @@ -1089,8 +1090,8 @@ Foam::mappedPatchBase::mappedPatchBase distance_(mpb.distance_), sameRegion_(mpb.sameRegion_), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(mpb.AMIReverse_), + AMIPtr_(mpb.AMIPtr_->clone()), surfPtr_(nullptr), surfDict_(mpb.surfDict_) {} @@ -1119,8 +1120,8 @@ Foam::mappedPatchBase::mappedPatchBase distance_(mpb.distance_), sameRegion_(mpb.sameRegion_), mapPtr_(nullptr), - AMIPtr_(nullptr), AMIReverse_(mpb.AMIReverse_), + AMIPtr_(mpb.AMIPtr_->clone()), surfPtr_(nullptr), surfDict_(mpb.surfDict_) {} @@ -1137,8 +1138,8 @@ Foam::mappedPatchBase::~mappedPatchBase() void Foam::mappedPatchBase::clearOut() { mapPtr_.clear(); - AMIPtr_.clear(); surfPtr_.clear(); + AMIPtr_->upToDate() = false; } diff --git a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H index ac4f6c7fb514960d71a0d9d195482878a8660445..d6b76023dba3cc5da7cf434398d2819e71a740f2 100644 --- a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H +++ b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBase.H @@ -231,12 +231,12 @@ protected: // AMI interpolator (only for NEARESTPATCHFACEAMI) - //- Pointer to AMI interpolator - mutable autoPtr<AMIPatchToPatchInterpolation> AMIPtr_; - //- Flag to indicate that slave patch should be reversed for AMI const bool AMIReverse_; + //- Pointer to AMI interpolator + mutable autoPtr<AMIPatchToPatchInterpolation> AMIPtr_; + //- Pointer to projection surface employed by AMI interpolator mutable autoPtr<searchableSurface> surfPtr_; diff --git a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H index 93e8c7c7de87a4aeb12a7c84ac88a60df3ad6edb..dc507b64e6c4c5e8cb411eb7958e89a368c8aff5 100644 --- a/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H +++ b/src/meshTools/mappedPatches/mappedPolyPatch/mappedPatchBaseI.H @@ -172,13 +172,10 @@ inline const Foam::AMIPatchToPatchInterpolation& Foam::mappedPatchBase::AMI if (topoChange || forceUpdate) { - AMIPtr_.clear(); + AMIPtr_->upToDate() = false; } - if (AMIPtr_.empty()) - { - calcAMI(); - } + calcAMI(); return *AMIPtr_; } diff --git a/src/meshTools/polyTopoChange/polyTopoChange.H b/src/meshTools/polyTopoChange/polyTopoChange.H index d861a2d7da259af1f9cfc462ecf6663ca794c0ef..613f6d398f3bafb16e051d0ca40b2d44c46da63d 100644 --- a/src/meshTools/polyTopoChange/polyTopoChange.H +++ b/src/meshTools/polyTopoChange/polyTopoChange.H @@ -94,7 +94,7 @@ class IOobject; template<class T, class Container> class CompactListList; /*---------------------------------------------------------------------------*\ - Class polyTopoChange Declaration + Class polyTopoChange Declaration \*---------------------------------------------------------------------------*/ class polyTopoChange @@ -121,7 +121,7 @@ class polyTopoChange DynamicList<label> pointMap_; //- For all original and added points contains new point label. - // (used to map return value of addPoint to new mesh point) + //- (used to map return value of addPoint to new mesh point) DynamicList<label> reversePointMap_; //- Zone of point @@ -324,10 +324,10 @@ class polyTopoChange ); //- Remove all unused/removed points/faces/cells and update - // face ordering (always), cell ordering (bandcompression, - // orderCells=true), - // point ordering (sorted into internal and boundary points, - // orderPoints=true) + //- face ordering (always), cell ordering (bandcompression, + //- orderCells=true), + //- point ordering (sorted into internal and boundary points, + //- orderPoints=true) void compact ( const bool orderCells, @@ -433,7 +433,7 @@ public: // Constructors //- Construct without mesh. Either specify nPatches or use - // setNumPatches before trying to make a mesh (makeMesh, changeMesh) + //- setNumPatches before trying to make a mesh (makeMesh, changeMesh) polyTopoChange(const label nPatches, const bool strict = true); //- Construct from mesh. Adds all points/face/cells from mesh. @@ -471,15 +471,15 @@ public: } //- Is point removed? - // Considered removed if point is GREAT. + //- Considered removed if point is GREAT. inline bool pointRemoved(const label pointi) const; //- Is face removed? - // Considered removed if face is empty + //- Considered removed if face is empty inline bool faceRemoved(const label facei) const; //- Is cell removed? - // Considered removed if the cellMap is -2 + //- Considered removed if the cellMap is -2 inline bool cellRemoved(const label celli) const; @@ -489,7 +489,7 @@ public: void clear(); //- Add all points/faces/cells of mesh. Additional offset for patch - // or zone ids. + //- or zone ids. void addMesh ( const polyMesh& mesh, @@ -500,7 +500,7 @@ public: ); //- Explicitly pre-size the dynamic storage for expected mesh - // size for if construct-without-mesh + //- size for if construct-without-mesh void setCapacity ( const label nPoints, @@ -590,7 +590,7 @@ public: void removeCell(const label celli, const label mergeCelli); //- Explicitly set the number of patches if construct-without-mesh - // used. + //- used. inline void setNumPatches(const label nPatches); // Other @@ -628,7 +628,6 @@ public: const bool orderCells = false, const bool orderPoints = false ); - }; diff --git a/src/regionModels/regionModel/regionModel/regionModel.C b/src/regionModels/regionModel/regionModel/regionModel.C index 0885dd53f6fa50c9dfaf5ebd1cc4ef4fca664b73..d92a4521725ea60801fe915138df9f7cbe0c26a6 100644 --- a/src/regionModels/regionModel/regionModel/regionModel.C +++ b/src/regionModels/regionModel/regionModel/regionModel.C @@ -31,6 +31,7 @@ License #include "Time.H" #include "mappedWallPolyPatch.H" #include "zeroGradientFvPatchFields.H" +#include "faceAreaWeightAMI.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -209,18 +210,16 @@ Foam::regionModels::regionModel::interRegionAMI interRegionAMI_[nbrRegionID].set ( regionPatchi, - new AMIPatchToPatchInterpolation + AMIInterpolation::New ( - p, - nbrP, - faceAreaIntersect::tmMesh, - true, - AMIPatchToPatchInterpolation::imFaceAreaWeight, - -1, + faceAreaWeightAMI::typeName, + true, // requireMatch flip ) ); + interRegionAMI_[nbrRegionID][regionPatchi].calculate(p, nbrP); + UPstream::msgType() = oldTag; } @@ -252,18 +251,16 @@ Foam::regionModels::regionModel::interRegionAMI interRegionAMI_[nbrRegionID].set ( regionPatchi, - new AMIPatchToPatchInterpolation + AMIInterpolation::New ( - p, - nbrP, - faceAreaIntersect::tmMesh, - true, - AMIPatchToPatchInterpolation::imFaceAreaWeight, - -1, - flip + faceAreaWeightAMI::typeName, + true, // requireMatch + flip // reverse ) ); + interRegionAMI_[nbrRegionID][regionPatchi].calculate(p, nbrP); + UPstream::msgType() = oldTag; return interRegionAMI_[nbrRegionID][regionPatchi]; diff --git a/src/sampling/meshToMesh/meshToMesh.C b/src/sampling/meshToMesh/meshToMesh.C index 591f67fc5e18db7baa5d8b47bf4d9dbc64d8d034..90d7b8b4d5279f8e197fc8a554e693992957a947 100644 --- a/src/sampling/meshToMesh/meshToMesh.C +++ b/src/sampling/meshToMesh/meshToMesh.C @@ -30,6 +30,8 @@ License #include "Time.H" #include "globalIndex.H" #include "meshToMeshMethod.H" +#include "nearestFaceAMI.H" +#include "faceAreaWeightAMI.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -633,25 +635,27 @@ void Foam::meshToMesh::calculate(const word& methodName, const bool normalise) } -Foam::AMIPatchToPatchInterpolation::interpolationMethod -Foam::meshToMesh::interpolationMethodAMI(const interpolationMethod method) +Foam::word Foam::meshToMesh::interpolationMethodAMI +( + const interpolationMethod method +) { switch (method) { case interpolationMethod::imDirect: { - return AMIPatchToPatchInterpolation::imDirect; + return nearestFaceAMI::typeName; break; } case interpolationMethod::imMapNearest: { - return AMIPatchToPatchInterpolation::imMapNearest; + return nearestFaceAMI::typeName; break; } case interpolationMethod::imCellVolumeWeight: case interpolationMethod::imCorrectedCellVolumeWeight: { - return AMIPatchToPatchInterpolation::imFaceAreaWeight; + return faceAreaWeightAMI::typeName; break; } default: @@ -662,7 +666,7 @@ Foam::meshToMesh::interpolationMethodAMI(const interpolationMethod method) } } - return AMIPatchToPatchInterpolation::imDirect; + return nearestFaceAMI::typeName; } @@ -695,18 +699,17 @@ void Foam::meshToMesh::calculatePatchAMIs(const word& AMIMethodName) patchAMIs_.set ( i, - new AMIPatchToPatchInterpolation + AMIInterpolation::New ( - srcPP, - tgtPP, - faceAreaIntersect::tmMesh, - false, AMIMethodName, - -1, - true // flip target patch since patch normals are aligned + false, // requireMatch + true, // flip target patch since patch normals are aligned + -1 // low weight correction ) ); + patchAMIs_[i].calculate(srcPP, tgtPP); + Info<< decrIndent; } } @@ -862,10 +865,7 @@ Foam::meshToMesh::meshToMesh constructNoCuttingPatches ( interpolationMethodNames_[method], - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - interpolationMethodAMI(method) - ], + interpolationMethodAMI(method), interpAllPatches ); } @@ -933,10 +933,7 @@ Foam::meshToMesh::meshToMesh constructFromCuttingPatches ( interpolationMethodNames_[method], - AMIPatchToPatchInterpolation::interpolationMethodNames_ - [ - interpolationMethodAMI(method) - ], + interpolationMethodAMI(method), patchMap, cuttingPatches, normalise diff --git a/src/sampling/meshToMesh/meshToMesh.H b/src/sampling/meshToMesh/meshToMesh.H index f3c64fa647f9065dcb8e87bb5641113617abb871..877259617de75a1ab10d4395109b0aee5f65aaf7 100644 --- a/src/sampling/meshToMesh/meshToMesh.H +++ b/src/sampling/meshToMesh/meshToMesh.H @@ -394,8 +394,7 @@ public: inline scalar V() const; //- Conversion between mesh and patch interpolation methods - static AMIPatchToPatchInterpolation::interpolationMethod - interpolationMethodAMI + static word interpolationMethodAMI ( const interpolationMethod method );