Commit 93808443 authored by mattijs's avatar mattijs
Browse files

ENH: directMapped: allow offset specification; allow fieldName specification;...

ENH: directMapped: allow offset specification; allow fieldName specification; allow non-constant interpolation
parent 191cc9a8
......@@ -26,6 +26,7 @@ License
#include "directMappedFixedValueFvPatchField.H"
#include "directMappedPatchBase.H"
#include "volFields.H"
#include "interpolationCell.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -42,8 +43,10 @@ directMappedFixedValueFvPatchField<Type>::directMappedFixedValueFvPatchField
)
:
fixedValueFvPatchField<Type>(p, iF),
fieldName_(iF.name()),
setAverage_(false),
average_(pTraits<Type>::zero)
average_(pTraits<Type>::zero),
interpolationScheme_(interpolationCell<Type>::typeName)
{}
......@@ -57,8 +60,10 @@ directMappedFixedValueFvPatchField<Type>::directMappedFixedValueFvPatchField
)
:
fixedValueFvPatchField<Type>(ptf, p, iF, mapper),
fieldName_(ptf.fieldName_),
setAverage_(ptf.setAverage_),
average_(ptf.average_)
average_(ptf.average_),
interpolationScheme_(ptf.interpolationScheme_)
{
if (!isA<directMappedPatchBase>(this->patch().patch()))
{
......@@ -91,8 +96,10 @@ directMappedFixedValueFvPatchField<Type>::directMappedFixedValueFvPatchField
)
:
fixedValueFvPatchField<Type>(p, iF, dict),
fieldName_(dict.lookupOrDefault<word>("fieldName", iF.name())),
setAverage_(readBool(dict.lookup("setAverage"))),
average_(pTraits<Type>(dict.lookup("average")))
average_(pTraits<Type>(dict.lookup("average"))),
interpolationScheme_(interpolationCell<Type>::typeName)
{
if (!isA<directMappedPatchBase>(this->patch().patch()))
{
......@@ -112,6 +119,15 @@ directMappedFixedValueFvPatchField<Type>::directMappedFixedValueFvPatchField
<< " in file " << this->dimensionedInternalField().objectPath()
<< exit(FatalError);
}
const directMappedPatchBase& mpp = refCast<const directMappedPatchBase>
(
directMappedFixedValueFvPatchField<Type>::patch().patch()
);
if (mpp.mode() == directMappedPatchBase::NEARESTCELL)
{
dict.lookup("interpolationScheme") >> interpolationScheme_;
}
}
......@@ -122,8 +138,10 @@ directMappedFixedValueFvPatchField<Type>::directMappedFixedValueFvPatchField
)
:
fixedValueFvPatchField<Type>(ptf),
fieldName_(ptf.fieldName_),
setAverage_(ptf.setAverage_),
average_(ptf.average_)
average_(ptf.average_),
interpolationScheme_(ptf.interpolationScheme_)
{}
......@@ -135,13 +153,67 @@ directMappedFixedValueFvPatchField<Type>::directMappedFixedValueFvPatchField
)
:
fixedValueFvPatchField<Type>(ptf, iF),
fieldName_(ptf.fieldName_),
setAverage_(ptf.setAverage_),
average_(ptf.average_)
average_(ptf.average_),
interpolationScheme_(ptf.interpolationScheme_)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
const GeometricField<Type, fvPatchField, volMesh>&
directMappedFixedValueFvPatchField<Type>::sampleField() const
{
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
const directMappedPatchBase& mpp = refCast<const directMappedPatchBase>
(
directMappedFixedValueFvPatchField<Type>::patch().patch()
);
const fvMesh& nbrMesh = refCast<const fvMesh>(mpp.sampleMesh());
if (mpp.sameRegion())
{
if (fieldName_ == this->dimensionedInternalField().name())
{
// Optimisation: bypass field lookup
return
dynamic_cast<const fieldType&>
(
this->dimensionedInternalField()
);
}
else
{
const fvMesh& thisMesh = this->patch().boundaryMesh().mesh();
return thisMesh.lookupObject<fieldType>(fieldName_);
}
}
else
{
return nbrMesh.lookupObject<fieldType>(fieldName_);
}
}
template<class Type>
const interpolation<Type>&
directMappedFixedValueFvPatchField<Type>::interpolator() const
{
if (!interpolator_.valid())
{
interpolator_ = interpolation<Type>::New
(
interpolationScheme_,
sampleField()
);
}
return interpolator_();
}
template<class Type>
void directMappedFixedValueFvPatchField<Type>::updateCoeffs()
{
......@@ -159,11 +231,8 @@ void directMappedFixedValueFvPatchField<Type>::updateCoeffs()
);
const mapDistribute& distMap = mpp.map();
// Force recalculation of schedule
(void)distMap.schedule();
const fvMesh& thisMesh = this->patch().boundaryMesh().mesh();
const fvMesh& nbrMesh = refCast<const fvMesh>(mpp.sampleMesh());
const word& fldName = this->dimensionedInternalField().name();
// Result of obtaining remote values
Field<Type> newValues;
......@@ -172,17 +241,37 @@ void directMappedFixedValueFvPatchField<Type>::updateCoeffs()
{
case directMappedPatchBase::NEARESTCELL:
{
if (mpp.sameRegion())
if (interpolationScheme_ != interpolationCell<Type>::typeName)
{
newValues = this->internalField();
// Send back sample points to the processor that holds the cell
vectorField samples(mpp.samplePoints());
distMap.reverseDistribute
(
(mpp.sameRegion() ? thisMesh.nCells() : nbrMesh.nCells()),
point::max,
samples
);
const interpolation<Type>& interp = interpolator();
newValues.setSize(samples.size(), pTraits<Type>::max);
forAll(samples, cellI)
{
if (samples[cellI] != point::max)
{
newValues[cellI] = interp.interpolate
(
samples[cellI],
cellI
);
}
}
}
else
{
newValues = nbrMesh.lookupObject<fieldType>
(
fldName
).internalField();
newValues = sampleField();
}
mapDistribute::distribute
(
Pstream::defaultCommsType,
......@@ -213,10 +302,8 @@ void directMappedFixedValueFvPatchField<Type>::updateCoeffs()
<< abort(FatalError);
}
const fieldType& nbrField = nbrMesh.lookupObject<fieldType>
(
fldName
);
const fieldType& nbrField = sampleField();
newValues = nbrField.boundaryField()[nbrPatchID];
mapDistribute::distribute
(
......@@ -234,10 +321,8 @@ void directMappedFixedValueFvPatchField<Type>::updateCoeffs()
{
Field<Type> allValues(nbrMesh.nFaces(), pTraits<Type>::zero);
const fieldType& nbrField = nbrMesh.lookupObject<fieldType>
(
fldName
);
const fieldType& nbrField = sampleField();
forAll(nbrField.boundaryField(), patchI)
{
const fvPatchField<Type>& pf =
......@@ -294,7 +379,8 @@ void directMappedFixedValueFvPatchField<Type>::updateCoeffs()
if (debug)
{
Info<< "directMapped on field:" << fldName
Info<< "directMapped on field:"
<< this->dimensionedInternalField().name()
<< " patch:" << this->patch().name()
<< " avg:" << gAverage(*this)
<< " min:" << gMin(*this)
......@@ -310,8 +396,11 @@ template<class Type>
void directMappedFixedValueFvPatchField<Type>::write(Ostream& os) const
{
fvPatchField<Type>::write(os);
os.writeKeyword("fieldName") << fieldName_ << token::END_STATEMENT << nl;
os.writeKeyword("setAverage") << setAverage_ << token::END_STATEMENT << nl;
os.writeKeyword("average") << average_ << token::END_STATEMENT << nl;
os.writeKeyword("interpolationScheme") << interpolationScheme_
<< token::END_STATEMENT << nl;
this->writeEntry("value", os);
}
......
......@@ -33,6 +33,17 @@ Description
mode = NEARESTFACE : sample nearest face on any patch. Note: does not
warn if nearest actually is on internal face!
For NEARESTCELL you have to provide an 'interpolationScheme' entry
which can be any one of the interpolation schemes (cell, cellPoint, etc.)
In case of interpolation (so scheme != cell) the limitation is that
there is only one value per cell. So e.g. if you have a cell with two
boundary faces and both faces sample into the cell both faces will get
the same value.
See directMappedPatchBase for options on sampling.
Optional 'fieldName' entry to supply a different filename
SourceFiles
directMappedFixedValueFvPatchField.C
......@@ -43,6 +54,7 @@ SourceFiles
#include "fixedValueFvPatchFields.H"
#include "directMappedFvPatch.H"
#include "interpolation.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -60,12 +72,29 @@ class directMappedFixedValueFvPatchField
{
// Private data
//- Name of field to sample - defaults to field associated with this
// patchField if not specified
word fieldName_;
//- If true adjust the mapped field to maintain average value average_
bool setAverage_;
const bool setAverage_;
//- Average value the mapped field is adjusted to maintain if
// setAverage_ is set true
Type average_;
const Type average_;
//- Interpolation scheme to use for nearestcell mode
word interpolationScheme_;
mutable autoPtr<interpolation<Type> > interpolator_;
// Private Member Functions
//- Field to sample. Either on my or nbr mesh
const GeometricField<Type, fvPatchField, volMesh>& sampleField() const;
//- Access the interpolation method
const interpolation<Type>& interpolator() const;
public:
......
......@@ -112,6 +112,29 @@ directMappedVelocityFluxFixedValueFvPatchField
<< " in file " << dimensionedInternalField().objectPath()
<< exit(FatalError);
}
const directMappedPatchBase& mpp = refCast<const directMappedPatchBase>
(
this->patch().patch()
);
if (mpp.mode() == directMappedPolyPatch::NEARESTCELL)
{
FatalErrorIn
(
"directMappedVelocityFluxFixedValueFvPatchField::"
"directMappedVelocityFluxFixedValueFvPatchField"
"("
"const fvPatch&, "
"const DimensionedField<vector, volMesh>&, "
"const dictionary&"
")"
) << "Patch " << p.name()
<< " of type '" << p.type()
<< "' can not be used in 'nearestCell' mode"
<< " of field " << dimensionedInternalField().name()
<< " in file " << dimensionedInternalField().objectPath()
<< exit(FatalError);
}
}
......
......@@ -54,6 +54,18 @@ namespace Foam
directMappedPatchBase::sampleModeNames_;
template<>
const char* NamedEnum<directMappedPatchBase::offsetMode, 3>::names[] =
{
"uniform",
"nonuniform",
"normal"
};
const NamedEnum<directMappedPatchBase::offsetMode, 3>
directMappedPatchBase::offsetModeNames_;
//- Private class for finding nearest
// - point+local index
// - sqr(distance)
......@@ -100,7 +112,7 @@ void Foam::directMappedPatchBase::collectSamples
labelListList globalFaces(Pstream::nProcs());
globalFc[Pstream::myProcNo()] = patch_.faceCentres();
globalSamples[Pstream::myProcNo()] = globalFc[Pstream::myProcNo()]+offsets_;
globalSamples[Pstream::myProcNo()] = samplePoints();
globalFaces[Pstream::myProcNo()] = identity(patch_.size());
// Distribute to all processors
......@@ -393,19 +405,34 @@ void Foam::directMappedPatchBase::calcMapping() const
<< "Mapping already calculated" << exit(FatalError);
}
if
// Do a sanity check
// Am I sampling my own patch? This only makes sense for a non-zero
// offset.
bool sampleMyself =
(
gAverage(mag(offsets_)) <= ROOTVSMALL
&& mode_ == NEARESTPATCHFACE
mode_ == NEARESTPATCHFACE
&& sampleRegion_ == patch_.boundaryMesh().mesh().name()
&& samplePatch_ == patch_.name()
)
);
// Check offset
vectorField d(samplePoints()-patch_.faceCentres());
if (sampleMyself && gAverage(mag(d)) <= ROOTVSMALL)
{
WarningIn("directMappedPatchBase::calcMapping() const")
<< "Invalid offset " << offsets_ << endl
WarningIn
(
"directMappedPatchBase::directMappedPatchBase\n"
"(\n"
" const polyPatch& pp,\n"
" const word& sampleRegion,\n"
" const sampleMode mode,\n"
" const word& samplePatch,\n"
" const vector& offset\n"
")\n"
) << "Invalid offset " << d << endl
<< "Offset is the vector added to the patch face centres to"
<< " find the patch face supplying the data." << endl
<< "Setting it to " << offsets_
<< "Setting it to " << d
<< " on the same patch, on the same region"
<< " will find the faces themselves which does not make sense"
<< " for anything but testing." << endl
......@@ -413,10 +440,11 @@ void Foam::directMappedPatchBase::calcMapping() const
<< "sampleRegion_:" << sampleRegion_ << endl
<< "mode_:" << sampleModeNames_[mode_] << endl
<< "samplePatch_:" << samplePatch_ << endl
<< "offsets_:" << offsets_ << endl;
<< "offsetMode_:" << offsetModeNames_[offsetMode_] << endl;
}
// Get global list of all samples and the processor and face they come from.
pointField samples;
labelList patchFaceProcs;
......@@ -477,40 +505,6 @@ void Foam::directMappedPatchBase::calcMapping() const
}
//// Check that actual offset vector (sampleLocations - patchFc) is more or
//// less constant.
//if (Pstream::master())
//{
// const scalarField magOffset(mag(sampleLocations - patchFc));
// const scalar avgOffset(average(magOffset));
//
// forAll(magOffset, sampleI)
// {
// if
// (
// mag(magOffset[sampleI]-avgOffset)
// > max(SMALL, 0.001*avgOffset)
// )
// {
// WarningIn("directMappedPatchBase::calcMapping() const")
// << "The actual cell/face centres picked up using offset "
// << offsets_ << " are not" << endl
// << " on a single plane."
// << " This might give numerical problems." << endl
// << " At patchface " << patchFc[sampleI]
// << " the sampled cell/face " << sampleLocations[sampleI]
// << endl
// << " is not on a plane " << avgOffset
// << " offset from the patch." << endl
// << " You might want to shift your plane offset."
// << " Set the debug flag to get a dump of sampled cells."
// << endl;
// break;
// }
// }
//}
// Determine schedule.
mapPtr_.reset(new mapDistribute(sampleProcs, patchFaceProcs));
......@@ -597,9 +591,10 @@ Foam::directMappedPatchBase::directMappedPatchBase
sampleRegion_(patch_.boundaryMesh().mesh().name()),
mode_(NEARESTPATCHFACE),
samplePatch_("none"),
uniformOffset_(true),
offsetMode_(UNIFORM),
offset_(vector::zero),
offsets_(pp.size(), offset_),
distance_(0),
sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
mapPtr_(NULL)
{}
......@@ -618,8 +613,10 @@ Foam::directMappedPatchBase::directMappedPatchBase
sampleRegion_(sampleRegion),
mode_(mode),
samplePatch_(samplePatch),
uniformOffset_(false),
offsetMode_(NONUNIFORM),
offset_(vector::zero),
offsets_(offsets),
distance_(0),
sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
mapPtr_(NULL)
{}
......@@ -638,9 +635,10 @@ Foam::directMappedPatchBase::directMappedPatchBase
sampleRegion_(sampleRegion),
mode_(mode),
samplePatch_(samplePatch),
uniformOffset_(true),
offsetMode_(UNIFORM),
offset_(offset),
offsets_(pp.size(), offset_),
offsets_(0),
distance_(0),
sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
mapPtr_(NULL)
{}
......@@ -663,22 +661,62 @@ Foam::directMappedPatchBase::directMappedPatchBase
),
mode_(sampleModeNames_.read(dict.lookup("sampleMode"))),
samplePatch_(dict.lookup("samplePatch")),
uniformOffset_(dict.found("offset")),
offset_
(
uniformOffset_
? point(dict.lookup("offset"))
: vector::zero
),
offsets_
(
uniformOffset_
? pointField(pp.size(), offset_)
: dict.lookup("offsets")
),
offsetMode_(UNIFORM),
offset_(vector::zero),
offsets_(0),
distance_(0.0),
sameRegion_(sampleRegion_ == patch_.boundaryMesh().mesh().name()),
mapPtr_(NULL)
{}
{
if (dict.found("offsetMode"))
{
offsetMode_ = offsetModeNames_.read(dict.lookup("offsetMode"));
switch(offsetMode_)
{
case UNIFORM:
{
offset_ = point(dict.lookup("offset"));
}
break;
case NONUNIFORM:
{
offsets_ = pointField(dict.lookup("offsets"));
}
break;
case NORMAL:
{
distance_ = readScalar(dict.lookup("distance"));
}
break;
}
}
else if (dict.found("offset"))
{
offsetMode_ = UNIFORM;
offset_ = point(dict.lookup("offset"));
}
else if (dict.found("offsets"))
{
offsetMode_ = NONUNIFORM;
offsets_ = pointField(dict.lookup("offsets"));
}
else
{
FatalErrorIn
(
"directMappedPatchBase::directMappedPatchBase\n"
"(\n"
" const polyPatch& pp,\n"
" const dictionary& dict\n"
")\n"
) << "Please supply the offsetMode as one of "
<< NamedEnum<offsetMode, 3>::words()
<< exit(FatalError);
}
}
Foam::directMappedPatchBase::directMappedPatchBase
......@@ -691,9 +729,10 @@ Foam::directMappedPatchBase::directMappedPatchBase
sampleRegion_(dmp.sampleRegion_),
mode_(dmp.mode_),
samplePatch_(dmp.samplePatch_),
uniformOffset_(dmp.uniformOffset_),
offsetMode_(dmp.offsetMode_),
offset_(dmp.offset_),
offsets_(dmp.offsets_),
distance_(dmp.distance_),
sameRegion_(dmp.sameRegion_),
mapPtr_(NULL)
{}
......@@ -710,9 +749,10 @@ Foam::directMappedPatchBase::directMappedPatchBase
sampleRegion_(dmp.sampleRegion_),
mode_(dmp.mode_),
samplePatch_(dmp.samplePatch_),
uniformOffset_(dmp.uniformOffset_),
offsetMode_(dmp.offsetMode_),
offset_(dmp.offset_),
offsets_(dmp.offsets_, mapAddressing),
distance_(dmp.distance_),
sameRegion_(dmp.sameRegion_),