ENH: norm: add new field function object

The 'norm' function object normalises an input field
with a chosen norm, and outputs a new normalised field.
This commit is contained in:
Kutalmis Bercin
2022-04-26 13:19:54 +01:00
parent 77ab7510a8
commit 14c8c312e8
4 changed files with 588 additions and 0 deletions

View File

@ -84,6 +84,7 @@ Curle/Curle.C
reference/reference.C reference/reference.C
log/log.C log/log.C
pow/pow.C pow/pow.C
norm/norm.C
fieldsExpression/fieldsExpression.C fieldsExpression/fieldsExpression.C
add/add.C add/add.C

View File

@ -0,0 +1,142 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "norm.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(norm, 0);
addToRunTimeSelectionTable(functionObject, norm, dictionary);
}
}
const Foam::Enum
<
Foam::functionObjects::norm::normType
>
Foam::functionObjects::norm::normTypeNames
({
{ normType::L1 , "L1" },
{ normType::L2 , "L2" },
{ normType::LP , "Lp" },
{ normType::MAX , "max" },
{ normType::COMPOSITE , "composite" },
{ normType::FIELD , "divisorField" }
});
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Implementation
#include "normImpl.C"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::functionObjects::norm::calc()
{
return
(
calcNorm<scalar>()
|| calcNorm<vector>()
|| calcNorm<sphericalTensor>()
|| calcNorm<symmTensor>()
|| calcNorm<tensor>()
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::norm::norm
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
fieldExpression(name, runTime, dict),
norm_(normType::L1),
divisorPtr_(nullptr),
divisorFieldName_(word::null),
p_(-1)
{
read(dict);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::norm::read(const dictionary& dict)
{
if (!fieldExpression::read(dict))
{
return false;
}
norm_ = normTypeNames.get("norm", dict);
if (norm_ == normType::LP)
{
p_ = dict.getCheck<scalar>("p", scalarMinMax::ge(1));
}
if (norm_ == normType::COMPOSITE)
{
divisorPtr_ = Function1<scalar>::New("divisor", dict, &mesh_);
if (!divisorPtr_)
{
FatalIOErrorInFunction(dict)
<< "The norm 'composite' needs the input entry 'divisor'."
<< abort(FatalIOError);
}
}
if (norm_ == normType::FIELD)
{
divisorFieldName_ = dict.get<word>("divisorField");
if (divisorFieldName_ == word::null)
{
FatalIOErrorInFunction(dict)
<< "The norm 'field' needs the input entry 'divisorField'."
<< abort(FatalIOError);
}
}
return true;
}
// ************************************************************************* //

View File

@ -0,0 +1,285 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::functionObjects::norm
Group
grpFieldFunctionObjects
Description
Normalises an input field with a chosen norm,
and outputs a new normalised field.
Operands:
\table
Operand | Type | Location
input | {vol,surface,polySurface}\<Type\>Field <!--
--> | \<case\>/\<time\>/\<inpField\>
output file | - | -
output field | {vol,surface,polySurface}\<Type\>Field <!--
--> | \<case\>/\<time\>/\<outField\>
\endtable
where \c \<Type\>=Scalar/Vector/SphericalTensor/SymmTensor/Tensor.
Usage
Minimal example by using \c system/controlDict.functions:
\verbatim
norm1
{
// Mandatory entries
type norm;
libs (fieldFunctionObjects);
field <word>;
norm <word>;
// Conditional entries
// when norm == Lp
p <scalar>;
// when norm == composite
divisor <Function1<scalar>>;
// when norm == divisorField
divisorField <word>;
// Inherited entries
...
}
\endverbatim
where the entries mean:
\table
Property | Description | Type | Reqd | Deflt
type | Type name: norm | word | yes | -
libs | Library name: fieldFunctionObjects | word | yes | -
field | Name of the operand field | word | yes | -
norm | Name of normalisation operation | word | yes | -
p | Norm exponent for the p-norm | scalar | cndtnl | -
divisor | Norm divisor for the composite norm <!--
--> | Function1\<scalar\> | cndtnl | -
divisorField | Divisor scalar field for the field norm <!--
--> | word | cndtnl | -
\endtable
Options for the \c norm entry:
\verbatim
L1 | L1/Taxicab norm
L2 | L2/Euclidean norm
Lp | p norm
max | Maximum norm
composite | Composite norm comprising Function1 divisor
divisorField | Normalise by a given field
\endverbatim
The inherited entries are elaborated in:
- \link functionObject.H \endlink
- \link fieldExpression.H \endlink
- \link Function1.H \endlink
The normalisations are held according to the following expressions:
- \c L1:
\f[
\mathbf{y} = \frac{\mathbf{x}}{\Sigma_{i=1}^n |x_i|}
\f]
- \c L2:
\f[
\mathbf{y} = \frac{\mathbf{x}}{\sqrt{x_1^2 + ... + x_n^2}}
\f]
- \c Lp:
\f[
\mathbf{y} = \frac{\mathbf{x}}{(\Sigma_{i=1}^n |x_i|^p)^{1/p}}
\f]
- \c max:
\f[
\mathbf{y} = \frac{\mathbf{x}}{max|x_i|}
\f]
- \c composite:
\f[
\mathbf{y} = \frac{\mathbf{x}}{f(t)}
\f]
- \c divisorField:
\f[
\mathbf{y} = \frac{\mathbf{x}}{\mathbf{z}}
\f]
Note
- Divisor quantity is perturbed by \c SMALL value to prevent any divisions
by zero irrespective of whether the quantity is close to zero or not.
SourceFiles
norm.C
normImpl.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_norm_H
#define functionObjects_norm_H
#include "fieldExpression.H"
#include "Function1.H"
#include "polySurfaceFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class norm Declaration
\*---------------------------------------------------------------------------*/
class norm
:
public fieldExpression
{
// Private Enumerations
//- Options for the norm algorithm
enum normType : char
{
L1, //!< "L1/Taxicab norm"
L2, //!< "L2/Euclidean norm"
LP, //!< "p norm"
MAX, //!< "Maximum norm"
COMPOSITE, //!< "Composite norm"
FIELD //!< "Normalise by a given field"
};
//- Names for normType
static const Enum<normType> normTypeNames;
// Private Data
//- Norm algorithm
enum normType norm_;
//- Norm divisor for the composite norm
autoPtr<Function1<scalar>> divisorPtr_;
//- Divisor scalar field for the field norm
word divisorFieldName_;
//- Norm exponent for the p norm
scalar p_;
// Private Member Functions
//- Calculate the chosen norm of the field and register the result
template<class Type>
bool calcNorm();
//- Return the chosen norm of the field
template<class GeoFieldType>
tmp<GeoFieldType> calcNormType();
//- Return the divisor volScalarField
template<class Type>
tmp<volScalarField> fieldNorm
(
const GeometricField<Type, fvPatchField, volMesh>&
);
//- Return the divisor surfaceScalarField
template<class Type>
tmp<surfaceScalarField> fieldNorm
(
const GeometricField<Type, fvsPatchField, surfaceMesh>&
);
//- Return the divisor polySurfaceScalarField
template<class Type>
tmp<polySurfaceScalarField> fieldNorm
(
const DimensionedField<Type, polySurfaceGeoMesh>&
);
//- Calculate the chosen norm of the field and return true if successful
virtual bool calc();
public:
//- Runtime type information
TypeName("norm");
// Constructors
//- Construct from name, Time and dictionary
norm
(
const word& name,
const Time& runTime,
const dictionary& dict
);
//- No copy construct
norm(const norm&) = delete;
//- No copy assignment
void operator=(const norm&) = delete;
//- Destructor
virtual ~norm() = default;
// Member Functions
//- Read the dictionary data
virtual bool read(const dictionary&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,160 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "volFields.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
bool Foam::functionObjects::norm::calcNorm()
{
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
typedef DimensionedField<Type, polySurfaceGeoMesh> SurfFieldType;
if (mesh_.foundObject<VolFieldType>(fieldName_))
{
return store
(
resultName_,
calcNormType<VolFieldType>()
);
}
else if (mesh_.foundObject<SurfaceFieldType>(fieldName_))
{
return store
(
resultName_,
calcNormType<SurfaceFieldType>()
);
}
else if (mesh_.foundObject<SurfFieldType>(fieldName_))
{
return store
(
resultName_,
calcNormType<SurfFieldType>()
);
}
return false;
}
template<class GeoFieldType>
Foam::tmp<GeoFieldType> Foam::functionObjects::norm::calcNormType()
{
const GeoFieldType& field = mesh_.lookupObject<GeoFieldType>(fieldName_);
const dimensionedScalar perturb(field.dimensions(), SMALL);
switch (norm_)
{
case normType::L1:
{
return field/stabilise(sumMag(field), perturb);
}
case normType::L2:
{
return field/stabilise(mag(field), perturb);
}
case normType::LP:
{
return
field
/stabilise
(
pow(pow(mag(field), p_), scalar(1)/p_),
perturb
);
}
case normType::MAX:
{
return field/stabilise(max(mag(field)), perturb);
}
case normType::COMPOSITE:
{
const scalar t = mesh_.time().timeOutputValue();
const dimensionedScalar divisor
(
field.dimensions(),
divisorPtr_->value(t)
);
return field/stabilise(divisor, perturb);
}
case normType::FIELD:
{
return field/stabilise(fieldNorm(field), perturb);
}
default:
break;
}
return nullptr;
}
template<class Type>
Foam::tmp<Foam::volScalarField> Foam::functionObjects::norm::fieldNorm
(
const GeometricField<Type, fvPatchField, volMesh>&
)
{
return mesh_.lookupObject<volScalarField>(divisorFieldName_);
}
template<class Type>
Foam::tmp<Foam::surfaceScalarField> Foam::functionObjects::norm::fieldNorm
(
const GeometricField<Type, fvsPatchField, surfaceMesh>&
)
{
return mesh_.lookupObject<surfaceScalarField>(divisorFieldName_);
}
template<class Type>
Foam::tmp<Foam::polySurfaceScalarField> Foam::functionObjects::norm::fieldNorm
(
const DimensionedField<Type, polySurfaceGeoMesh>&
)
{
return mesh_.lookupObject<polySurfaceScalarField>(divisorFieldName_);
}
// ************************************************************************* //