diff --git a/README.txt b/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..273b4dad2085f94fcdb458d476d3ca83ac62eee9 --- /dev/null +++ b/README.txt @@ -0,0 +1,47 @@ +Notes from merging Integration-TUD-addOns and plus. + +0) +- Changed +dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C +to created internal faces out-of-nothing. +- Added the mapNewInternalFaces to dynamicRefineFvMesh +- unset FOAM_SETNAN, FOAM_SIGFPE and run + + testCases/testAMRandLoadBalancing/damBreakWithObstacle + +- However when writing V0 we noticed a nan in the V0 field. + (this doesn't get written anymore but it might indicate a bug) + + +1) Tried moving additional mapping of surface fields to + + virtual dynamicRefineFvMesh::mapFields(const mapPolyMesh&); + +so it would get called from the fvMesh::updateMesh. However +this mapping (explicitly) gets done using unadapted addressing +and it causes the cell addressing to be wrong: + + +[1] --> FOAM FATAL ERROR: +[1] index 826015320 out of range 0 ... 71079 +[1] +[1] From function void Foam::UList<T>::checkIndex(Foam::label) const [with T = Foam::cell; Foam::label = int] +[1] in file /home/preston2/mattijs/OpenFOAM/work/OpenFOAM-plus.integration-TUD/src/OpenFOAM/lnInclude/UListI.H at line 106. + + +From dynamicRefineFvMesh::mapNewInternalFaces : (I think) + + cell faceOwner = this->cells()[owner[facei]]; + +So this adaptation should be done in a separate pass + + +2) Mapping new internal faces: +- currently done by averaging the values of 'properly' mapped + faces from owner and neighbour. +- this would not work if a cell gets split into 3x3x3 +- instead this should be done by some geometric interpolation + from point values? +- have selection mechanism instead or use oriented flag on surfaceFields + +3) Current averaging is valid only for internal faces & only scalar/vector diff --git a/src/dynamicFvMesh/Make/files b/src/dynamicFvMesh/Make/files index b8432c07c905108747f9b94eb4cffefd26d1e0bd..bb04e8ac64705ac6dc159ca970a4bc5dc7320ca9 100644 --- a/src/dynamicFvMesh/Make/files +++ b/src/dynamicFvMesh/Make/files @@ -5,6 +5,7 @@ dynamicMotionSolverFvMesh/dynamicMotionSolverFvMesh.C dynamicMultiMotionSolverFvMesh/dynamicMultiMotionSolverFvMesh.C dynamicInkJetFvMesh/dynamicInkJetFvMesh.C dynamicRefineFvMesh/dynamicRefineFvMesh.C +dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.C dynamicMotionSolverListFvMesh/dynamicMotionSolverListFvMesh.C simplifiedDynamicFvMesh/simplifiedDynamicFvMeshes.C diff --git a/src/dynamicFvMesh/Make/options b/src/dynamicFvMesh/Make/options index 3540c13bfc8d77a85b5642874b6806561cfdacd8..718fde7d5c5de0e42db7e1a715730dd1bcc68f47 100644 --- a/src/dynamicFvMesh/Make/options +++ b/src/dynamicFvMesh/Make/options @@ -1,10 +1,13 @@ EXE_INC = \ + -g -DFULLDEBUG -O0 -g \ + -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \ -I$(LIB_SRC)/surfMesh/lnInclude \ -I$(LIB_SRC)/meshTools/lnInclude \ -I$(LIB_SRC)/dynamicMesh/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude LIB_LIBS = \ + -ldecompositionMethods \ -lmeshTools \ -ldynamicMesh \ -lfiniteVolume diff --git a/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/balanceParDict b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/balanceParDict new file mode 100644 index 0000000000000000000000000000000000000000..08d1ef65388aa50771de1f3b78493a2d4bbdad0b --- /dev/null +++ b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/balanceParDict @@ -0,0 +1,29 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: 2.1.1 | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object balanceParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +numberOfSubdomains 2; + +method ptscotch; + +constraints +{ + refinementHistory + { + type refinementHistory; + } +} +// ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicMeshDict b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..a8df1cb7efa27c0931063127ac6dd3d65dd2cefc --- /dev/null +++ b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicMeshDict @@ -0,0 +1,125 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: dev | +| \\ / A nd | Web: www.OpenFOAM.org | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dynamicFvMesh dynamicRefineBalancedFvMesh; + +refinementControls +{ + enableRefinementControl true; + + fields // must be scalarFields + ( + //alpha (min max refineLevel) + alpha (0.01 0.99 2) // refine cells where alpha in [0.01:0.99] with maximal 2 refinement layers + ); + + interface // must be a scalarField (only one dictionary!) + ( + alpha // refine interface (found based on snGrad of alpha > 0.1) + { + innerRefLayers 2; // describes how many cell layers inside phase alpha are to be refined + outerRefLayers 5; // describes how many cell layers outside phase alpha are to be refined + + // optional settings: + maxRefineLevel 4; // max refinement layers; Default: maxRefinement from dynamicRefineFvMeshCoeffs is used + // to get slower than 2:1 refinement; add #nAddLayers between each refinement level at the interface + nAddLayers 1; //Default: 0 + } + ); + + gradients // must be scalars + ( + // arguments as in 'fields' + // min/max values are based on mag(fvc::grad(volScalarField)) * cellVolume + T (0.01 10 1) + ); + + curls // must be vectors + ( + // arguments as in 'fields' + // min/max values are based on mag(fvc::curl(volVectorField)) + U (0.5 1 2) + ); + + regions + ( + boxToCell + { + minLevel 1; + + box (-1 0.001 0.002)(1 0.005 0.003); + } + + ); +} + +dynamicRefineFvMeshCoeffs +{ + // Extra entries for balancing + enableBalancing true; + allowableImbalance 0.15; + + // How often to refine + refineInterval 10; + + // Field to be refinement on (set it to 'internalRefinementField' to use the + // refinementControls dictionary entries above) + field internalRefinementField; + + // Refine field inbetween lower..upper + lowerRefineLevel 0.5; // do not change + upperRefineLevel 3.5; // maxRefinement+0.5 + + // If value < unrefineLevel unrefine + unrefineLevel -0.5; // do not change + + // Have slower than 2:1 refinement + nBufferLayers 4; + + // Refine cells only up to maxRefinement levels + maxRefinement 3; + + // Stop refinement if maxCells reached + maxCells 200000; + + // Flux field and corresponding velocity field. Fluxes on changed + // faces get recalculated by interpolating the velocity. Use 'none' + // on surfaceScalarFields that do not need to be reinterpolated. + correctFluxes + ( + (phi Urel) + (phiAbs U) + (phiAbs_0 U_0) + (nHatf none) + (rho*phi none) + (ghf none) + ); + + // List of non-flux surface<Type>Fields to be mapped + // only for new internal faces (AMR refine) + mapSurfaceFields + ( + Uf + Uf_0 + ); + + // Write the refinement level as a volScalarField + dumpLevel true; +} + + +// ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.C b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.C new file mode 100644 index 0000000000000000000000000000000000000000..d5098ffe6805cbe0c7b58dd3c47c91423036ca70 --- /dev/null +++ b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.C @@ -0,0 +1,843 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2014 Tyler Voskuilen + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is a derivative work 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 "dynamicRefineBalancedFvMesh.H" +#include "addToRunTimeSelectionTable.H" +#include "surfaceInterpolate.H" +#include "volFields.H" +#include "polyTopoChange.H" +#include "surfaceFields.H" +#include "syncTools.H" +#include "pointFields.H" +#include "fvCFD.H" +#include "volPointInterpolation.H" +#include "pointMesh.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(dynamicRefineBalancedFvMesh, 0); + addToRunTimeSelectionTable(dynamicFvMesh, dynamicRefineBalancedFvMesh, IOobject); +} + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // +Foam::label Foam::dynamicRefineBalancedFvMesh::topParentID(label p) +{ + label nextP = meshCutter().history().splitCells()[p].parent_; + if( nextP < 0 ) + { + return p; + } + else + { + return topParentID(nextP); + } +} + +Foam::List<Foam::scalar> Foam::dynamicRefineBalancedFvMesh::readRefinementPoints() +{ + dictionary refineDict + ( + IOdictionary + ( + IOobject + ( + "dynamicMeshDict", + time().constant(), + *this, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE, + false + ) + ).subDict("dynamicRefineFvMeshCoeffs") + ); + + List<scalar> refData(4, scalar(0)); + + refData[0] = readScalar(refineDict.lookup("unrefineLevel")); + refData[1] = readScalar(refineDict.lookup("lowerRefineLevel")); + refData[2] = readScalar(refineDict.lookup("refineInterval")); + refData[3] = readScalar(refineDict.lookup("maxRefinement")); + + return refData; +} + +void Foam::dynamicRefineBalancedFvMesh::updateRefinementField() +{ + Info<< "Calculating internal refinement field" << endl; + + volScalarField& intRefFld = *internalRefinementFieldPtr_; + volScalarField& targetFld = *targetLevelPtr_; + volScalarField& currFld = *isLevelPtr_; + + // Set the internal refinement field to zero to start with + intRefFld = dimensionedScalar("zero",dimless,0.0); + + // Get the cell level field from dynamicRefineFvMesh + const labelList& cellLevel = meshCutter().cellLevel(); + + // Read the points at which refinement and unrefinement occur from the + // dynamicMeshDict entries + List<scalar> refinePoints = readRefinementPoints(); + + // init list for refine/unrefine field (-1=unrefine, 1=refine, 0=do nothing) + labelList markRefineCells (this->nCells(), 0); + + // init list for target refinement level per cell + labelList targetLevel (this->nCells(), 0); + + // First fields + List<word> fieldNames = fields_.toc(); + Field<scalar> refFld(nCells(),0.0); + + forAll(fieldNames, i) + { + word fldName = fieldNames[i]; + scalar minValue = fields_[fldName][0]; + scalar maxValue = fields_[fldName][1]; + label refineLevel = static_cast<label>(fields_[fldName][2]); + + const volScalarField& fld = this->lookupObject<volScalarField>(fldName); + + // Limit the value of refFld based on its max level + forAll(fld, cellI) + { + if ((fld[cellI] >= minValue) && (fld[cellI] <= maxValue)) + { + // increase targetLevel up to refineLevel + // BUT: do not decrease if cell already marked for higher refinement level by previous criterion + targetLevel[cellI] = max(targetLevel[cellI], refineLevel); + } + } + } + + // Then gradients + List<word> gradFieldNames = gradFields_.toc(); + + Field<scalar> cubeRtV = Foam::pow(this->V(),1.0/3.0); + + forAll(gradFieldNames, i) + { + word fldName = gradFieldNames[i]; + scalar minValue = gradFields_[fldName][0]; + scalar maxValue = gradFields_[fldName][1]; + label refineLevel = static_cast<label>(gradFields_[fldName][2]); + + const volScalarField& fld = this->lookupObject<volScalarField>(fldName); + + refFld = mag(fvc::grad(fld)) * cubeRtV; + + // Limit the value of refFld based on its max level + forAll(refFld, cellI) + { + if ((refFld[cellI] >= minValue) && (refFld[cellI] <= maxValue)) + { + targetLevel[cellI] = max(targetLevel[cellI], refineLevel); + } + } + } + + // Then curls + List<word> curlFieldNames = curlFields_.toc(); + + + forAll(curlFieldNames, i) + { + word fldName = curlFieldNames[i]; + scalar minValue = curlFields_[fldName][0]; + scalar maxValue = curlFields_[fldName][1]; + label refineLevel = static_cast<label>(curlFields_[fldName][2]); + + const volVectorField& fld = this->lookupObject<volVectorField>(fldName); + + refFld = mag(fvc::curl(fld)); + + // Limit the value of refFld based on its max level + forAll(refFld, cellI) + { + if ((refFld[cellI] >= minValue) && (refFld[cellI] <= maxValue)) + { + targetLevel[cellI] = max(targetLevel[cellI], refineLevel); + } + } + } + + // At the interface, assumed to be always the maximum refinement level + List<word> interfaceRefineField = interface_.toc(); + forAll(interfaceRefineField, i) + { + word fldName = interfaceRefineField[i]; + // read region of maximum refinement levels inside and outside of interface indicator field + // (does not need to be alpha, can also be a concentration field) + + scalar innerRefLayers = readScalar(interface_[fldName].lookup("innerRefLayers")); + scalar outerRefLayers = readScalar(interface_[fldName].lookup("outerRefLayers")); + + scalar nAddLayers(0); + if (interface_[fldName].found("nAddLayers")) + { + nAddLayers = readScalar(interface_[fldName].lookup("nAddLayers")); + } + + label refineLevel = refinePoints[3]; + + if (interface_[fldName].found("maxRefineLevel")) + { + refineLevel = readScalar(interface_[fldName].lookup("maxRefineLevel")); + + // to avoid user input mistakes, limit the value with the maximum allowed + refineLevel = min(refinePoints[3], refineLevel); + } + + const volScalarField& fld = this->lookupObject<volScalarField>(fldName); + + volScalarField isInterface(intRefFld * 0.0); + isInterface = dimensionedScalar("isInterface",dimless,0.0); + + surfaceScalarField deltaAlpha = mag(fvc::snGrad(fld) / this->deltaCoeffs()); + + const labelUList& owner = this->owner(); + const labelUList& neighbour = this->neighbour(); + + forAll(deltaAlpha, faceI) + { + //TODO: add a min max value of the specified field to be marked for refinement + // NOW: hard-coded method snGradAlpha: checks mag(alpha_N - alpha_P) > 0.1 ? 1:0 + if (deltaAlpha[faceI] > 0.1) // currently a fixed prescribed value; should be read from dÃctionary + { + label own = owner[faceI]; + label nei = neighbour[faceI]; + + // set isInterface field to one + isInterface[own] = 1.0; + isInterface[nei] = 1.0; + } + } + + // assumed fld=0.5*(fldMax+fldMin) defines the interface + dimensionedScalar fldInterfaceValue(0.5*(max(fld)+min(fld))); + + //-DD: old implementation based on face interpolation + // which results in slower transport in diagonal direction + // add inner refinement layers + //for(label i=0; i < innerRefLayers; i++) + //{ + // isInterface += neg(- fvc::average(fvc::interpolate(isInterface)) * pos(fld - fldInterfaceValue)); + // isInterface = neg(- isInterface); + //} + // + // add outer refinement layers + //for(label i=0; i < outerRefLayers; i++) + //{ + // isInterface += neg(- fvc::average(fvc::interpolate(isInterface)) * pos(fldInterfaceValue - fld)); + // isInterface = neg(- isInterface); + //} + // + //forAll(isInterface, cellI) + //{ + // if (isInterface[cellI] > 0.5) + // { + // targetLevel[cellI] = max(targetLevel[cellI], refineLevel); + // } + //} + + //-DD: new version using volPointInterpolation (direction independent buffer layer) + const volPointInterpolation& pInterp = volPointInterpolation::New(*this); + const fvMesh& mesh = fld.mesh(); + + // add inner refinement layers + for(label i=0; i < innerRefLayers; i++) + { + volScalarField markInner(isInterface*pos(fld - fldInterfaceValue)); + pointScalarField markLayerP(pInterp.interpolate(markInner)); + + forAll(mesh.C(), cellI) + { + scalar sum = 0.; + label nPoints = 0; + + forAll(mesh.cellPoints()[cellI], pointI) + { + sum += markLayerP[mesh.cellPoints()[cellI][pointI]]; + nPoints++; + } + if (nPoints > 0) + { + sum /= nPoints; + } + isInterface[cellI] += sum; + } + } + isInterface = pos(isInterface - SMALL); + + // add outer refinement layers + for(label i=0; i < outerRefLayers; i++) + { + volScalarField markOuter(isInterface*pos(fldInterfaceValue - fld)); + pointScalarField markLayerP(pInterp.interpolate(markOuter)); + + forAll(mesh.C(), cellI) + { + scalar sum = 0.; + label nPoints = 0; + + forAll(mesh.cellPoints()[cellI], pointI) + { + sum += markLayerP[mesh.cellPoints()[cellI][pointI]]; + nPoints++; + } + if (nPoints > 0) + { + sum /= nPoints; + } + isInterface[cellI] += sum; + } + } + isInterface = pos(isInterface - SMALL); + + forAll(isInterface, cellI) + { + if (isInterface[cellI] > 0.5) + { + targetLevel[cellI] = max(targetLevel[cellI], refineLevel); + } + } + + //-DD: old implementation based on face interpolation + // which results in slower transport in diagonal direction + // expand additional layers if specified: + if (nAddLayers > 0) + { + // loop over additional layers + for(label i=1; i < refineLevel; i++) + { + // #nAddLayers cells per additional level + for(label j=0; j < nAddLayers; j++) + { + isInterface += neg(- fvc::average(fvc::interpolate(isInterface))); + isInterface = neg(- isInterface); + } + + forAll(isInterface, cellI) + { + if (isInterface[cellI] == 1.0) + { + targetLevel[cellI] = max(targetLevel[cellI], (refineLevel - i)); + } + } + } + } + } + + // The set refinement physical regions (force the mesh to stay refined + // near key features) + forAll(refinedRegions_, regionI) + { + const entry& region = refinedRegions_[regionI]; + + autoPtr<topoSetSource> source = + topoSetSource::New(region.keyword(), *this, region.dict()); + + cellSet selectedCellSet + ( + *this, + "cellSet", + nCells()/10+1 //estimate + ); + + source->applyToSet + ( + topoSetSource::NEW, + selectedCellSet + ); + + const labelList cells = selectedCellSet.toc(); + + label minLevel = readLabel(region.dict().lookup("minLevel")); + + forAll(cells, i) + { + const label& cellI = cells[i]; + + targetLevel[cellI] = max(targetLevel[cellI], minLevel); + } + } + + //-DD: add buffer layer based on targetLevel field to prevent 2-to-1 refinement + + volScalarField blockedLevel = targetFld * 0.; + + for (label currLayer=refinePoints[3]; currLayer>=1; currLayer--) + { + forAll (targetLevel, cellI) + { + if (targetLevel[cellI] >= currLayer) + { + blockedLevel[cellI] = targetLevel[cellI]; + } + } + + for (label i=0; i<nBufferLayers_; i++) + { + blockedLevel = max(blockedLevel, pos(fvc::average(fvc::interpolate(blockedLevel)) - SMALL)*(currLayer-1)); + } + + labelList blockLev(blockedLevel.internalField().size(), 0); + forAll (blockLev, cellI) + { + blockLev[cellI] = blockedLevel[cellI]; + } + targetLevel = max(targetLevel, blockLev); + } + + // mark cells to be refined/unrefined based on above criteria: + // simply check, if targetLevel lower or higher cellLevel + forAll (intRefFld.internalField(), cellI) + { + intRefFld.primitiveFieldRef()[cellI] = targetLevel[cellI] - cellLevel[cellI]; + targetFld.primitiveFieldRef()[cellI] = targetLevel[cellI]; + currFld.primitiveFieldRef()[cellI] = cellLevel[cellI]; + } + + intRefFld.correctBoundaryConditions(); + + Info<<"Min,max refinement field = " << Foam::min(intRefFld).value() << ", " + << Foam::max(intRefFld).value() << endl; +} + +void Foam::dynamicRefineBalancedFvMesh::readRefinementDict() +{ + dictionary dynamicMeshDict + ( + IOdictionary + ( + IOobject + ( + "dynamicMeshDict", + time().constant(), + *this, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE, + false + ) + ) + ); + + const dictionary refineDict + ( + IOdictionary + ( + IOobject + ( + "dynamicMeshDict", + time().constant(), + *this, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE, + false + ) + ).subDict("dynamicRefineFvMeshCoeffs") + ); + + { + wordList surfFlds; + if (refineDict.readIfPresent("mapSurfaceFields", surfFlds)) + { + // Rework into hashtable. + mapSurfaceFields_.resize(surfFlds.size()); + forAll(surfFlds, i) + { + mapSurfaceFields_.insert(surfFlds[i], surfFlds[i]); + } + } + } + + nBufferLayers_ = readLabel(refineDict.lookup("nBufferLayers")); + + if( dynamicMeshDict.isDict("refinementControls") ) + { + dictionary refineControlDict = + dynamicMeshDict.subDict("refinementControls"); + + enableRefinementControl_ = + Switch(refineControlDict.lookup("enableRefinementControl")); + + if( enableRefinementControl_ ) + { + // Overwrite field name entry in dynamicRefineFvMeshCoeffs? + // For now you just have to be smart and enter + // 'internalRefinementField' for the field name manually + + // Read HashTable of field-refinement scalars + if( refineControlDict.found("fields") ) + { + fields_ = HashTable< List<scalar> > + ( + refineControlDict.lookup("fields") + ); + } + + // Read HashTable of gradient-refinement scalars + if( refineControlDict.found("gradients") ) + { + gradFields_ = HashTable< List<scalar> > + ( + refineControlDict.lookup("gradients") + ); + } + + // Read HashTable of curl-refinement vectors + if( refineControlDict.found("curls") ) + { + curlFields_ = HashTable< List<scalar> > + ( + refineControlDict.lookup("curls") + ); + } + + // Read interface refinement data + if( refineControlDict.found("interface") ) + { + interface_ = HashTable< dictionary > + ( + refineControlDict.lookup("interface") + ); + } + + // Read refinement regions + if( refineControlDict.found("regions") ) + { + refinedRegions_ = PtrList<entry> + ( + refineControlDict.lookup("regions") + ); + } + } + } +} + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::dynamicRefineBalancedFvMesh::dynamicRefineBalancedFvMesh +( + const IOobject& io +) +: + dynamicRefineFvMesh(io), + internalRefinementFieldPtr_(NULL), + targetLevelPtr_(NULL), + isLevelPtr_(NULL), + fields_(), + gradFields_(), + curlFields_(), + interface_(), + refinedRegions_(), + enableRefinementControl_(false), + nBufferLayers_(0), + rebalance_(false) +{ + readRefinementDict(); + + if( enableRefinementControl_ ) + { + internalRefinementFieldPtr_ = new volScalarField + ( + IOobject + ( + "internalRefinementField", + time().timeName(), + *this, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + *this, + dimensionedScalar("zero", dimless, 0.0) + ); + + targetLevelPtr_ = new volScalarField + ( + IOobject + ( + "targetLevel", + time().timeName(), + *this, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + *this, + dimensionedScalar("zero", dimless, 0.0) + ); + + isLevelPtr_ = new volScalarField + ( + IOobject + ( + "isLevel", + time().timeName(), + *this, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), + *this, + dimensionedScalar("zero", dimless, 0.0) + ); + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::dynamicRefineBalancedFvMesh::~dynamicRefineBalancedFvMesh() +{ + +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::dynamicRefineBalancedFvMesh::mapFields(const mapPolyMesh& mpm) +{ +DebugVar(mpm.nOldCells()); + dynamicRefineFvMesh::mapFields(mpm); + + // Correct surface fields on introduced internal faces. These get + // created out-of-nothing so get an interpolated value. + mapNewInternalFaces<scalar>(mpm.faceMap()); + mapNewInternalFaces<vector>(mpm.faceMap()); + mapNewInternalFaces<sphericalTensor>(mpm.faceMap()); + mapNewInternalFaces<symmTensor>(mpm.faceMap()); + mapNewInternalFaces<tensor>(mpm.faceMap()); +} + + +bool Foam::dynamicRefineBalancedFvMesh::update() +{ + //Part 0 - Update internally calculated refinement field + readRefinementDict(); + + List<scalar> refinePoints = readRefinementPoints(); + label refineInterval = refinePoints[2]; + + if( enableRefinementControl_ && time().timeIndex() > 0 && time().timeIndex() % refineInterval == 0 ) + { + updateRefinementField(); + } + + //Part 1 - Call normal update from dynamicRefineFvMesh + bool hasChanged = dynamicRefineFvMesh::update(); + + if( Pstream::parRun() && hasChanged) + { + //Correct values on all coupled patches + correctBoundaries<scalar>(); + correctBoundaries<vector>(); + correctBoundaries<sphericalTensor>(); + correctBoundaries<symmTensor>(); + correctBoundaries<tensor>(); + } + + dictionary decomposeParDict + ( + IOdictionary + ( + IOobject + ( + "decomposeParDict", + time().system(), + *this, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE, + false + ) + ) + ); + + rebalance_ = false; + + // Part 2 - Load Balancing + { + dictionary refineDict + ( + IOdictionary + ( + IOobject + ( + "dynamicMeshDict", + time().constant(), + *this, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE, + false + ) + ).subDict("dynamicRefineFvMeshCoeffs") + ); + + Switch enableBalancing = refineDict.lookup("enableBalancing"); + + if ( Pstream::parRun() && hasChanged ) + { + const scalar allowableImbalance = + readScalar(refineDict.lookup("allowableImbalance")); + + //First determine current level of imbalance - do this for all + // parallel runs with a changing mesh, even if balancing is disabled + label nGlobalCells = globalData().nTotalCells(); + scalar idealNCells = scalar(nGlobalCells)/scalar(Pstream::nProcs()); + scalar localImbalance = mag(scalar(nCells()) - idealNCells); + Foam::reduce(localImbalance, maxOp<scalar>()); + scalar maxImbalance = localImbalance/idealNCells; + + Info<<"Maximum imbalance = " << 100*maxImbalance << " %" << endl; + + //If imbalanced, construct weighted coarse graph (level 0) with node + // weights equal to their number of subcells. This partitioning works + // as long as the number of level 0 cells is several times greater than + // the number of processors. + if( maxImbalance > allowableImbalance && enableBalancing) + { + Info << "\n**Solver hold for redistribution at time = " << time().timeName() << " s" << endl; + + rebalance_ = true; + + const labelIOList& cellLevel = meshCutter().cellLevel(); + Map<label> coarseIDmap(100); + labelList uniqueIndex(nCells(),0); + + label nCoarse = 0; + + forAll(cells(), cellI) + { + if( cellLevel[cellI] > 0 ) + { + uniqueIndex[cellI] = nCells() + topParentID + ( + meshCutter().history().parentIndex(cellI) + ); + } + else + { + uniqueIndex[cellI] = cellI; + } + + if( coarseIDmap.insert(uniqueIndex[cellI], nCoarse) ) + { + ++nCoarse; + } + } + + // Convert to local sequential indexing and calculate coarse + // points and weights + labelList localIndex(nCells(),0); + pointField coarsePoints(nCoarse,vector::zero); + scalarField coarseWeights(nCoarse,0.0); + + forAll(uniqueIndex, cellI) + { + localIndex[cellI] = coarseIDmap[uniqueIndex[cellI]]; + + // If 2D refinement (quadtree) is ever implemented, this '3' + // should be set in general as the number of refinement + // dimensions. + label w = (1 << (3*cellLevel[cellI])); + + coarseWeights[localIndex[cellI]] += 1.0; + coarsePoints[localIndex[cellI]] += C()[cellI]/w; + } + + // Set up decomposer - a separate dictionary is used here so + // you can use a simple partitioning for decomposePar and + // ptscotch for the rebalancing (or any chosen algorithms) + autoPtr<decompositionMethod> decomposer + ( + decompositionMethod::New + ( + IOdictionary + ( + IOobject + ( + "balanceParDict", + time().system(), + *this, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE + ) + ) + ) + ); + + labelList finalDecomp = decomposer().decompose + ( + *this, + localIndex, + coarsePoints, + coarseWeights + ); + + scalar tolDim = globalMeshData::matchTol_ * bounds().mag(); + + Info<< "Distributing the mesh ..." << endl; + fvMeshDistribute distributor(*this, tolDim); + + Info<< "Mapping the fields ..." << endl; + autoPtr<mapDistributePolyMesh> map = + distributor.distribute(finalDecomp); + + Info<< "Distribute the map ..." << endl; + meshCutter_.distribute(map); + + + Info << "Successfully distributed mesh" << endl; + + scalarList procLoadNew (Pstream::nProcs(), 0.0); + procLoadNew[Pstream::myProcNo()] = this->nCells(); + + reduce(procLoadNew, sumOp<List<scalar> >()); + + scalar overallLoadNew = sum(procLoadNew); + scalar averageLoadNew = overallLoadNew/double(Pstream::nProcs()); + + Info << "New distribution: " << procLoadNew << endl; + Info << "Max deviation: " << max(Foam::mag(procLoadNew-averageLoadNew)/averageLoadNew)*100.0 << " %" << endl; + } + } + } + + if( Pstream::parRun() && rebalance_) + { + //Correct values on all coupled patches + correctBoundaries<scalar>(); + correctBoundaries<vector>(); + correctBoundaries<sphericalTensor>(); + correctBoundaries<symmTensor>(); + correctBoundaries<tensor>(); + } + + return hasChanged; +} + + +// ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.H b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.H new file mode 100644 index 0000000000000000000000000000000000000000..f4944d5c850a8c0df73c88e02eeb1654bf4d7aa9 --- /dev/null +++ b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMesh.H @@ -0,0 +1,206 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2014 Tyler Voskuilen + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is a derivative work 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::dynamicRefineBalancedFvMesh + +SourceFiles + dynamicRefineBalancedFvMesh.C + dynamicRefineBalancedFvMeshTemplates.C + +Authors + T.G. Voskuilen ( https://github.com/tgvoskuilen/meshBalancing ) + Daniel Deising <deising@mma.tu-darmstadt.de> + Daniel Rettenmaier <rettenmaier@gsc.tu-darmstadt.de> + All rights reserved. + +Description + A fvMesh with built-in multi-criterion refinement + and run-time load balancing. + + You may refer to this software as : + //- full bibliographic data to be provided + + This code has been developed by : + Daniel Rettenmaier (main developer). + + Method Development and Intellectual Property : + T.G. Voskuilen (Purdue University) + Timothée Pourpoint <timothee@purdue.edu> (Purdue University + Daniel Rettenmaier <rettenmaier@gsc.tu-darmstadt.de> + Daniel Deising <deising@mma.tu-darmstadt.de> + Holger Marschall <marschall@csi.tu-darmstadt.de> + Dieter Bothe <bothe@csi.tu-darmstadt.de> + Cameron Tropea <ctropea@sla.tu-darmstadt.de> + + School of Aeronautics and Astronautics + Purdue University + Mathematical Modeling and Analysis + Institute for Fluid Mechanics and Aerodynamics + Center of Smart Interfaces + Technische Universitaet Darmstadt + + If you use this software for your scientific work or your publications, + please don't forget to acknowledge explicitly the use of it. + +\*---------------------------------------------------------------------------*/ + +#ifndef dynamicRefineBalancedFvMesh_H +#define dynamicRefineBalancedFvMesh_H + + +#include "dynamicFvMesh.H" +#include "dynamicRefineFvMesh.H" +#include "hexRef8.H" +#include "PackedBoolList.H" +#include "Switch.H" +#include "decompositionMethod.H" +#include "fvMeshDistribute.H" +#include "mapDistributePolyMesh.H" +#include "HashTable.H" +#include "topoSetSource.H" +#include "cellSet.H" +#include "PtrDictionary.H" +#include "dictionaryEntry.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class dynamicRefineBalancedFvMesh Declaration +\*---------------------------------------------------------------------------*/ + +class dynamicRefineBalancedFvMesh +: + public dynamicRefineFvMesh +{ + +private: + + //- (non-flux)SurfaceFields to map + HashTable<word> mapSurfaceFields_; + + //- + volScalarField* internalRefinementFieldPtr_; + volScalarField* targetLevelPtr_; + volScalarField* isLevelPtr_; + + //- + HashTable< List<scalar> > fields_; + + //- + HashTable< List<scalar> > gradFields_; + + //- + HashTable< List<scalar> > curlFields_; + + //- + HashTable< dictionary > interface_; + + //- + PtrList<entry> refinedRegions_; + + //- + Switch enableRefinementControl_; + + //- + void updateRefinementField(); + + //- + void readRefinementDict(); + + //- + List<scalar> readRefinementPoints(); + + //- Disallow default bitwise copy construct + dynamicRefineBalancedFvMesh(const dynamicRefineBalancedFvMesh&); + + //- Disallow default bitwise assignment + void operator=(const dynamicRefineBalancedFvMesh&); + + //- + label topParentID(label p); + + //- + label nBufferLayers_; + + //- + bool rebalance_; + + //- Map non-flux surface<Type>Fields for new internal faces + // (from cell splitting) + template <class T> + void mapNewInternalFaces(const labelList& faceMap); + + +public: + + //- Runtime type information + TypeName("dynamicRefineBalancedFvMesh"); + + + // Constructors + + //- Construct from IOobject + explicit dynamicRefineBalancedFvMesh(const IOobject& io); + + + //- Destructor + virtual ~dynamicRefineBalancedFvMesh(); + + + // Member Functions + + //- Update the mesh for both mesh motion and topology change + virtual bool update(); + + //- Map all fields in time using given map + virtual void mapFields(const mapPolyMesh& mpm); + + //- Template to update all volField boundaries + template<class Type> void correctBoundaries(); + + //- + bool rebalance() + { + return rebalance_; + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "dynamicRefineBalancedFvMeshTemplates.C" +#endif + +#endif + +// ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMeshTemplates.C b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMeshTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..200e3f831d3356fb5316e8785ae55715f6c4add3 --- /dev/null +++ b/src/dynamicFvMesh/dynamicRefineBalancedFvMesh/dynamicRefineBalancedFvMeshTemplates.C @@ -0,0 +1,217 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2014 Tyler Voskuilen + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "volMesh.H" +#include "fvPatchField.H" +#include "surfaceFields.H" + +template <class T> +void Foam::dynamicRefineBalancedFvMesh::mapNewInternalFaces +( + const labelList& faceMap +) +{ + typedef GeometricField<T, fvsPatchField, surfaceMesh> GeoField; + HashTable<GeoField*> sFlds(this->objectRegistry::lookupClass<GeoField>()); + + const labelUList& owner = this->faceOwner(); + const labelUList& neighbour = this->faceNeighbour(); + const dimensionedScalar deltaN = 1e-8 / pow(average(this->V()), 1.0 / 3.0); + + forAllIter(typename HashTable<GeoField*>, sFlds, iter) + { + GeoField& sFld = *iter(); + if (mapSurfaceFields_.found(iter.key())) + { + if (debug) + { + InfoInFunction << iter.key()<< endl; + } + + + // Create flat version of field + Field<T> tsFld(this->nFaces(), pTraits<T>::zero); + { + forAll(sFld.internalField(), iFace) + { + tsFld[iFace] = sFld.internalField()[iFace]; + } + forAll(sFld.boundaryField(), iPatch) + { + const fvsPatchField<T>& pfld = sFld.boundaryField()[iPatch]; + + label start = pfld.patch().start(); + forAll(pfld, faceI) + { + tsFld[faceI+start] = pfld[faceI]; + } + } + } + + + // Loop over all faces + for (label facei = 0; facei < nInternalFaces(); facei++) + { + label oldFacei = faceMap[facei]; + + //- map surface field on newly generated faces + if (oldFacei == -1) + { + //- find owner and neighbour cell + const cell& ownFaces = this->cells()[owner[facei]]; + const cell& neiFaces = this->cells()[neighbour[facei]]; + + //- loop over all owner/neighbour cell faces + //- and find already mapped ones (master-faces): + T tmpValue = pTraits<T>::zero; + scalar magFld = 0; + label counter = 0; + + //- simple averaging of all neighbour master-faces + forAll(ownFaces, iFace) + { + if (faceMap[ownFaces[iFace]] != -1) + { + tmpValue += tsFld[ownFaces[iFace]]; + magFld += mag(tsFld[ownFaces[iFace]]); + counter++; + } + } + + forAll(neiFaces, iFace) + { + if (faceMap[neiFaces[iFace]] != -1) + { + tmpValue = tmpValue + tsFld[neiFaces[iFace]]; + magFld += mag(tsFld[neiFaces[iFace]]); + counter++; + } + } + + if(counter > 0) + { + if + ( + GeometricField<T, fvsPatchField, surfaceMesh>::typeName + == "surfaceScalarField" + ) + { + tmpValue /= counter; + } + else if + ( + GeometricField<T, fvsPatchField, surfaceMesh>::typeName + == "surfaceVectorField" + ) + { + magFld /= counter; + tmpValue *= magFld/(mag(tmpValue)+deltaN.value()); + } + else + { + FatalErrorInFunction + << "mapping implementation only valid for" + << " scalar and vector fields! \n Field " + << sFld.name() << " is of type: " + << GeometricField<T, fvsPatchField, surfaceMesh>::typeName + << abort(FatalError); + } + } + + sFld[facei] = tmpValue; + } + } + } + } +} + + +template<class Type> +void Foam::dynamicRefineBalancedFvMesh::correctBoundaries() +{ + typedef GeometricField<Type, fvPatchField, volMesh> GeoField; + + HashTable<GeoField*> flds(this->objectRegistry::lookupClass<GeoField>()); + + forAllIter(typename HashTable<GeoField*>, flds, iter) + { + GeoField& fld = *iter(); + + //mimic "evaluate" but only for coupled patches (processor or cyclic) + // and only for blocking or nonBlocking comms (no scheduled comms) + if + ( + Pstream::defaultCommsType == Pstream::commsTypes::blocking + || Pstream::defaultCommsType == Pstream::commsTypes::nonBlocking + ) + { + label nReq = Pstream::nRequests(); + + forAll(fld.boundaryField(), patchi) + { + if(fld.boundaryField()[patchi].coupled()) + { + fld.boundaryFieldRef()[patchi].initEvaluate + ( + Pstream::defaultCommsType + ); + } + } + + // Block for any outstanding requests + if + ( + Pstream::parRun() + && Pstream::defaultCommsType == Pstream::commsTypes::nonBlocking + ) + { + Pstream::waitRequests(nReq); + } + + forAll(fld.boundaryField(), patchi) + { + if(fld.boundaryField()[patchi].coupled()) + { + fld.boundaryFieldRef()[patchi].evaluate + ( + Pstream::defaultCommsType + ); + } + } + } + else + { + //Scheduled patch updates not supported + FatalErrorIn + ( + "dynamicRefineBalancedFvMeshTemplates::correctBoundaries" + ) << "Unsuported communications type " + << Pstream::commsTypeNames[Pstream::defaultCommsType] + << exit(FatalError); + } + } +} + +// ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C index 466b7d4e5ef2a904e4ce8b5ea35623f0f002e495..91aad27d1eea8d8f94e4ce4d92038d50c6d1f1d5 100644 --- a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C +++ b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C @@ -46,7 +46,7 @@ namespace Foam Foam::label Foam::dynamicRefineFvMesh::count ( - const bitSet& l, + const PackedBoolList& l, const unsigned int val ) { @@ -58,9 +58,9 @@ Foam::label Foam::dynamicRefineFvMesh::count n++; } - // debug also serves to get-around Clang compiler trying to optimise + // debug also serves to get-around Clang compiler trying to optimsie // out this forAll loop under O3 optimisation - if (debug) + if (debug & 128) { Info<< "n=" << n << endl; } @@ -72,7 +72,7 @@ Foam::label Foam::dynamicRefineFvMesh::count void Foam::dynamicRefineFvMesh::calculateProtectedCells ( - bitSet& unrefineableCell + PackedBoolList& unrefineableCell ) const { if (protectedCell_.empty()) @@ -86,7 +86,7 @@ void Foam::dynamicRefineFvMesh::calculateProtectedCells unrefineableCell = protectedCell_; // Get neighbouring cell level - labelList neiLevel(nBoundaryFaces()); + labelList neiLevel(nFaces()-nInternalFaces()); for (label facei = nInternalFaces(); facei < nFaces(); facei++) { @@ -103,10 +103,9 @@ void Foam::dynamicRefineFvMesh::calculateProtectedCells forAll(faceNeighbour(), facei) { label own = faceOwner()[facei]; + bool ownProtected = unrefineableCell.get(own); label nei = faceNeighbour()[facei]; - - bool ownProtected = unrefineableCell.test(own); - bool neiProtected = unrefineableCell.test(nei); + bool neiProtected = unrefineableCell.get(nei); if (ownProtected && (cellLevel[nei] > cellLevel[own])) { @@ -120,7 +119,7 @@ void Foam::dynamicRefineFvMesh::calculateProtectedCells for (label facei = nInternalFaces(); facei < nFaces(); facei++) { label own = faceOwner()[facei]; - bool ownProtected = unrefineableCell.test(own); + bool ownProtected = unrefineableCell.get(own); if ( ownProtected @@ -142,14 +141,16 @@ void Foam::dynamicRefineFvMesh::calculateProtectedCells if (seedFace[facei]) { label own = faceOwner()[facei]; - if (unrefineableCell.set(own)) + if (unrefineableCell.get(own) == 0) { + unrefineableCell.set(own, 1); hasExtended = true; } label nei = faceNeighbour()[facei]; - if (unrefineableCell.set(nei)) + if (unrefineableCell.get(nei) == 0) { + unrefineableCell.set(nei, 1); hasExtended = true; } } @@ -159,8 +160,9 @@ void Foam::dynamicRefineFvMesh::calculateProtectedCells if (seedFace[facei]) { label own = faceOwner()[facei]; - if (unrefineableCell.set(own)) + if (unrefineableCell.get(own) == 0) { + unrefineableCell.set(own, 1); hasExtended = true; } } @@ -205,63 +207,27 @@ void Foam::dynamicRefineFvMesh::readDict() } -// Refines cells, maps fields and recalculates (an approximate) flux -Foam::autoPtr<Foam::mapPolyMesh> -Foam::dynamicRefineFvMesh::refine -( - const labelList& cellsToRefine -) +void Foam::dynamicRefineFvMesh::mapFields(const mapPolyMesh& mpm) { - // Mesh changing engine. - polyTopoChange meshMod(*this); - - // Play refinement commands into mesh changer. - meshCutter_.setRefinement(cellsToRefine, meshMod); - - // Create mesh (with inflation), return map from old to new mesh. - autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(*this, false); - mapPolyMesh& map = *mapPtr; - - Info<< "Refined from " - << returnReduce(map.nOldCells(), sumOp<label>()) - << " to " << globalData().nTotalCells() << " cells." << endl; - - if (debug) - { - // Check map. - for (label facei = 0; facei < nInternalFaces(); facei++) - { - label oldFacei = map.faceMap()[facei]; - - if (oldFacei >= nInternalFaces()) - { - FatalErrorInFunction - << "New internal face:" << facei - << " fc:" << faceCentres()[facei] - << " originates from boundary oldFace:" << oldFacei - << abort(FatalError); - } - } - } - - // // Remove the stored tet base points - // tetBasePtIsPtr_.clear(); - // // Remove the cell tree - // cellTreePtr_.clear(); - - // Update fields - updateMesh(map); - + dynamicFvMesh::mapFields(mpm); // Correct the flux for modified/added faces. All the faces which only // have been renumbered will already have been handled by the mapping. { - const labelList& faceMap = map.faceMap(); - const labelList& reverseFaceMap = map.reverseFaceMap(); + const labelList& faceMap = mpm.faceMap(); + const labelList& reverseFaceMap = mpm.reverseFaceMap(); // Storage for any master faces. These will be the original faces // on the coarse cell that get split into four (or rather the // master face gets modified and three faces get added from the master) - labelHashSet masterFaces(4*cellsToRefine.size()); + // Estimate number of faces created + labelHashSet masterFaces + ( + max + ( + mag(nFaces()-mpm.nOldFaces())/4, + nFaces()/100 + ) + ); forAll(faceMap, facei) { @@ -393,8 +359,10 @@ Foam::dynamicRefineFvMesh::refine } // Update master faces - for (const label facei : masterFaces) + forAllConstIter(labelHashSet, masterFaces, iter) { + label facei = iter.key(); + if (isInternalFace(facei)) { phi[facei] = phiU[facei]; @@ -415,6 +383,86 @@ Foam::dynamicRefineFvMesh::refine } } + // Correct the flux for injected faces - these are the faces which have + // no correspondence to the old mesh (i.e. added without a masterFace, edge + // or point). An example is the internal faces from hexRef8. + { + const labelList& faceMap = mpm.faceMap(); + + mapNewInternalFaces<scalar>(this->Sf(), this->magSf(), faceMap); + mapNewInternalFaces<vector>(this->Sf(), this->magSf(), faceMap); + + // No oriented fields of more complex type + mapNewInternalFaces<sphericalTensor>(faceMap); + mapNewInternalFaces<symmTensor>(faceMap); + mapNewInternalFaces<tensor>(faceMap); + } +} + + +// Refines cells, maps fields and recalculates (an approximate) flux +Foam::autoPtr<Foam::mapPolyMesh> +Foam::dynamicRefineFvMesh::refine +( + const labelList& cellsToRefine +) +{ + // Mesh changing engine. + polyTopoChange meshMod(*this); + + // Play refinement commands into mesh changer. + meshCutter_.setRefinement(cellsToRefine, meshMod); + + // Create mesh (with inflation), return map from old to new mesh. + //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true); + autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false); + + Info<< "Refined from " + << returnReduce(map().nOldCells(), sumOp<label>()) + << " to " << globalData().nTotalCells() << " cells." << endl; + + if (debug) + { + // Check map. + for (label facei = 0; facei < nInternalFaces(); facei++) + { + label oldFacei = map().faceMap()[facei]; + + if (oldFacei >= nInternalFaces()) + { + FatalErrorInFunction + << "New internal face:" << facei + << " fc:" << faceCentres()[facei] + << " originates from boundary oldFace:" << oldFacei + << abort(FatalError); + } + } + } + + // // Remove the stored tet base points + // tetBasePtIsPtr_.clear(); + // // Remove the cell tree + // cellTreePtr_.clear(); + + // Update fields + updateMesh(map); + + + // Move mesh + /* + pointField newPoints; + if (map().hasMotionPoints()) + { + newPoints = map().preMotionPoints(); + } + else + { + newPoints = points(); + } + movePoints(newPoints); + */ + + // Update numbering of cells/vertices. meshCutter_.updateMesh(map); @@ -422,12 +470,12 @@ Foam::dynamicRefineFvMesh::refine // Update numbering of protectedCell_ if (protectedCell_.size()) { - bitSet newProtectedCell(nCells()); + PackedBoolList newProtectedCell(nCells()); forAll(newProtectedCell, celli) { - const label oldCelli = map.cellMap()[celli]; - newProtectedCell.set(celli, protectedCell_.test(oldCelli)); + label oldCelli = map().cellMap()[celli]; + newProtectedCell.set(celli, protectedCell_.get(oldCelli)); } protectedCell_.transfer(newProtectedCell); } @@ -435,7 +483,7 @@ Foam::dynamicRefineFvMesh::refine // Debug: Check refinement levels (across faces only) meshCutter_.checkRefinementLevels(-1, labelList(0)); - return mapPtr; + return map; } @@ -482,21 +530,36 @@ Foam::dynamicRefineFvMesh::unrefine // Change mesh and generate map. - autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(*this, false); - mapPolyMesh& map = *mapPtr; + //autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true); + autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false); Info<< "Unrefined from " - << returnReduce(map.nOldCells(), sumOp<label>()) + << returnReduce(map().nOldCells(), sumOp<label>()) << " to " << globalData().nTotalCells() << " cells." << endl; // Update fields updateMesh(map); + + // Move mesh + /* + pointField newPoints; + if (map().hasMotionPoints()) + { + newPoints = map().preMotionPoints(); + } + else + { + newPoints = points(); + } + movePoints(newPoints); + */ + // Correct the flux for modified faces. { - const labelList& reversePointMap = map.reversePointMap(); - const labelList& reverseFaceMap = map.reverseFaceMap(); + const labelList& reversePointMap = map().reversePointMap(); + const labelList& reverseFaceMap = map().reverseFaceMap(); HashTable<surfaceScalarField*> fluxes ( @@ -585,14 +648,14 @@ Foam::dynamicRefineFvMesh::unrefine // Update numbering of protectedCell_ if (protectedCell_.size()) { - bitSet newProtectedCell(nCells()); + PackedBoolList newProtectedCell(nCells()); forAll(newProtectedCell, celli) { - label oldCelli = map.cellMap()[celli]; + label oldCelli = map().cellMap()[celli]; if (oldCelli >= 0) { - newProtectedCell.set(celli, protectedCell_.test(oldCelli)); + newProtectedCell.set(celli, protectedCell_.get(oldCelli)); } } protectedCell_.transfer(newProtectedCell); @@ -601,7 +664,7 @@ Foam::dynamicRefineFvMesh::unrefine // Debug: Check refinement levels (across faces only) meshCutter_.checkRefinementLevels(-1, labelList(0)); - return mapPtr; + return map; } @@ -688,7 +751,7 @@ void Foam::dynamicRefineFvMesh::selectRefineCandidates const scalar lowerRefineLevel, const scalar upperRefineLevel, const scalarField& vFld, - bitSet& candidateCell + PackedBoolList& candidateCell ) const { // Get error per cell. Is -1 (not to be refined) to >0 (to be refined, @@ -711,7 +774,7 @@ void Foam::dynamicRefineFvMesh::selectRefineCandidates { if (cellError[celli] > 0) { - candidateCell.set(celli); + candidateCell.set(celli, 1); } } } @@ -721,7 +784,7 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectRefineCells ( const label maxCells, const label maxRefinement, - const bitSet& candidateCell + const PackedBoolList& candidateCell ) const { // Every refined cell causes 7 extra cells @@ -731,7 +794,7 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectRefineCells // Mark cells that cannot be refined since they would trigger refinement // of protected cells (since 2:1 cascade) - bitSet unrefineableCell; + PackedBoolList unrefineableCell; calculateProtectedCells(unrefineableCell); // Count current selection @@ -748,8 +811,11 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectRefineCells if ( cellLevel[celli] < maxRefinement - && candidateCell.test(celli) - && !unrefineableCell.test(celli) + && candidateCell.get(celli) + && ( + unrefineableCell.empty() + || !unrefineableCell.get(celli) + ) ) { candidates.append(celli); @@ -766,8 +832,11 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectRefineCells if ( cellLevel[celli] == level - && candidateCell.test(celli) - && !unrefineableCell.test(celli) + && candidateCell.get(celli) + && ( + unrefineableCell.empty() + || !unrefineableCell.get(celli) + ) ) { candidates.append(celli); @@ -802,7 +871,7 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectRefineCells Foam::labelList Foam::dynamicRefineFvMesh::selectUnrefinePoints ( const scalar unrefineLevel, - const bitSet& markedCell, + const PackedBoolList& markedCell, const scalarField& pFld ) const { @@ -815,7 +884,7 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectUnrefinePoints // If we have any protected cells make sure they also are not being // unrefined - bitSet protectedPoint(nPoints()); + PackedBoolList protectedPoint(nPoints()); if (protectedCell_.size()) { @@ -828,9 +897,9 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectUnrefinePoints { label cellI = pCells[pCellI]; - if (protectedCell_.test(cellI)) + if (protectedCell_[cellI]) { - protectedPoint.set(pointI); + protectedPoint[pointI] = true; break; } } @@ -870,7 +939,7 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectUnrefinePoints forAll(pCells, pCelli) { - if (markedCell.test(pCells[pCelli])) + if (markedCell.get(pCells[pCelli])) { hasMarked = true; break; @@ -907,7 +976,7 @@ Foam::labelList Foam::dynamicRefineFvMesh::selectUnrefinePoints void Foam::dynamicRefineFvMesh::extendMarkedCells ( - bitSet& markedCell + PackedBoolList& markedCell ) const { // Mark faces using any marked cell @@ -915,7 +984,7 @@ void Foam::dynamicRefineFvMesh::extendMarkedCells forAll(markedCell, celli) { - if (markedCell.test(celli)) + if (markedCell.get(celli)) { const cell& cFaces = cells()[celli]; @@ -933,15 +1002,15 @@ void Foam::dynamicRefineFvMesh::extendMarkedCells { if (markedFace[facei]) { - markedCell.set(faceOwner()[facei]); - markedCell.set(faceNeighbour()[facei]); + markedCell.set(faceOwner()[facei], 1); + markedCell.set(faceNeighbour()[facei], 1); } } for (label facei = nInternalFaces(); facei < nFaces(); facei++) { if (markedFace[facei]) { - markedCell.set(faceOwner()[facei]); + markedCell.set(faceOwner()[facei], 1); } } } @@ -949,7 +1018,7 @@ void Foam::dynamicRefineFvMesh::extendMarkedCells void Foam::dynamicRefineFvMesh::checkEightAnchorPoints ( - bitSet& protectedCell, + PackedBoolList& protectedCell, label& nProtected ) const { @@ -971,7 +1040,7 @@ void Foam::dynamicRefineFvMesh::checkEightAnchorPoints // Check if cell has already 8 anchor points -> protect cell if (nAnchorPoints[celli] == 8) { - if (protectedCell.set(celli)) + if (protectedCell.set(celli, true)) { nProtected++; } @@ -988,9 +1057,9 @@ void Foam::dynamicRefineFvMesh::checkEightAnchorPoints forAll(protectedCell, celli) { - if (!protectedCell.test(celli) && nAnchorPoints[celli] != 8) + if (!protectedCell[celli] && nAnchorPoints[celli] != 8) { - protectedCell.set(celli); + protectedCell.set(celli, true); nProtected++; } } @@ -1005,7 +1074,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) meshCutter_(*this), dumpLevel_(false), nRefinementIterations_(0), - protectedCell_(nCells(), false) + protectedCell_(nCells(), 0) { // Read static part of dictionary readDict(); @@ -1034,7 +1103,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) { label celli = pCells[i]; - if (!protectedCell_.test(celli)) + if (!protectedCell_.get(celli)) { if (pointLevel[pointi] <= cellLevel[celli]) { @@ -1042,7 +1111,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) if (nAnchors[celli] > 8) { - protectedCell_.set(celli); + protectedCell_.set(celli, 1); nProtected++; } } @@ -1105,9 +1174,9 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) { if (protectedFace[facei]) { - protectedCell_.set(faceOwner()[facei]); + protectedCell_.set(faceOwner()[facei], 1); nProtected++; - protectedCell_.set(faceNeighbour()[facei]); + protectedCell_.set(faceNeighbour()[facei], 1); nProtected++; } } @@ -1115,7 +1184,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) { if (protectedFace[facei]) { - protectedCell_.set(faceOwner()[facei]); + protectedCell_.set(faceOwner()[facei], 1); nProtected++; } } @@ -1127,7 +1196,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) if (cFaces.size() < 6) { - if (protectedCell_.set(celli)) + if (protectedCell_.set(celli, 1)) { nProtected++; } @@ -1138,7 +1207,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) { if (faces()[cFaces[cFacei]].size() < 4) { - if (protectedCell_.set(celli)) + if (protectedCell_.set(celli, 1)) { nProtected++; } @@ -1158,6 +1227,7 @@ Foam::dynamicRefineFvMesh::dynamicRefineFvMesh(const IOobject& io) } else { + cellSet protectedCells(*this, "protectedCells", nProtected); forAll(protectedCell_, celli) { @@ -1188,9 +1258,9 @@ Foam::dynamicRefineFvMesh::~dynamicRefineFvMesh() bool Foam::dynamicRefineFvMesh::update() { - // Re-read dictionary. Usually small so takes trivial amount of time - // compared to actual refinement. Also very useful to be able to modify - // on-the-fly. + // Re-read dictionary. Choosen since usually -small so trivial amount + // of time compared to actual refinement. Also very useful to be able + // to modify on-the-fly. dictionary refineDict ( IOdictionary @@ -1264,18 +1334,16 @@ bool Foam::dynamicRefineFvMesh::update() refineDict.get<scalar>("lowerRefineLevel"); const scalar upperRefineLevel = refineDict.get<scalar>("upperRefineLevel"); - const scalar unrefineLevel = refineDict.lookupOrDefault<scalar> ( "unrefineLevel", GREAT ); - const label nBufferLayers = refineDict.get<label>("nBufferLayers"); // Cells marked for refinement or otherwise protected from unrefinement. - bitSet refineCell(nCells()); + PackedBoolList refineCell(nCells()); // Determine candidates for refinement (looking at field only) selectRefineCandidates @@ -1316,7 +1384,7 @@ bool Foam::dynamicRefineFvMesh::update() const labelList& cellMap = map().cellMap(); const labelList& reverseCellMap = map().reverseCellMap(); - bitSet newRefineCell(cellMap.size()); + PackedBoolList newRefineCell(cellMap.size()); forAll(cellMap, celli) { @@ -1324,15 +1392,15 @@ bool Foam::dynamicRefineFvMesh::update() if (oldCelli < 0) { - newRefineCell.set(celli); + newRefineCell.set(celli, 1); } else if (reverseCellMap[oldCelli] != celli) { - newRefineCell.set(celli); + newRefineCell.set(celli, 1); } else { - newRefineCell.set(celli, refineCell.test(oldCelli)); + newRefineCell.set(celli, refineCell.get(oldCelli)); } } refineCell.transfer(newRefineCell); @@ -1380,7 +1448,7 @@ bool Foam::dynamicRefineFvMesh::update() if ((nRefinementIterations_ % 10) == 0) { - // Compact refinement history occasionally (how often?). + // Compact refinement history occassionally (how often?). // Unrefinement causes holes in the refinementHistory. const_cast<refinementHistory&>(meshCutter().history()).compact(); } @@ -1403,8 +1471,7 @@ bool Foam::dynamicRefineFvMesh::writeObject ( IOstream::streamFormat fmt, IOstream::versionNumber ver, - IOstream::compressionType cmp, - const bool valid + IOstream::compressionType cmp ) const { // Force refinement data to go to the current time directory. @@ -1412,8 +1479,8 @@ bool Foam::dynamicRefineFvMesh::writeObject bool writeOk = ( - dynamicFvMesh::writeObject(fmt, ver, cmp, valid) - && meshCutter_.write(valid) + dynamicFvMesh::writeObject(fmt, ver, cmp) + && meshCutter_.write() ); if (dumpLevel_) @@ -1430,7 +1497,7 @@ bool Foam::dynamicRefineFvMesh::writeObject false ), *this, - dimensionedScalar(dimless, Zero) + dimensionedScalar("level", dimless, 0) ); const labelList& cellLevel = meshCutter_.cellLevel(); diff --git a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.H b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.H index babbceabea16533c071745a7768ccd93f4100865..2ccd3244866eb69ed6af56835f049857b6004650 100644 --- a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.H +++ b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.H @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2017-2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -56,6 +56,7 @@ Description (rho*phi none) //none) (ghf none) //NaN) //none) ); + // Write the refinement level as a volScalarField dumpLevel true; @@ -117,10 +118,10 @@ protected: //- Refine cells. Update mesh and fields. - autoPtr<mapPolyMesh> refine(const labelList&); + virtual autoPtr<mapPolyMesh> refine(const labelList&); //- Unrefine cells. Gets passed in centre points of cells to combine. - autoPtr<mapPolyMesh> unrefine(const labelList&); + virtual autoPtr<mapPolyMesh> unrefine(const labelList&); // Selection of cells to un/refine @@ -185,6 +186,32 @@ protected: label& nProtected ) const; + //- Map single non-flux surface<Type>Field + // for new internal faces (e.g. AMR refine). This currently + // interpolates values from surrounding faces (faces on + // neighbouring cells) that do have a value. + template <class T> + void mapNewInternalFaces + ( + const labelList& faceMap, + GeometricField<T, fvsPatchField, surfaceMesh>& + ); + + //- Correct surface fields for new faces + template <class T> + void mapNewInternalFaces(const labelList& faceMap); + + //- Correct surface fields for new faces. Converts any oriented + // fields into non-oriented (i.e. phi -> Uf) before mapping + template <class T> + void mapNewInternalFaces + ( + const surfaceVectorField& Sf, + const surfaceScalarField& magSf, + const labelList& faceMap + ); + + private: //- No copy construct @@ -232,6 +259,9 @@ public: //- Update the mesh for both mesh motion and topology change virtual bool update(); + //- Map all fields in time using given map. + virtual void mapFields(const mapPolyMesh& mpm); + // Writing @@ -243,16 +273,20 @@ public: IOstream::compressionType cmp, const bool valid ) const; - }; - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#ifdef NoRepository + #include "dynamicRefineFvMeshTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + #endif // ************************************************************************* // diff --git a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..6bf655a7ec36c7dca235a428bf164c47a2b3beb6 --- /dev/null +++ b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C @@ -0,0 +1,196 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "surfaceFields.H" + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +template<class T> +void Foam::dynamicRefineFvMesh::mapNewInternalFaces +( + const labelList& faceMap, + GeometricField<T, fvsPatchField, surfaceMesh>& sFld +) +{ + typedef GeometricField<T, fvsPatchField, surfaceMesh> GeoField; + + //- Make flat field for ease of looping + Field<T> tsFld(this->nFaces(), pTraits<T>::zero); + SubField<T>(tsFld, this->nInternalFaces()) = sFld.internalField(); + + const typename GeoField::Boundary& bFld = sFld.boundaryField(); + forAll(bFld, patchi) + { + label facei = this->boundaryMesh()[patchi].start(); + for (const T& val : bFld[patchi]) + { + tsFld[facei++] = val; + } + } + + const labelUList& owner = this->faceOwner(); + const labelUList& neighbour = this->faceNeighbour(); + const cellList& cells = this->cells(); + + for (label facei = 0; facei < nInternalFaces(); facei++) + { + label oldFacei = faceMap[facei]; + + // Map surface field on newly generated faces by obtaining the + // hull of the outside faces + if (oldFacei == -1) + { + // Loop over all owner/neighbour cell faces + // and find already mapped ones (master-faces): + T tmpValue = pTraits<T>::zero; + label counter = 0; + + const cell& ownFaces = cells[owner[facei]]; + for (auto ownFacei : ownFaces) + { + if (faceMap[ownFacei] != -1) + { + tmpValue += tsFld[ownFacei]; + counter++; + } + } + + const cell& neiFaces = cells[neighbour[facei]]; + for (auto neiFacei : neiFaces) + { + if (faceMap[neiFacei] != -1) + { + tmpValue += tsFld[neiFacei]; + counter++; + } + } + + if (counter > 0) + { + sFld[facei] = tmpValue/counter; + } + } + } +} + + +template<class T> +void Foam::dynamicRefineFvMesh::mapNewInternalFaces +( + const labelList& faceMap +) +{ + typedef GeometricField<T, fvsPatchField, surfaceMesh> GeoField; + HashTable<GeoField*> sFlds(this->objectRegistry::lookupClass<GeoField>()); + + forAllIter(typename HashTable<GeoField*>, sFlds, iter) + { + //if (mapSurfaceFields_.found(iter.key())) + { + if (debug) + { + Info<< "dynamicRefineFvMesh::mapNewInternalFaces():" + << " Mapping new internal faces by interpolation on " + << iter.key()<< endl; + } + + GeoField& sFld = *iter(); + + if (sFld.oriented()()) + { + WarningInFunction << "Ignoring mapping oriented field " + << sFld.name() << " since of type " << sFld.type() + << endl; + } + else + { + mapNewInternalFaces(faceMap, sFld); + } + } + } +} + +template<class T> +void Foam::dynamicRefineFvMesh::mapNewInternalFaces +( + const surfaceVectorField& Sf, + const surfaceScalarField& magSf, + const labelList& faceMap +) +{ + typedef GeometricField<T, fvsPatchField, surfaceMesh> GeoField; + HashTable<GeoField*> sFlds(this->objectRegistry::lookupClass<GeoField>()); + + forAllIter(typename HashTable<GeoField*>, sFlds, iter) + { + //if (mapSurfaceFields_.found(iter.key())) + { + if (debug) + { + Info<< "dynamicRefineFvMesh::mapNewInternalFaces():" + << " Mapping new internal faces by interpolation on " + << iter.key()<< endl; + } + + GeoField& sFld = *iter(); + + if (sFld.oriented()()) + { + if (debug) + { + Info<< "dynamicRefineFvMesh::mapNewInternalFaces(): " + << "Converting oriented field " << iter.key() + << " to intensive field and mapping" << endl; + } + + // Assume any oriented field is face area weighted (i.e. a flux) + // Convert to intensive (& oriented) before mapping. Untested. + + typedef GeometricField + < + typename outerProduct<vector, T>::type, + fvsPatchField, + surfaceMesh + > NormalGeoField; + + // Convert to intensive and non oriented + NormalGeoField fFld(sFld*Sf/Foam::sqr(magSf)); + + // Interpolate + mapNewInternalFaces(faceMap, fFld); + + // Convert back to extensive and oriented + sFld = (fFld & Sf); + } + else + { + mapNewInternalFaces(faceMap, sFld); + } + } + } +} + + +// ************************************************************************* // diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C index a66bd7c48636b3114e5c095d5173c7b87682b264..f535a71cd4a438ee53555e343d41190b11e9dec8 100644 --- a/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C +++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C @@ -210,7 +210,7 @@ Foam::label Foam::hexRef8::addInternalFace nei, // neighbour -1, // master point -1, // master edge - meshFacei, // master face for addition + -1, // master face for addition false, // flux flip -1, // patch for face -1, // zone for face diff --git a/src/finiteVolume/fvMesh/fvMesh.C b/src/finiteVolume/fvMesh/fvMesh.C index a0a032935b2884b08bd2e027389fae842084c908..41dc37f78422fc70228995cc609e23d2ae824268 100644 --- a/src/finiteVolume/fvMesh/fvMesh.C +++ b/src/finiteVolume/fvMesh/fvMesh.C @@ -571,6 +571,13 @@ const Foam::lduAddressing& Foam::fvMesh::lduAddr() const { if (!lduPtr_) { + if (debug) + { + InfoInFunction + << " calculating fvMeshLduAddressing from nFaces:" + << nFaces() << endl; + } + lduPtr_ = new fvMeshLduAddressing(*this); } @@ -821,6 +828,9 @@ void Foam::fvMesh::updateMesh(const mapPolyMesh& mpm) // Update polyMesh. This needs to keep volume existent! polyMesh::updateMesh(mpm); + // Our slice of the addressing is no longer valid + deleteDemandDrivenData(lduPtr_); + if (VPtr_) { // Grab old time volumes if the time has been incremented diff --git a/tutorials/multiphase/interFoam/laminar/damBreakWithObstacle/constant/dynamicMeshDict b/tutorials/multiphase/interFoam/laminar/damBreakWithObstacle/constant/dynamicMeshDict index 88613b395f8a76e75bc238b10ca6751a78d7c52f..88a8b82bb86c09881cfec7f563c7f927f306de48 100644 --- a/tutorials/multiphase/interFoam/laminar/damBreakWithObstacle/constant/dynamicMeshDict +++ b/tutorials/multiphase/interFoam/laminar/damBreakWithObstacle/constant/dynamicMeshDict @@ -49,6 +49,7 @@ correctFluxes (rhoPhi none) (alphaPhi0.water none) (ghf none) + (alphaPhiUn none) ); // Write the refinement level as a volScalarField