diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C index dbc4f0c31506fc33e64fa3e4010eafd2f50054ec..a816af06e72013c7cd2a8ba22a8c7560f87221a1 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-2021 OpenCFD Ltd. + Copyright (C) 2017-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,6 +38,9 @@ License // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +// Max number of warnings +static constexpr const unsigned maxWarnings = 10u; + namespace Foam { namespace functionObjects @@ -136,39 +139,13 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces() mesh_.faceZones().indices(selectionNames_) ); - // Total number of faces selected + // Total number of faces that could be selected (before patch filtering) label numFaces = 0; for (const label zoneId : zoneIds) { numFaces += mesh_.faceZones()[zoneId].size(); } - if (zoneIds.empty()) - { - FatalErrorInFunction - << type() << ' ' << name() << ": " - << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl - << " No matching face zone(s): " - << flatOutput(selectionNames_) << nl - << " Known face zones: " - << flatOutput(mesh_.faceZones().names()) << nl - << exit(FatalError); - } - - // Could also check this - #if 0 - if (!returnReduce(bool(numFaces), orOp<bool>())) - { - WarningInFunction - << type() << ' ' << name() << ": " - << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl - << " The faceZone specification: " - << flatOutput(selectionNames_) << nl - << " resulted in 0 faces" << nl - << exit(FatalError); - } - #endif - faceId_.resize(numFaces); facePatchId_.resize(numFaces); faceFlip_.resize(numFaces); @@ -231,7 +208,73 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces() faceId_.resize(numFaces); facePatchId_.resize(numFaces); faceFlip_.resize(numFaces); - nFaces_ = returnReduce(faceId_.size(), sumOp<label>()); + nFaces_ = returnReduce(numFaces, sumOp<label>()); + + if (!nFaces_) + { + // Raise warning or error + refPtr<OSstream> os; + bool fatal = false; + + switch (emptySurfaceError_) + { + case error::handlerTypes::IGNORE: + { + break; + } + + case error::handlerTypes::WARN: + { + if (++nWarnings_ <= maxWarnings) + { + os.ref(WarningInFunction); + } + break; + } + + // STRICT / DEFAULT + default: + { + os.ref(FatalErrorInFunction); + fatal = true; + break; + } + } + + if (os) + { + os.ref() + << type() << ' ' << name() << ": " + << regionTypeNames_[regionType_] + << '(' << regionName_ << "):" << nl; + + if (zoneIds.empty()) + { + os.ref() + << " No matching face zones: " + << flatOutput(selectionNames_) << nl + << " Known face zones: " + << flatOutput(mesh_.faceZones().names()) << nl; + } + else + { + os.ref() + << " The face zones: " + << flatOutput(selectionNames_) << nl + << " resulted in 0 faces" << nl; + } + + if (fatal) + { + FatalError<< exit(FatalError); + } + else if (nWarnings_ == maxWarnings) + { + os.ref() + << "... suppressing further warnings." << nl; + } + } + } } @@ -307,36 +350,10 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces() patchIds = std::move(selected); } - if (patchIds.empty()) - { - FatalErrorInFunction - << type() << ' ' << name() << ": " - << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl - << " No matching patch name(s): " - << flatOutput(selectionNames_) << nl - << " Known patch names:" << nl - << mesh_.boundaryMesh().names() << nl - << exit(FatalError); - } - - // Could also check this - #if 0 - if (!returnReduce(bool(numFaces), orOp<bool>())) - { - WarningInFunction - << type() << ' ' << name() << ": " - << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl - << " The patch specification: " - << flatOutput(selectionNames_) << nl - << " resulted in 0 faces" << nl - << exit(FatalError); - } - #endif - faceId_.resize(numFaces); facePatchId_.resize(numFaces); faceFlip_.resize(numFaces); - nFaces_ = returnReduce(faceId_.size(), sumOp<label>()); + nFaces_ = returnReduce(numFaces, sumOp<label>()); numFaces = 0; for (const label patchi : patchIds) @@ -350,6 +367,72 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces() numFaces += len; } + + if (!nFaces_) + { + refPtr<OSstream> os; + bool fatal = false; + + // Raise warning or error + switch (emptySurfaceError_) + { + case error::handlerTypes::IGNORE: + { + break; + } + + case error::handlerTypes::WARN: + { + if (++nWarnings_ <= maxWarnings) + { + os.ref(WarningInFunction); + } + break; + } + + // STRICT / DEFAULT + default: + { + os.ref(FatalErrorInFunction); + fatal = true; + break; + } + } + + if (os) + { + os.ref() + << type() << ' ' << name() << ": " + << regionTypeNames_[regionType_] + << '(' << regionName_ << "):" << nl; + + if (patchIds.empty()) + { + os.ref() + << " No matching patches: " + << flatOutput(selectionNames_) << nl + << " Known patch names:" << nl + << mesh_.boundaryMesh().names() << nl; + } + else + { + os.ref() + << " The patches: " + << flatOutput(selectionNames_) << nl + << " resulted in 0 faces" << nl; + } + + if (fatal) + { + FatalError<< exit(FatalError); + } + else if (nWarnings_ == maxWarnings) + { + os.ref() + << "... suppressing further warnings." << nl; + } + } + } } @@ -583,20 +666,29 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::update() return false; } + // Reset some values + totalArea_ = 0; + nFaces_ = 0; + switch (regionType_) { case stFaceZone: { + // Raises warning or error internally setFaceZoneFaces(); + if (!nFaces_) return true; break; } case stPatch: { + // Raises warning or error internally setPatchFaces(); + if (!nFaces_) return true; break; } case stObject: { + // TBD: special handling of cast errors? const polySurface& s = dynamicCast<const polySurface>(obr()); nFaces_ = returnReduce(s.size(), sumOp<label>()); break; @@ -610,12 +702,61 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::update() // Compiler warning if we forgot an enumeration } - if (nFaces_ == 0) + if (nFaces_) { - FatalErrorInFunction - << type() << ' ' << name() << ": " - << regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl - << " Region has no faces" << exit(FatalError); + // Appears to be successful - reset warnings counter + nWarnings_ = 0u; + } + else + { + // Raise warning or error + refPtr<OSstream> os; + bool fatal = false; + + switch (emptySurfaceError_) + { + case error::handlerTypes::IGNORE: + { + break; + } + + case error::handlerTypes::WARN: + { + if (++nWarnings_ <= maxWarnings) + { + os.ref(WarningInFunction); + } + break; + } + + // STRICT / DEFAULT + default: + { + os.ref(FatalErrorInFunction); + fatal = true; + break; + } + } + + if (os) + { + os.ref() + << type() << ' ' << name() << ": " + << regionTypeNames_[regionType_] + << '(' << regionName_ << "):" << nl + << " Region has no faces" << endl; + + if (fatal) + { + FatalError<< exit(FatalError); + } + else if (nWarnings_ == maxWarnings) + { + os.ref() + << "... suppressing further warnings." << nl; + } + } + return true; } totalArea_ = totalArea(); @@ -919,10 +1060,12 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue ), needsUpdate_(true), writeArea_(false), + emptySurfaceError_(error::handlerTypes::DEFAULT), selectionNames_(), weightFieldNames_(), totalArea_(0), nFaces_(0), + nWarnings_(0), faceId_(), facePatchId_(), faceFlip_() @@ -953,10 +1096,12 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue ), needsUpdate_(true), writeArea_(false), + emptySurfaceError_(error::handlerTypes::DEFAULT), selectionNames_(), weightFieldNames_(), totalArea_(0), nFaces_(0), + nWarnings_(0), faceId_(), facePatchId_(), faceFlip_() @@ -976,10 +1121,19 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read needsUpdate_ = true; writeArea_ = dict.getOrDefault("writeArea", false); + emptySurfaceError_ = error::handlerNames.getOrDefault + ( + "empty-surface", + dict, + error::handlerTypes::DEFAULT, + true // Failsafe behaviour + ); + weightFieldNames_.clear(); totalArea_ = 0; nFaces_ = 0; + nWarnings_ = 0; faceId_.clear(); facePatchId_.clear(); faceFlip_.clear(); @@ -1154,6 +1308,12 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write() update(); + if (!nFaces_) + { + // Encountered an error + return true; + } + if (operation_ != opNone) { writeCurrentTime(file()); diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.H index 1933802913d8b72bae544fd8f5e549351c03c7ae..1e8ece066817c16adc680627a013d980bb8abe9b 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-2020 OpenCFD Ltd. + Copyright (C) 2015-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -88,6 +88,7 @@ Usage scaleFactor 1.0; writeArea false; surfaceFormat none; + empty-surface warn; // default | warn | ignore | strict // Optional (inherited) entries ... @@ -111,6 +112,7 @@ Usage writeArea | Write the surface area | bool | no | false surfaceFormat | Output value format | word <!-- --> | conditional on writeFields | none + empty-surface | Error handling for empty surfaces | enum | no | default \endtable The inherited entries are elaborated in: @@ -401,6 +403,9 @@ protected: //- Optionally write the area of the surfaceFieldValue bool writeArea_; + //- Handling of empty surfaces (nFaces = 0). Default is Fatal. + error::handlerTypes emptySurfaceError_; + //- Extended selections wordRes selectionNames_; @@ -413,6 +418,9 @@ protected: //- Global number of faces label nFaces_; + //- Number of warnings emitted since the last valid update + unsigned nWarnings_; + // If operating on mesh faces (faceZone, patch)