ENH: directMapped: allow offset specification; allow fieldName specification; allow non-constant interpolation

This commit is contained in:
mattijs
2010-11-25 13:33:27 +00:00
parent 191cc9a814
commit 938084438e
5 changed files with 389 additions and 103 deletions

View File

@ -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);
}

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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_),
mapPtr_(NULL)
{}
@ -762,6 +802,40 @@ const Foam::polyPatch& Foam::directMappedPatchBase::samplePolyPatch() const
}
Foam::tmp<Foam::pointField> Foam::directMappedPatchBase::samplePoints() const
{
tmp<pointField> tfld(new pointField(patch_.faceCentres()));
pointField& fld = tfld();
switch(offsetMode_)
{
case UNIFORM:
{
fld += offset_;
}
break;
case NONUNIFORM:
{
fld += offsets_;
}
break;
case NORMAL:
{
// Get outwards pointing normal
vectorField n(patch_.faceAreas());
n /= mag(n);
fld += distance_*n;
}
break;
}
return tfld;
}
void Foam::directMappedPatchBase::write(Ostream& os) const
{
os.writeKeyword("sampleMode") << sampleModeNames_[mode_]
@ -770,13 +844,31 @@ void Foam::directMappedPatchBase::write(Ostream& os) const
<< token::END_STATEMENT << nl;
os.writeKeyword("samplePatch") << samplePatch_
<< token::END_STATEMENT << nl;
if (uniformOffset_)
os.writeKeyword("offsetMode") << offsetModeNames_[offsetMode_]
<< token::END_STATEMENT << nl;
switch(offsetMode_)
{
os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
}
else
{
os.writeKeyword("offsets") << offsets_ << token::END_STATEMENT << nl;
case UNIFORM:
{
os.writeKeyword("offset") << offset_ << token::END_STATEMENT << nl;
}
break;
case NONUNIFORM:
{
os.writeKeyword("offsets") << offsets_ << token::END_STATEMENT
<< nl;
}
break;
case NORMAL:
{
os.writeKeyword("distance") << distance_ << token::END_STATEMENT
<< nl;
}
break;
}
}

View File

@ -28,6 +28,33 @@ Description
Determines a mapping between patch face centres and mesh cell or face
centres and processors they're on.
If constructed from dictionary:
// Region to sample (default is region0)
sampleRegion region0;
// What to sample:
// - nearestCell : sample nearest cell
// - nearestPatchFace : nearest face on selected patch
// - nearestFace : nearest boundary face on any patch
sampleMode nearestCell;
// If sampleMod is nearestPatchFace : patch to find faces of
samplePatch movingWall;
// How to supply offset (w.r.t. my patch face centres):
// - uniform : single offset vector
// - nonuniform : per-face offset vector
// - normal : using supplied distance and face normal
offsetMode uniform;
// According to offsetMode (see above) supply one of
// offset, offsets or distance
offset (1 0 0);
Note: if offsetMode is 'normal' it uses outwards pointing normals. So
supply a negative distance if sampling inside the domain.
Note
Storage is not optimal. It temporary collects all (patch)face centres
on all processors to keep the addressing calculation simple.
@ -71,12 +98,22 @@ public:
NEARESTFACE // nearest face
};
//- How to project face centres
enum offsetMode
{
UNIFORM, // single offset vector
NONUNIFORM, // per-face offset vector
NORMAL // use face normal + distance
};
private:
// Private data
static const NamedEnum<sampleMode, 3> sampleModeNames_;
static const NamedEnum<offsetMode, 3> offsetModeNames_;
//- Patch to sample
const polyPatch& patch_;
@ -89,14 +126,17 @@ private:
//- Patch (only if NEARESTPATCHFACE)
const word samplePatch_;
//- For backwards compatibility : reading/writing of uniform offset.
const bool uniformOffset_;
//- How to obtain samples
offsetMode offsetMode_;
//- Offset vector (uniform)
const vector offset_;
vector offset_;
//- Offset vector
const vectorField offsets_;
//- Offset vector (nonuniform)
vectorField offsets_;
//- Offset distance (normal)
scalar distance_;
//- Same region
const bool sameRegion_;
@ -146,17 +186,17 @@ public:
//- Construct from patch
directMappedPatchBase(const polyPatch&);
//- Construct from components
//- Construct with offsetMode=non-uniform
directMappedPatchBase
(
const polyPatch& pp,
const word& sampleRegion,
const sampleMode sampleMode,
const word& samplePatch,
const vectorField& offset
const vectorField& offsets
);
//- Construct from components
//- Construct from offsetMode=uniform
directMappedPatchBase
(
const polyPatch& pp,
@ -166,6 +206,16 @@ public:
const vector& offset
);
////- Construct from normal and distance
//directMappedPatchBase
//(
// const polyPatch& pp,
// const word& sampleRegion,
// const word& samplePatch,
// const sampleMode sampleMode,
// const vector& offset
//);
//- Construct from dictionary
directMappedPatchBase(const polyPatch&, const dictionary&);
@ -241,6 +291,9 @@ public:
//- Get the patch on the region
const polyPatch& samplePolyPatch() const;
//- Get the sample points
tmp<pointField> samplePoints() const;
//- Write as a dictionary
virtual void write(Ostream&) const;
};