From 2c4b639e1f8da3ef977d46284d1adf5be11557b3 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Wed, 11 Mar 2020 10:51:14 +0100 Subject: [PATCH] ENH: 'mag' postOperation for surfaceFieldValue (#1622) - support postOperation for volFieldValue as well --- .../surfaceFieldValue/surfaceFieldValue.C | 11 ++- .../surfaceFieldValue/surfaceFieldValue.H | 18 +++- .../surfaceFieldValueTemplates.C | 15 ++- .../fieldValues/volFieldValue/volFieldValue.C | 95 +++++++++++++------ .../fieldValues/volFieldValue/volFieldValue.H | 54 ++++++++--- .../volFieldValue/volFieldValueTemplates.C | 81 ++++++++++++++-- .../twoSimpleRotors/system/controlDict | 1 + 7 files changed, 210 insertions(+), 65 deletions(-) diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C index 58b381e52e..2035fd66c3 100644 --- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C +++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2017-2019 OpenCFD Ltd. + Copyright (C) 2017-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -109,6 +109,7 @@ const Foam::Enum Foam::functionObjects::fieldValues::surfaceFieldValue::postOperationTypeNames_ ({ { postOperationType::postOpNone, "none" }, + { postOperationType::postOpMag, "mag" }, { postOperationType::postOpSqrt, "sqrt" }, }); @@ -564,6 +565,8 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader os << tab << "Area"; } + // TBD: add in postOperation information? + for (const word& fieldName : fields_) { os << tab << operationTypeNames_[operation_] @@ -755,6 +758,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::weightingFactor ) const { // scalar * Area + if (returnReduce(weightField.empty(), andOp())) { // No weight field - revert to unweighted form @@ -778,6 +782,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::weightingFactor ) const { // vector (dot) Area + if (returnReduce(weightField.empty(), andOp())) { // No weight field - revert to unweighted form @@ -806,7 +811,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue operation_(operationTypeNames_.get("operation", dict)), postOperation_ ( - postOperationTypeNames_.lookupOrDefault + postOperationTypeNames_.getOrDefault ( "postOperation", dict, @@ -839,7 +844,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue operation_(operationTypeNames_.get("operation", dict)), postOperation_ ( - postOperationTypeNames_.lookupOrDefault + postOperationTypeNames_.getOrDefault ( "postOperation", dict, diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H index 8912f1c76c..4431170675 100644 --- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H +++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2019 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -131,6 +131,13 @@ Usage absWeightedUniformity | uniformity index using absolute weighting \endplaintable + The \c postOperation is one of: + \plaintable + none | No additional operation after calculation + mag | Component-wise \c mag() after normal operation + sqrt | Component-wise \c sqrt() after normal operation + \endplaintable + Note - The values reported by the areaNormalAverage and areaNormalIntegrate operations are written as the first component of a field with the same @@ -193,7 +200,7 @@ SourceFiles namespace Foam { -// Forward declarations +// Forward Declarations class sampledSurface; class surfaceWriter; @@ -311,7 +318,8 @@ public: enum postOperationType { postOpNone, //!< No additional operation after calculation - postOpSqrt //!< Perform sqrt after normal operation + postOpMag, //!< Component-wise mag after normal operation + postOpSqrt //!< Component-wise sqrt after normal operation }; //- Operation type names @@ -526,7 +534,7 @@ protected: public: - //- Run-time type information + //- Declare type-name, virtual type (with debug switch) TypeName("surfaceFieldValue"); @@ -553,7 +561,7 @@ public: virtual ~surfaceFieldValue() = default; - // Public Member Functions + // Member Functions //- Return the region type inline regionTypes regionType() const; diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValueTemplates.C b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValueTemplates.C index f80579a09c..cd8e94ddae 100644 --- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValueTemplates.C +++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValueTemplates.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2019 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -407,9 +407,19 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues { break; } + case postOpMag: + { + // mag: component-wise - does not change the type + for (direction d=0; d < pTraits::nComponents; ++d) + { + setComponent(result, d) + = mag(component(result, d)); + } + break; + } case postOpSqrt: { - // sqrt: component-wise - doesn't change the type + // sqrt: component-wise - does not change the type for (direction d=0; d < pTraits::nComponents; ++d) { setComponent(result, d) @@ -442,6 +452,7 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues Log << " " << prefix << regionName_ << suffix << " of " << fieldName << " = "; + // Operation tagged that it always returns scalar? const bool alwaysScalar(operation_ & typeScalar); diff --git a/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.C b/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.C index 3066f707e8..9ac7caec75 100644 --- a/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.C +++ b/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2017-2019 OpenCFD Ltd. + Copyright (C) 2017-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -70,6 +70,17 @@ Foam::functionObjects::fieldValues::volFieldValue::operationTypeNames_ { operationType::opWeightedVolIntegrate, "weightedVolIntegrate" }, }); +const Foam::Enum +< + Foam::functionObjects::fieldValues::volFieldValue::postOperationType +> +Foam::functionObjects::fieldValues::volFieldValue::postOperationTypeNames_ +({ + { postOperationType::postOpNone, "none" }, + { postOperationType::postOpMag, "mag" }, + { postOperationType::postOpSqrt, "sqrt" }, +}); + // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // @@ -91,6 +102,13 @@ bool Foam::functionObjects::fieldValues::volFieldValue::usesVol() const } +bool Foam::functionObjects::fieldValues::volFieldValue::usesMag() const +{ + // Operation specifically tagged to use mag + return (operation_ & typeAbsolute); +} + + bool Foam::functionObjects::fieldValues::volFieldValue::usesWeight() const { // Operation specifically tagged to require a weight field @@ -111,35 +129,6 @@ bool Foam::functionObjects::fieldValues::volFieldValue::canWeight } -void Foam::functionObjects::fieldValues::volFieldValue::initialise -( - const dictionary& dict -) -{ - weightFieldName_ = "none"; - if (usesWeight()) - { - if (dict.readIfPresent("weightField", weightFieldName_)) - { - Info<< " weight field = " << weightFieldName_; - } - else - { - // Suggest possible alternative unweighted operation? - FatalIOErrorInFunction(dict) - << "The '" << operationTypeNames_[operation_] - << "' operation is missing a weightField." << nl - << "Either provide the weightField, " - << "use weightField 'none' to suppress weighting," << nl - << "or use a different operation." - << exit(FatalIOError); - } - } - - Info<< nl << endl; -} - - void Foam::functionObjects::fieldValues::volFieldValue::writeFileHeader ( Ostream& os @@ -153,6 +142,8 @@ void Foam::functionObjects::fieldValues::volFieldValue::writeFileHeader writeCommented(os, "Time"); + // TBD: add in postOperation information? + for (const word& fieldName : fields_) { os << tab << operationTypeNames_[operation_] @@ -209,6 +200,16 @@ Foam::functionObjects::fieldValues::volFieldValue::volFieldValue fieldValue(name, runTime, dict, typeName), volRegion(fieldValue::mesh_, dict), operation_(operationTypeNames_.get("operation", dict)), + postOperation_ + ( + postOperationTypeNames_.getOrDefault + ( + "postOperation", + dict, + postOperationType::postOpNone, + true // Failsafe behaviour + ) + ), weightFieldName_("none") { read(dict); @@ -226,6 +227,16 @@ Foam::functionObjects::fieldValues::volFieldValue::volFieldValue fieldValue(name, obr, dict, typeName), volRegion(fieldValue::mesh_, dict), operation_(operationTypeNames_.get("operation", dict)), + postOperation_ + ( + postOperationTypeNames_.getOrDefault + ( + "postOperation", + dict, + postOperationType::postOpNone, + true // Failsafe behaviour + ) + ), weightFieldName_("none") { read(dict); @@ -240,7 +251,29 @@ bool Foam::functionObjects::fieldValues::volFieldValue::read ) { fieldValue::read(dict); - initialise(dict); + + weightFieldName_ = "none"; + + if (usesWeight()) + { + if (dict.readIfPresent("weightField", weightFieldName_)) + { + Info<< " weight field = " << weightFieldName_; + } + else + { + // Suggest possible alternative unweighted operation? + FatalIOErrorInFunction(dict) + << "The '" << operationTypeNames_[operation_] + << "' operation is missing a weightField." << nl + << "Either provide the weightField, " + << "use weightField 'none' to suppress weighting," << nl + << "or use a different operation." + << exit(FatalIOError); + } + } + + Info<< nl << endl; return true; } diff --git a/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.H b/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.H index bafe8cff6b..f633e87d4d 100644 --- a/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.H +++ b/src/functionObjects/field/fieldValues/volFieldValue/volFieldValue.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2016-2019 OpenCFD Ltd. + Copyright (C) 2016-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -71,6 +71,7 @@ Usage regionType | volRegion type: see below | yes | name | Name of volRegion if required | no | operation | Operation to perform | yes | + postOperation | Post-operation to perform | no | none weightField | Name of field to apply weighting | no | fields | List of fields to operate on | yes | \endtable @@ -98,6 +99,13 @@ Usage weightedVolIntegrate | Weighted volume integral \endplaintable + The \c postOperation is one of: + \plaintable + none | No additional operation after calculation + mag | Component-wise \c mag() after normal operation + sqrt | Component-wise \c sqrt() after normal operation + \endplaintable + See also Foam::functionObjects::fieldValues::fieldValue Foam::functionObjects::volRegion @@ -132,16 +140,17 @@ class volFieldValue public fieldValue, public volRegion { - public: - // Public data types + // Public Data Types //- Bitmask values for operation variants enum operationVariant { typeBase = 0, //!< Base operation + typeScalar = 0x100, //!< Operation returns a scalar typeWeighted = 0x200, //!< Operation using weighting + typeAbsolute = 0x400, //!< Operation using mag (eg, for weighting) }; //- Operation type enumeration @@ -150,11 +159,11 @@ public: // Normal operations opNone = 0, //!< No operation - opMin, //!< Minimum - opMax, //!< Maximum - opSum, //!< Sum - opSumMag, //!< Magnitude of sum - opAverage, //!< Average + opMin, //!< Minimum value + opMax, //!< Maximum value + opSum, //!< Sum of values + opSumMag, //!< Sum of component magnitudes + opAverage, //!< Ensemble average opVolAverage, //!< Volume average opVolIntegrate, //!< Volume integral opCoV, //!< Coefficient of variation @@ -172,19 +181,36 @@ public: //! Weighted volume integral opWeightedVolIntegrate = (opVolIntegrate | typeWeighted), + + // Variants using absolute weighting }; //- Operation type names static const Enum operationTypeNames_; + //- Post-operation type enumeration + enum postOperationType + { + postOpNone, //!< No additional operation after calculation + postOpMag, //!< Component-wise mag after normal operation + postOpSqrt //!< Component-wise sqrt after normal operation + }; + + //- Operation type names + static const Enum postOperationTypeNames_; + + protected: - // Protected data + // Protected Data //- Operation to apply to values operationType operation_; + //- Optional post-evaluation operation + postOperationType postOperation_; + //- Weight field name - only used for weighted modes word weightFieldName_; @@ -194,6 +220,9 @@ protected: //- True if the operation needs the cell-volume bool usesVol() const; + //- True if the operation variant uses mag + bool usesMag() const; + //- True if the operation variant uses a weight-field bool usesWeight() const; @@ -201,9 +230,6 @@ protected: // Checks for availability on any processor. inline bool canWeight(const scalarField& weightField) const; - //- Initialise, e.g. cell addressing - void initialise(const dictionary& dict); - //- Return true if the field name is valid template bool validField(const word& fieldName) const; @@ -251,7 +277,7 @@ protected: public: - //- Run-time type information + //- Declare type-name, virtual type (with debug switch) TypeName("volFieldValue"); @@ -278,7 +304,7 @@ public: virtual ~volFieldValue() = default; - // Public Member Functions + // Member Functions //- Read from dictionary virtual bool read(const dictionary& dict); diff --git a/src/functionObjects/field/fieldValues/volFieldValue/volFieldValueTemplates.C b/src/functionObjects/field/fieldValues/volFieldValue/volFieldValueTemplates.C index d0585d2969..9a16129ba1 100644 --- a/src/functionObjects/field/fieldValues/volFieldValue/volFieldValueTemplates.C +++ b/src/functionObjects/field/fieldValues/volFieldValue/volFieldValueTemplates.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2019 OpenCFD Ltd. + Copyright (C) 2015-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -237,22 +237,83 @@ bool Foam::functionObjects::fieldValues::volFieldValue::writeValues Type result = processValues(values, V, weightField); + switch (postOperation_) + { + case postOpNone: + { + break; + } + case postOpMag: + { + // mag: component-wise - does not change the type + for (direction d=0; d < pTraits::nComponents; ++d) + { + setComponent(result, d) + = mag(component(result, d)); + } + break; + } + case postOpSqrt: + { + // sqrt: component-wise - does not change the type + for (direction d=0; d < pTraits::nComponents; ++d) + { + setComponent(result, d) + = sqrt(mag(component(result, d))); + } + break; + } + } + // Write state/results information - const word& opName = operationTypeNames_[operation_]; - word outName = fieldName; + word prefix, suffix; + { + if (postOperation_ != postOpNone) + { + // Adjust result name to include post-operation + prefix += postOperationTypeNames_[postOperation_]; + prefix += '('; + suffix += ')'; + } + + prefix += operationTypeNames_[operation_]; + prefix += '('; + suffix += ')'; + } + + word regionPrefix; if (this->volRegion::regionName_ != polyMesh::defaultRegion) { - outName = this->volRegion::regionName_ + ',' + outName; + regionPrefix = this->volRegion::regionName_ + ','; } - word resultName = opName + '(' + outName + ')'; - file()<< tab << result; + word resultName = prefix + regionPrefix + fieldName + suffix; - Log << " " << opName - << '(' << this->volRegion::regionName_ << ") of " << fieldName - << " = " << result << endl; + Log << " " << prefix << this->volRegion::regionName_ << suffix + << " of " << fieldName << " = "; - this->setResult(resultName, result); + + // Operation tagged that it always returns scalar? + const bool alwaysScalar(operation_ & typeScalar); + + if (alwaysScalar) + { + const scalar sresult = component(result, 0); + + file()<< tab << sresult; + + Log << sresult << endl; + + this->setResult(resultName, sresult); + } + else + { + file()<< tab << result; + + Log << result << endl; + + this->setResult(resultName, result); + } } } diff --git a/tutorials/compressible/overRhoPimpleDyMFoam/twoSimpleRotors/system/controlDict b/tutorials/compressible/overRhoPimpleDyMFoam/twoSimpleRotors/system/controlDict index dfb019b99c..4a63280719 100644 --- a/tutorials/compressible/overRhoPimpleDyMFoam/twoSimpleRotors/system/controlDict +++ b/tutorials/compressible/overRhoPimpleDyMFoam/twoSimpleRotors/system/controlDict @@ -96,6 +96,7 @@ functions log true; operation volIntegrate; + // postOperation mag; fields (