diff --git a/src/sampling/Make/files b/src/sampling/Make/files index ad272d0e20..752ef13579 100644 --- a/src/sampling/Make/files +++ b/src/sampling/Make/files @@ -1,6 +1,5 @@ probes/probes.C probes/patchProbes.C -probes/probesGrouping.C sampledSet/circle/circleSet.C sampledSet/cloud/cloudSet.C diff --git a/src/sampling/probes/patchProbes.C b/src/sampling/probes/patchProbes.C index c630eeacb9..1763352469 100644 --- a/src/sampling/probes/patchProbes.C +++ b/src/sampling/probes/patchProbes.C @@ -201,13 +201,16 @@ void Foam::patchProbes::findElements(const fvMesh& mesh) // - faceList_ : faces (now patch faces) // - patchIDList_ : patch corresponding to faceList // - processor_ : processor - elementList_.setSize(nearest.size()); + elementList_.resize_nocopy(nearest.size()); elementList_ = -1; - faceList_.setSize(nearest.size()); + + faceList_.resize_nocopy(nearest.size()); faceList_ = -1; - processor_.setSize(nearest.size()); + + processor_.resize_nocopy(nearest.size()); processor_ = -1; - patchIDList_.setSize(nearest.size()); + + patchIDList_.resize_nocopy(nearest.size()); patchIDList_ = -1; forAll(nearest, sampleI) @@ -236,13 +239,13 @@ void Foam::patchProbes::findElements(const fvMesh& mesh) Foam::patchProbes::patchProbes ( const word& name, - const Time& t, + const Time& runTime, const dictionary& dict, const bool loadFromFiles, const bool readFields ) : - probes(name, t, dict, loadFromFiles, false) + probes(name, runTime, dict, loadFromFiles, false) { if (readFields) { @@ -253,27 +256,43 @@ Foam::patchProbes::patchProbes // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::patchProbes::write() +bool Foam::patchProbes::performAction(unsigned request) { - if (this->size() && prepare()) + if (!pointField::empty() && request && prepare(request)) { - sampleAndWrite(scalarFields_); - sampleAndWrite(vectorFields_); - sampleAndWrite(sphericalTensorFields_); - sampleAndWrite(symmTensorFields_); - sampleAndWrite(tensorFields_); + performAction(scalarFields_, request); + performAction(vectorFields_, request); + performAction(sphericalTensorFields_, request); + performAction(symmTensorFields_, request); + performAction(tensorFields_, request); - sampleAndWriteSurfaceFields(surfaceScalarFields_); - sampleAndWriteSurfaceFields(surfaceVectorFields_); - sampleAndWriteSurfaceFields(surfaceSphericalTensorFields_); - sampleAndWriteSurfaceFields(surfaceSymmTensorFields_); - sampleAndWriteSurfaceFields(surfaceTensorFields_); + performAction(surfaceScalarFields_, request); + performAction(surfaceVectorFields_, request); + performAction(surfaceSphericalTensorFields_, request); + performAction(surfaceSymmTensorFields_, request); + performAction(surfaceTensorFields_, request); + } + return true; +} + + +bool Foam::patchProbes::execute() +{ + if (onExecute_) + { + return performAction(ACTION_ALL & ~ACTION_WRITE); } return true; } +bool Foam::patchProbes::write() +{ + return performAction(ACTION_ALL); +} + + bool Foam::patchProbes::read(const dictionary& dict) { if (!dict.readIfPresent("patches", patchNames_)) diff --git a/src/sampling/probes/patchProbes.H b/src/sampling/probes/patchProbes.H index daf0a823e2..640b356941 100644 --- a/src/sampling/probes/patchProbes.H +++ b/src/sampling/probes/patchProbes.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2020 OpenCFD Ltd. + Copyright (C) 2016-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -64,14 +64,14 @@ Description } \endverbatim - SourceFiles patchProbes.C + patchProbesTemplates.C \*---------------------------------------------------------------------------*/ -#ifndef patchProbes_H -#define patchProbes_H +#ifndef Foam_patchProbes_H +#define Foam_patchProbes_H #include "probes.H" @@ -80,12 +80,6 @@ SourceFiles namespace Foam { -// Forward declaration of classes -class objectRegistry; -class dictionary; -class fvMesh; -class mapPolyMesh; - /*---------------------------------------------------------------------------*\ Class patchProbes Declaration \*---------------------------------------------------------------------------*/ @@ -96,7 +90,7 @@ class patchProbes { protected: - // Protected data + // Protected Data //- Patches to sample wordRes patchNames_; @@ -104,52 +98,35 @@ protected: // Protected Member Functions - //- Sample and write a particular volume field - template - void sampleAndWrite - ( - const GeometricField& - ); - - //- Sample and write a particular surface field - template - void sampleAndWrite - ( - const GeometricField& - ); - - //- Sample and write all the fields of the given type - template - void sampleAndWrite(const fieldGroup&); - - //- Sample and write all the surface fields of the given type - template - void sampleAndWriteSurfaceFields(const fieldGroup&); - - //- Sample a volume field at all locations - template - tmp> sample - ( - const GeometricField& - ) const; - - //- Sample a surface field at all locations - template - tmp> sample - ( - const GeometricField& - ) const; - - //- Sample a single field on all sample locations - template - tmp> sample(const word& fieldName) const; - //- Find elements containing patchProbes - virtual void findElements(const fvMesh&); + virtual void findElements(const fvMesh& mesh); // override private: + // Private Member Functions + + //- Write field values + template + void writeValues + ( + const word& fieldName, + const Field& values, + const scalar timeValue + ); + + //- Sample and store/write applicable volume/surface fields + template + void performAction + ( + const fieldGroup& fieldNames, /* must be sorted */ + unsigned request + ); + + //- Perform sampling action with store/write + bool performAction(unsigned request); + + //- No copy construct patchProbes(const patchProbes&) = delete; @@ -169,7 +146,7 @@ public: patchProbes ( const word& name, - const Time& time, + const Time& runTime, const dictionary& dict, const bool loadFromFiles = false, const bool readFields = true @@ -179,13 +156,35 @@ public: virtual ~patchProbes() = default; - //- Public members + // Member Functions + + //- Sample and store result if the sampleOnExecute is enabled. + virtual bool execute(); //- Sample and write virtual bool write(); //- Read virtual bool read(const dictionary&); + + + // Sampling + + //- Sample a volume field at all locations + template + tmp> sample(const VolumeField&) const; + + //- Sample a surface field at all locations + template + tmp> sample(const SurfaceField&) const; + + //- Sample a single field on all sample locations + template + tmp> sample(const word& fieldName) const; + + //- Sample a surface field at all locations + template + tmp> sampleSurfaceField(const word& fieldName) const; }; diff --git a/src/sampling/probes/patchProbesTemplates.C b/src/sampling/probes/patchProbesTemplates.C index 530e1a7698..7ba5c78dc5 100644 --- a/src/sampling/probes/patchProbesTemplates.C +++ b/src/sampling/probes/patchProbesTemplates.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2021 OpenCFD Ltd. + Copyright (C) 2021-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,153 +28,57 @@ License #include "patchProbes.H" #include "volFields.H" +#include "surfaceFields.H" #include "IOmanip.H" - // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template -void Foam::patchProbes::sampleAndWrite +void Foam::patchProbes::writeValues ( - const GeometricField& vField + const word& fieldName, + const Field& values, + const scalar timeValue ) { - Field values(sample(vField)); - if (Pstream::master()) { - unsigned int w = IOstream::defaultPrecision() + 7; - OFstream& probeStream = *probeFilePtrs_[vField.name()]; + const unsigned int w = IOstream::defaultPrecision() + 7; + OFstream& os = *probeFilePtrs_[fieldName]; - probeStream - << setw(w) - << vField.time().timeOutputValue(); + os << setw(w) << timeValue; for (const auto& v : values) { - probeStream << ' ' << setw(w) << v; + os << ' ' << setw(w) << v; } - probeStream << endl; + os << endl; } - - const word& fieldName = vField.name(); - this->setResult("average(" + fieldName + ")", average(values)); - this->setResult("min(" + fieldName + ")", min(values)); - this->setResult("max(" + fieldName + ")", max(values)); - this->setResult("size(" + fieldName + ")", values.size()); } -template -void Foam::patchProbes::sampleAndWrite +template +void Foam::patchProbes::performAction ( - const GeometricField& sField + const fieldGroup& fieldNames, + unsigned request ) { - Field values(sample(sField)); - - if (Pstream::master()) + for (const word& fieldName : fieldNames) { - unsigned int w = IOstream::defaultPrecision() + 7; - OFstream& probeStream = *probeFilePtrs_[sField.name()]; + tmp tfield = getOrLoadField(fieldName); - probeStream - << setw(w) - << sField.time().timeOutputValue(); - - for (const auto& v : values) + if (tfield) { - probeStream << ' ' << setw(w) << v; - } - probeStream << endl; - } + const auto& field = tfield(); + const scalar timeValue = field.time().timeOutputValue(); - const word& fieldName = sField.name(); - this->setResult("average(" + fieldName + ")", average(values)); - this->setResult("min(" + fieldName + ")", min(values)); - this->setResult("max(" + fieldName + ")", max(values)); - this->setResult("size(" + fieldName + ")", values.size()); -} + Field values(sample(field)); - -template -void Foam::patchProbes::sampleAndWrite -( - const fieldGroup& fields -) -{ - typedef GeometricField VolFieldType; - - for (const auto& fieldName : fields) - { - if (loadFromFiles_) - { - sampleAndWrite - ( - VolFieldType - ( - IOobject - ( - fieldName, - mesh_.time().timeName(), - mesh_, - IOobject::MUST_READ, - IOobject::NO_WRITE, - false - ), - mesh_ - ) - ); - } - else - { - objectRegistry::const_iterator iter = mesh_.find(fieldName); - - if (iter.found() && iter()->type() == VolFieldType::typeName) + this->storeResults(fieldName, values); + if (request & ACTION_WRITE) { - sampleAndWrite(mesh_.lookupObject(fieldName)); - } - } - } -} - - -template -void Foam::patchProbes::sampleAndWriteSurfaceFields -( - const fieldGroup& fields -) -{ - typedef GeometricField SurfaceFieldType; - - for (const auto& fieldName : fields) - { - if (loadFromFiles_) - { - sampleAndWrite - ( - SurfaceFieldType - ( - IOobject - ( - fieldName, - mesh_.time().timeName(), - mesh_, - IOobject::MUST_READ, - IOobject::NO_WRITE, - false - ), - mesh_ - ) - ); - } - else - { - objectRegistry::const_iterator iter = mesh_.find(fieldName); - - if (iter.found() && iter()->type() == SurfaceFieldType::typeName) - { - sampleAndWrite(mesh_.lookupObject(fieldName)); + this->writeValues(fieldName, values, timeValue); } } } @@ -185,17 +89,15 @@ void Foam::patchProbes::sampleAndWriteSurfaceFields template Foam::tmp> -Foam::patchProbes::sample -( - const GeometricField& vField -) const +Foam::patchProbes::sample(const VolumeField& vField) const { const Type unsetVal(-VGREAT*pTraits::one); - auto tValues = tmp>::New(Field(this->size(), unsetVal)); - auto& values = tValues.ref(); + auto tvalues = tmp>::New(Field(this->size(), unsetVal)); + auto& values = tvalues.ref(); const polyBoundaryMesh& patches = mesh_.boundaryMesh(); + const auto& bField = vField.boundaryField(); forAll(*this, probei) { @@ -205,14 +107,45 @@ Foam::patchProbes::sample { label patchi = patches.whichPatch(facei); label localFacei = patches[patchi].whichFace(facei); - values[probei] = vField.boundaryField()[patchi][localFacei]; + values[probei] = bField[patchi][localFacei]; } } Pstream::listCombineGather(values, isNotEqOp()); Pstream::listCombineScatter(values); - return tValues; + return tvalues; +} + + +template +Foam::tmp> +Foam::patchProbes::sample(const SurfaceField& sField) const +{ + const Type unsetVal(-VGREAT*pTraits::one); + + auto tvalues = tmp>::New(Field(this->size(), unsetVal)); + auto& values = tvalues.ref(); + + const polyBoundaryMesh& patches = mesh_.boundaryMesh(); + const auto& bField = sField.boundaryField(); + + forAll(*this, probei) + { + label facei = faceList_[probei]; + + if (facei >= 0) + { + label patchi = patches.whichPatch(facei); + label localFacei = patches[patchi].whichFace(facei); + values[probei] = bField[patchi][localFacei]; + } + } + + Pstream::listCombineGather(values, isNotEqOp()); + Pstream::listCombineScatter(values); + + return tvalues; } @@ -220,46 +153,15 @@ template Foam::tmp> Foam::patchProbes::sample(const word& fieldName) const { - return sample - ( - mesh_.lookupObject> - ( - fieldName - ) - ); + return sample(mesh_.lookupObject>(fieldName)); } template Foam::tmp> -Foam::patchProbes::sample -( - const GeometricField& sField -) const +Foam::patchProbes::sampleSurfaceField(const word& fieldName) const { - const Type unsetVal(-VGREAT*pTraits::one); - - auto tValues = tmp>::New(Field(this->size(), unsetVal)); - auto& values = tValues.ref(); - - const polyBoundaryMesh& patches = mesh_.boundaryMesh(); - - forAll(*this, probei) - { - label facei = faceList_[probei]; - - if (facei >= 0) - { - label patchi = patches.whichPatch(facei); - label localFacei = patches[patchi].whichFace(facei); - values[probei] = sField.boundaryField()[patchi][localFacei]; - } - } - - Pstream::listCombineGather(values, isNotEqOp()); - Pstream::listCombineScatter(values); - - return tValues; + return sample(mesh_.lookupObject>(fieldName)); } diff --git a/src/sampling/probes/probes.C b/src/sampling/probes/probes.C index cd73a5e7c5..de8eb42ce7 100644 --- a/src/sampling/probes/probes.C +++ b/src/sampling/probes/probes.C @@ -27,8 +27,9 @@ License \*---------------------------------------------------------------------------*/ #include "probes.H" -#include "volFields.H" #include "dictionary.H" +#include "volFields.H" +#include "surfaceFields.H" #include "Time.H" #include "IOmanip.H" #include "mapPolyMesh.H" @@ -55,18 +56,14 @@ void Foam::probes::findElements(const fvMesh& mesh) { DebugInfo<< "probes: resetting sample locations" << endl; - elementList_.clear(); - elementList_.setSize(size()); - - faceList_.clear(); - faceList_.setSize(size()); - - processor_.setSize(size()); + elementList_.resize_nocopy(pointField::size()); + faceList_.resize_nocopy(pointField::size()); + processor_.resize_nocopy(pointField::size()); processor_ = -1; forAll(*this, probei) { - const vector& location = operator[](probei); + const point& location = (*this)[probei]; const label celli = mesh.findCell(location); @@ -107,7 +104,7 @@ void Foam::probes::findElements(const fvMesh& mesh) // Check if all probes have been found. forAll(elementList_, probei) { - const vector& location = operator[](probei); + const point& location = operator[](probei); label celli = elementList_[probei]; label facei = faceList_[probei]; @@ -171,15 +168,53 @@ void Foam::probes::findElements(const fvMesh& mesh) } -Foam::label Foam::probes::prepare() +Foam::label Foam::probes::prepare(unsigned request) { - const label nFields = classifyFields(); + // Prefilter on selection + HashTable selected = + ( + loadFromFiles_ + ? IOobjectList(mesh_, mesh_.time().timeName()).classes(fieldSelection_) + : mesh_.classes(fieldSelection_) + ); - // adjust file streams + // Classify and count fields + label nFields = 0; + do + { + #undef doLocalCode + #define doLocalCode(InputType, Target) \ + { \ + Target.clear(); /* Remove old values */ \ + const auto iter = selected.cfind(InputType::typeName); \ + if (iter.found()) \ + { \ + /* Add new (current) values */ \ + Target.append(iter.val().sortedToc()); \ + nFields += Target.size(); \ + } \ + } + + doLocalCode(volScalarField, scalarFields_); + doLocalCode(volVectorField, vectorFields_) + doLocalCode(volSphericalTensorField, sphericalTensorFields_); + doLocalCode(volSymmTensorField, symmTensorFields_); + doLocalCode(volTensorField, tensorFields_); + + doLocalCode(surfaceScalarField, surfaceScalarFields_); + doLocalCode(surfaceVectorField, surfaceVectorFields_); + doLocalCode(surfaceSphericalTensorField, surfaceSphericalTensorFields_); + doLocalCode(surfaceSymmTensorField, surfaceSymmTensorFields_); + doLocalCode(surfaceTensorField, surfaceTensorFields_); + #undef doLocalCode + } + while (false); + + + // Adjust file streams if (Pstream::master()) { - wordHashSet currentFields; - + wordHashSet currentFields(2*nFields); currentFields.insert(scalarFields_); currentFields.insert(vectorFields_); currentFields.insert(sphericalTensorFields_); @@ -197,27 +232,7 @@ Foam::label Foam::probes::prepare() << "Probing locations: " << *this << nl << endl; - - fileName probeSubDir = name(); - - if (mesh_.name() != polyMesh::defaultRegion) - { - probeSubDir = probeSubDir/mesh_.name(); - } - - // Put in undecomposed case - // (Note: gives problems for distributed data running) - - fileName probeDir - ( - mesh_.time().globalPath() - / functionObject::outputPrefix - / probeSubDir - / mesh_.time().timeName() - ); - probeDir.clean(); // Remove unneeded ".." - - // ignore known fields, close streams for fields that no longer exist + // Close streams for fields that no longer exist forAllIters(probeFilePtrs_, iter) { if (!currentFields.erase(iter.key())) @@ -228,28 +243,59 @@ Foam::label Foam::probes::prepare() } } - // currentFields now just has the new fields - open streams for them - for (const word& fieldName : currentFields) + if (!(request & ACTION_WRITE)) { - // Create directory if does not exist. - mkDir(probeDir); + // No writing - can return now + return nFields; + } + else if (currentFields.empty()) + { + // No new fields - can return now + return nFields; + } - auto fPtr = autoPtr::New(probeDir/fieldName); - auto& fout = *fPtr; - DebugInfo<< "open probe stream: " << fout.name() << endl; + // Have new fields - open streams for them - probeFilePtrs_.insert(fieldName, fPtr); + // Put in undecomposed case + // (Note: gives problems for distributed data running) - unsigned int w = IOstream::defaultPrecision() + 7; + fileName probeSubDir = name(); + if (mesh_.name() != polyMesh::defaultRegion) + { + probeSubDir = probeSubDir/mesh_.name(); + } + + fileName probeDir + ( + mesh_.time().globalPath() + / functionObject::outputPrefix + / probeSubDir + / mesh_.time().timeName() + ); + probeDir.clean(); // Remove unneeded ".." + + // Create directory if needed + mkDir(probeDir); + + for (const word& fieldName : currentFields.sortedToc()) + { + auto osPtr = autoPtr::New(probeDir/fieldName); + auto& os = *osPtr; + + probeFilePtrs_.insert(fieldName, osPtr); + + DebugInfo<< "open probe stream: " << os.name() << endl; + + const unsigned int w = IOstream::defaultPrecision() + 7; forAll(*this, probei) { - fout<< "# Probe " << probei << ' ' << operator[](probei); + os << "# Probe " << probei << ' ' << operator[](probei); if (processor_[probei] == -1) { - fout<< " # Not Found"; + os << " # Not Found"; } // Only for patchProbes else if (probei < patchIDList_.size()) @@ -264,31 +310,31 @@ Foam::label Foam::probes::prepare() || processor_[probei] == Pstream::myProcNo() ) { - fout<< " at patch " << bm[patchi].name(); + os << " at patch " << bm[patchi].name(); } - fout<< " with a distance of " + os << " with a distance of " << mag(operator[](probei)-oldPoints_[probei]) << " m to the original point " << oldPoints_[probei]; } } - fout<< endl; + os << nl; } - fout<< '#' << setw(IOstream::defaultPrecision() + 6) + os << '#' << setw(IOstream::defaultPrecision() + 6) << "Probe"; forAll(*this, probei) { if (includeOutOfBounds_ || processor_[probei] != -1) { - fout<< ' ' << setw(w) << probei; + os << ' ' << setw(w) << probei; } } - fout<< endl; + os << nl; - fout<< '#' << setw(IOstream::defaultPrecision() + 6) + os << '#' << setw(IOstream::defaultPrecision() + 6) << "Time" << endl; } } @@ -308,23 +354,15 @@ Foam::probes::probes const bool readFields ) : - stateFunctionObject(name, runTime), - pointField(0), - mesh_ - ( - refCast - ( - runTime.lookupObject - ( - dict.getOrDefault("region", polyMesh::defaultRegion) - ) - ) - ), + functionObjects::fvMeshFunctionObject(name, runTime, dict), + pointField(), loadFromFiles_(loadFromFiles), - fieldSelection_(), fixedLocations_(true), - interpolationScheme_("cell"), - includeOutOfBounds_(true) + includeOutOfBounds_(true), + verbose_(false), + onExecute_(false), + fieldSelection_(), + samplePointScheme_("cell") { if (readFields) { @@ -335,15 +373,28 @@ Foam::probes::probes // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +bool Foam::probes::verbose(const bool on) noexcept +{ + bool old(verbose_); + verbose_ = on; + return old; +} + + bool Foam::probes::read(const dictionary& dict) { dict.readEntry("probeLocations", static_cast(*this)); dict.readEntry("fields", fieldSelection_); dict.readIfPresent("fixedLocations", fixedLocations_); - if (dict.readIfPresent("interpolationScheme", interpolationScheme_)) + dict.readIfPresent("includeOutOfBounds", includeOutOfBounds_); + + verbose_ = dict.getOrDefault("verbose", false); + onExecute_ = dict.getOrDefault("sampleOnExecute", false); + + if (dict.readIfPresent("interpolationScheme", samplePointScheme_)) { - if (!fixedLocations_ && interpolationScheme_ != "cell") + if (!fixedLocations_ && samplePointScheme_ != "cell") { WarningInFunction << "Only cell interpolation can be applied when " @@ -352,41 +403,51 @@ bool Foam::probes::read(const dictionary& dict) << endl; } } - dict.readIfPresent("includeOutOfBounds", includeOutOfBounds_); // Initialise cells to sample from supplied locations findElements(mesh_); - prepare(); + // Close old (ununsed) streams + prepare(ACTION_NONE); return true; } +bool Foam::probes::performAction(unsigned request) +{ + if (!pointField::empty() && request && prepare(request)) + { + performAction(scalarFields_, request); + performAction(vectorFields_, request); + performAction(sphericalTensorFields_, request); + performAction(symmTensorFields_, request); + performAction(tensorFields_, request); + + performAction(surfaceScalarFields_, request); + performAction(surfaceVectorFields_, request); + performAction(surfaceSphericalTensorFields_, request); + performAction(surfaceSymmTensorFields_, request); + performAction(surfaceTensorFields_, request); + } + return true; +} + + bool Foam::probes::execute() { + if (onExecute_) + { + return performAction(ACTION_ALL & ~ACTION_WRITE); + } + return true; } bool Foam::probes::write() { - if (size() && prepare()) - { - sampleAndWrite(scalarFields_); - sampleAndWrite(vectorFields_); - sampleAndWrite(sphericalTensorFields_); - sampleAndWrite(symmTensorFields_); - sampleAndWrite(tensorFields_); - - sampleAndWriteSurfaceFields(surfaceScalarFields_); - sampleAndWriteSurfaceFields(surfaceVectorFields_); - sampleAndWriteSurfaceFields(surfaceSphericalTensorFields_); - sampleAndWriteSurfaceFields(surfaceSymmTensorFields_); - sampleAndWriteSurfaceFields(surfaceTensorFields_); - } - - return true; + return performAction(ACTION_ALL); } diff --git a/src/sampling/probes/probes.H b/src/sampling/probes/probes.H index 0c6639e85c..d51b308c1e 100644 --- a/src/sampling/probes/probes.H +++ b/src/sampling/probes/probes.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2021 OpenCFD Ltd. + Copyright (C) 2016-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -50,7 +50,7 @@ Description writeInterval 1; // Fields to be probed - fields (p U); + fields (U "p.*"); // Optional: do not recalculate cells if mesh moves fixedLocations false; @@ -72,15 +72,28 @@ Description } \endverbatim + Entries: + \table + Property | Description | Required | Default + type | Type-name: probes | yes | + probeLocations | Probe locations | yes | + fields | word/regex list of fields to sample | yes | + interpolationScheme | scheme to obtain values | no | cell + fixedLocations | Do not recalculate cells if mesh moves | no | true + includeOutOfBounds | Include out-of-bounds locations | no | true + sampleOnExecute | Sample on execution and store results | no | false + \endtable + SourceFiles probes.C + probesTemplates.C \*---------------------------------------------------------------------------*/ -#ifndef probes_H -#define probes_H +#ifndef Foam_probes_H +#define Foam_probes_H -#include "stateFunctionObject.H" +#include "fvMeshFunctionObject.H" #include "HashPtrTable.H" #include "OFstream.H" #include "polyMesh.H" @@ -89,15 +102,14 @@ SourceFiles #include "surfaceFieldsFwd.H" #include "surfaceMesh.H" #include "wordRes.H" - -using namespace Foam::functionObjects; +#include "IOobjectList.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -// Forward declaration of classes +// Forward Declarations class Time; class objectRegistry; class dictionary; @@ -110,70 +122,75 @@ class mapPolyMesh; class probes : - public stateFunctionObject, + public functionObjects::fvMeshFunctionObject, public pointField { protected: - // Protected classes + // Protected Classes - //- Class used for grouping field types - template - class fieldGroup - : - public DynamicList + //- Grouping of field names by GeometricField type + template + struct fieldGroup : public DynamicList {}; + + + // Data Types + + //- Local control for sampling actions + enum sampleActionType : unsigned { - public: - //- Construct null - fieldGroup() - : - DynamicList(0) - {} + ACTION_NONE = 0, + ACTION_WRITE = 0x1, + ACTION_STORE = 0x2, + ACTION_ALL = 0xF }; - // Protected data - - //- Const reference to fvMesh - const fvMesh& mesh_; + // Protected Data //- Load fields from files (not from objectRegistry) bool loadFromFiles_; - - // Read from dictionary - - //- Names of fields to probe - wordRes fieldSelection_; - - //- Fixed locations, default = yes + //- Fixed locations (default: true) // Note: set to false for moving mesh calculations where locations // should move with the mesh bool fixedLocations_; - //- Interpolation scheme name - // Note: only possible when fixedLocations_ is true - word interpolationScheme_; - - //- Include probes that were not found + //- Include probes that were not found (default: true) bool includeOutOfBounds_; + //- Output verbosity + bool verbose_; - // Calculated + //- Perform sample actions on execute as well + bool onExecute_; - //- Categorized scalar/vector/tensor vol fields - fieldGroup scalarFields_; - fieldGroup vectorFields_; - fieldGroup sphericalTensorFields_; - fieldGroup symmTensorFields_; - fieldGroup tensorFields_; + //- Requested names of fields to probe + wordRes fieldSelection_; - //- Categorized scalar/vector/tensor surf fields - fieldGroup surfaceScalarFields_; - fieldGroup surfaceVectorFields_; - fieldGroup surfaceSphericalTensorFields_; - fieldGroup surfaceSymmTensorFields_; - fieldGroup surfaceTensorFields_; + //- Interpolation/sample scheme to obtain values at the points + // Note: only possible when fixedLocations_ is true + word samplePointScheme_; + + + // Calculated + + //- Current list of field names selected for sampling + DynamicList selectedFieldNames_; + + //- Categorized scalar/vector/tensor volume fields + fieldGroup scalarFields_; + fieldGroup vectorFields_; + fieldGroup sphericalTensorFields_; + fieldGroup symmTensorFields_; + fieldGroup tensorFields_; + + //- Categorized scalar/vector/tensor surface fields + fieldGroup surfaceScalarFields_; + fieldGroup surfaceVectorFields_; + fieldGroup surfaceSphericalTensorFields_; + fieldGroup surfaceSymmTensorFields_; + fieldGroup surfaceTensorFields_; //- Cells to be probed (obtained from the locations) labelList elementList_; @@ -185,58 +202,57 @@ protected: // on any processor) labelList processor_; - //- Current open files + //- Current open files (non-empty on master only) HashPtrTable probeFilePtrs_; - // Additional fields for patchProbes + //- Patch IDs on which the new probes are located (for patchProbes) + labelList patchIDList_; - //- Patch IDs on which the new probes are located - labelList patchIDList_; - - //- Original probes location (only used for patchProbes) - pointField oldPoints_; + //- Original probes location (only used for patchProbes) + pointField oldPoints_; // Protected Member Functions - //- Clear old field groups - void clearFieldGroups(); - - //- Classify field types, returns the number of fields - label classifyFields(); - //- Find cells and faces containing probes virtual void findElements(const fvMesh& mesh); - //- Classify field type and open/close file streams, - // returns number of fields to sample - label prepare(); + //- Classify field types, close/open file streams + // \return number of fields to sample + label prepare(unsigned request); + + //- Get from registry or load from disk + template + tmp getOrLoadField(const word& fieldName) const; + + //- Store results: min/max/average/size + template + void storeResults(const word& fieldName, const Field& values); private: - //- Sample and write a particular volume field + // Private Member Functions + + //- Write field values template - void sampleAndWrite + void writeValues ( - const GeometricField& + const word& fieldName, + const Field& values, + const scalar timeValue ); - - //- Sample and write a particular surface field - template - void sampleAndWrite + //- Sample and store/write all applicable sampled fields + template + void performAction ( - const GeometricField& + const fieldGroup& fieldNames, /* must be sorted */ + unsigned request ); - //- Sample and write all the fields of the given type - template - void sampleAndWrite(const fieldGroup&); - - //- Sample and write all the surface fields of the given type - template - void sampleAndWriteSurfaceFields(const fieldGroup&); + //- Perform sampling action with store/write + bool performAction(unsigned request); //- No copy construct probes(const probes&) = delete; @@ -244,7 +260,6 @@ private: //- No copy assignment void operator=(const probes&) = delete; - public: //- Runtime type information @@ -270,14 +285,18 @@ public: // Member Functions + //- Enable/disable verbose output + // \return old value + bool verbose(const bool on) noexcept; + //- Return names of fields to probe - virtual const wordRes& fieldNames() const + virtual const wordRes& fieldNames() const noexcept { return fieldSelection_; } //- Return locations to probe - virtual const pointField& probeLocations() const + virtual const pointField& probeLocations() const noexcept { return *this; } @@ -289,7 +308,7 @@ public: } //- Cells to be probed (obtained from the locations) - const labelList& elements() const + const labelList& elements() const noexcept { return elementList_; } @@ -297,7 +316,7 @@ public: //- Read the probes virtual bool read(const dictionary&); - //- Execute, currently does nothing + //- Sample and store result if the sampleOnExecute is enabled. virtual bool execute(); //- Sample and write @@ -313,27 +332,24 @@ public: virtual void readUpdate(const polyMesh::readUpdateState state) {} + + // Sampling + //- Sample a volume field at all locations template - tmp> sample - ( - const GeometricField& - ) const; - - //- Sample a single vol field on all sample locations - template - tmp> sample(const word& fieldName) const; - - //- Sample a single scalar field on all sample locations - template - tmp> sampleSurfaceFields(const word& fieldName) const; + tmp> sample(const VolumeField&) const; //- Sample a surface field at all locations template - tmp> sample - ( - const GeometricField& - ) const; + tmp> sample(const SurfaceField&) const; + + //- Sample a volume field at all locations + template + tmp> sample(const word& fieldName) const; + + //- Sample a surface field at all locations + template + tmp> sampleSurfaceField(const word& fieldName) const; }; diff --git a/src/sampling/probes/probesGrouping.C b/src/sampling/probes/probesGrouping.C deleted file mode 100644 index c1ccfb2221..0000000000 --- a/src/sampling/probes/probesGrouping.C +++ /dev/null @@ -1,127 +0,0 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2011-2016 OpenFOAM Foundation -------------------------------------------------------------------------------- -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 . - -\*---------------------------------------------------------------------------*/ - -#include "probes.H" -#include "volFields.H" -#include "surfaceFields.H" -#include "IOobjectList.H" -#include "stringListOps.H" - -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -void Foam::probes::clearFieldGroups() -{ - scalarFields_.clear(); - vectorFields_.clear(); - sphericalTensorFields_.clear(); - symmTensorFields_.clear(); - tensorFields_.clear(); - - surfaceScalarFields_.clear(); - surfaceVectorFields_.clear(); - surfaceSphericalTensorFields_.clear(); - surfaceSymmTensorFields_.clear(); - surfaceTensorFields_.clear(); -} - - -Foam::label Foam::probes::classifyFields() -{ - label nFields = 0; - clearFieldGroups(); - - HashTable available = - ( - loadFromFiles_ - ? IOobjectList(mesh_, mesh_.time().timeName()).classes(fieldSelection_) - : mesh_.classes(fieldSelection_) - ); - - forAllConstIters(available, iter) - { - const word& fieldType = iter.key(); - const wordList fieldNames = iter.val().sortedToc(); - - const label count = fieldNames.size(); // pre-filtered, so non-empty - - if (fieldType == volScalarField::typeName) - { - scalarFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == volVectorField::typeName) - { - vectorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == volSphericalTensorField::typeName) - { - sphericalTensorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == volSymmTensorField::typeName) - { - symmTensorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == volTensorField::typeName) - { - tensorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == surfaceScalarField::typeName) - { - surfaceScalarFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == surfaceVectorField::typeName) - { - surfaceVectorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == surfaceSphericalTensorField::typeName) - { - surfaceSphericalTensorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == surfaceSymmTensorField::typeName) - { - surfaceSymmTensorFields_.append(fieldNames); - nFields += count; - } - else if (fieldType == surfaceTensorField::typeName) - { - surfaceTensorFields_.append(fieldNames); - nFields += count; - } - } - - return nFields; -} - - -// ************************************************************************* // diff --git a/src/sampling/probes/probesTemplates.C b/src/sampling/probes/probesTemplates.C index 1ad0d4bd1a..4ac886ec45 100644 --- a/src/sampling/probes/probesTemplates.C +++ b/src/sampling/probes/probesTemplates.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2017-2021 OpenCFD Ltd. + Copyright (C) 2017-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,10 +38,8 @@ namespace Foam { template -class isNotEqOp +struct isNotEqOp { -public: - void operator()(T& x, const T& y) const { const T unsetVal(-VGREAT*pTraits::one); @@ -61,25 +59,87 @@ public: } }; +} // End namespace Foam + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +template +Foam::tmp +Foam::probes::getOrLoadField(const word& fieldName) const +{ + tmp tfield; + + if (loadFromFiles_) + { + tfield.reset + ( + new GeoField + ( + IOobject + ( + fieldName, + mesh_.time().timeName(), + mesh_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ), + mesh_ + ) + ); + } + else + { + // Slightly paranoid here + tfield.cref(mesh_.cfindObject(fieldName)); + } + + return tfield; +} + + +template +void Foam::probes::storeResults +( + const word& fieldName, + const Field& values +) +{ + const MinMax limits(values); + const Type avgVal = average(values); + + this->setResult("average(" + fieldName + ")", avgVal); + this->setResult("min(" + fieldName + ")", limits.min()); + this->setResult("max(" + fieldName + ")", limits.max()); + this->setResult("size(" + fieldName + ")", values.size()); + + if (verbose_) + { + Info<< name() << " : " << fieldName << nl + << " avg: " << avgVal << nl + << " min: " << limits.min() << nl + << " max: " << limits.max() << nl << nl; + } } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template -void Foam::probes::sampleAndWrite +void Foam::probes::writeValues ( - const GeometricField& vField + const word& fieldName, + const Field& values, + const scalar timeValue ) { - Field values(sample(vField)); - if (Pstream::master()) { - unsigned int w = IOstream::defaultPrecision() + 7; - OFstream& os = *probeFilePtrs_[vField.name()]; + const unsigned int w = IOstream::defaultPrecision() + 7; + OFstream& os = *probeFilePtrs_[fieldName]; - os << setw(w) << vField.time().timeOutputValue(); + os << setw(w) << timeValue; forAll(values, probei) { @@ -90,144 +150,53 @@ void Foam::probes::sampleAndWrite } os << endl; } - - const word& fieldName = vField.name(); - this->setResult("average(" + fieldName + ")", average(values)); - this->setResult("min(" + fieldName + ")", min(values)); - this->setResult("max(" + fieldName + ")", max(values)); - this->setResult("size(" + fieldName + ")", values.size()); } -template -void Foam::probes::sampleAndWrite +template +void Foam::probes::performAction ( - const GeometricField& sField + const fieldGroup& fieldNames, + unsigned request ) { - Field values(sample(sField)); - - if (Pstream::master()) + for (const word& fieldName : fieldNames) { - unsigned int w = IOstream::defaultPrecision() + 7; - OFstream& os = *probeFilePtrs_[sField.name()]; + tmp tfield = getOrLoadField(fieldName); - os << setw(w) << sField.time().timeOutputValue(); - - forAll(values, probei) + if (tfield) { - if (includeOutOfBounds_ || processor_[probei] != -1) + const auto& field = tfield(); + const scalar timeValue = field.time().timeOutputValue(); + + Field values(sample(field)); + + this->storeResults(fieldName, values); + if (request & ACTION_WRITE) { - os << ' ' << setw(w) << values[probei]; - } - } - os << endl; - } - - const word& fieldName = sField.name(); - this->setResult("average(" + fieldName + ")", average(values)); - this->setResult("min(" + fieldName + ")", min(values)); - this->setResult("max(" + fieldName + ")", max(values)); - this->setResult("size(" + fieldName + ")", values.size()); -} - - -template -void Foam::probes::sampleAndWrite(const fieldGroup& fields) -{ - typedef GeometricField VolFieldType; - - for (const auto& fieldName : fields) - { - if (loadFromFiles_) - { - sampleAndWrite - ( - VolFieldType - ( - IOobject - ( - fieldName, - mesh_.time().timeName(), - mesh_, - IOobject::MUST_READ, - IOobject::NO_WRITE, - false - ), - mesh_ - ) - ); - } - else - { - objectRegistry::const_iterator iter = mesh_.find(fieldName); - - if (iter.found() && iter()->type() == VolFieldType::typeName) - { - sampleAndWrite(mesh_.lookupObject(fieldName)); + this->writeValues(fieldName, values, timeValue); } } } } -template -void Foam::probes::sampleAndWriteSurfaceFields(const fieldGroup& fields) -{ - typedef GeometricField SurfaceFieldType; - - for (const auto& fieldName : fields) - { - if (loadFromFiles_) - { - sampleAndWrite - ( - SurfaceFieldType - ( - IOobject - ( - fieldName, - mesh_.time().timeName(), - mesh_, - IOobject::MUST_READ, - IOobject::NO_WRITE, - false - ), - mesh_ - ) - ); - } - else - { - objectRegistry::const_iterator iter = mesh_.find(fieldName); - - if (iter.found() && iter()->type() == SurfaceFieldType::typeName) - { - sampleAndWrite(mesh_.lookupObject(fieldName)); - } - } - } -} - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template Foam::tmp> -Foam::probes::sample -( - const GeometricField& vField -) const +Foam::probes::sample(const VolumeField& vField) const { const Type unsetVal(-VGREAT*pTraits::one); - auto tValues = tmp>::New(Field(this->size(), unsetVal)); - auto& values = tValues.ref(); + auto tvalues = tmp>::New(Field(this->size(), unsetVal)); + auto& values = tvalues.ref(); if (fixedLocations_) { - autoPtr> interpolator + autoPtr> interpPtr ( - interpolation::New(interpolationScheme_, vField) + interpolation::New(samplePointScheme_, vField) ); forAll(*this, probei) @@ -236,7 +205,7 @@ Foam::probes::sample { const vector& position = operator[](probei); - values[probei] = interpolator().interpolate + values[probei] = interpPtr().interpolate ( position, elementList_[probei], @@ -259,35 +228,18 @@ Foam::probes::sample Pstream::listCombineGather(values, isNotEqOp()); Pstream::listCombineScatter(values); - return tValues; + return tvalues; } template Foam::tmp> -Foam::probes::sample(const word& fieldName) const -{ - return sample - ( - mesh_.lookupObject> - ( - fieldName - ) - ); -} - - -template -Foam::tmp> -Foam::probes::sample -( - const GeometricField& sField -) const +Foam::probes::sample(const SurfaceField& sField) const { const Type unsetVal(-VGREAT*pTraits::one); - auto tValues = tmp>::New(Field(this->size(), unsetVal)); - auto& values = tValues.ref(); + auto tvalues = tmp>::New(Field(this->size(), unsetVal)); + auto& values = tvalues.ref(); forAll(*this, probei) { @@ -300,21 +252,24 @@ Foam::probes::sample Pstream::listCombineGather(values, isNotEqOp()); Pstream::listCombineScatter(values); - return tValues; + return tvalues; } template Foam::tmp> -Foam::probes::sampleSurfaceFields(const word& fieldName) const +Foam::probes::sample(const word& fieldName) const { - return sample - ( - mesh_.lookupObject> - ( - fieldName - ) - ); + return sample(mesh_.lookupObject>(fieldName)); } + +template +Foam::tmp> +Foam::probes::sampleSurfaceField(const word& fieldName) const +{ + return sample(mesh_.lookupObject>(fieldName)); +} + + // ************************************************************************* // diff --git a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/probes b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/probes index 371870a929..867a6b5eb8 100644 --- a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/probes +++ b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/probes @@ -36,46 +36,40 @@ Volume3_v_fins probesFins { - type probes; + type probes; libs (sampling); writeControl timeStep; writeInterval 1; interpolationScheme cell; - region v_fins; - setFormat raw; - log true; - valueOutput false; - writeFields false; + region v_fins; + + fields ( T ); probeLocations ( (0.118 0.01 -0.125) (0.118 0.03 -0.125) ); - - fields ( T ); } probesFluid { - type probes; + type probes; libs (sampling); writeControl timeStep; writeInterval 1; interpolationScheme cell; - region domain0; - setFormat raw; + region domain0; log true; - valueOutput false; - writeFields false; + verbose true; + + fields (T U); probeLocations ( (0.118 0.035 -0.125) (0.118 0.07 -0.125) ); - - fields ( T U); } #remove (_volFieldValue _surfaceFieldValue)